Implement FlashesEntityMessage trait across multiple controllers for consistent flash messaging. Update flash messages in various methods to utilize the new trait, enhancing code maintainability and readability. Additionally, add attribute methods in request classes for improved validation feedback.

This commit is contained in:
Yoga Pangestu 2026-06-12 22:48:23 +07:00
parent a6e8c67910
commit eb2047a3e2
194 changed files with 3174 additions and 1078 deletions

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Admin\Account; namespace App\Http\Controllers\Admin\Account;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Account\UpdateAppearanceRequest; use App\Http\Requests\Admin\Account\UpdateAppearanceRequest;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
@ -11,6 +12,8 @@
class AppearanceController extends Controller class AppearanceController extends Controller
{ {
use FlashesEntityMessage;
public function edit(): Response public function edit(): Response
{ {
return Inertia::render('admin/account/Appearance', [ return Inertia::render('admin/account/Appearance', [
@ -22,7 +25,7 @@ public function update(UpdateAppearanceRequest $request): RedirectResponse
{ {
$appearance = $request->string('appearance')->toString(); $appearance = $request->string('appearance')->toString();
Inertia::flash('success', 'Tampilan berhasil diperbarui.'); $this->flashUpdated('Tampilan');
return redirect() return redirect()
->route('admin.account.appearance') ->route('admin.account.appearance')

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Admin\Account; namespace App\Http\Controllers\Admin\Account;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Account\UpdatePasswordRequest; use App\Http\Requests\Admin\Account\UpdatePasswordRequest;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
@ -11,6 +12,8 @@
class PasswordController extends Controller class PasswordController extends Controller
{ {
use FlashesEntityMessage;
public function edit(): Response public function edit(): Response
{ {
return Inertia::render('admin/account/Password'); return Inertia::render('admin/account/Password');
@ -19,10 +22,10 @@ public function edit(): Response
public function update(UpdatePasswordRequest $request): RedirectResponse public function update(UpdatePasswordRequest $request): RedirectResponse
{ {
$user = $request->user(); $user = $request->user();
$user->password = Hash::make($request->string('password')->toString()); $user->password = Hash::make($request->validated('password'));
$user->save(); $user->save();
Inertia::flash('success', 'Kata sandi berhasil diperbarui.'); $this->flashUpdated('Kata sandi');
return redirect()->route('admin.account.password'); return redirect()->route('admin.account.password');
} }

View File

@ -3,6 +3,7 @@
namespace App\Http\Controllers\Admin\Account; namespace App\Http\Controllers\Admin\Account;
use App\Enums\Gender; use App\Enums\Gender;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Account\UpdateProfileRequest; use App\Http\Requests\Admin\Account\UpdateProfileRequest;
use App\Services\Account\ProfileService; use App\Services\Account\ProfileService;
@ -12,6 +13,8 @@
class ProfileController extends Controller class ProfileController extends Controller
{ {
use FlashesEntityMessage;
public function __construct( public function __construct(
private readonly ProfileService $profileService, private readonly ProfileService $profileService,
) {} ) {}
@ -28,9 +31,9 @@ public function edit(): Response
public function update(UpdateProfileRequest $request): RedirectResponse public function update(UpdateProfileRequest $request): RedirectResponse
{ {
$this->profileService->update($request->validated()); $this->profileService->update($request->validated(), $request->user());
Inertia::flash('success', 'Profil berhasil diperbarui.'); $this->flashUpdated('Profil');
return redirect()->route('admin.account.profile'); return redirect()->route('admin.account.profile');
} }

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Admin\Finance; namespace App\Http\Controllers\Admin\Finance;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Concerns\ParsesDataTableQuery;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Finance\DepositCashRequest; use App\Http\Requests\Admin\Finance\DepositCashRequest;
@ -15,6 +16,7 @@
class CashController extends Controller class CashController extends Controller
{ {
use FlashesEntityMessage;
use ParsesDataTableQuery; use ParsesDataTableQuery;
public function __construct( public function __construct(
@ -39,7 +41,7 @@ public function deposit(DepositCashRequest $request): RedirectResponse
$this->cashService->deposit($cashAccount, $request->validated(), $request->user()); $this->cashService->deposit($cashAccount, $request->validated(), $request->user());
Inertia::flash('success', 'Setor kas berhasil dicatat.'); $this->flashSuccess('Setor kas berhasil dicatat.');
return redirect()->route('admin.finance.cash.index'); return redirect()->route('admin.finance.cash.index');
} }
@ -48,7 +50,7 @@ public function update(UpdateCashTransactionRequest $request, CashTransaction $c
{ {
$this->cashService->updateDeposit($cashTransaction, $request->validated()); $this->cashService->updateDeposit($cashTransaction, $request->validated());
Inertia::flash('success', 'Setor kas berhasil diperbarui.'); $this->flashSuccess('Setor kas berhasil diperbarui.');
return redirect()->route('admin.finance.cash.index'); return redirect()->route('admin.finance.cash.index');
} }
@ -57,7 +59,7 @@ public function destroy(CashTransaction $cashTransaction): RedirectResponse
{ {
$this->cashService->deleteTransaction($cashTransaction); $this->cashService->deleteTransaction($cashTransaction);
Inertia::flash('success', 'Setor kas berhasil dihapus.'); $this->flashSuccess('Setor kas berhasil dihapus.');
return redirect()->route('admin.finance.cash.index'); return redirect()->route('admin.finance.cash.index');
} }

View File

@ -3,6 +3,7 @@
namespace App\Http\Controllers\Admin\Finance; namespace App\Http\Controllers\Admin\Finance;
use App\Enums\Permission; use App\Enums\Permission;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Concerns\ParsesDataTableQuery;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Finance\EmployeeAdvanceRequest; use App\Http\Requests\Admin\Finance\EmployeeAdvanceRequest;
@ -16,6 +17,7 @@
class EmployeeAdvanceController extends Controller class EmployeeAdvanceController extends Controller
{ {
use FlashesEntityMessage;
use ParsesDataTableQuery; use ParsesDataTableQuery;
public function __construct( public function __construct(
@ -25,7 +27,7 @@ public function __construct(
public function index(Request $request): Response public function index(Request $request): Response
{ {
$tableQuery = $this->parseDataTableQuery($request); $tableQuery = $this->parseDataTableQuery($request);
$user = auth()->user(); $user = $request->user();
return Inertia::render('admin/finance/employee-advances/Index', [ return Inertia::render('admin/finance/employee-advances/Index', [
'employeeAdvances' => $this->employeeAdvanceService->paginateForIndex($tableQuery), 'employeeAdvances' => $this->employeeAdvanceService->paginateForIndex($tableQuery),
@ -40,18 +42,18 @@ public function index(Request $request): Response
public function store(EmployeeAdvanceRequest $request): RedirectResponse public function store(EmployeeAdvanceRequest $request): RedirectResponse
{ {
$this->employeeAdvanceService->create($request->validated()); $this->employeeAdvanceService->create($request->validated(), $request->user());
Inertia::flash('success', 'Kasbon berhasil diajukan.'); $this->flashSuccess('Kasbon berhasil diajukan.');
return redirect()->route('admin.finance.employee-advances.index'); return redirect()->route('admin.finance.employee-advances.index');
} }
public function update(EmployeeAdvanceRequest $request, EmployeeAdvance $employeeAdvance): RedirectResponse public function update(EmployeeAdvanceRequest $request, EmployeeAdvance $employeeAdvance): RedirectResponse
{ {
$this->employeeAdvanceService->update($employeeAdvance, $request->validated()); $this->employeeAdvanceService->update($employeeAdvance, $request->validated(), $request->user());
Inertia::flash('success', 'Kasbon berhasil diperbarui.'); $this->flashUpdated('Kasbon');
return redirect()->route('admin.finance.employee-advances.index'); return redirect()->route('admin.finance.employee-advances.index');
} }
@ -60,18 +62,18 @@ public function destroy(EmployeeAdvance $employeeAdvance): RedirectResponse
{ {
abort_unless(! auth()->user()?->can(Permission::EMPLOYEE_ADVANCES_VERIFY->value), 403); abort_unless(! auth()->user()?->can(Permission::EMPLOYEE_ADVANCES_VERIFY->value), 403);
$this->employeeAdvanceService->delete($employeeAdvance); $this->employeeAdvanceService->delete($employeeAdvance, auth()->user());
Inertia::flash('success', 'Kasbon berhasil dihapus.'); $this->flashDeleted('Kasbon');
return redirect()->route('admin.finance.employee-advances.index'); return redirect()->route('admin.finance.employee-advances.index');
} }
public function approve(EmployeeAdvance $employeeAdvance): RedirectResponse public function approve(EmployeeAdvance $employeeAdvance): RedirectResponse
{ {
$this->employeeAdvanceService->approve($employeeAdvance); $this->employeeAdvanceService->approve($employeeAdvance, auth()->user());
Inertia::flash('success', 'Kasbon disetujui dan dicairkan dari kas.'); $this->flashSuccess('Kasbon berhasil disetujui dan dicairkan dari kas.');
return redirect()->route('admin.finance.employee-advances.index'); return redirect()->route('admin.finance.employee-advances.index');
} }
@ -81,18 +83,19 @@ public function reject(RejectEmployeeAdvanceRequest $request, EmployeeAdvance $e
$this->employeeAdvanceService->reject( $this->employeeAdvanceService->reject(
$employeeAdvance, $employeeAdvance,
$request->validated('reason'), $request->validated('reason'),
auth()->user(),
); );
Inertia::flash('success', 'Kasbon berhasil ditolak.'); $this->flashSuccess('Kasbon berhasil ditolak.');
return redirect()->route('admin.finance.employee-advances.index'); return redirect()->route('admin.finance.employee-advances.index');
} }
public function pay(EmployeeAdvance $employeeAdvance): RedirectResponse public function pay(EmployeeAdvance $employeeAdvance): RedirectResponse
{ {
$this->employeeAdvanceService->pay($employeeAdvance); $this->employeeAdvanceService->pay($employeeAdvance, auth()->user());
Inertia::flash('success', 'Kasbon berhasil dilunasi.'); $this->flashSuccess('Kasbon berhasil dilunasi.');
return redirect()->route('admin.finance.employee-advances.index'); return redirect()->route('admin.finance.employee-advances.index');
} }

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Admin\Finance; namespace App\Http\Controllers\Admin\Finance;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Concerns\ParsesDataTableQuery;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Finance\ExpenseRequest; use App\Http\Requests\Admin\Finance\ExpenseRequest;
@ -14,6 +15,7 @@
class ExpenseController extends Controller class ExpenseController extends Controller
{ {
use FlashesEntityMessage;
use ParsesDataTableQuery; use ParsesDataTableQuery;
public function __construct( public function __construct(
@ -34,7 +36,7 @@ public function store(ExpenseRequest $request): RedirectResponse
{ {
$this->expenseService->create($request->validated(), $request->user()); $this->expenseService->create($request->validated(), $request->user());
Inertia::flash('success', 'Pengeluaran berhasil ditambahkan.'); $this->flashCreated('Pengeluaran');
return redirect()->route('admin.finance.expenses.index'); return redirect()->route('admin.finance.expenses.index');
} }
@ -43,7 +45,7 @@ public function update(ExpenseRequest $request, Expense $expense): RedirectRespo
{ {
$this->expenseService->update($expense, $request->validated()); $this->expenseService->update($expense, $request->validated());
Inertia::flash('success', 'Pengeluaran berhasil diperbarui.'); $this->flashUpdated('Pengeluaran');
return redirect()->route('admin.finance.expenses.index'); return redirect()->route('admin.finance.expenses.index');
} }
@ -52,7 +54,7 @@ public function destroy(Expense $expense): RedirectResponse
{ {
$this->expenseService->delete($expense); $this->expenseService->delete($expense);
Inertia::flash('success', 'Pengeluaran berhasil dihapus.'); $this->flashDeleted('Pengeluaran');
return redirect()->route('admin.finance.expenses.index'); return redirect()->route('admin.finance.expenses.index');
} }

View File

@ -2,15 +2,17 @@
namespace App\Http\Controllers\Admin\Finance; namespace App\Http\Controllers\Admin\Finance;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Finance\PayrollAdjustmentRequest; use App\Http\Requests\Admin\Finance\PayrollAdjustmentRequest;
use App\Models\Payroll; use App\Models\Payroll;
use App\Services\Finance\PayrollService; use App\Services\Finance\PayrollService;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Inertia\Inertia;
class PayrollController extends Controller class PayrollController extends Controller
{ {
use FlashesEntityMessage;
public function __construct( public function __construct(
private readonly PayrollService $payrollService, private readonly PayrollService $payrollService,
) {} ) {}
@ -19,7 +21,7 @@ public function pay(Payroll $payroll): RedirectResponse
{ {
$this->payrollService->pay($payroll, auth()->user()); $this->payrollService->pay($payroll, auth()->user());
Inertia::flash('success', 'Gaji berhasil dibayar.'); $this->flashSuccess('Gaji berhasil dibayar.');
return redirect()->route('admin.finance.payroll.index', [ return redirect()->route('admin.finance.payroll.index', [
'period_id' => $payroll->payroll_period_id, 'period_id' => $payroll->payroll_period_id,
@ -34,7 +36,7 @@ public function storeAdjustment(PayrollAdjustmentRequest $request, Payroll $payr
auth()->user(), auth()->user(),
); );
Inertia::flash('success', 'Penyesuaian gaji berhasil ditambahkan.'); $this->flashSuccess('Penyesuaian gaji berhasil ditambahkan.');
return redirect()->route('admin.finance.payroll.index', [ return redirect()->route('admin.finance.payroll.index', [
'period_id' => $payroll->payroll_period_id, 'period_id' => $payroll->payroll_period_id,

View File

@ -3,6 +3,7 @@
namespace App\Http\Controllers\Admin\Finance; namespace App\Http\Controllers\Admin\Finance;
use App\Enums\PayrollAdjustmentType; use App\Enums\PayrollAdjustmentType;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Concerns\ParsesDataTableQuery;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\PayrollPeriod; use App\Models\PayrollPeriod;
@ -14,6 +15,7 @@
class PayrollPeriodController extends Controller class PayrollPeriodController extends Controller
{ {
use FlashesEntityMessage;
use ParsesDataTableQuery; use ParsesDataTableQuery;
public function __construct( public function __construct(
@ -47,7 +49,7 @@ public function close(PayrollPeriod $payrollPeriod): RedirectResponse
{ {
$this->payrollService->closePeriod($payrollPeriod, auth()->user()); $this->payrollService->closePeriod($payrollPeriod, auth()->user());
Inertia::flash('success', 'Periode gaji berhasil ditutup.'); $this->flashSuccess('Periode gaji berhasil ditutup.');
return redirect()->route('admin.finance.payroll.index', [ return redirect()->route('admin.finance.payroll.index', [
'period_id' => $payrollPeriod->id, 'period_id' => $payrollPeriod->id,

View File

@ -3,6 +3,7 @@
namespace App\Http\Controllers\Admin\Hr; namespace App\Http\Controllers\Admin\Hr;
use App\Enums\Permission; use App\Enums\Permission;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Hr\AttendanceCheckInRequest; use App\Http\Requests\Admin\Hr\AttendanceCheckInRequest;
use App\Http\Requests\Admin\Hr\AttendanceCheckOutRequest; use App\Http\Requests\Admin\Hr\AttendanceCheckOutRequest;
@ -15,13 +16,15 @@
class AttendanceController extends Controller class AttendanceController extends Controller
{ {
use FlashesEntityMessage;
public function __construct( public function __construct(
private readonly AttendanceService $attendanceService, private readonly AttendanceService $attendanceService,
) {} ) {}
public function index(Request $request): Response public function index(Request $request): Response
{ {
$user = auth()->user(); $user = $request->user();
$employee = $user?->employee; $employee = $user?->employee;
$canManageAll = $user?->can(Permission::ATTENDANCES_MANAGE->value) ?? false; $canManageAll = $user?->can(Permission::ATTENDANCES_MANAGE->value) ?? false;
@ -53,18 +56,18 @@ public function index(Request $request): Response
public function checkIn(AttendanceCheckInRequest $request): RedirectResponse public function checkIn(AttendanceCheckInRequest $request): RedirectResponse
{ {
$this->attendanceService->checkIn($request->validated()); $this->attendanceService->checkIn($request->validated(), $request->user());
Inertia::flash('success', 'Presensi masuk berhasil dicatat.'); $this->flashSuccess('Presensi masuk berhasil dicatat.');
return redirect()->route('admin.hr.attendances.index'); return redirect()->route('admin.hr.attendances.index');
} }
public function checkOut(AttendanceCheckOutRequest $request): RedirectResponse public function checkOut(AttendanceCheckOutRequest $request): RedirectResponse
{ {
$this->attendanceService->checkOut($request->validated()); $this->attendanceService->checkOut($request->validated(), $request->user());
Inertia::flash('success', 'Presensi pulang berhasil dicatat.'); $this->flashSuccess('Presensi pulang berhasil dicatat.');
return redirect()->route('admin.hr.attendances.index'); return redirect()->route('admin.hr.attendances.index');
} }
@ -73,7 +76,7 @@ public function destroy(Attendance $attendance): RedirectResponse
{ {
$this->attendanceService->delete($attendance); $this->attendanceService->delete($attendance);
Inertia::flash('success', 'Data presensi berhasil dihapus.'); $this->flashDeleted('Data presensi');
return redirect()->route('admin.hr.attendances.index'); return redirect()->route('admin.hr.attendances.index');
} }

View File

@ -5,6 +5,7 @@
use App\Enums\EmploymentStatus; use App\Enums\EmploymentStatus;
use App\Enums\Gender; use App\Enums\Gender;
use App\Enums\Role; use App\Enums\Role;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Concerns\ParsesDataTableQuery;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Hr\EmployeeRequest; use App\Http\Requests\Admin\Hr\EmployeeRequest;
@ -17,6 +18,7 @@
class EmployeeController extends Controller class EmployeeController extends Controller
{ {
use FlashesEntityMessage;
use ParsesDataTableQuery; use ParsesDataTableQuery;
public function __construct( public function __construct(
@ -50,7 +52,7 @@ public function store(EmployeeRequest $request): RedirectResponse
{ {
$this->employeeService->create($request->validated()); $this->employeeService->create($request->validated());
Inertia::flash('success', 'Pegawai berhasil ditambahkan.'); $this->flashCreated('Pegawai');
return redirect()->route('admin.hr.employees.index'); return redirect()->route('admin.hr.employees.index');
} }
@ -71,7 +73,7 @@ public function update(EmployeeRequest $request, User $user): RedirectResponse
{ {
$this->employeeService->update($user, $request->validated()); $this->employeeService->update($user, $request->validated());
Inertia::flash('success', 'Data pegawai berhasil diperbarui.'); $this->flashSuccess('Data pegawai berhasil diperbarui.');
return redirect()->route('admin.hr.employees.index'); return redirect()->route('admin.hr.employees.index');
} }
@ -84,7 +86,7 @@ public function toggleStatus(Request $request, User $user): RedirectResponse
$this->employeeService->toggleStatus($user, $validated['is_active']); $this->employeeService->toggleStatus($user, $validated['is_active']);
Inertia::flash('success', 'Status pegawai berhasil diperbarui.'); $this->flashStatusUpdated('pegawai');
return back(); return back();
} }
@ -93,7 +95,7 @@ public function resetPassword(User $user): RedirectResponse
{ {
$this->employeeService->resetPassword($user); $this->employeeService->resetPassword($user);
Inertia::flash('success', 'Kata sandi berhasil direset. Pengguna telah logout dari semua sesi.'); $this->flashSuccess('Kata sandi berhasil direset. Pengguna telah logout dari semua sesi.');
return back(); return back();
} }
@ -102,7 +104,7 @@ public function destroy(User $user): RedirectResponse
{ {
$this->employeeService->delete($user); $this->employeeService->delete($user);
Inertia::flash('success', 'Pegawai berhasil dihapus.'); $this->flashDeleted('Pegawai');
return redirect()->route('admin.hr.employees.index'); return redirect()->route('admin.hr.employees.index');
} }

View File

@ -3,6 +3,7 @@
namespace App\Http\Controllers\Admin\Hr; namespace App\Http\Controllers\Admin\Hr;
use App\Enums\Permission; use App\Enums\Permission;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Concerns\ParsesDataTableQuery;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Hr\RejectLeaveRequestRequest; use App\Http\Requests\Admin\Hr\RejectLeaveRequestRequest;
@ -16,6 +17,7 @@
class LeaveRequestController extends Controller class LeaveRequestController extends Controller
{ {
use FlashesEntityMessage;
use ParsesDataTableQuery; use ParsesDataTableQuery;
public function __construct( public function __construct(
@ -25,7 +27,7 @@ public function __construct(
public function index(Request $request): Response public function index(Request $request): Response
{ {
$tableQuery = $this->parseDataTableQuery($request); $tableQuery = $this->parseDataTableQuery($request);
$user = auth()->user(); $user = $request->user();
return Inertia::render('admin/hr/leave-requests/Index', [ return Inertia::render('admin/hr/leave-requests/Index', [
'leaveRequests' => $this->leaveRequestService->paginateForIndex($tableQuery), 'leaveRequests' => $this->leaveRequestService->paginateForIndex($tableQuery),
@ -39,18 +41,18 @@ public function index(Request $request): Response
public function store(SubmitLeaveRequest $request): RedirectResponse public function store(SubmitLeaveRequest $request): RedirectResponse
{ {
$this->leaveRequestService->create($request->validated()); $this->leaveRequestService->create($request->validated(), $request->user());
Inertia::flash('success', 'Pengajuan cuti berhasil diajukan.'); $this->flashSuccess('Pengajuan cuti berhasil diajukan.');
return redirect()->route('admin.hr.leave-requests.index'); return redirect()->route('admin.hr.leave-requests.index');
} }
public function update(SubmitLeaveRequest $request, LeaveRequest $leaveRequest): RedirectResponse public function update(SubmitLeaveRequest $request, LeaveRequest $leaveRequest): RedirectResponse
{ {
$this->leaveRequestService->update($leaveRequest, $request->validated()); $this->leaveRequestService->update($leaveRequest, $request->validated(), $request->user());
Inertia::flash('success', 'Pengajuan cuti berhasil diperbarui.'); $this->flashUpdated('Pengajuan cuti');
return redirect()->route('admin.hr.leave-requests.index'); return redirect()->route('admin.hr.leave-requests.index');
} }
@ -59,18 +61,18 @@ public function destroy(LeaveRequest $leaveRequest): RedirectResponse
{ {
abort_unless(! auth()->user()?->can(Permission::LEAVE_REQUESTS_VERIFY->value), 403); abort_unless(! auth()->user()?->can(Permission::LEAVE_REQUESTS_VERIFY->value), 403);
$this->leaveRequestService->delete($leaveRequest); $this->leaveRequestService->delete($leaveRequest, auth()->user());
Inertia::flash('success', 'Pengajuan cuti berhasil dihapus.'); $this->flashDeleted('Pengajuan cuti');
return redirect()->route('admin.hr.leave-requests.index'); return redirect()->route('admin.hr.leave-requests.index');
} }
public function approve(LeaveRequest $leaveRequest): RedirectResponse public function approve(LeaveRequest $leaveRequest): RedirectResponse
{ {
$this->leaveRequestService->approve($leaveRequest); $this->leaveRequestService->approve($leaveRequest, auth()->user());
Inertia::flash('success', 'Pengajuan cuti disetujui.'); $this->flashSuccess('Pengajuan cuti berhasil disetujui.');
return redirect()->route('admin.hr.leave-requests.index'); return redirect()->route('admin.hr.leave-requests.index');
} }
@ -80,9 +82,10 @@ public function reject(RejectLeaveRequestRequest $request, LeaveRequest $leaveRe
$this->leaveRequestService->reject( $this->leaveRequestService->reject(
$leaveRequest, $leaveRequest,
$request->validated('reason'), $request->validated('reason'),
auth()->user(),
); );
Inertia::flash('success', 'Pengajuan cuti berhasil ditolak.'); $this->flashSuccess('Pengajuan cuti berhasil ditolak.');
return redirect()->route('admin.hr.leave-requests.index'); return redirect()->route('admin.hr.leave-requests.index');
} }

View File

@ -3,6 +3,7 @@
namespace App\Http\Controllers\Admin\Manage; namespace App\Http\Controllers\Admin\Manage;
use App\Enums\CuttingStatus; use App\Enums\CuttingStatus;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Concerns\ParsesDataTableQuery;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Manage\CuttingRequest; use App\Http\Requests\Admin\Manage\CuttingRequest;
@ -16,6 +17,7 @@
class CuttingController extends Controller class CuttingController extends Controller
{ {
use FlashesEntityMessage;
use ParsesDataTableQuery; use ParsesDataTableQuery;
public function __construct( public function __construct(
@ -44,7 +46,7 @@ public function store(CuttingRequest $request): RedirectResponse
{ {
$this->cuttingService->create($request->validated(), $request->user()); $this->cuttingService->create($request->validated(), $request->user());
Inertia::flash('success', 'Cutting berhasil ditambahkan.'); $this->flashCreated('Proses potong');
return redirect()->route('admin.manage.cuttings.index'); return redirect()->route('admin.manage.cuttings.index');
} }
@ -52,7 +54,7 @@ public function store(CuttingRequest $request): RedirectResponse
public function edit(Cutting $cutting): Response|RedirectResponse public function edit(Cutting $cutting): Response|RedirectResponse
{ {
if (! $cutting->status->isEditable()) { if (! $cutting->status->isEditable()) {
Inertia::flash('error', 'Cutting tidak dapat diubah.'); $this->flashError('Proses potong tidak dapat diubah.');
return redirect()->route('admin.manage.cuttings.index'); return redirect()->route('admin.manage.cuttings.index');
} }
@ -68,7 +70,7 @@ public function update(CuttingRequest $request, Cutting $cutting): RedirectRespo
{ {
$this->cuttingService->update($cutting, $request->validated()); $this->cuttingService->update($cutting, $request->validated());
Inertia::flash('success', 'Cutting berhasil diperbarui.'); $this->flashUpdated('Proses potong');
return redirect()->route('admin.manage.cuttings.index'); return redirect()->route('admin.manage.cuttings.index');
} }
@ -77,7 +79,7 @@ public function destroy(Cutting $cutting): RedirectResponse
{ {
$this->cuttingService->delete($cutting); $this->cuttingService->delete($cutting);
Inertia::flash('success', 'Cutting berhasil dihapus.'); $this->flashDeleted('Proses potong');
return redirect()->route('admin.manage.cuttings.index'); return redirect()->route('admin.manage.cuttings.index');
} }
@ -89,18 +91,19 @@ public function transitionStatus(CuttingStatusTransitionRequest $request, Cuttin
$this->cuttingService->transitionStatus( $this->cuttingService->transitionStatus(
$cutting, $cutting,
$status, $status,
$request->user(),
$request->validated('reason'), $request->validated('reason'),
); );
$message = match ($status) { $message = match ($status) {
CuttingStatus::COMPLETED => 'Cutting berhasil diselesaikan. Menunggu verifikasi admin toko.', CuttingStatus::COMPLETED => 'Proses potong berhasil diselesaikan. Menunggu verifikasi admin toko.',
CuttingStatus::VERIFIED => 'Cutting berhasil diverifikasi. Stok produk telah diperbarui.', CuttingStatus::VERIFIED => 'Proses potong berhasil diverifikasi. Stok produk telah diperbarui.',
CuttingStatus::REJECTED => 'Cutting ditolak.', CuttingStatus::REJECTED => 'Proses potong berhasil ditolak.',
CuttingStatus::IN_PROGRESS => 'Cutting dikembalikan ke proses.', CuttingStatus::IN_PROGRESS => 'Proses potong dikembalikan ke proses.',
default => 'Status cutting berhasil diperbarui.', default => 'Status proses potong berhasil diperbarui.',
}; };
Inertia::flash('success', $message); $this->flashSuccess($message);
return redirect()->route('admin.manage.cuttings.index'); return redirect()->route('admin.manage.cuttings.index');
} }

View File

@ -4,6 +4,7 @@
use App\Enums\OrderChannel; use App\Enums\OrderChannel;
use App\Enums\OrderStatus; use App\Enums\OrderStatus;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Concerns\ParsesDataTableQuery;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Manage\OrderRequest; use App\Http\Requests\Admin\Manage\OrderRequest;
@ -17,6 +18,7 @@
class OrderController extends Controller class OrderController extends Controller
{ {
use FlashesEntityMessage;
use ParsesDataTableQuery; use ParsesDataTableQuery;
public function __construct( public function __construct(
@ -47,7 +49,7 @@ public function store(OrderRequest $request): RedirectResponse
{ {
$this->orderService->create($request->validated(), $request->user()); $this->orderService->create($request->validated(), $request->user());
Inertia::flash('success', 'Pesanan berhasil ditambahkan.'); $this->flashCreated('Pesanan');
return redirect()->route('admin.manage.orders.index'); return redirect()->route('admin.manage.orders.index');
} }
@ -55,7 +57,7 @@ public function store(OrderRequest $request): RedirectResponse
public function edit(Order $order): Response|RedirectResponse public function edit(Order $order): Response|RedirectResponse
{ {
if (! $order->status->isEditable()) { if (! $order->status->isEditable()) {
Inertia::flash('error', 'Pesanan tidak dapat diubah.'); $this->flashError('Pesanan tidak dapat diubah.');
return redirect()->route('admin.manage.orders.index'); return redirect()->route('admin.manage.orders.index');
} }
@ -73,7 +75,7 @@ public function update(OrderRequest $request, Order $order): RedirectResponse
{ {
$this->orderService->update($order, $request->validated()); $this->orderService->update($order, $request->validated());
Inertia::flash('success', 'Pesanan berhasil diperbarui.'); $this->flashUpdated('Pesanan');
return redirect()->route('admin.manage.orders.index'); return redirect()->route('admin.manage.orders.index');
} }
@ -82,7 +84,7 @@ public function destroy(Order $order): RedirectResponse
{ {
$this->orderService->delete($order); $this->orderService->delete($order);
Inertia::flash('success', 'Pesanan berhasil dihapus.'); $this->flashDeleted('Pesanan');
return redirect()->route('admin.manage.orders.index'); return redirect()->route('admin.manage.orders.index');
} }
@ -100,7 +102,7 @@ public function transitionStatus(OrderStatusTransitionRequest $request, Order $o
default => 'Status pesanan berhasil diperbarui.', default => 'Status pesanan berhasil diperbarui.',
}; };
Inertia::flash('success', $message); $this->flashSuccess($message);
return redirect()->route('admin.manage.orders.index'); return redirect()->route('admin.manage.orders.index');
} }

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Admin\Manage; namespace App\Http\Controllers\Admin\Manage;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Concerns\ParsesDataTableQuery;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Manage\PurchaseRequest; use App\Http\Requests\Admin\Manage\PurchaseRequest;
@ -14,6 +15,7 @@
class PurchaseController extends Controller class PurchaseController extends Controller
{ {
use FlashesEntityMessage;
use ParsesDataTableQuery; use ParsesDataTableQuery;
public function __construct( public function __construct(
@ -42,7 +44,7 @@ public function store(PurchaseRequest $request): RedirectResponse
{ {
$this->purchaseService->create($request->validated(), $request->user()); $this->purchaseService->create($request->validated(), $request->user());
Inertia::flash('success', 'Belanja berhasil ditambahkan.'); $this->flashCreated('Belanja');
return redirect()->route('admin.manage.purchases.index'); return redirect()->route('admin.manage.purchases.index');
} }
@ -60,7 +62,7 @@ public function update(PurchaseRequest $request, Purchase $purchase): RedirectRe
{ {
$this->purchaseService->update($purchase, $request->validated()); $this->purchaseService->update($purchase, $request->validated());
Inertia::flash('success', 'Belanja berhasil diperbarui.'); $this->flashUpdated('Belanja');
return redirect()->route('admin.manage.purchases.index'); return redirect()->route('admin.manage.purchases.index');
} }
@ -69,7 +71,7 @@ public function destroy(Purchase $purchase): RedirectResponse
{ {
$this->purchaseService->delete($purchase); $this->purchaseService->delete($purchase);
Inertia::flash('success', 'Belanja berhasil dihapus.'); $this->flashDeleted('Belanja');
return redirect()->route('admin.manage.purchases.index'); return redirect()->route('admin.manage.purchases.index');
} }

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Admin\Master; namespace App\Http\Controllers\Admin\Master;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Concerns\ParsesDataTableQuery;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Master\CategoryRequest; use App\Http\Requests\Admin\Master\CategoryRequest;
@ -14,6 +15,7 @@
class CategoryController extends Controller class CategoryController extends Controller
{ {
use FlashesEntityMessage;
use ParsesDataTableQuery; use ParsesDataTableQuery;
public function __construct( public function __construct(
@ -34,7 +36,7 @@ public function store(CategoryRequest $request): RedirectResponse
{ {
$this->categoryService->create($request->validated()); $this->categoryService->create($request->validated());
Inertia::flash('success', 'Kategori berhasil ditambahkan.'); $this->flashCreated('Kategori');
return redirect()->route('admin.master.categories.index'); return redirect()->route('admin.master.categories.index');
} }
@ -43,7 +45,7 @@ public function update(CategoryRequest $request, Category $category): RedirectRe
{ {
$this->categoryService->update($category, $request->validated()); $this->categoryService->update($category, $request->validated());
Inertia::flash('success', 'Kategori berhasil diperbarui.'); $this->flashUpdated('Kategori');
return redirect()->route('admin.master.categories.index'); return redirect()->route('admin.master.categories.index');
} }
@ -52,7 +54,7 @@ public function destroy(Category $category): RedirectResponse
{ {
$this->categoryService->delete($category); $this->categoryService->delete($category);
Inertia::flash('success', 'Kategori berhasil dihapus.'); $this->flashDeleted('Kategori');
return redirect()->route('admin.master.categories.index'); return redirect()->route('admin.master.categories.index');
} }

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Admin\Master; namespace App\Http\Controllers\Admin\Master;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Concerns\ParsesDataTableQuery;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Master\CustomerRequest; use App\Http\Requests\Admin\Master\CustomerRequest;
@ -14,6 +15,7 @@
class CustomerController extends Controller class CustomerController extends Controller
{ {
use FlashesEntityMessage;
use ParsesDataTableQuery; use ParsesDataTableQuery;
public function __construct( public function __construct(
@ -34,7 +36,7 @@ public function store(CustomerRequest $request): RedirectResponse
{ {
$this->customerService->create($request->validated()); $this->customerService->create($request->validated());
Inertia::flash('success', 'Customer berhasil ditambahkan.'); $this->flashCreated('Pelanggan');
return redirect()->route('admin.master.customers.index'); return redirect()->route('admin.master.customers.index');
} }
@ -43,7 +45,7 @@ public function update(CustomerRequest $request, Customer $customer): RedirectRe
{ {
$this->customerService->update($customer, $request->validated()); $this->customerService->update($customer, $request->validated());
Inertia::flash('success', 'Customer berhasil diperbarui.'); $this->flashUpdated('Pelanggan');
return redirect()->route('admin.master.customers.index'); return redirect()->route('admin.master.customers.index');
} }
@ -52,7 +54,7 @@ public function destroy(Customer $customer): RedirectResponse
{ {
$this->customerService->delete($customer); $this->customerService->delete($customer);
Inertia::flash('success', 'Customer berhasil dihapus.'); $this->flashDeleted('Pelanggan');
return redirect()->route('admin.master.customers.index'); return redirect()->route('admin.master.customers.index');
} }

View File

@ -3,6 +3,7 @@
namespace App\Http\Controllers\Admin\Master; namespace App\Http\Controllers\Admin\Master;
use App\Enums\PriceType; use App\Enums\PriceType;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Concerns\ParsesDataTableQuery;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Master\ProductRequest; use App\Http\Requests\Admin\Master\ProductRequest;
@ -17,6 +18,7 @@
class ProductController extends Controller class ProductController extends Controller
{ {
use FlashesEntityMessage;
use ParsesDataTableQuery; use ParsesDataTableQuery;
public function __construct( public function __construct(
@ -48,7 +50,7 @@ public function store(ProductRequest $request): RedirectResponse
{ {
$this->productService->create($request->validated()); $this->productService->create($request->validated());
Inertia::flash('success', 'Produk berhasil ditambahkan.'); $this->flashCreated('Produk');
return redirect()->route('admin.master.products.index'); return redirect()->route('admin.master.products.index');
} }
@ -77,7 +79,7 @@ public function update(ProductRequest $request, Product $product): RedirectRespo
{ {
$this->productService->update($product, $request->validated()); $this->productService->update($product, $request->validated());
Inertia::flash('success', 'Produk berhasil diperbarui.'); $this->flashUpdated('Produk');
return redirect()->route('admin.master.products.index'); return redirect()->route('admin.master.products.index');
} }
@ -90,7 +92,7 @@ public function toggleStatus(Request $request, Product $product): RedirectRespon
$this->productService->toggleStatus($product, $validated['is_active']); $this->productService->toggleStatus($product, $validated['is_active']);
Inertia::flash('success', 'Status produk berhasil diperbarui.'); $this->flashStatusUpdated('produk');
return back(); return back();
} }
@ -99,7 +101,7 @@ public function destroy(Product $product): RedirectResponse
{ {
$this->productService->delete($product); $this->productService->delete($product);
Inertia::flash('success', 'Produk berhasil dihapus.'); $this->flashDeleted('Produk');
return redirect()->route('admin.master.products.index'); return redirect()->route('admin.master.products.index');
} }

View File

@ -3,6 +3,7 @@
namespace App\Http\Controllers\Admin\Master; namespace App\Http\Controllers\Admin\Master;
use App\Enums\RawMaterialUnit; use App\Enums\RawMaterialUnit;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Concerns\ParsesDataTableQuery;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Master\RawMaterialRequest; use App\Http\Requests\Admin\Master\RawMaterialRequest;
@ -17,6 +18,7 @@
class RawMaterialController extends Controller class RawMaterialController extends Controller
{ {
use FlashesEntityMessage;
use ParsesDataTableQuery; use ParsesDataTableQuery;
public function __construct( public function __construct(
@ -47,7 +49,7 @@ public function store(RawMaterialRequest $request): RedirectResponse
{ {
$this->rawMaterialService->create($request->validated()); $this->rawMaterialService->create($request->validated());
Inertia::flash('success', 'Bahan baku berhasil ditambahkan.'); $this->flashCreated('Bahan baku');
return redirect()->route('admin.master.raw-materials.index'); return redirect()->route('admin.master.raw-materials.index');
} }
@ -72,7 +74,7 @@ public function update(RawMaterialRequest $request, RawMaterial $rawMaterial): R
{ {
$this->rawMaterialService->update($rawMaterial, $request->validated()); $this->rawMaterialService->update($rawMaterial, $request->validated());
Inertia::flash('success', 'Bahan baku berhasil diperbarui.'); $this->flashUpdated('Bahan baku');
return redirect()->route('admin.master.raw-materials.index'); return redirect()->route('admin.master.raw-materials.index');
} }
@ -85,7 +87,7 @@ public function toggleStatus(Request $request, RawMaterial $rawMaterial): Redire
$this->rawMaterialService->toggleStatus($rawMaterial, $validated['is_active']); $this->rawMaterialService->toggleStatus($rawMaterial, $validated['is_active']);
Inertia::flash('success', 'Status bahan baku berhasil diperbarui.'); $this->flashStatusUpdated('bahan baku');
return back(); return back();
} }
@ -94,7 +96,7 @@ public function destroy(RawMaterial $rawMaterial): RedirectResponse
{ {
$this->rawMaterialService->delete($rawMaterial); $this->rawMaterialService->delete($rawMaterial);
Inertia::flash('success', 'Bahan baku berhasil dihapus.'); $this->flashDeleted('Bahan baku');
return redirect()->route('admin.master.raw-materials.index'); return redirect()->route('admin.master.raw-materials.index');
} }

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Admin\Master; namespace App\Http\Controllers\Admin\Master;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Concerns\ParsesDataTableQuery;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Master\SupplierRequest; use App\Http\Requests\Admin\Master\SupplierRequest;
@ -14,6 +15,7 @@
class SupplierController extends Controller class SupplierController extends Controller
{ {
use FlashesEntityMessage;
use ParsesDataTableQuery; use ParsesDataTableQuery;
public function __construct( public function __construct(
@ -34,7 +36,7 @@ public function store(SupplierRequest $request): RedirectResponse
{ {
$this->supplierService->create($request->validated()); $this->supplierService->create($request->validated());
Inertia::flash('success', 'Supplier berhasil ditambahkan.'); $this->flashCreated('Pemasok');
return redirect()->route('admin.master.suppliers.index'); return redirect()->route('admin.master.suppliers.index');
} }
@ -43,7 +45,7 @@ public function update(SupplierRequest $request, Supplier $supplier): RedirectRe
{ {
$this->supplierService->update($supplier, $request->validated()); $this->supplierService->update($supplier, $request->validated());
Inertia::flash('success', 'Supplier berhasil diperbarui.'); $this->flashUpdated('Pemasok');
return redirect()->route('admin.master.suppliers.index'); return redirect()->route('admin.master.suppliers.index');
} }
@ -52,7 +54,7 @@ public function destroy(Supplier $supplier): RedirectResponse
{ {
$this->supplierService->delete($supplier); $this->supplierService->delete($supplier);
Inertia::flash('success', 'Supplier berhasil dihapus.'); $this->flashDeleted('Pemasok');
return redirect()->route('admin.master.suppliers.index'); return redirect()->route('admin.master.suppliers.index');
} }

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Admin\System; namespace App\Http\Controllers\Admin\System;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\System\Setting\MarketplaceRequest; use App\Http\Requests\Admin\System\Setting\MarketplaceRequest;
use App\Http\Requests\Admin\System\Setting\SocialMediaRequest; use App\Http\Requests\Admin\System\Setting\SocialMediaRequest;
@ -15,6 +16,8 @@
class SettingController extends Controller class SettingController extends Controller
{ {
use FlashesEntityMessage;
public function __construct( public function __construct(
private readonly SystemService $systemService, private readonly SystemService $systemService,
private readonly SocialMediaService $socialMediaService, private readonly SocialMediaService $socialMediaService,
@ -34,7 +37,7 @@ public function updateSystem(SystemRequest $request): RedirectResponse
{ {
$this->systemService->updateSystem($request->validated()); $this->systemService->updateSystem($request->validated());
Inertia::flash('success', 'Pengaturan sistem berhasil disimpan.'); $this->flashSuccess('Pengaturan sistem berhasil disimpan.');
return redirect()->route('admin.system.setting.index'); return redirect()->route('admin.system.setting.index');
} }
@ -43,7 +46,7 @@ public function updateSocialMedia(SocialMediaRequest $request): RedirectResponse
{ {
$this->socialMediaService->updateSocialMedia($request->validated()); $this->socialMediaService->updateSocialMedia($request->validated());
Inertia::flash('success', 'Pengaturan media sosial berhasil disimpan.'); $this->flashSuccess('Pengaturan media sosial berhasil disimpan.');
return redirect()->route('admin.system.setting.index'); return redirect()->route('admin.system.setting.index');
} }
@ -52,7 +55,7 @@ public function updateMarketplace(MarketplaceRequest $request): RedirectResponse
{ {
$this->marketplaceService->updateMarketplace($request->validated()); $this->marketplaceService->updateMarketplace($request->validated());
Inertia::flash('success', 'Pengaturan marketplace berhasil disimpan.'); $this->flashSuccess('Pengaturan marketplace berhasil disimpan.');
return redirect()->route('admin.system.setting.index'); return redirect()->route('admin.system.setting.index');
} }

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Auth; namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\LoginRequest; use App\Http\Requests\Auth\LoginRequest;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
@ -10,6 +11,8 @@
class LoginController extends Controller class LoginController extends Controller
{ {
use FlashesEntityMessage;
public function index(): Response public function index(): Response
{ {
return Inertia::render('auth/Login'); return Inertia::render('auth/Login');
@ -30,8 +33,8 @@ public function store(LoginRequest $request): RedirectResponse
$user?->update(['last_login_at' => now()]); $user?->update(['last_login_at' => now()]);
return redirect() $this->flashSuccess('Berhasil masuk. Selamat datang kembali!');
->intended(route('admin.dashboard'))
->with('success', 'Berhasil masuk. Selamat datang kembali!'); return redirect()->intended(route('admin.dashboard'));
} }
} }

View File

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Auth; namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
@ -9,6 +10,8 @@
class LogoutController extends Controller class LogoutController extends Controller
{ {
use FlashesEntityMessage;
public function store(Request $request): RedirectResponse public function store(Request $request): RedirectResponse
{ {
if ($user = $request->user()) { if ($user = $request->user()) {
@ -23,8 +26,8 @@ public function store(Request $request): RedirectResponse
$request->session()->invalidate(); $request->session()->invalidate();
$request->session()->regenerateToken(); $request->session()->regenerateToken();
return redirect() $this->flashSuccess('Anda berhasil keluar.');
->route('login')
->with('success', 'Anda berhasil keluar.'); return redirect()->route('login');
} }
} }

View File

@ -0,0 +1,38 @@
<?php
namespace App\Http\Controllers\Concerns;
use Inertia\Inertia;
trait FlashesEntityMessage
{
protected function flashCreated(string $entity): void
{
Inertia::flash('success', "{$entity} berhasil ditambahkan.");
}
protected function flashUpdated(string $entity): void
{
Inertia::flash('success', "{$entity} berhasil diperbarui.");
}
protected function flashDeleted(string $entity): void
{
Inertia::flash('success', "{$entity} berhasil dihapus.");
}
protected function flashStatusUpdated(string $entity): void
{
Inertia::flash('success', "Status {$entity} berhasil diperbarui.");
}
protected function flashSuccess(string $message): void
{
Inertia::flash('success', $message);
}
protected function flashError(string $message): void
{
Inertia::flash('error', $message);
}
}

View File

@ -12,10 +12,23 @@ public function authorize(): bool
return auth()->check(); return auth()->check();
} }
/**
* @return array<string, mixed>
*/
public function rules(): array public function rules(): array
{ {
return [ return [
'appearance' => ['required', Rule::in(['light', 'dark', 'system'])], 'appearance' => ['required', Rule::in(['light', 'dark', 'system'])],
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'appearance' => 'tampilan',
];
}
} }

View File

@ -12,6 +12,9 @@ public function authorize(): bool
return auth()->check(); return auth()->check();
} }
/**
* @return array<string, mixed>
*/
public function rules(): array public function rules(): array
{ {
return [ return [
@ -19,4 +22,16 @@ public function rules(): array
'password' => ['required', 'confirmed', Password::defaults()], 'password' => ['required', 'confirmed', Password::defaults()],
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'current_password' => 'kata sandi saat ini',
'password' => 'kata sandi baru',
'password_confirmation' => 'konfirmasi kata sandi baru',
];
}
} }

View File

@ -13,16 +13,35 @@ public function authorize(): bool
return auth()->check(); return auth()->check();
} }
/**
* @return array<string, mixed>
*/
public function rules(): array public function rules(): array
{ {
return [ return [
'email' => ['required', 'email', 'max:100', Rule::unique('users', 'email')->ignore($this->user()?->id)], 'email' => ['required', 'email', 'max:100', Rule::unique('users', 'email')->ignore($this->user()?->id)],
'username' => ['required', 'string', 'max:20', 'alpha_dash', Rule::unique('users', 'username')->ignore($this->user()?->id)], 'username' => ['required', 'string', 'max:20', 'alpha_dash', Rule::unique('users', 'username')->ignore($this->user()?->id)],
'full_name' => ['required', 'string', 'max:200'], 'full_name' => ['required', 'string', 'max:200'],
'phone_number' => ['nullable', 'string', 'regex:/^08\d{8,11}$/'], 'phone_number' => ['nullable', 'string', 'max:20', 'regex:/^08\d{8,11}$/'],
'gender' => ['nullable', Rule::enum(Gender::class)], 'gender' => ['nullable', Rule::enum(Gender::class)],
'birth_date' => ['nullable', 'date', 'before:today'], 'birth_date' => ['nullable', 'date', 'before:today'],
'address' => ['nullable', 'string'], 'address' => ['nullable', 'string'],
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'email' => 'email',
'username' => 'username',
'full_name' => 'nama lengkap',
'phone_number' => 'nomor telepon',
'gender' => 'jenis kelamin',
'birth_date' => 'tanggal lahir',
'address' => 'alamat',
];
}
} }

View File

@ -15,12 +15,27 @@ public function authorize(): bool
return $this->user()?->can(Permission::CASH_DEPOSIT->value) ?? false; return $this->user()?->can(Permission::CASH_DEPOSIT->value) ?? false;
} }
/**
* @return array<string, mixed>
*/
public function rules(): array public function rules(): array
{ {
return [ return [
'amount' => ['required', 'integer', 'min:1'], 'amount' => ['required', 'integer', 'min:1'],
'description' => ['required', 'string', 'max:200'], 'description' => ['required', 'string', 'max:100'],
...$this->photoRules(), ...$this->photoRules(),
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'amount' => 'jumlah',
'description' => 'keterangan',
...$this->photoUploadAttributes('foto bukti'),
];
}
} }

View File

@ -43,9 +43,22 @@ public function rules(): array
{ {
return [ return [
'amount' => ['required', 'integer', 'min:1'], 'amount' => ['required', 'integer', 'min:1'],
'description' => ['required', 'string', 'max:500'], 'description' => ['required', 'string', 'max:100'],
'due_date' => ['required', 'date'], 'due_date' => ['required', 'date'],
...$this->photoRules(), ...$this->photoRules(),
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'amount' => 'jumlah',
'description' => 'keterangan',
'due_date' => 'jatuh tempo',
...$this->photoUploadAttributes('foto bukti'),
];
}
} }

View File

@ -26,8 +26,20 @@ public function rules(): array
{ {
return [ return [
'amount' => ['required', 'integer', 'min:1'], 'amount' => ['required', 'integer', 'min:1'],
'description' => ['required', 'string', 'max:500'], 'description' => ['required', 'string', 'max:100'],
...$this->photoRules(), ...$this->photoRules(),
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'amount' => 'jumlah',
'description' => 'keterangan',
...$this->photoUploadAttributes('foto bukti'),
];
}
} }

View File

@ -22,7 +22,19 @@ public function rules(): array
return [ return [
'type' => ['required', Rule::enum(PayrollAdjustmentType::class)], 'type' => ['required', Rule::enum(PayrollAdjustmentType::class)],
'amount' => ['required', 'integer', 'min:1'], 'amount' => ['required', 'integer', 'min:1'],
'description' => ['required', 'string', 'max:500'], 'description' => ['required', 'string', 'max:100'],
];
}
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'type' => 'jenis',
'amount' => 'jumlah',
'description' => 'keterangan',
]; ];
} }
} }

View File

@ -21,4 +21,14 @@ public function rules(): array
'reason' => ['required', 'string', 'max:500'], 'reason' => ['required', 'string', 'max:500'],
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'reason' => 'alasan penolakan',
];
}
} }

View File

@ -18,12 +18,27 @@ public function authorize(): bool
&& $transaction?->reference_type === null; && $transaction?->reference_type === null;
} }
/**
* @return array<string, mixed>
*/
public function rules(): array public function rules(): array
{ {
return [ return [
'amount' => ['required', 'integer', 'min:1'], 'amount' => ['required', 'integer', 'min:1'],
'description' => ['required', 'string', 'max:200'], 'description' => ['required', 'string', 'max:100'],
...$this->photoRules(), ...$this->photoRules(),
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'amount' => 'jumlah',
'description' => 'keterangan',
...$this->photoUploadAttributes('foto bukti'),
];
}
} }

View File

@ -18,10 +18,23 @@ public function authorize(): bool
public function rules(): array public function rules(): array
{ {
return [ return [
'photo' => ['required', 'string'], 'photo' => ['required', 'string', 'max:255'],
'latitude' => ['required', 'numeric', 'between:-90,90'], 'latitude' => ['required', 'numeric', 'decimal:0,7', 'between:-90,90'],
'longitude' => ['required', 'numeric', 'between:-180,180'], 'longitude' => ['required', 'numeric', 'decimal:0,7', 'between:-180,180'],
'location_tag' => ['required', 'string', 'max:255'], 'location_tag' => ['required', 'string', 'max:255'],
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'photo' => 'foto',
'latitude' => 'latitude',
'longitude' => 'longitude',
'location_tag' => 'lokasi',
];
}
} }

View File

@ -18,10 +18,23 @@ public function authorize(): bool
public function rules(): array public function rules(): array
{ {
return [ return [
'photo' => ['required', 'string'], 'photo' => ['required', 'string', 'max:255'],
'latitude' => ['required', 'numeric', 'between:-90,90'], 'latitude' => ['required', 'numeric', 'decimal:0,7', 'between:-90,90'],
'longitude' => ['required', 'numeric', 'between:-180,180'], 'longitude' => ['required', 'numeric', 'decimal:0,7', 'between:-180,180'],
'location_tag' => ['required', 'string', 'max:255'], 'location_tag' => ['required', 'string', 'max:255'],
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'photo' => 'foto',
'latitude' => 'latitude',
'longitude' => 'longitude',
'location_tag' => 'lokasi',
];
}
} }

View File

@ -29,7 +29,7 @@ public function rules(): array
'email' => ['required', 'email', 'max:100', Rule::unique('users', 'email')->ignore($this->route('user')?->id)], 'email' => ['required', 'email', 'max:100', Rule::unique('users', 'email')->ignore($this->route('user')?->id)],
'username' => ['required', 'string', 'max:20', 'alpha_dash', Rule::unique('users', 'username')->ignore($this->route('user')?->id)], 'username' => ['required', 'string', 'max:20', 'alpha_dash', Rule::unique('users', 'username')->ignore($this->route('user')?->id)],
'full_name' => ['required', 'string', 'max:200'], 'full_name' => ['required', 'string', 'max:200'],
'phone_number' => ['nullable', 'string', 'regex:/^08\d{8,11}$/'], 'phone_number' => ['nullable', 'string', 'max:20', 'regex:/^08\d{8,11}$/'],
'gender' => ['nullable', Rule::enum(Gender::class)], 'gender' => ['nullable', Rule::enum(Gender::class)],
'birth_date' => ['nullable', 'date', 'before:today'], 'birth_date' => ['nullable', 'date', 'before:today'],
'address' => ['nullable', 'string'], 'address' => ['nullable', 'string'],
@ -39,4 +39,24 @@ public function rules(): array
'role' => ['required', Rule::in(Role::assignableValues())], 'role' => ['required', Rule::in(Role::assignableValues())],
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'email' => 'email',
'username' => 'username',
'full_name' => 'nama lengkap',
'phone_number' => 'nomor telepon',
'gender' => 'jenis kelamin',
'birth_date' => 'tanggal lahir',
'address' => 'alamat',
'join_date' => 'tanggal bergabung',
'employment_status' => 'status kepegawaian',
'base_salary' => 'gaji pokok',
'role' => 'role',
];
}
} }

View File

@ -21,4 +21,14 @@ public function rules(): array
'reason' => ['required', 'string', 'max:500'], 'reason' => ['required', 'string', 'max:500'],
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'reason' => 'alasan penolakan',
];
}
} }

View File

@ -43,4 +43,15 @@ public function rules(): array
'end_date' => ['required', 'date', 'after_or_equal:start_date'], 'end_date' => ['required', 'date', 'after_or_equal:start_date'],
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'start_date' => 'tanggal mulai',
'end_date' => 'tanggal selesai',
];
}
} }

View File

@ -23,7 +23,8 @@ public function authorize(): bool
public function rules(): array public function rules(): array
{ {
return [ return [
'description' => ['nullable', 'string', 'max:500'], 'description' => ['nullable', 'string', 'max:100'],
'materials' => ['required', 'array', 'min:1'], 'materials' => ['required', 'array', 'min:1'],
'materials.*.raw_material_price_id' => [ 'materials.*.raw_material_price_id' => [
'required', 'required',
@ -31,8 +32,9 @@ public function rules(): array
'distinct', 'distinct',
Rule::exists('raw_material_prices', 'id')->whereNull('deleted_at'), Rule::exists('raw_material_prices', 'id')->whereNull('deleted_at'),
], ],
'materials.*.material_usage' => ['required', 'numeric', 'gt:0'], 'materials.*.material_usage' => ['required', 'numeric', 'decimal:0,4', 'gt:0'],
'materials.*.remaining_material' => ['required', 'numeric', 'gte:0'], 'materials.*.remaining_material' => ['required', 'numeric', 'decimal:0,4', 'gte:0'],
'results' => ['required', 'array', 'min:1'], 'results' => ['required', 'array', 'min:1'],
'results.*.product_variant_id' => [ 'results.*.product_variant_id' => [
'required', 'required',
@ -42,7 +44,26 @@ public function rules(): array
], ],
'results.*.cutting_result' => ['required', 'integer', 'min:1'], 'results.*.cutting_result' => ['required', 'integer', 'min:1'],
'results.*.warehouse_stock' => ['required', 'integer', 'min:0'], 'results.*.warehouse_stock' => ['required', 'integer', 'min:0'],
'results.*.cutting_reject' => ['nullable', 'integer', 'min:0'], 'results.*.cutting_reject' => ['required', 'integer', 'min:0'],
];
}
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'description' => 'keterangan',
'materials' => 'bahan baku',
'materials.*.raw_material_price_id' => 'bahan baku',
'materials.*.material_usage' => 'pemakaian',
'materials.*.remaining_material' => 'sisa',
'results' => 'hasil produk',
'results.*.product_variant_id' => 'varian produk',
'results.*.cutting_result' => 'hasil',
'results.*.warehouse_stock' => 'gudang',
'results.*.cutting_reject' => 'reject',
]; ];
} }
} }

View File

@ -27,11 +27,22 @@ public function authorize(): bool
public function rules(): array public function rules(): array
{ {
return [ return [
'status' => ['required', 'string', Rule::in(array_column(CuttingStatus::cases(), 'value'))], 'status' => ['required', Rule::enum(CuttingStatus::class)],
'reason' => ['nullable', 'string', 'max:500'], 'reason' => ['nullable', 'string', 'max:500'],
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'status' => 'status',
'reason' => 'alasan penolakan',
];
}
public function withValidator(Validator $validator): void public function withValidator(Validator $validator): void
{ {
$validator->after(function (Validator $validator): void { $validator->after(function (Validator $validator): void {

View File

@ -28,11 +28,12 @@ public function rules(): array
{ {
$rules = [ $rules = [
'customer_id' => ['nullable', 'integer', Rule::exists('customers', 'id')->whereNull('deleted_at')], 'customer_id' => ['nullable', 'integer', Rule::exists('customers', 'id')->whereNull('deleted_at')],
'channel' => ['required', 'string', Rule::in(array_column(OrderChannel::cases(), 'value'))], 'channel' => ['required', Rule::enum(OrderChannel::class)],
'price_type' => ['required', 'string', Rule::in(array_column(PriceType::cases(), 'value'))], 'price_type' => ['required', Rule::enum(PriceType::class)],
'discount' => ['nullable', 'integer', 'min:0'], 'discount' => ['nullable', 'integer', 'min:0'],
'marketplace_fee' => ['nullable', 'integer', 'min:0'], 'marketplace_fee' => ['nullable', 'integer', 'min:0'],
'notes' => ['nullable', 'string', 'max:100'], 'notes' => ['nullable', 'string'],
'items' => ['required', 'array', 'min:1'], 'items' => ['required', 'array', 'min:1'],
'items.*.product_variant_id' => [ 'items.*.product_variant_id' => [
'required', 'required',
@ -45,6 +46,24 @@ public function rules(): array
return $rules; return $rules;
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'customer_id' => 'pelanggan',
'channel' => 'channel',
'price_type' => 'tipe harga',
'discount' => 'diskon',
'marketplace_fee' => 'biaya marketplace',
'notes' => 'keterangan',
'items' => 'produk',
'items.*.product_variant_id' => 'varian produk',
'items.*.quantity' => 'jumlah',
];
}
public function withValidator(Validator $validator): void public function withValidator(Validator $validator): void
{ {
if (! $this->isMethod('PUT') && ! $this->isMethod('PATCH')) { if (! $this->isMethod('PUT') && ! $this->isMethod('PATCH')) {

View File

@ -27,7 +27,17 @@ public function authorize(): bool
public function rules(): array public function rules(): array
{ {
return [ return [
'status' => ['required', 'string', Rule::in(array_column(OrderStatus::cases(), 'value'))], 'status' => ['required', Rule::enum(OrderStatus::class)],
];
}
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'status' => 'status',
]; ];
} }

View File

@ -29,14 +29,31 @@ public function rules(): array
'supplier_id' => ['required', 'integer', Rule::exists('suppliers', 'id')->whereNull('deleted_at')], 'supplier_id' => ['required', 'integer', Rule::exists('suppliers', 'id')->whereNull('deleted_at')],
'discount' => ['nullable', 'integer', 'min:0'], 'discount' => ['nullable', 'integer', 'min:0'],
'notes' => ['nullable', 'string', 'max:100'], 'notes' => ['nullable', 'string', 'max:100'],
'items' => ['required', 'array', 'min:1'], 'items' => ['required', 'array', 'min:1'],
'items.*.raw_material_price_id' => [ 'items.*.raw_material_price_id' => [
'required', 'required',
'integer', 'integer',
Rule::exists('raw_material_prices', 'id')->whereNull('deleted_at'), Rule::exists('raw_material_prices', 'id')->whereNull('deleted_at'),
], ],
'items.*.quantity' => ['required', 'numeric', 'gt:0'], 'items.*.quantity' => ['required', 'numeric', 'decimal:0,4', 'gt:0'],
...$this->photoRules(), ...$this->photoRules(),
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'supplier_id' => 'supplier',
'discount' => 'diskon',
'notes' => 'keterangan',
'items' => 'bahan baku',
'items.*.raw_material_price_id' => 'bahan baku',
'items.*.quantity' => 'jumlah',
...$this->photoUploadAttributes('bukti transaksi'),
];
}
} }

View File

@ -25,4 +25,14 @@ public function rules(): array
'name' => ['required', 'string', 'max:50'], 'name' => ['required', 'string', 'max:50'],
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'name' => 'nama',
];
}
} }

View File

@ -23,8 +23,20 @@ public function rules(): array
{ {
return [ return [
'name' => ['required', 'string', 'max:200'], 'name' => ['required', 'string', 'max:200'],
'address' => ['required', 'string'], 'phone_number' => ['nullable', 'string', 'max:20'],
'phone_number' => ['required', 'string', 'max:20'], 'address' => ['nullable', 'string'],
];
}
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'name' => 'nama',
'phone_number' => 'nomor telepon',
'address' => 'alamat',
]; ];
} }
} }

View File

@ -29,8 +29,10 @@ public function rules(): array
return [ return [
'name' => ['required', 'string', 'max:200'], 'name' => ['required', 'string', 'max:200'],
'description' => ['nullable', 'string'], 'description' => ['nullable', 'string'],
'category_ids' => ['required', 'array', 'min:1'], 'category_ids' => ['required', 'array', 'min:1'],
'category_ids.*' => ['integer', Rule::exists('categories', 'id')->whereNull('deleted_at')], 'category_ids.*' => ['integer', Rule::exists('categories', 'id')->whereNull('deleted_at')],
'variants' => ['required', 'array', 'min:1'], 'variants' => ['required', 'array', 'min:1'],
'variants.*.id' => [ 'variants.*.id' => [
'nullable', 'nullable',
@ -43,8 +45,28 @@ public function rules(): array
'variants.*.stock' => ['required', 'integer', 'min:0'], 'variants.*.stock' => ['required', 'integer', 'min:0'],
'variants.*.prices' => ['required', 'array', 'min:1'], 'variants.*.prices' => ['required', 'array', 'min:1'],
'variants.*.prices.*.type' => ['required', Rule::enum(PriceType::class)], 'variants.*.prices.*.type' => ['required', Rule::enum(PriceType::class)],
'variants.*.prices.*.price' => ['required', 'numeric', 'gt:0'], 'variants.*.prices.*.price' => ['required', 'numeric', 'decimal:0,2', 'gt:0'],
...$this->variantImageRules(), ...$this->variantImageRules(),
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'name' => 'nama produk',
'description' => 'deskripsi',
'category_ids' => 'kategori',
'category_ids.*' => 'kategori',
'variants' => 'varian',
'variants.*.name' => 'nama varian',
'variants.*.stock' => 'stok',
'variants.*.prices' => 'harga',
'variants.*.prices.*.type' => 'tipe harga',
'variants.*.prices.*.price' => 'harga',
...$this->variantImageAttributes('variants', 'foto varian'),
];
}
} }

View File

@ -29,6 +29,7 @@ public function rules(): array
return [ return [
'name' => ['required', 'string', 'max:200'], 'name' => ['required', 'string', 'max:200'],
'unit' => ['required', Rule::enum(RawMaterialUnit::class)], 'unit' => ['required', Rule::enum(RawMaterialUnit::class)],
'prices' => ['required', 'array', 'min:1'], 'prices' => ['required', 'array', 'min:1'],
'prices.*.id' => [ 'prices.*.id' => [
'nullable', 'nullable',
@ -38,9 +39,25 @@ public function rules(): array
->whereNull('deleted_at'), ->whereNull('deleted_at'),
], ],
'prices.*.variant' => ['required', 'string', 'max:200'], 'prices.*.variant' => ['required', 'string', 'max:200'],
'prices.*.price' => ['required', 'numeric', 'gt:0'], 'prices.*.price' => ['required', 'numeric', 'decimal:0,2', 'gt:0'],
'prices.*.stock' => ['required', 'numeric', 'min:0'], 'prices.*.stock' => ['required', 'numeric', 'decimal:0,4', 'min:0'],
...$this->variantImageRules('prices'), ...$this->variantImageRules('prices'),
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'name' => 'nama bahan baku',
'unit' => 'satuan',
'prices' => 'varian',
'prices.*.variant' => 'nama varian',
'prices.*.price' => 'harga',
'prices.*.stock' => 'stok',
...$this->variantImageAttributes('prices', 'foto varian'),
];
}
} }

View File

@ -23,8 +23,20 @@ public function rules(): array
{ {
return [ return [
'name' => ['required', 'string', 'max:200'], 'name' => ['required', 'string', 'max:200'],
'address' => ['required', 'string'], 'phone_number' => ['nullable', 'string', 'max:20'],
'phone_number' => ['required', 'string', 'max:20'], 'address' => ['nullable', 'string'],
];
}
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'name' => 'nama',
'phone_number' => 'nomor telepon',
'address' => 'alamat',
]; ];
} }
} }

View File

@ -12,6 +12,9 @@ public function authorize(): bool
return $this->user()?->can(Permission::SETTINGS_UPDATE->value) ?? false; return $this->user()?->can(Permission::SETTINGS_UPDATE->value) ?? false;
} }
/**
* @return array<string, mixed>
*/
public function rules(): array public function rules(): array
{ {
return [ return [
@ -33,4 +36,28 @@ public function rules(): array
'shopee_voucher_fee' => ['required', 'numeric', 'min:0', 'max:100'], 'shopee_voucher_fee' => ['required', 'numeric', 'min:0', 'max:100'],
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'tiktok_shop_enabled' => 'aktif',
'tiktok_shop_admin_fee' => 'biaya admin TikTok Shop',
'tiktok_shop_transaction_fee' => 'biaya transaksi TikTok Shop',
'tiktok_shop_payment_fee' => 'biaya pembayaran TikTok Shop',
'tiktok_shop_affiliate_commission' => 'komisi afiliasi TikTok Shop',
'tiktok_shop_shipping_subsidy' => 'subsidi ongkir TikTok Shop',
'tiktok_shop_vat_rate' => 'PPN / pajak TikTok Shop',
'shopee_enabled' => 'aktif',
'shopee_commission_fee' => 'komisi Shopee',
'shopee_transaction_fee' => 'biaya transaksi Shopee',
'shopee_service_fee' => 'biaya layanan Shopee',
'shopee_payment_fee' => 'biaya pembayaran Shopee',
'shopee_affiliate_commission' => 'komisi afiliasi Shopee',
'shopee_shipping_subsidy' => 'subsidi ongkir Shopee',
'shopee_voucher_fee' => 'biaya voucher / diskon Shopee',
];
}
} }

View File

@ -12,6 +12,9 @@ public function authorize(): bool
return $this->user()?->can(Permission::SETTINGS_UPDATE->value) ?? false; return $this->user()?->can(Permission::SETTINGS_UPDATE->value) ?? false;
} }
/**
* @return array<string, mixed>
*/
public function rules(): array public function rules(): array
{ {
return [ return [
@ -20,4 +23,16 @@ public function rules(): array
'tiktok_url' => ['nullable', 'url', 'max:100'], 'tiktok_url' => ['nullable', 'url', 'max:100'],
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'instagram_url' => 'Instagram',
'facebook_url' => 'Facebook',
'tiktok_url' => 'TikTok',
];
}
} }

View File

@ -12,6 +12,9 @@ public function authorize(): bool
return $this->user()?->can(Permission::SETTINGS_UPDATE->value) ?? false; return $this->user()?->can(Permission::SETTINGS_UPDATE->value) ?? false;
} }
/**
* @return array<string, mixed>
*/
public function rules(): array public function rules(): array
{ {
return [ return [
@ -24,4 +27,20 @@ public function rules(): array
'login_cover' => ['required', 'image', 'max:5120'], 'login_cover' => ['required', 'image', 'max:5120'],
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'app_name' => 'nama aplikasi',
'about_app' => 'tentang aplikasi',
'email' => 'email',
'phone' => 'nomor telepon',
'address' => 'alamat',
'logo' => 'logo',
'login_cover' => 'cover login',
];
}
} }

View File

@ -27,6 +27,17 @@ public function rules(): array
]; ];
} }
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'login' => 'email/username',
'password' => 'kata sandi',
];
}
/** /**
* @throws ValidationException * @throws ValidationException
*/ */

View File

@ -29,4 +29,30 @@ protected function variantImageRules(string $variantsKey = 'variants', int $max
"{$variantsKey}.*.remove_media_ids.*" => ['integer'], "{$variantsKey}.*.remove_media_ids.*" => ['integer'],
]; ];
} }
/**
* @return array<string, string>
*/
protected function photoUploadAttributes(string $label): array
{
return [
'photos' => $label,
'photos.*' => $label,
'remove_media_ids' => 'media yang dihapus',
'remove_media_ids.*' => 'media yang dihapus',
];
}
/**
* @return array<string, string>
*/
protected function variantImageAttributes(string $variantsKey, string $label): array
{
return [
"{$variantsKey}.*.images" => $label,
"{$variantsKey}.*.images.*" => $label,
"{$variantsKey}.*.remove_media_ids" => 'media yang dihapus',
"{$variantsKey}.*.remove_media_ids.*" => 'media yang dihapus',
];
}
} }

View File

@ -9,6 +9,7 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\HasMedia;
@ -25,20 +26,10 @@
])] ])]
class Attendance extends Model implements HasMedia class Attendance extends Model implements HasMedia
{ {
use HasFactory;
use HasModuleMedia; use HasModuleMedia;
use InteractsWithActivityLog; use InteractsWithActivityLog;
public static function mediaModuleName(): string
{
return 'attendance';
}
public function registerMediaCollections(): void
{
$this->addMediaCollection('checkin')->singleFile();
$this->addMediaCollection('checkout')->singleFile();
}
protected function casts(): array protected function casts(): array
{ {
return [ return [
@ -58,13 +49,6 @@ public function employee(): BelongsTo
return $this->belongsTo(Employee::class); return $this->belongsTo(Employee::class);
} }
public function employeeName(): Attribute
{
return Attribute::make(
get: fn () => $this->employee?->user?->profile?->full_name,
);
}
public function attendanceDateFormatted(): Attribute public function attendanceDateFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -79,6 +63,17 @@ public function checkInAtFormatted(): Attribute
); );
} }
public function checkInPhotoUrl(): Attribute
{
return Attribute::make(
get: function () {
$photo = MediaPresenter::first($this, 'checkin');
return $photo['url'] ?? null;
},
);
}
public function checkOutAtFormatted(): Attribute public function checkOutAtFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -86,6 +81,24 @@ public function checkOutAtFormatted(): Attribute
); );
} }
public function checkOutPhotoUrl(): Attribute
{
return Attribute::make(
get: function () {
$photo = MediaPresenter::first($this, 'checkout');
return $photo['url'] ?? null;
},
);
}
public function employeeName(): Attribute
{
return Attribute::make(
get: fn () => $this->employee?->user?->profile?->full_name,
);
}
public function workDurationFormatted(): Attribute public function workDurationFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -106,25 +119,14 @@ public function workDurationFormatted(): Attribute
); );
} }
public function checkInPhotoUrl(): Attribute public static function mediaModuleName(): string
{ {
return Attribute::make( return 'attendance';
get: function () {
$photo = MediaPresenter::first($this, 'checkin');
return $photo['url'] ?? null;
},
);
} }
public function checkOutPhotoUrl(): Attribute public function registerMediaCollections(): void
{ {
return Attribute::make( $this->addMediaCollection('checkin')->singleFile();
get: function () { $this->addMediaCollection('checkout')->singleFile();
$photo = MediaPresenter::first($this, 'checkout');
return $photo['url'] ?? null;
},
);
} }
} }

View File

@ -6,6 +6,7 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
@ -13,6 +14,7 @@
#[Appends(['balance_formatted'])] #[Appends(['balance_formatted'])]
class CashAccount extends Model class CashAccount extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
protected function casts(): array protected function casts(): array
@ -22,15 +24,15 @@ protected function casts(): array
]; ];
} }
public function transactions(): HasMany
{
return $this->hasMany(CashTransaction::class);
}
public function balanceFormatted(): Attribute public function balanceFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: fn () => 'Rp '.number_format($this->balance, 0, ',', '.'), get: fn () => 'Rp '.number_format($this->balance, 0, ',', '.'),
); );
} }
public function transactions(): HasMany
{
return $this->hasMany(CashTransaction::class);
}
} }

View File

@ -7,6 +7,7 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\Relations\MorphTo;
@ -24,20 +25,11 @@
])] ])]
class CashTransaction extends Model implements HasMedia class CashTransaction extends Model implements HasMedia
{ {
use HasFactory;
use HasModuleMedia; use HasModuleMedia;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes; use SoftDeletes;
public static function mediaModuleName(): string
{
return 'cash';
}
public function registerMediaCollections(): void
{
$this->addMediaCollection('photos');
}
protected function casts(): array protected function casts(): array
{ {
return [ return [
@ -46,6 +38,21 @@ protected function casts(): array
]; ];
} }
public function cashAccount(): BelongsTo
{
return $this->belongsTo(CashAccount::class);
}
public function createdBy(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by_id');
}
public function reference(): MorphTo
{
return $this->morphTo();
}
public function amountFormatted(): Attribute public function amountFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -60,6 +67,33 @@ public function balanceAfterFormatted(): Attribute
); );
} }
public function createdAtFormatted(): Attribute
{
return Attribute::make(
get: fn () => $this->created_at?->translatedFormat('l, d F Y H:i'),
);
}
public function createdByName(): Attribute
{
return Attribute::make(
get: fn () => $this->createdBy?->profile?->full_name ?? $this->createdBy?->username,
);
}
public function isIncoming(): Attribute
{
return Attribute::make(
get: function () {
if ($this->reference_type === EmployeeAdvance::class && $this->reference instanceof EmployeeAdvance) {
return $this->reference->repayment_cash_transaction_id === $this->id;
}
return self::isIncomingTransaction($this);
},
);
}
public function referenceLabel(): Attribute public function referenceLabel(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -75,31 +109,14 @@ public function referenceLabel(): Attribute
); );
} }
public function isIncoming(): Attribute public static function mediaModuleName(): string
{ {
return Attribute::make( return 'cash';
get: function () {
if ($this->reference_type === EmployeeAdvance::class && $this->reference instanceof EmployeeAdvance) {
return $this->reference->repayment_cash_transaction_id === $this->id;
}
return self::isIncomingTransaction($this);
},
);
} }
public function createdAtFormatted(): Attribute public function registerMediaCollections(): void
{ {
return Attribute::make( $this->addMediaCollection('photos');
get: fn () => $this->created_at?->translatedFormat('l, d F Y H:i'),
);
}
public function createdByName(): Attribute
{
return Attribute::make(
get: fn () => $this->createdBy?->profile?->full_name ?? $this->createdBy?->username,
);
} }
public static function labelForReferenceType(?string $referenceType): string public static function labelForReferenceType(?string $referenceType): string
@ -135,19 +152,4 @@ public static function isIncomingTransaction(self $transaction): bool
return self::isIncomingReference($transaction->reference_type); return self::isIncomingReference($transaction->reference_type);
} }
public function cashAccount(): BelongsTo
{
return $this->belongsTo(CashAccount::class);
}
public function createdBy(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by_id');
}
public function reference(): MorphTo
{
return $this->morphTo();
}
} }

View File

@ -4,6 +4,7 @@
use App\Models\Concerns\InteractsWithActivityLog; use App\Models\Concerns\InteractsWithActivityLog;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
@ -13,6 +14,7 @@
#[Sluggable(from: 'name', to: 'slug')] #[Sluggable(from: 'name', to: 'slug')]
class Category extends Model class Category extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes; use SoftDeletes;

View File

@ -4,6 +4,7 @@
use App\Models\Concerns\InteractsWithActivityLog; use App\Models\Concerns\InteractsWithActivityLog;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
@ -11,6 +12,7 @@
#[Guarded(['id'])] #[Guarded(['id'])]
class Customer extends Model class Customer extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes; use SoftDeletes;

View File

@ -8,6 +8,7 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
@ -20,6 +21,7 @@
])] ])]
class Cutting extends Model class Cutting extends Model
{ {
use HasFactory;
use HasRejection; use HasRejection;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes; use SoftDeletes;
@ -31,20 +33,6 @@ protected function casts(): array
]; ];
} }
public function statusLabel(): Attribute
{
return Attribute::make(
get: fn () => $this->status->label(),
);
}
public function createdAtFormatted(): Attribute
{
return Attribute::make(
get: fn () => $this->created_at?->translatedFormat('l, d F Y H:i'),
);
}
public function createdBy(): BelongsTo public function createdBy(): BelongsTo
{ {
return $this->belongsTo(User::class, 'created_by_id'); return $this->belongsTo(User::class, 'created_by_id');
@ -59,4 +47,18 @@ public function results(): HasMany
{ {
return $this->hasMany(CuttingResult::class); return $this->hasMany(CuttingResult::class);
} }
public function createdAtFormatted(): Attribute
{
return Attribute::make(
get: fn () => $this->created_at?->translatedFormat('l, d F Y H:i'),
);
}
public function statusLabel(): Attribute
{
return Attribute::make(
get: fn () => $this->status->label(),
);
}
} }

