From 4cbd296c0c720d8642c89c1db8053cbb2b67b8e4 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Sun, 21 Jun 2026 15:16:58 +0700 Subject: [PATCH] feat: add submittedBy relationship to Cutting model and enhance notification system for cutting updates and deletions --- app/Models/Cutting.php | 5 ++ .../Finance/EmployeeAdvanceService.php | 17 +++++++ app/Services/Finance/PayrollService.php | 9 ++++ app/Services/Hr/AttendanceService.php | 11 +++++ app/Services/Hr/LeaveRequestService.php | 17 +++++++ app/Services/Manage/CuttingService.php | 14 +++++- app/Services/Manage/StockService.php | 10 ++++ ..._add_submitted_by_id_to_cuttings_table.php | 26 +++++++++++ database/seeders/DatabaseSeeder.php | 46 +++++++++---------- 9 files changed, 131 insertions(+), 24 deletions(-) create mode 100644 database/migrations/2026_06_21_150000_add_submitted_by_id_to_cuttings_table.php diff --git a/app/Models/Cutting.php b/app/Models/Cutting.php index 832825b..235e60c 100644 --- a/app/Models/Cutting.php +++ b/app/Models/Cutting.php @@ -39,6 +39,11 @@ public function createdBy(): BelongsTo return $this->belongsTo(User::class, 'created_by_id'); } + public function submittedBy(): BelongsTo + { + return $this->belongsTo(User::class, 'submitted_by_id'); + } + public function materials(): HasMany { return $this->hasMany(CuttingMaterial::class); diff --git a/app/Services/Finance/EmployeeAdvanceService.php b/app/Services/Finance/EmployeeAdvanceService.php index 1214aed..5abd78f 100644 --- a/app/Services/Finance/EmployeeAdvanceService.php +++ b/app/Services/Finance/EmployeeAdvanceService.php @@ -106,11 +106,28 @@ public function update(EmployeeAdvance $employeeAdvance, array $validated, User $employeeAdvance->due_date = $validated['due_date']; $employeeAdvance->save(); }); + + $this->pushNotificationService->sendToRoles( + '✏️ Kasbon Diperbarui', + "Kasbon sebesar {$employeeAdvance->amount_formatted} telah diperbarui oleh {$user->profile?->full_name}.", + ['owner', 'developer'], + '/admin/finance/employee-advances', + ); } public function delete(EmployeeAdvance $employeeAdvance, User $user): void { + $amount = $employeeAdvance->amount_formatted; + $description = $employeeAdvance->description; + $employeeAdvance->delete(); + + $this->pushNotificationService->sendToRoles( + '🗑️ Kasbon Dihapus', + "Kasbon sebesar {$amount} dengan keterangan {$description} telah dihapus.", + ['owner', 'developer'], + '/admin/finance/employee-advances', + ); } public function approve(EmployeeAdvance $employeeAdvance, User $user): void diff --git a/app/Services/Finance/PayrollService.php b/app/Services/Finance/PayrollService.php index cb525fd..28bdcdd 100644 --- a/app/Services/Finance/PayrollService.php +++ b/app/Services/Finance/PayrollService.php @@ -269,6 +269,15 @@ public function deleteAdjustment(PayrollAdjustment $adjustment): void $payroll->recalculateAmounts(); $payroll->save(); }); + + if ($payroll->employee?->user_id) { + $this->pushNotificationService->sendToUser( + '📊 Penyesuaian Gaji Dihapus', + "Penyesuaian gaji Anda untuk periode {$payroll->payrollPeriod->period_label} telah dihapus.", + $payroll->employee->user_id, + '/admin/finance/payrolls', + ); + } } public function pay(Payroll $payroll, User $user): void diff --git a/app/Services/Hr/AttendanceService.php b/app/Services/Hr/AttendanceService.php index 2d73f62..9cf5757 100644 --- a/app/Services/Hr/AttendanceService.php +++ b/app/Services/Hr/AttendanceService.php @@ -160,8 +160,19 @@ public function checkOut(array $validated, User $user): void public function delete(Attendance $attendance): void { + $attendance->loadMissing('employee.user.profile'); + $employeeName = $attendance->employee?->user?->profile?->full_name; + $date = $attendance->attendance_date; + $attendance->clearMediaCollection('checkin'); $attendance->clearMediaCollection('checkout'); $attendance->delete(); + + $this->pushNotificationService->sendToRoles( + '🗑️ Presensi Dihapus', + "Data presensi {$employeeName} tanggal {$date} telah dihapus.", + ['owner', 'developer'], + '/admin/hr/attendances', + ); } } diff --git a/app/Services/Hr/LeaveRequestService.php b/app/Services/Hr/LeaveRequestService.php index a0b33fe..cdc5a27 100644 --- a/app/Services/Hr/LeaveRequestService.php +++ b/app/Services/Hr/LeaveRequestService.php @@ -101,11 +101,28 @@ public function update(LeaveRequest $leaveRequest, array $validated, User $user) $leaveRequest->end_date = $endDate; $leaveRequest->total_days = $this->calculateTotalDays($startDate, $endDate); $leaveRequest->save(); + + $this->pushNotificationService->sendToRoles( + '✏️ Pengajuan Cuti Diperbarui', + "Pengajuan cuti oleh {$user->profile?->full_name} telah diperbarui.", + ['owner', 'developer'], + '/admin/hr/leave-requests', + ); } public function delete(LeaveRequest $leaveRequest): void { + $totalDays = $leaveRequest->total_days; + $employeeName = $leaveRequest->employee?->user?->profile?->full_name; + $leaveRequest->delete(); + + $this->pushNotificationService->sendToRoles( + '🗑️ Pengajuan Cuti Dihapus', + "Pengajuan cuti {$totalDays} hari oleh {$employeeName} telah dihapus.", + ['owner', 'developer'], + '/admin/hr/leave-requests', + ); } public function approve(LeaveRequest $leaveRequest, User $user): void diff --git a/app/Services/Manage/CuttingService.php b/app/Services/Manage/CuttingService.php index 2d01d36..5556cfc 100644 --- a/app/Services/Manage/CuttingService.php +++ b/app/Services/Manage/CuttingService.php @@ -506,6 +506,14 @@ public function update(Cutting $cutting, array $validated): void $this->deductMaterialStock($cutting); } }); + + $description = $cutting->description ?? '-'; + $this->pushNotificationService->sendToRoles( + '✏️ Proses Cutting Diperbarui', + "Proses cutting dengan deskripsi '{$description}' telah diperbarui.", + ['owner', 'developer'], + '/admin/manage/cuttings', + ); } public function delete(Cutting $cutting): void @@ -615,10 +623,14 @@ public function transitionStatus( default => '✂️ Proses Cutting Diperbarui', }; + $roles = $status === CuttingStatus::COMPLETED + ? ['owner', 'developer', 'admin-toko'] + : ['owner', 'developer']; + $this->pushNotificationService->sendToRoles( $title, $message, - ['owner', 'developer'], + $roles, '/admin/manage/cuttings', ); } diff --git a/app/Services/Manage/StockService.php b/app/Services/Manage/StockService.php index 044a2e5..d670cfa 100644 --- a/app/Services/Manage/StockService.php +++ b/app/Services/Manage/StockService.php @@ -109,6 +109,7 @@ public function submitVerification( ]); } + $cutting->submitted_by_id = $user->id; $cutting->status = CuttingStatus::PENDING_VERIFICATION; $cutting->save(); }); @@ -195,6 +196,15 @@ public function rejectVerification( ['owner', 'developer'], '/admin/manage/owner-verifications', ); + + if ($cutting->submitted_by_id) { + $this->pushNotificationService->sendToUser( + '📦 Verifikasi Cutting Ditolak Owner', + "Cutting dengan deskripsi '{$description}' yang Anda verifikasi ditolak oleh owner dengan alasan: '{$reason}'.", + $cutting->submitted_by_id, + '/admin/manage/owner-verifications', + ); + } } private function applyProductStockOnVerify(Cutting $cutting): void diff --git a/database/migrations/2026_06_21_150000_add_submitted_by_id_to_cuttings_table.php b/database/migrations/2026_06_21_150000_add_submitted_by_id_to_cuttings_table.php new file mode 100644 index 0000000..ac2e377 --- /dev/null +++ b/database/migrations/2026_06_21_150000_add_submitted_by_id_to_cuttings_table.php @@ -0,0 +1,26 @@ +foreignId('submitted_by_id') + ->nullable() + ->after('created_by_id') + ->constrained('users') + ->nullOnDelete(); + }); + } + + public function down(): void + { + Schema::table('cuttings', function (Blueprint $table) { + $table->dropConstrainedForeignId('submitted_by_id'); + }); + } +}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index d0a01d8..c1bb9ab 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -15,30 +15,30 @@ public function run(): void RolePermissionSeeder::class, UserSeeder::class, SystemConfigurationSeeder::class, - CategorySeeder::class, - ProductSeeder::class, - ProductVariantSeeder::class, - RawMaterialSeeder::class, - RawMaterialPriceSeeder::class, - SupplierSeeder::class, - CustomerSeeder::class, + // CategorySeeder::class, + // ProductSeeder::class, + // ProductVariantSeeder::class, + // RawMaterialSeeder::class, + // RawMaterialPriceSeeder::class, + // SupplierSeeder::class, + // CustomerSeeder::class, CashAccountSeeder::class, - CashTransactionSeeder::class, - ExpenseSeeder::class, - PayrollPeriodSeeder::class, - PayrollSeeder::class, - PayrollAdjustmentSeeder::class, - AttendanceSeeder::class, - LeaveRequestSeeder::class, - EmployeeAdvanceSeeder::class, - RejectionSeeder::class, - PurchaseSeeder::class, - PurchaseItemSeeder::class, - OrderSeeder::class, - OrderItemSeeder::class, - CuttingSeeder::class, - CuttingMaterialSeeder::class, - CuttingResultSeeder::class, + // CashTransactionSeeder::class, + // ExpenseSeeder::class, + // PayrollPeriodSeeder::class, + // PayrollSeeder::class, + // PayrollAdjustmentSeeder::class, + // AttendanceSeeder::class, + // LeaveRequestSeeder::class, + // EmployeeAdvanceSeeder::class, + // RejectionSeeder::class, + // PurchaseSeeder::class, + // PurchaseItemSeeder::class, + // OrderSeeder::class, + // OrderItemSeeder::class, + // CuttingSeeder::class, + // CuttingMaterialSeeder::class, + // CuttingResultSeeder::class, ]); } }