Files
minicrm/app/Services/ClosingService.php
phuongtc 3a8db5cae6
Some checks failed
Tests / PHP 8.3 (push) Has been cancelled
Tests / PHP 8.4 (push) Has been cancelled
Tests / PHP 8.5 (push) Has been cancelled
feat: granular permissions, export backup, user/role management
- PermissionSeeder: 29 permissions with role mapping (admin/manager/staff)
- Policies updated to use hasPermissionTo() instead of hasRole()
- ExportBackup command: JSON per-table backup with chunk processing
- UserResource: CRUD users with role assignment (admin only)
- RoleResource: CRUD roles with permission assignment (admin only)
- UserPolicy + RolePolicy: admin-only access control
- ImportCskh: detailed skip logging with color in dry-run mode
- Widgets: permission-based visibility checks
- Tests: 8/8 pass (21 assertions)
2026-05-02 04:47:10 +00:00

75 lines
2.5 KiB
PHP

<?php
namespace App\Services;
use App\Models\Department;
use App\Models\Feedback;
use App\Models\User;
use Illuminate\Support\Facades\App;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\HttpException;
class ClosingService
{
/**
* Close a feedback. Throws if staff tries to close or no proof exists.
*/
public function close(Feedback $feedback, User $actor): void
{
if ($feedback->status === 'closed') {
throw ValidationException::withMessages([
'status' => __('Phiếu này đã được đóng.'),
]);
}
if (! $actor->hasPermissionTo('close-ticket')) {
throw new HttpException(403, __('Chỉ lãnh đạo cấp phòng mới có quyền đóng phiếu.'));
}
if ($actor->hasRole('manager') && ! $actor->hasRole('admin')) {
$managedDeptIds = Department::where('manager_id', $actor->id)->pluck('id');
if (! $managedDeptIds->contains($feedback->current_department_id)) {
throw new HttpException(403, __('Bạn chỉ có thể đóng phiếu thuộc phòng ban mình quản lý.'));
}
}
$fileService = App::make(FileService::class);
if (! $fileService->hasCollection($feedback, 'proof_of_resolution')) {
throw ValidationException::withMessages([
'status' => __('Yêu cầu cung cấp tài liệu bằng chứng để hoàn tất quy trình.'),
]);
}
$feedback->update(['status' => 'closed']);
$this->notifyStakeholders($feedback, $actor);
}
/**
* Resolve a feedback. Any role can resolve.
*/
public function resolve(Feedback $feedback, User $actor): void
{
if (in_array($feedback->status, ['closed', 'resolved'])) {
throw ValidationException::withMessages([
'status' => __('Phiếu này đã được xử lý hoặc đóng.'),
]);
}
$feedback->update(['status' => 'resolved']);
}
protected function notifyStakeholders(Feedback $feedback, User $actor): void
{
if ($feedback->assignedTo) {
$feedback->assignedTo->notify(new \App\Notifications\TicketClosed($feedback, $actor));
}
$department = $feedback->currentDepartment;
if ($department && $department->manager && $department->manager->id !== ($feedback->assignedTo?->id ?? null)) {
$department->manager->notify(new \App\Notifications\TicketClosed($feedback, $actor));
}
}
}