View File

@ -6,8 +6,10 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
#[Guarded(['id'])] #[Guarded(['id'])]
#[Appends([ #[Appends([
@ -19,7 +21,9 @@
])] ])]
class CuttingMaterial extends Model class CuttingMaterial extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes;
protected function casts(): array protected function casts(): array
{ {
@ -29,6 +33,16 @@ protected function casts(): array
]; ];
} }
public function cutting(): BelongsTo
{
return $this->belongsTo(Cutting::class);
}
public function rawMaterialPrice(): BelongsTo
{
return $this->belongsTo(RawMaterialPrice::class);
}
public function materialUsageFormatted(): Attribute public function materialUsageFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -64,16 +78,6 @@ public function unitAbbreviation(): Attribute
); );
} }
public function cutting(): BelongsTo
{
return $this->belongsTo(Cutting::class);
}
public function rawMaterialPrice(): BelongsTo
{
return $this->belongsTo(RawMaterialPrice::class);
}
private function formatQuantity(float|string|null $value): string private function formatQuantity(float|string|null $value): string
{ {
$formatted = rtrim(rtrim(number_format((float) $value, 4, ',', '.'), '0'), ','); $formatted = rtrim(rtrim(number_format((float) $value, 4, ',', '.'), '0'), ',');

View File

@ -4,13 +4,17 @@
use App\Models\Concerns\InteractsWithActivityLog; use App\Models\Concerns\InteractsWithActivityLog;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
#[Guarded(['id'])] #[Guarded(['id'])]
class CuttingResult extends Model class CuttingResult extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes;
protected function casts(): array protected function casts(): array
{ {

View File

@ -10,6 +10,7 @@
use Illuminate\Database\Eloquent\Attributes\Scope; use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
@ -19,6 +20,7 @@
#[Appends(['base_salary_formatted', 'join_date_formatted', 'resign_date_formatted', 'join_date_input', 'employment_status_label'])] #[Appends(['base_salary_formatted', 'join_date_formatted', 'resign_date_formatted', 'join_date_input', 'employment_status_label'])]
class Employee extends Model class Employee extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes; use SoftDeletes;
@ -32,6 +34,13 @@ protected function casts(): array
]; ];
} }
#[Scope]
public function contract(Builder $query): void
{
$query->where('employment_status', EmploymentStatus::CONTRACT->value);
}
#[Scope]
public function fullTime(Builder $query): void public function fullTime(Builder $query): void
{ {
$query->where('employment_status', EmploymentStatus::FULL_TIME->value); $query->where('employment_status', EmploymentStatus::FULL_TIME->value);
@ -43,68 +52,17 @@ public function partTime(Builder $query): void
$query->where('employment_status', EmploymentStatus::PART_TIME->value); $query->where('employment_status', EmploymentStatus::PART_TIME->value);
} }
#[Scope]
public function contract(Builder $query): void
{
$query->where('employment_status', EmploymentStatus::CONTRACT->value);
}
#[Scope] #[Scope]
public function temporary(Builder $query): void public function temporary(Builder $query): void
{ {
$query->where('employment_status', EmploymentStatus::TEMPORARY->value); $query->where('employment_status', EmploymentStatus::TEMPORARY->value);
} }
public function baseSalaryFormatted(): Attribute
{
return Attribute::make(
get: fn () => 'Rp '.number_format($this->base_salary, 0, ',', '.'),
);
}
public function joinDateFormatted(): Attribute
{
return Attribute::make(
get: fn () => Carbon::parse($this->join_date)->format('l, d F Y'),
);
}
public function resignDateFormatted(): Attribute
{
return Attribute::make(
get: fn () => $this->resign_date ? Carbon::parse($this->resign_date)->format('l, d F Y') : null,
);
}
public function joinDateInput(): Attribute
{
return Attribute::make(
get: fn () => $this->join_date?->format('Y-m-d'),
);
}
public function employmentStatusLabel(): Attribute
{
return Attribute::make(
get: fn () => $this->employment_status?->label(),
);
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function advances(): HasMany public function advances(): HasMany
{ {
return $this->hasMany(EmployeeAdvance::class); return $this->hasMany(EmployeeAdvance::class);
} }
public function payrolls(): HasMany
{
return $this->hasMany(Payroll::class);
}
public function attendances(): HasMany public function attendances(): HasMany
{ {
return $this->hasMany(Attendance::class); return $this->hasMany(Attendance::class);
@ -114,4 +72,49 @@ public function leaveRequests(): HasMany
{ {
return $this->hasMany(LeaveRequest::class); return $this->hasMany(LeaveRequest::class);
} }
public function payrolls(): HasMany
{
return $this->hasMany(Payroll::class);
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function baseSalaryFormatted(): Attribute
{
return Attribute::make(
get: fn () => 'Rp '.number_format($this->base_salary, 0, ',', '.'),
);
}
public function employmentStatusLabel(): Attribute
{
return Attribute::make(
get: fn () => $this->employment_status?->label(),
);
}
public function joinDateFormatted(): Attribute
{
return Attribute::make(
get: fn () => Carbon::parse($this->join_date)->format('l, d F Y'),
);
}
public function joinDateInput(): Attribute
{
return Attribute::make(
get: fn () => $this->join_date?->format('Y-m-d'),
);
}
public function resignDateFormatted(): Attribute
{
return Attribute::make(
get: fn () => $this->resign_date ? Carbon::parse($this->resign_date)->format('l, d F Y') : null,
);
}
} }

View File

@ -9,6 +9,7 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\HasMedia;
@ -28,20 +29,11 @@
])] ])]
class EmployeeAdvance extends Model implements HasMedia class EmployeeAdvance extends Model implements HasMedia
{ {
use HasFactory;
use HasModuleMedia; use HasModuleMedia;
use HasRejection; use HasRejection;
use InteractsWithActivityLog; use InteractsWithActivityLog;
public static function mediaModuleName(): string
{
return 'employee-advance';
}
public function registerMediaCollections(): void
{
$this->addMediaCollection('photos');
}
protected function casts(): array protected function casts(): array
{ {
return [ return [
@ -53,6 +45,31 @@ protected function casts(): array
]; ];
} }
public function cashTransaction(): BelongsTo
{
return $this->belongsTo(CashTransaction::class);
}
public function employee(): BelongsTo
{
return $this->belongsTo(Employee::class);
}
public function paidBy(): BelongsTo
{
return $this->belongsTo(User::class, 'paid_by_id');
}
public function repaymentCashTransaction(): BelongsTo
{
return $this->belongsTo(CashTransaction::class, 'repayment_cash_transaction_id');
}
public function verifiedBy(): BelongsTo
{
return $this->belongsTo(User::class, 'verified_by_id');
}
public function amountFormatted(): Attribute public function amountFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -60,6 +77,27 @@ public function amountFormatted(): Attribute
); );
} }
public function canPay(): Attribute
{
return Attribute::make(
get: fn () => $this->status === EmployeeAdvanceStatus::APPROVED,
);
}
public function canVerify(): Attribute
{
return Attribute::make(
get: fn () => $this->status === EmployeeAdvanceStatus::PENDING,
);
}
public function createdAtFormatted(): Attribute
{
return Attribute::make(
get: fn () => $this->created_at?->translatedFormat('l, d F Y H:i'),
);
}
public function dueDateFormatted(): Attribute public function dueDateFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -74,13 +112,6 @@ public function dueDateInput(): Attribute
); );
} }
public function statusLabel(): Attribute
{
return Attribute::make(
get: fn () => $this->status?->label(),
);
}
public function employeeName(): Attribute public function employeeName(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -89,20 +120,6 @@ public function employeeName(): Attribute
); );
} }
public function rejectionReason(): Attribute
{
return Attribute::make(
get: fn () => $this->rejection?->reason,
);
}
public function createdAtFormatted(): Attribute
{
return Attribute::make(
get: fn () => $this->created_at?->translatedFormat('l, d F Y H:i'),
);
}
public function isEditable(): Attribute public function isEditable(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -110,42 +127,27 @@ public function isEditable(): Attribute
); );
} }
public function canVerify(): Attribute public function rejectionReason(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: fn () => $this->status === EmployeeAdvanceStatus::PENDING, get: fn () => $this->rejection?->reason,
); );
} }
public function canPay(): Attribute public function statusLabel(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: fn () => $this->status === EmployeeAdvanceStatus::APPROVED, get: fn () => $this->status?->label(),
); );
} }
public function employee(): BelongsTo public static function mediaModuleName(): string
{ {
return $this->belongsTo(Employee::class); return 'employee-advance';
} }
public function cashTransaction(): BelongsTo public function registerMediaCollections(): void
{ {
return $this->belongsTo(CashTransaction::class); $this->addMediaCollection('photos');
}
public function repaymentCashTransaction(): BelongsTo
{
return $this->belongsTo(CashTransaction::class, 'repayment_cash_transaction_id');
}
public function verifiedBy(): BelongsTo
{
return $this->belongsTo(User::class, 'verified_by_id');
}
public function paidBy(): BelongsTo
{
return $this->belongsTo(User::class, 'paid_by_id');
} }
} }

