feat: add submittedBy relationship to Cutting model and enhance notification system for cutting updates and deletions

This commit is contained in:
Yoga Pangestu 2026-06-21 15:16:58 +07:00
parent 9170e5fd1e
commit 4cbd296c0c
9 changed files with 131 additions and 24 deletions

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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',
);
}
}

View File

@ -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

View File

@ -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',
);
}

View File

@ -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

View File

@ -0,0 +1,26 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('cuttings', function (Blueprint $table) {
$table->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');
});
}
};

View File

@ -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,
]);
}
}