View File

@ -7,6 +7,7 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
@ -16,20 +17,11 @@
#[Appends(['amount_formatted', 'created_at_formatted', 'created_by_name'])] #[Appends(['amount_formatted', 'created_at_formatted', 'created_by_name'])]
class Expense extends Model implements HasMedia class Expense extends Model implements HasMedia
{ {
use HasFactory;
use HasModuleMedia; use HasModuleMedia;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes; use SoftDeletes;
public static function mediaModuleName(): string
{
return 'expense';
}
public function registerMediaCollections(): void
{
$this->addMediaCollection('photos');
}
protected function casts(): array protected function casts(): array
{ {
return [ return [
@ -37,6 +29,16 @@ protected function casts(): array
]; ];
} }
public function cashTransaction(): BelongsTo
{
return $this->belongsTo(CashTransaction::class);
}
public function createdBy(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by_id');
}
public function amountFormatted(): Attribute public function amountFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -58,13 +60,13 @@ public function createdByName(): Attribute
); );
} }
public function cashTransaction(): BelongsTo public static function mediaModuleName(): string
{ {
return $this->belongsTo(CashTransaction::class); return 'expense';
} }
public function createdBy(): BelongsTo public function registerMediaCollections(): void
{ {
return $this->belongsTo(User::class, 'created_by_id'); $this->addMediaCollection('photos');
} }
} }

View File

@ -8,6 +8,7 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -26,6 +27,7 @@
])] ])]
class LeaveRequest extends Model class LeaveRequest extends Model
{ {
use HasFactory;
use HasRejection; use HasRejection;
use InteractsWithActivityLog; use InteractsWithActivityLog;
@ -40,38 +42,27 @@ protected function casts(): array
]; ];
} }
public function startDateFormatted(): Attribute public function employee(): BelongsTo
{
return $this->belongsTo(Employee::class);
}
public function verifiedBy(): BelongsTo
{
return $this->belongsTo(User::class, 'verified_by_id');
}
public function canVerify(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: fn () => $this->start_date?->translatedFormat('l, d F Y'), get: fn () => $this->status === LeaveRequestStatus::PENDING,
); );
} }
public function endDateFormatted(): Attribute public function createdAtFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: fn () => $this->end_date?->translatedFormat('l, d F Y'), get: fn () => $this->created_at?->translatedFormat('l, d F Y H:i'),
);
}
public function startDateInput(): Attribute
{
return Attribute::make(
get: fn () => $this->start_date?->format('Y-m-d'),
);
}
public function endDateInput(): Attribute
{
return Attribute::make(
get: fn () => $this->end_date?->format('Y-m-d'),
);
}
public function statusLabel(): Attribute
{
return Attribute::make(
get: fn () => $this->status?->label(),
); );
} }
@ -83,17 +74,17 @@ public function employeeName(): Attribute
); );
} }
public function rejectionReason(): Attribute public function endDateFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: fn () => $this->rejection?->reason, get: fn () => $this->end_date?->translatedFormat('l, d F Y'),
); );
} }
public function createdAtFormatted(): Attribute public function endDateInput(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: fn () => $this->created_at?->translatedFormat('l, d F Y H:i'), get: fn () => $this->end_date?->format('Y-m-d'),
); );
} }
@ -104,20 +95,31 @@ public function isEditable(): Attribute
); );
} }
public function canVerify(): Attribute public function rejectionReason(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: fn () => $this->status === LeaveRequestStatus::PENDING, get: fn () => $this->rejection?->reason,
); );
} }
public function employee(): BelongsTo public function startDateFormatted(): Attribute
{ {
return $this->belongsTo(Employee::class); return Attribute::make(
get: fn () => $this->start_date?->translatedFormat('l, d F Y'),
);
} }
public function verifiedBy(): BelongsTo public function startDateInput(): Attribute
{ {
return $this->belongsTo(User::class, 'verified_by_id'); return Attribute::make(
get: fn () => $this->start_date?->format('Y-m-d'),
);
}
public function statusLabel(): Attribute
{
return Attribute::make(
get: fn () => $this->status?->label(),
);
} }
} }

View File

@ -9,6 +9,7 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
@ -27,6 +28,7 @@
])] ])]
class Order extends Model class Order extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes; use SoftDeletes;
@ -43,10 +45,37 @@ protected function casts(): array
]; ];
} }
public function subtotalFormatted(): Attribute public function cashTransaction(): BelongsTo
{
return $this->belongsTo(CashTransaction::class);
}
public function createdBy(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by_id');
}
public function customer(): BelongsTo
{
return $this->belongsTo(Customer::class);
}
public function items(): HasMany
{
return $this->hasMany(OrderItem::class);
}
public function channelLabel(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: fn () => 'Rp '.number_format($this->subtotal, 0, ',', '.'), get: fn () => $this->channel->label(),
);
}
public function createdAtFormatted(): Attribute
{
return Attribute::make(
get: fn () => $this->created_at?->translatedFormat('l, d F Y H:i'),
); );
} }
@ -71,20 +100,6 @@ public function netAmountFormatted(): Attribute
); );
} }
public function createdAtFormatted(): Attribute
{
return Attribute::make(
get: fn () => $this->created_at?->translatedFormat('l, d F Y H:i'),
);
}
public function channelLabel(): Attribute
{
return Attribute::make(
get: fn () => $this->channel->label(),
);
}
public function priceTypeLabel(): Attribute public function priceTypeLabel(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -99,23 +114,10 @@ public function statusLabel(): Attribute
); );
} }
public function customer(): BelongsTo public function subtotalFormatted(): Attribute
{ {
return $this->belongsTo(Customer::class); return Attribute::make(
} get: fn () => 'Rp '.number_format($this->subtotal, 0, ',', '.'),
);
public function items(): HasMany
{
return $this->hasMany(OrderItem::class);
}
public function cashTransaction(): BelongsTo
{
return $this->belongsTo(CashTransaction::class);
}
public function createdBy(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by_id');
} }
} }

View File

@ -6,8 +6,10 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
#[Guarded(['id'])] #[Guarded(['id'])]
#[Appends([ #[Appends([
@ -18,7 +20,9 @@
])] ])]
class OrderItem extends Model class OrderItem extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes;
protected function casts(): array protected function casts(): array
{ {
@ -29,6 +33,16 @@ protected function casts(): array
]; ];
} }
public function order(): BelongsTo
{
return $this->belongsTo(Order::class);
}
public function productVariant(): BelongsTo
{
return $this->belongsTo(ProductVariant::class);
}
public function quantityFormatted(): Attribute public function quantityFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -43,13 +57,6 @@ public function quantityInput(): Attribute
); );
} }
public function unitPriceFormatted(): Attribute
{
return Attribute::make(
get: fn () => 'Rp '.number_format($this->unit_price, 0, ',', '.'),
);
}
public function subtotalFormatted(): Attribute public function subtotalFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -57,13 +64,10 @@ public function subtotalFormatted(): Attribute
); );
} }
public function order(): BelongsTo public function unitPriceFormatted(): Attribute
{ {
return $this->belongsTo(Order::class); return Attribute::make(
} get: fn () => 'Rp '.number_format($this->unit_price, 0, ',', '.'),
);
public function productVariant(): BelongsTo
{
return $this->belongsTo(ProductVariant::class);
} }
} }

View File

@ -9,6 +9,7 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
@ -27,6 +28,7 @@
])] ])]
class Payroll extends Model class Payroll extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
protected function casts(): array protected function casts(): array
@ -41,6 +43,31 @@ protected function casts(): array
]; ];
} }
public function adjustments(): HasMany
{
return $this->hasMany(PayrollAdjustment::class);
}
public function cashTransaction(): BelongsTo
{
return $this->belongsTo(CashTransaction::class);
}
public function employee(): BelongsTo
{
return $this->belongsTo(Employee::class);
}
public function paidBy(): BelongsTo
{
return $this->belongsTo(User::class, 'paid_by_id');
}
public function payrollPeriod(): BelongsTo
{
return $this->belongsTo(PayrollPeriod::class);
}
public function baseSalaryFormatted(): Attribute public function baseSalaryFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -55,39 +82,12 @@ public function bonusAmountFormatted(): Attribute
); );
} }
public function deductionAmountFormatted(): Attribute public function canAdjust(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: fn () => 'Rp '.number_format($this->deduction_amount, 0, ',', '.'), get: fn () => $this->status === PayrollStatus::UNPAID
); && $this->relationLoaded('payrollPeriod')
} && $this->payrollPeriod?->isOpen(),
public function netAmountFormatted(): Attribute
{
return Attribute::make(
get: fn () => 'Rp '.number_format($this->net_amount, 0, ',', '.'),
);
}
public function statusLabel(): Attribute
{
return Attribute::make(
get: fn () => $this->status?->label(),
);
}
public function employeeName(): Attribute
{
return Attribute::make(
get: fn () => $this->employee?->user?->profile?->full_name
?? $this->employee?->user?->username,
);
}
public function paidAtFormatted(): Attribute
{
return Attribute::make(
get: fn () => $this->paid_at?->translatedFormat('l, d F Y H:i'),
); );
} }
@ -100,38 +100,52 @@ public function canPay(): Attribute
); );
} }
public function canAdjust(): Attribute public function deductionAmountFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: fn () => $this->status === PayrollStatus::UNPAID get: fn () => 'Rp '.number_format($this->deduction_amount, 0, ',', '.'),
&& $this->relationLoaded('payrollPeriod')
&& $this->payrollPeriod?->isOpen(),
); );
} }
public function payrollPeriod(): BelongsTo public function employeeName(): Attribute
{ {
return $this->belongsTo(PayrollPeriod::class); return Attribute::make(
get: fn () => $this->employee?->user?->profile?->full_name
?? $this->employee?->user?->username,
);
} }
public function employee(): BelongsTo public function netAmountFormatted(): Attribute
{ {
return $this->belongsTo(Employee::class); return Attribute::make(
get: fn () => 'Rp '.number_format($this->net_amount, 0, ',', '.'),
);
} }
public function paidBy(): BelongsTo public function paidAtFormatted(): Attribute
{ {
return $this->belongsTo(User::class, 'paid_by_id'); return Attribute::make(
get: fn () => $this->paid_at?->translatedFormat('l, d F Y H:i'),
);
} }
public function cashTransaction(): BelongsTo public function statusLabel(): Attribute
{ {
return $this->belongsTo(CashTransaction::class); return Attribute::make(
get: fn () => $this->status?->label(),
);
} }
public function adjustments(): HasMany public function calculateKasbonDeduction(): int
{ {
return $this->hasMany(PayrollAdjustment::class); $outstanding = (int) EmployeeAdvance::query()
->where('employee_id', $this->employee_id)
->where('status', EmployeeAdvanceStatus::APPROVED)
->sum('amount');
return min($outstanding, $this->base_salary + (int) $this->adjustments()
->where('type', PayrollAdjustmentType::BONUS)
->sum('amount'));
} }
public function recalculateAmounts(): void public function recalculateAmounts(): void
@ -150,16 +164,4 @@ public function recalculateAmounts(): void
$this->deduction_amount = $kasbonDeduction + $manualDeduction; $this->deduction_amount = $kasbonDeduction + $manualDeduction;
$this->net_amount = max(0, $this->base_salary + $bonusAmount - $this->deduction_amount); $this->net_amount = max(0, $this->base_salary + $bonusAmount - $this->deduction_amount);
} }
public function calculateKasbonDeduction(): int
{
$outstanding = (int) EmployeeAdvance::query()
->where('employee_id', $this->employee_id)
->where('status', EmployeeAdvanceStatus::APPROVED)
->sum('amount');
return min($outstanding, $this->base_salary + (int) $this->adjustments()
->where('type', PayrollAdjustmentType::BONUS)
->sum('amount'));
}
} }

View File

@ -7,6 +7,7 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -14,6 +15,7 @@
#[Appends(['amount_formatted', 'type_label', 'created_at_formatted', 'created_by_name'])] #[Appends(['amount_formatted', 'type_label', 'created_at_formatted', 'created_by_name'])]
class PayrollAdjustment extends Model class PayrollAdjustment extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
public $timestamps = false; public $timestamps = false;
@ -27,6 +29,16 @@ protected function casts(): array
]; ];
} }
public function createdBy(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by_id');
}
public function payroll(): BelongsTo
{
return $this->belongsTo(Payroll::class);
}
public function amountFormatted(): Attribute public function amountFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -34,13 +46,6 @@ public function amountFormatted(): Attribute
); );
} }
public function typeLabel(): Attribute
{
return Attribute::make(
get: fn () => $this->type?->label(),
);
}
public function createdAtFormatted(): Attribute public function createdAtFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -55,13 +60,10 @@ public function createdByName(): Attribute
); );
} }
public function payroll(): BelongsTo public function typeLabel(): Attribute
{ {
return $this->belongsTo(Payroll::class); return Attribute::make(
} get: fn () => $this->type?->label(),
);
public function createdBy(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by_id');
} }
} }

View File

@ -8,6 +8,7 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
@ -16,6 +17,7 @@
#[Appends(['period_label', 'status_label', 'closed_at_formatted'])] #[Appends(['period_label', 'status_label', 'closed_at_formatted'])]
class PayrollPeriod extends Model class PayrollPeriod extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
protected function casts(): array protected function casts(): array
@ -26,6 +28,23 @@ protected function casts(): array
]; ];
} }
public function closedBy(): BelongsTo
{
return $this->belongsTo(User::class, 'closed_by_id');
}
public function payrolls(): HasMany
{
return $this->hasMany(Payroll::class);
}
public function closedAtFormatted(): Attribute
{
return Attribute::make(
get: fn () => $this->closed_at?->translatedFormat('l, d F Y H:i'),
);
}
public function periodLabel(): Attribute public function periodLabel(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -40,23 +59,6 @@ public function statusLabel(): Attribute
); );
} }
public function closedAtFormatted(): Attribute
{
return Attribute::make(
get: fn () => $this->closed_at?->translatedFormat('l, d F Y H:i'),
);
}
public function payrolls(): HasMany
{
return $this->hasMany(Payroll::class);
}
public function closedBy(): BelongsTo
{
return $this->belongsTo(User::class, 'closed_by_id');
}
public function isOpen(): bool public function isOpen(): bool
{ {
return $this->status === PayrollPeriodStatus::OPEN; return $this->status === PayrollPeriodStatus::OPEN;

View File

@ -4,6 +4,7 @@
use App\Models\Concerns\InteractsWithActivityLog; use App\Models\Concerns\InteractsWithActivityLog;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
@ -14,6 +15,7 @@
#[Sluggable(from: 'name', to: 'slug')] #[Sluggable(from: 'name', to: 'slug')]
class Product extends Model class Product extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes; use SoftDeletes;

View File

@ -7,6 +7,7 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
@ -14,6 +15,7 @@
#[Appends(['price_formatted', 'price_input', 'type_label'])] #[Appends(['price_formatted', 'price_input', 'type_label'])]
class ProductPrice extends Model class ProductPrice extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
protected function casts(): array protected function casts(): array
@ -24,6 +26,11 @@ protected function casts(): array
]; ];
} }
public function variant(): BelongsTo
{
return $this->belongsTo(ProductVariant::class, 'variant_id');
}
public function priceFormatted(): Attribute public function priceFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -44,9 +51,4 @@ public function typeLabel(): Attribute
get: fn () => $this->type->label(), get: fn () => $this->type->label(),
); );
} }
public function variant(): BelongsTo
{
return $this->belongsTo(ProductVariant::class, 'variant_id');
}
} }

View File

@ -5,6 +5,7 @@
use App\Models\Concerns\HasModuleMedia; use App\Models\Concerns\HasModuleMedia;
use App\Models\Concerns\InteractsWithActivityLog; use App\Models\Concerns\InteractsWithActivityLog;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
@ -14,10 +15,38 @@
#[Guarded(['id'])] #[Guarded(['id'])]
class ProductVariant extends Model implements HasMedia class ProductVariant extends Model implements HasMedia
{ {
use HasFactory;
use HasModuleMedia; use HasModuleMedia;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes; use SoftDeletes;
protected function casts(): array
{
return [
'stock' => 'integer',
];
}
public function cuttingResults(): HasMany
{
return $this->hasMany(CuttingResult::class);
}
public function orderItems(): HasMany
{
return $this->hasMany(OrderItem::class);
}
public function prices(): HasMany
{
return $this->hasMany(ProductPrice::class, 'variant_id');
}
public function product(): BelongsTo
{
return $this->belongsTo(Product::class);
}
public static function mediaModuleName(): string public static function mediaModuleName(): string
{ {
return 'product'; return 'product';
@ -27,31 +56,4 @@ public function registerMediaCollections(): void
{ {
$this->addMediaCollection('images'); $this->addMediaCollection('images');
} }
protected function casts(): array
{
return [
'stock' => 'integer',
];
}
public function product(): BelongsTo
{
return $this->belongsTo(Product::class);
}
public function prices(): HasMany
{
return $this->hasMany(ProductPrice::class, 'variant_id');
}
public function orderItems(): HasMany
{
return $this->hasMany(OrderItem::class);
}
public function cuttingResults(): HasMany
{
return $this->hasMany(CuttingResult::class);
}
} }

View File

@ -7,6 +7,7 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
@ -22,20 +23,11 @@
])] ])]
class Purchase extends Model implements HasMedia class Purchase extends Model implements HasMedia
{ {
use HasFactory;
use HasModuleMedia; use HasModuleMedia;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes; use SoftDeletes;
public static function mediaModuleName(): string
{
return 'purchase';
}
public function registerMediaCollections(): void
{
$this->addMediaCollection('photos');
}
protected function casts(): array protected function casts(): array
{ {
return [ return [
@ -45,39 +37,6 @@ protected function casts(): array
]; ];
} }
public function subtotalFormatted(): Attribute
{
return Attribute::make(
get: fn () => 'Rp '.number_format($this->subtotal, 0, ',', '.'),
);
}
public function discountFormatted(): Attribute
{
return Attribute::make(
get: fn () => 'Rp '.number_format($this->discount, 0, ',', '.'),
);
}
public function totalFormatted(): Attribute
{
return Attribute::make(
get: fn () => 'Rp '.number_format($this->total, 0, ',', '.'),
);
}
public function createdAtFormatted(): Attribute
{
return Attribute::make(
get: fn () => $this->created_at?->translatedFormat('l, d F Y H:i'),
);
}
public function supplier(): BelongsTo
{
return $this->belongsTo(Supplier::class);
}
public function createdBy(): BelongsTo public function createdBy(): BelongsTo
{ {
return $this->belongsTo(User::class, 'created_by_id'); return $this->belongsTo(User::class, 'created_by_id');
@ -87,4 +46,47 @@ public function items(): HasMany
{ {
return $this->hasMany(PurchaseItem::class); return $this->hasMany(PurchaseItem::class);
} }
public function supplier(): BelongsTo
{
return $this->belongsTo(Supplier::class);
}
public function createdAtFormatted(): Attribute
{
return Attribute::make(
get: fn () => $this->created_at?->translatedFormat('l, d F Y H:i'),
);
}
public function discountFormatted(): Attribute
{
return Attribute::make(
get: fn () => 'Rp '.number_format($this->discount, 0, ',', '.'),
);
}
public function subtotalFormatted(): Attribute
{
return Attribute::make(
get: fn () => 'Rp '.number_format($this->subtotal, 0, ',', '.'),
);
}
public function totalFormatted(): Attribute
{
return Attribute::make(
get: fn () => 'Rp '.number_format($this->total, 0, ',', '.'),
);
}
public static function mediaModuleName(): string
{
return 'purchase';
}
public function registerMediaCollections(): void
{
$this->addMediaCollection('photos');
}
} }

View File

@ -6,6 +6,7 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
@ -20,6 +21,7 @@
])] ])]
class PurchaseItem extends Model class PurchaseItem extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes; use SoftDeletes;
@ -32,6 +34,16 @@ protected function casts(): array
]; ];
} }
public function purchase(): BelongsTo
{
return $this->belongsTo(Purchase::class);
}
public function rawMaterialPrice(): BelongsTo
{
return $this->belongsTo(RawMaterialPrice::class);
}
public function quantityFormatted(): Attribute public function quantityFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -50,13 +62,6 @@ public function quantityInput(): Attribute
); );
} }
public function unitPriceFormatted(): Attribute
{
return Attribute::make(
get: fn () => 'Rp '.number_format($this->unit_price, 0, ',', '.'),
);
}
public function subtotalFormatted(): Attribute public function subtotalFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -71,13 +76,10 @@ public function unitAbbreviation(): Attribute
); );
} }
public function purchase(): BelongsTo public function unitPriceFormatted(): Attribute
{ {
return $this->belongsTo(Purchase::class); return Attribute::make(
} get: fn () => 'Rp '.number_format($this->unit_price, 0, ',', '.'),
);
public function rawMaterialPrice(): BelongsTo
{
return $this->belongsTo(RawMaterialPrice::class);
} }
} }

View File

@ -9,6 +9,7 @@
use Illuminate\Database\Eloquent\Attributes\Scope; use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
@ -17,6 +18,7 @@
#[Appends(['unit_label', 'unit_abbreviation'])] #[Appends(['unit_label', 'unit_abbreviation'])]
class RawMaterial extends Model class RawMaterial extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes; use SoftDeletes;
@ -40,11 +42,9 @@ public function inactive(Builder $query): void
$query->where('is_active', false); $query->where('is_active', false);
} }
public function unitLabel(): Attribute public function prices(): HasMany
{ {
return Attribute::make( return $this->hasMany(RawMaterialPrice::class);
get: fn () => $this->unit->label(),
);
} }
public function unitAbbreviation(): Attribute public function unitAbbreviation(): Attribute
@ -54,8 +54,10 @@ public function unitAbbreviation(): Attribute
); );
} }
public function prices(): HasMany public function unitLabel(): Attribute
{ {
return $this->hasMany(RawMaterialPrice::class); return Attribute::make(
get: fn () => $this->unit->label(),
);
} }
} }

View File

@ -7,6 +7,7 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
@ -17,20 +18,11 @@
#[Appends(['price_formatted', 'stock_formatted', 'price_input', 'stock_input'])] #[Appends(['price_formatted', 'stock_formatted', 'price_input', 'stock_input'])]
class RawMaterialPrice extends Model implements HasMedia class RawMaterialPrice extends Model implements HasMedia
{ {
use HasFactory;
use HasModuleMedia; use HasModuleMedia;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes; use SoftDeletes;
public static function mediaModuleName(): string
{
return 'raw-material';
}
public function registerMediaCollections(): void
{
$this->addMediaCollection('images');
}
protected function casts(): array protected function casts(): array
{ {
return [ return [
@ -39,6 +31,16 @@ protected function casts(): array
]; ];
} }
public function cuttingMaterials(): HasMany
{
return $this->hasMany(CuttingMaterial::class);
}
public function rawMaterial(): BelongsTo
{
return $this->belongsTo(RawMaterial::class);
}
public function priceFormatted(): Attribute public function priceFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -46,6 +48,13 @@ public function priceFormatted(): Attribute
); );
} }
public function priceInput(): Attribute
{
return Attribute::make(
get: fn () => (string) (int) $this->price,
);
}
public function stockFormatted(): Attribute public function stockFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -57,13 +66,6 @@ public function stockFormatted(): Attribute
); );
} }
public function priceInput(): Attribute
{
return Attribute::make(
get: fn () => (string) (int) $this->price,
);
}
public function stockInput(): Attribute public function stockInput(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -71,13 +73,13 @@ public function stockInput(): Attribute
); );
} }
public function rawMaterial(): BelongsTo public static function mediaModuleName(): string
{ {
return $this->belongsTo(RawMaterial::class); return 'raw-material';
} }
public function cuttingMaterials(): HasMany public function registerMediaCollections(): void
{ {
return $this->hasMany(CuttingMaterial::class); $this->addMediaCollection('images');
} }
} }

View File

@ -4,6 +4,7 @@
use App\Models\Concerns\InteractsWithActivityLog; use App\Models\Concerns\InteractsWithActivityLog;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\Relations\MorphTo;
@ -11,6 +12,7 @@
#[Guarded(['id'])] #[Guarded(['id'])]
class Rejection extends Model class Rejection extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
public function rejectable(): MorphTo public function rejectable(): MorphTo

View File

@ -4,6 +4,7 @@
use App\Models\Concerns\InteractsWithActivityLog; use App\Models\Concerns\InteractsWithActivityLog;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
@ -11,6 +12,7 @@
#[Guarded(['id'])] #[Guarded(['id'])]
class Supplier extends Model class Supplier extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes; use SoftDeletes;

View File

@ -5,12 +5,14 @@
use App\Models\Concerns\HasModuleMedia; use App\Models\Concerns\HasModuleMedia;
use App\Models\Concerns\InteractsWithActivityLog; use App\Models\Concerns\InteractsWithActivityLog;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Spatie\MediaLibrary\HasMedia; use Spatie\MediaLibrary\HasMedia;
#[Guarded(['id'])] #[Guarded(['id'])]
class SystemConfiguration extends Model implements HasMedia class SystemConfiguration extends Model implements HasMedia
{ {
use HasFactory;
use HasModuleMedia; use HasModuleMedia;
use InteractsWithActivityLog; use InteractsWithActivityLog;

View File

@ -24,7 +24,12 @@
#[Appends(['role_label'])] #[Appends(['role_label'])]
class User extends Authenticatable class User extends Authenticatable
{ {
use CausesActivity, HasFactory, HasRoles, InteractsWithActivityLog, Notifiable, SoftDeletes; use CausesActivity;
use HasFactory;
use HasRoles;
use InteractsWithActivityLog;
use Notifiable;
use SoftDeletes;
protected function casts(): array protected function casts(): array
{ {
@ -47,6 +52,36 @@ public function inactive(Builder $query): void
$query->where('is_active', false); $query->where('is_active', false);
} }
public function cashTransactions(): HasMany
{
return $this->hasMany(CashTransaction::class, 'created_by_id');
}
public function employee(): HasOne
{
return $this->hasOne(Employee::class);
}
public function expenses(): HasMany
{
return $this->hasMany(Expense::class, 'created_by_id');
}
public function orders(): HasMany
{
return $this->hasMany(Order::class, 'created_by_id');
}
public function profile(): HasOne
{
return $this->hasOne(UserProfile::class);
}
public function purchases(): HasMany
{
return $this->hasMany(Purchase::class, 'created_by_id');
}
public function roleLabel(): Attribute public function roleLabel(): Attribute
{ {
return Attribute::make( return Attribute::make(
@ -57,34 +92,4 @@ public function roleLabel(): Attribute
}, },
); );
} }
public function profile(): HasOne
{
return $this->hasOne(UserProfile::class);
}
public function employee(): HasOne
{
return $this->hasOne(Employee::class);
}
public function cashTransactions(): HasMany
{
return $this->hasMany(CashTransaction::class, 'created_by_id');
}
public function expenses(): HasMany
{
return $this->hasMany(Expense::class, 'created_by_id');
}
public function purchases(): HasMany
{
return $this->hasMany(Purchase::class, 'created_by_id');
}
public function orders(): HasMany
{
return $this->hasMany(Order::class, 'created_by_id');
}
} }

View File

@ -8,6 +8,7 @@
use Illuminate\Database\Eloquent\Attributes\Appends; use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded; use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
@ -16,6 +17,7 @@
#[Appends(['birth_date_formatted', 'birth_date_input', 'gender_label'])] #[Appends(['birth_date_formatted', 'birth_date_input', 'gender_label'])]
class UserProfile extends Model class UserProfile extends Model
{ {
use HasFactory;
use InteractsWithActivityLog; use InteractsWithActivityLog;
use SoftDeletes; use SoftDeletes;
@ -27,29 +29,29 @@ protected function casts(): array
]; ];
} }
protected function birthDateFormatted(): Attribute public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function birthDateFormatted(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: fn () => Carbon::parse($this->birth_date)->format('l, d F Y'), get: fn () => Carbon::parse($this->birth_date)->format('l, d F Y'),
); );
} }
protected function birthDateInput(): Attribute public function birthDateInput(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: fn () => $this->birth_date?->format('Y-m-d'), get: fn () => $this->birth_date?->format('Y-m-d'),
); );
} }
protected function genderLabel(): Attribute public function genderLabel(): Attribute
{ {
return Attribute::make( return Attribute::make(
get: fn () => $this->gender?->label(), get: fn () => $this->gender?->label(),
); );
} }
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
} }

View File

@ -2,14 +2,16 @@
namespace App\Services\Account; namespace App\Services\Account;
use App\Models\User;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
class ProfileService class ProfileService
{ {
public function update(array $validated): void /**
* @param array<string, mixed> $validated
*/
public function update(array $validated, User $user): void
{ {
$user = auth()->user();
DB::transaction(function () use ($user, $validated): void { DB::transaction(function () use ($user, $validated): void {
$user->email = $validated['email']; $user->email = $validated['email'];
$user->username = $validated['username']; $user->username = $validated['username'];

View File

@ -0,0 +1,23 @@
<?php
namespace App\Services\Concerns;
use App\Models\Employee;
use App\Models\User;
use Illuminate\Validation\ValidationException;
trait ResolvesAuthEmployee
{
private function resolveAuthEmployee(?User $user = null): Employee
{
$employee = ($user ?? auth()->user())?->employee;
if ($employee === null) {
throw ValidationException::withMessages([
'employee' => 'Akun Anda tidak terhubung ke data pegawai.',
]);
}
return $employee;
}
}

View File

@ -4,6 +4,8 @@
use App\Enums\EmployeeAdvanceStatus; use App\Enums\EmployeeAdvanceStatus;
use App\Models\EmployeeAdvance; use App\Models\EmployeeAdvance;
use App\Models\User;
use App\Services\Concerns\ResolvesAuthEmployee;
use App\Services\Media\MediaService; use App\Services\Media\MediaService;
use App\Support\Media\MediaPresenter; use App\Support\Media\MediaPresenter;
use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Contracts\Pagination\LengthAwarePaginator;
@ -13,6 +15,8 @@
class EmployeeAdvanceService class EmployeeAdvanceService
{ {
use ResolvesAuthEmployee;
private const MAX_PHOTOS = 1; private const MAX_PHOTOS = 1;
public function __construct( public function __construct(
@ -75,15 +79,9 @@ public function paginateForIndex(array $tableQuery): LengthAwarePaginator
/** /**
* @param array{amount: int, description: string, due_date: string} $validated * @param array{amount: int, description: string, due_date: string} $validated
*/ */
public function create(array $validated): void public function create(array $validated, User $user): void
{ {
$employee = auth()->user()?->employee; $employee = $this->resolveAuthEmployee($user);
if ($employee === null) {
throw ValidationException::withMessages([
'employee' => 'Akun Anda tidak terhubung ke data pegawai.',
]);
}
DB::transaction(function () use ($validated, $employee): void { DB::transaction(function () use ($validated, $employee): void {
$employeeAdvance = EmployeeAdvance::create([ $employeeAdvance = EmployeeAdvance::create([
@ -101,9 +99,9 @@ public function create(array $validated): void
/** /**
* @param array{amount: int, description: string, due_date: string} $validated * @param array{amount: int, description: string, due_date: string} $validated
*/ */
public function update(EmployeeAdvance $employeeAdvance, array $validated): void public function update(EmployeeAdvance $employeeAdvance, array $validated, User $user): void
{ {
$this->ensureOwnedBySubmitter($employeeAdvance); $this->ensureOwnedBySubmitter($employeeAdvance, $user);
$this->ensurePending($employeeAdvance, 'Kasbon hanya dapat diubah saat status menunggu.'); $this->ensurePending($employeeAdvance, 'Kasbon hanya dapat diubah saat status menunggu.');
DB::transaction(function () use ($employeeAdvance, $validated): void { DB::transaction(function () use ($employeeAdvance, $validated): void {
@ -116,21 +114,19 @@ public function update(EmployeeAdvance $employeeAdvance, array $validated): void
}); });
} }
public function delete(EmployeeAdvance $employeeAdvance): void public function delete(EmployeeAdvance $employeeAdvance, User $user): void
{ {
$this->ensureOwnedBySubmitter($employeeAdvance); $this->ensureOwnedBySubmitter($employeeAdvance, $user);
$this->ensurePending($employeeAdvance, 'Kasbon hanya dapat dihapus saat status menunggu.'); $this->ensurePending($employeeAdvance, 'Kasbon hanya dapat dihapus saat status menunggu.');
$employeeAdvance->clearMediaCollection('photos'); $employeeAdvance->clearMediaCollection('photos');
$employeeAdvance->delete(); $employeeAdvance->delete();
} }
public function approve(EmployeeAdvance $employeeAdvance): void public function approve(EmployeeAdvance $employeeAdvance, User $user): void
{ {
$this->ensurePending($employeeAdvance, 'Kasbon ini sudah diverifikasi.'); $this->ensurePending($employeeAdvance, 'Kasbon ini sudah diverifikasi.');
$user = auth()->user();
DB::transaction(function () use ($employeeAdvance, $user): void { DB::transaction(function () use ($employeeAdvance, $user): void {
$employeeAdvance->loadMissing('employee.user.profile'); $employeeAdvance->loadMissing('employee.user.profile');
@ -154,12 +150,10 @@ public function approve(EmployeeAdvance $employeeAdvance): void
}); });
} }
public function reject(EmployeeAdvance $employeeAdvance, string $reason): void public function reject(EmployeeAdvance $employeeAdvance, string $reason, User $user): void
{ {
$this->ensurePending($employeeAdvance, 'Kasbon ini sudah diverifikasi.'); $this->ensurePending($employeeAdvance, 'Kasbon ini sudah diverifikasi.');
$user = auth()->user();
DB::transaction(function () use ($employeeAdvance, $user, $reason): void { DB::transaction(function () use ($employeeAdvance, $user, $reason): void {
$employeeAdvance->status = EmployeeAdvanceStatus::REJECTED; $employeeAdvance->status = EmployeeAdvanceStatus::REJECTED;
$employeeAdvance->verified_at = now(); $employeeAdvance->verified_at = now();
@ -173,7 +167,7 @@ public function reject(EmployeeAdvance $employeeAdvance, string $reason): void
}); });
} }
public function pay(EmployeeAdvance $employeeAdvance): void public function pay(EmployeeAdvance $employeeAdvance, User $user): void
{ {
if ($employeeAdvance->status !== EmployeeAdvanceStatus::APPROVED) { if ($employeeAdvance->status !== EmployeeAdvanceStatus::APPROVED) {
throw ValidationException::withMessages([ throw ValidationException::withMessages([
@ -181,8 +175,6 @@ public function pay(EmployeeAdvance $employeeAdvance): void
]); ]);
} }
$user = auth()->user();
DB::transaction(function () use ($employeeAdvance, $user): void { DB::transaction(function () use ($employeeAdvance, $user): void {
$employeeAdvance->loadMissing('employee.user.profile'); $employeeAdvance->loadMissing('employee.user.profile');
@ -222,9 +214,9 @@ private function syncPhotos(EmployeeAdvance $employeeAdvance, array $validated):
); );
} }
private function ensureOwnedBySubmitter(EmployeeAdvance $employeeAdvance): void private function ensureOwnedBySubmitter(EmployeeAdvance $employeeAdvance, User $user): void
{ {
if (auth()->user()?->employee?->id !== $employeeAdvance->employee_id) { if ($user->employee?->id !== $employeeAdvance->employee_id) {
throw ValidationException::withMessages([ throw ValidationException::withMessages([
'employee_advance' => 'Anda tidak memiliki akses untuk mengubah kasbon ini.', 'employee_advance' => 'Anda tidak memiliki akses untuk mengubah kasbon ini.',
]); ]);

View File

@ -4,6 +4,8 @@
use App\Models\Attendance; use App\Models\Attendance;
use App\Models\Employee; use App\Models\Employee;
use App\Models\User;
use App\Services\Concerns\ResolvesAuthEmployee;
use App\Services\Media\MediaService; use App\Services\Media\MediaService;
use Carbon\CarbonInterface; use Carbon\CarbonInterface;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
@ -13,6 +15,8 @@
class AttendanceService class AttendanceService
{ {
use ResolvesAuthEmployee;
public function __construct( public function __construct(
private readonly MediaService $mediaService, private readonly MediaService $mediaService,
) {} ) {}
@ -55,9 +59,9 @@ public function todayAttendanceForEmployee(Employee $employee): ?array
/** /**
* @param array{photo: string, latitude: float, longitude: float, location_tag: string} $validated * @param array{photo: string, latitude: float, longitude: float, location_tag: string} $validated
*/ */
public function checkIn(array $validated): void public function checkIn(array $validated, User $user): void
{ {
$employee = $this->resolveAuthEmployee(); $employee = $this->resolveAuthEmployee($user);
$existing = Attendance::query() $existing = Attendance::query()
->where('employee_id', $employee->id) ->where('employee_id', $employee->id)
@ -96,9 +100,9 @@ public function checkIn(array $validated): void
/** /**
* @param array{photo: string, latitude: float, longitude: float, location_tag: string} $validated * @param array{photo: string, latitude: float, longitude: float, location_tag: string} $validated
*/ */
public function checkOut(array $validated): void public function checkOut(array $validated, User $user): void
{ {
$employee = $this->resolveAuthEmployee(); $employee = $this->resolveAuthEmployee($user);
$attendance = Attendance::query() $attendance = Attendance::query()
->where('employee_id', $employee->id) ->where('employee_id', $employee->id)
@ -148,19 +152,6 @@ public function delete(Attendance $attendance): void
$attendance->delete(); $attendance->delete();
} }
private function resolveAuthEmployee(): Employee
{
$employee = auth()->user()?->employee;
if ($employee === null) {
throw ValidationException::withMessages([
'employee' => 'Akun Anda tidak terhubung ke data pegawai.',
]);
}
return $employee;
}
private function resolveLocationTag(string $clientTag, float $latitude, float $longitude): string private function resolveLocationTag(string $clientTag, float $latitude, float $longitude): string
{ {
if ($clientTag !== '') { if ($clientTag !== '') {

View File

@ -4,6 +4,8 @@
use App\Enums\LeaveRequestStatus; use App\Enums\LeaveRequestStatus;
use App\Models\LeaveRequest; use App\Models\LeaveRequest;
use App\Models\User;
use App\Services\Concerns\ResolvesAuthEmployee;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
@ -12,6 +14,8 @@
class LeaveRequestService class LeaveRequestService
{ {
use ResolvesAuthEmployee;
/** /**
* @param array{search: string, sort: string, direction: 'asc'|'desc'} $tableQuery * @param array{search: string, sort: string, direction: 'asc'|'desc'} $tableQuery
*/ */
@ -38,15 +42,9 @@ public function paginateForIndex(array $tableQuery): LengthAwarePaginator
/** /**
* @param array{start_date: string, end_date: string} $validated * @param array{start_date: string, end_date: string} $validated
*/ */
public function create(array $validated): void public function create(array $validated, User $user): void
{ {
$employee = auth()->user()?->employee; $employee = $this->resolveAuthEmployee($user);
if ($employee === null) {
throw ValidationException::withMessages([
'employee' => 'Akun Anda tidak terhubung ke data pegawai.',
]);
}
$startDate = Carbon::parse($validated['start_date'])->startOfDay(); $startDate = Carbon::parse($validated['start_date'])->startOfDay();
$endDate = Carbon::parse($validated['end_date'])->startOfDay(); $endDate = Carbon::parse($validated['end_date'])->startOfDay();
@ -66,9 +64,9 @@ public function create(array $validated): void
/** /**
* @param array{start_date: string, end_date: string} $validated * @param array{start_date: string, end_date: string} $validated
*/ */
public function update(LeaveRequest $leaveRequest, array $validated): void public function update(LeaveRequest $leaveRequest, array $validated, User $user): void
{ {
$this->ensureOwnedBySubmitter($leaveRequest); $this->ensureOwnedBySubmitter($leaveRequest, $user);
$this->ensurePending($leaveRequest, 'Pengajuan cuti hanya dapat diubah saat status menunggu.'); $this->ensurePending($leaveRequest, 'Pengajuan cuti hanya dapat diubah saat status menunggu.');
$startDate = Carbon::parse($validated['start_date'])->startOfDay(); $startDate = Carbon::parse($validated['start_date'])->startOfDay();
@ -83,20 +81,18 @@ public function update(LeaveRequest $leaveRequest, array $validated): void
$leaveRequest->save(); $leaveRequest->save();
} }
public function delete(LeaveRequest $leaveRequest): void public function delete(LeaveRequest $leaveRequest, User $user): void
{ {
$this->ensureOwnedBySubmitter($leaveRequest); $this->ensureOwnedBySubmitter($leaveRequest, $user);
$this->ensurePending($leaveRequest, 'Pengajuan cuti hanya dapat dihapus saat status menunggu.'); $this->ensurePending($leaveRequest, 'Pengajuan cuti hanya dapat dihapus saat status menunggu.');
$leaveRequest->delete(); $leaveRequest->delete();
} }
public function approve(LeaveRequest $leaveRequest): void public function approve(LeaveRequest $leaveRequest, User $user): void
{ {
$this->ensurePending($leaveRequest, 'Pengajuan cuti ini sudah diverifikasi.'); $this->ensurePending($leaveRequest, 'Pengajuan cuti ini sudah diverifikasi.');
$user = auth()->user();
DB::transaction(function () use ($leaveRequest, $user): void { DB::transaction(function () use ($leaveRequest, $user): void {
$leaveRequest->status = LeaveRequestStatus::APPROVED; $leaveRequest->status = LeaveRequestStatus::APPROVED;
$leaveRequest->verified_at = now(); $leaveRequest->verified_at = now();
@ -105,12 +101,10 @@ public function approve(LeaveRequest $leaveRequest): void
}); });
} }
public function reject(LeaveRequest $leaveRequest, string $reason): void public function reject(LeaveRequest $leaveRequest, string $reason, User $user): void
{ {
$this->ensurePending($leaveRequest, 'Pengajuan cuti ini sudah diverifikasi.'); $this->ensurePending($leaveRequest, 'Pengajuan cuti ini sudah diverifikasi.');
$user = auth()->user();
DB::transaction(function () use ($leaveRequest, $user, $reason): void { DB::transaction(function () use ($leaveRequest, $user, $reason): void {
$leaveRequest->status = LeaveRequestStatus::REJECTED; $leaveRequest->status = LeaveRequestStatus::REJECTED;
$leaveRequest->verified_at = now(); $leaveRequest->verified_at = now();
@ -149,9 +143,9 @@ private function ensureValidDateRange(Carbon $startDate, Carbon $endDate): void
} }
} }
private function ensureOwnedBySubmitter(LeaveRequest $leaveRequest): void private function ensureOwnedBySubmitter(LeaveRequest $leaveRequest, User $user): void
{ {
if (auth()->user()?->employee?->id !== $leaveRequest->employee_id) { if ($user->employee?->id !== $leaveRequest->employee_id) {
throw ValidationException::withMessages([ throw ValidationException::withMessages([
'leave_request' => 'Anda tidak memiliki akses untuk mengubah pengajuan cuti ini.', 'leave_request' => 'Anda tidak memiliki akses untuk mengubah pengajuan cuti ini.',
]); ]);

View File

@ -209,7 +209,7 @@ public function update(Cutting $cutting, array $validated): void
{ {
if (! $cutting->status->isEditable()) { if (! $cutting->status->isEditable()) {
throw ValidationException::withMessages([ throw ValidationException::withMessages([
'status' => 'Cutting tidak dapat diubah.', 'status' => 'Proses potong tidak dapat diubah.',
]); ]);
} }
@ -241,7 +241,7 @@ public function delete(Cutting $cutting): void
{ {
if ($cutting->status !== CuttingStatus::IN_PROGRESS) { if ($cutting->status !== CuttingStatus::IN_PROGRESS) {
throw ValidationException::withMessages([ throw ValidationException::withMessages([
'status' => 'Cutting hanya dapat dihapus saat masih proses.', 'status' => 'Proses potong hanya dapat dihapus saat masih proses.',
]); ]);
} }
@ -252,15 +252,15 @@ public function delete(Cutting $cutting): void
}); });
} }
public function transitionStatus(Cutting $cutting, CuttingStatus $status, ?string $reason = null): void public function transitionStatus(Cutting $cutting, CuttingStatus $status, User $user, ?string $reason = null): void
{ {
if (! $cutting->status->canTransitionTo($status)) { if (! $cutting->status->canTransitionTo($status)) {
throw ValidationException::withMessages([ throw ValidationException::withMessages([
'status' => 'Status cutting tidak dapat diubah.', 'status' => 'Status proses potong tidak dapat diubah.',
]); ]);
} }
DB::transaction(function () use ($cutting, $status, $reason): void { DB::transaction(function () use ($cutting, $status, $reason, $user): void {
$cutting->load(['materials', 'results']); $cutting->load(['materials', 'results']);
if ($status === CuttingStatus::COMPLETED) { if ($status === CuttingStatus::COMPLETED) {
@ -273,7 +273,7 @@ public function transitionStatus(Cutting $cutting, CuttingStatus $status, ?strin
if ($status === CuttingStatus::REJECTED) { if ($status === CuttingStatus::REJECTED) {
$this->reverseMaterialStock($cutting); $this->reverseMaterialStock($cutting);
$this->storeRejection($cutting, $reason); $this->storeRejection($cutting, $reason, $user);
} }
if ($status === CuttingStatus::IN_PROGRESS && $cutting->status === CuttingStatus::REJECTED) { if ($status === CuttingStatus::IN_PROGRESS && $cutting->status === CuttingStatus::REJECTED) {
@ -347,7 +347,7 @@ private function buildResults(array $results): array
if ($cuttingResult < 1) { if ($cuttingResult < 1) {
throw ValidationException::withMessages([ throw ValidationException::withMessages([
"results.{$index}.cutting_result" => 'Hasil cutting minimal 1 pcs.', "results.{$index}.cutting_result" => 'Hasil potong minimal 1 pcs.',
]); ]);
} }
@ -365,7 +365,7 @@ private function buildResults(array $results): array
if (($warehouseStock + $cuttingReject) !== $cuttingResult) { if (($warehouseStock + $cuttingReject) !== $cuttingResult) {
throw ValidationException::withMessages([ throw ValidationException::withMessages([
"results.{$index}.cutting_result" => 'Hasil cutting harus sama dengan stok gudang ditambah reject.', "results.{$index}.cutting_result" => 'Hasil potong harus sama dengan stok gudang ditambah reject.',
]); ]);
} }
@ -427,7 +427,7 @@ private function applyProductStockOnVerify(Cutting $cutting): void
} }
} }
private function storeRejection(Cutting $cutting, ?string $reason): void private function storeRejection(Cutting $cutting, ?string $reason, User $user): void
{ {
if ($reason === null || trim($reason) === '') { if ($reason === null || trim($reason) === '') {
throw ValidationException::withMessages([ throw ValidationException::withMessages([
@ -435,8 +435,6 @@ private function storeRejection(Cutting $cutting, ?string $reason): void
]); ]);
} }
$user = auth()->user();
$cutting->rejection()?->delete(); $cutting->rejection()?->delete();
$cutting->rejection()->create([ $cutting->rejection()->create([

View File

@ -18,7 +18,7 @@
class PurchaseService class PurchaseService
{ {
private const MAX_PHOTOS_FILES = 1; private const MAX_PHOTOS = 1;
public function __construct( public function __construct(
private readonly MediaService $mediaService, private readonly MediaService $mediaService,
@ -262,7 +262,7 @@ private function syncPhotos(Purchase $purchase, array $validated): void
'photos', 'photos',
$validated['photos'] ?? null, $validated['photos'] ?? null,
$validated['remove_media_ids'] ?? null, $validated['remove_media_ids'] ?? null,
self::MAX_PHOTOS_FILES, self::MAX_PHOTOS,
required: false, required: false,
errorKey: 'photos', errorKey: 'photos',
); );

View File

@ -41,8 +41,7 @@ public function create(array $validated): void
*/ */
public function update(Category $category, array $validated): void public function update(Category $category, array $validated): void
{ {
$category->name = $validated['name']; $category->fill($validated)->save();
$category->save();
} }
public function delete(Category $category): void public function delete(Category $category): void

View File

@ -43,10 +43,7 @@ public function create(array $validated): void
*/ */
public function update(Customer $customer, array $validated): void public function update(Customer $customer, array $validated): void
{ {
$customer->name = $validated['name']; $customer->fill($validated)->save();
$customer->phone_number = $validated['phone_number'];
$customer->address = $validated['address'];
$customer->save();
} }
public function delete(Customer $customer): void public function delete(Customer $customer): void

View File

@ -43,10 +43,7 @@ public function create(array $validated): void
*/ */
public function update(Supplier $supplier, array $validated): void public function update(Supplier $supplier, array $validated): void
{ {
$supplier->name = $validated['name']; $supplier->fill($validated)->save();
$supplier->phone_number = $validated['phone_number'];
$supplier->address = $validated['address'];
$supplier->save();
} }
public function delete(Supplier $supplier): void public function delete(Supplier $supplier): void

View File

@ -0,0 +1,47 @@
<?php
namespace Database\Factories;
use App\Models\Attendance;
use App\Models\Employee;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<Attendance>
*/
class AttendanceFactory extends Factory
{
public function definition(): array
{
$checkInAt = fake()->dateTimeBetween('-30 days', 'now');
$checkOutAt = (clone $checkInAt)->modify('+'.fake()->numberBetween(4, 9).' hours');
return [
'employee_id' => Employee::factory(),
'attendance_date' => $checkInAt->format('Y-m-d'),
'check_in_at' => $checkInAt,
'check_out_at' => $checkOutAt,
'check_in_photo_path' => 'attendance/checkin/'.fake()->uuid().'.jpg',
'check_out_photo_path' => 'attendance/checkout/'.fake()->uuid().'.jpg',
'check_in_latitude' => fake()->latitude(-7, -6),
'check_in_longitude' => fake()->longitude(106, 107),
'check_out_latitude' => fake()->latitude(-7, -6),
'check_out_longitude' => fake()->longitude(106, 107),
'check_in_location_tag' => fake()->optional()->city(),
'check_out_location_tag' => fake()->optional()->city(),
'work_duration_minutes' => fake()->numberBetween(240, 540),
];
}
public function checkedInOnly(): static
{
return $this->state(fn (array $attributes) => [
'check_out_at' => null,
'check_out_photo_path' => null,
'check_out_latitude' => null,
'check_out_longitude' => null,
'check_out_location_tag' => null,
'work_duration_minutes' => null,
]);
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace Database\Factories;
use App\Models\CashAccount;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<CashAccount>
*/
class CashAccountFactory extends Factory
{
public function definition(): array
{
return [
'created_by_id' => User::factory(),
'name' => fake()->randomElement(['Kas Toko', 'Kas Operasional', 'Kas Utama']),
'balance' => 0,
];
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Database\Factories;
use App\Models\CashAccount;
use App\Models\CashTransaction;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<CashTransaction>
*/
class CashTransactionFactory extends Factory
{
public function definition(): array
{
$amount = fake()->numberBetween(10_000, 5_000_000);
return [
'cash_account_id' => CashAccount::factory(),
'created_by_id' => User::factory(),
'reference_type' => null,
'reference_id' => null,
'amount' => $amount,
'balance_after' => $amount,
'description' => fake()->sentence(3),
];
}
public function deposit(): static
{
return $this->state(fn (array $attributes) => [
'reference_type' => null,
'reference_id' => null,
]);
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace Database\Factories;
use App\Models\Category;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
/**
* @extends Factory<Category>
*/
class CategoryFactory extends Factory
{
public function definition(): array
{
$name = fake()->unique()->words(2, true);
return [
'name' => Str::limit($name, 50, ''),
'slug' => Str::slug($name),
];
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace Database\Factories;
use App\Models\Customer;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<Customer>
*/
class CustomerFactory extends Factory
{
public function definition(): array
{
return [
'name' => fake()->name(),
'phone_number' => fake()->numerify('08##########'),
'address' => fake()->optional()->address(),
];
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Database\Factories;
use App\Enums\CuttingStatus;
use App\Models\Cutting;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<Cutting>
*/
class CuttingFactory extends Factory
{
public function definition(): array
{
return [
'status' => CuttingStatus::IN_PROGRESS->value,
'description' => fake()->optional()->sentence(3),
'created_by_id' => User::factory(),
];
}
public function completed(): static
{
return $this->state(fn (array $attributes) => [
'status' => CuttingStatus::COMPLETED->value,
]);
}
public function verified(): static
{
return $this->state(fn (array $attributes) => [
'status' => CuttingStatus::VERIFIED->value,
]);
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace Database\Factories;
use App\Models\Cutting;
use App\Models\CuttingMaterial;
use App\Models\RawMaterialPrice;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<CuttingMaterial>
*/
class CuttingMaterialFactory extends Factory
{
public function definition(): array
{
$materialUsage = fake()->randomFloat(4, 1, 25);
$remainingMaterial = fake()->randomFloat(4, 0, 10);
return [
'cutting_id' => Cutting::factory(),
'raw_material_price_id' => RawMaterialPrice::factory(),
'material_usage' => $materialUsage,
'remaining_material' => $remainingMaterial,
];
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace Database\Factories;
use App\Models\Cutting;
use App\Models\CuttingResult;
use App\Models\ProductVariant;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<CuttingResult>
*/
class CuttingResultFactory extends Factory
{
public function definition(): array
{
$cuttingResult = fake()->numberBetween(10, 200);
$cuttingReject = fake()->numberBetween(0, (int) ($cuttingResult * 0.1));
return [
'cutting_id' => Cutting::factory(),
'product_variant_id' => ProductVariant::factory(),
'cutting_result' => $cuttingResult,
'warehouse_stock' => $cuttingResult - $cuttingReject,
'cutting_reject' => $cuttingReject,
];
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace Database\Factories;
use App\Enums\EmployeeAdvanceStatus;
use App\Models\Employee;
use App\Models\EmployeeAdvance;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<EmployeeAdvance>
*/
class EmployeeAdvanceFactory extends Factory
{
public function definition(): array
{
return [
'employee_id' => Employee::factory(),
'amount' => fake()->numberBetween(100_000, 3_000_000),
'description' => fake()->sentence(3),
'due_date' => fake()->dateTimeBetween('now', '+3 months'),
'status' => EmployeeAdvanceStatus::PENDING->value,
'cash_transaction_id' => null,
'repayment_cash_transaction_id' => null,
'verified_at' => null,
'verified_by_id' => null,
'paid_at' => null,
'paid_by_id' => null,
];
}
public function approved(): static
{
return $this->state(fn (array $attributes) => [
'status' => EmployeeAdvanceStatus::APPROVED->value,
'verified_at' => now(),
'verified_by_id' => User::factory(),
]);
}
public function rejected(): static
{
return $this->state(fn (array $attributes) => [
'status' => EmployeeAdvanceStatus::REJECTED->value,
'verified_at' => now(),
'verified_by_id' => User::factory(),
]);
}
}

Some files were not shown because too many files have changed in this diff Show More