141 lines
4.6 KiB
PHP
141 lines
4.6 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\AttendanceCommentTemplate; // <-- change if your model class name differs
|
|
use Illuminate\Database\Eloquent\Collection;
|
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class AttendanceCommentTemplateService
|
|
{
|
|
public function list(bool $activeOnly = false): array
|
|
{
|
|
$query = AttendanceCommentTemplate::query()->orderBy('min_score', 'asc');
|
|
|
|
if ($activeOnly) {
|
|
$query->where('is_active', 1);
|
|
}
|
|
|
|
return $query->get()
|
|
->map(fn ($row) => $this->transform($row))
|
|
->values()
|
|
->all();
|
|
}
|
|
|
|
public function findOrFail(int $id): array
|
|
{
|
|
$template = AttendanceCommentTemplate::query()->find($id);
|
|
|
|
if (!$template) {
|
|
throw new ModelNotFoundException("Attendance comment template not found.");
|
|
}
|
|
|
|
return $this->transform($template);
|
|
}
|
|
|
|
public function create(array $data): array
|
|
{
|
|
return DB::transaction(function () use ($data) {
|
|
$this->ensureNoOverlap(
|
|
(int) $data['min_score'],
|
|
(int) $data['max_score'],
|
|
null,
|
|
!empty($data['is_active'])
|
|
);
|
|
|
|
$template = AttendanceCommentTemplate::query()->create([
|
|
'min_score' => (int) $data['min_score'],
|
|
'max_score' => (int) $data['max_score'],
|
|
'template_text' => (string) $data['template_text'],
|
|
'is_active' => (bool) ($data['is_active'] ?? true),
|
|
]);
|
|
|
|
return $this->transform($template->fresh());
|
|
});
|
|
}
|
|
|
|
public function update(int $id, array $data): array
|
|
{
|
|
return DB::transaction(function () use ($id, $data) {
|
|
$template = AttendanceCommentTemplate::query()->find($id);
|
|
|
|
if (!$template) {
|
|
throw new ModelNotFoundException("Attendance comment template not found.");
|
|
}
|
|
|
|
$newMin = array_key_exists('min_score', $data) ? (int) $data['min_score'] : (int) $template->min_score;
|
|
$newMax = array_key_exists('max_score', $data) ? (int) $data['max_score'] : (int) $template->max_score;
|
|
$newIsActive = array_key_exists('is_active', $data) ? (bool) $data['is_active'] : (bool) $template->is_active;
|
|
|
|
$this->ensureNoOverlap($newMin, $newMax, $id, $newIsActive);
|
|
|
|
$template->fill([
|
|
'min_score' => $newMin,
|
|
'max_score' => $newMax,
|
|
'template_text' => array_key_exists('template_text', $data)
|
|
? (string) $data['template_text']
|
|
: (string) $template->template_text,
|
|
'is_active' => $newIsActive,
|
|
]);
|
|
|
|
$template->save();
|
|
|
|
return $this->transform($template->fresh());
|
|
});
|
|
}
|
|
|
|
public function delete(int $id): void
|
|
{
|
|
$template = AttendanceCommentTemplate::query()->find($id);
|
|
|
|
if (!$template) {
|
|
throw new ModelNotFoundException("Attendance comment template not found.");
|
|
}
|
|
|
|
$template->delete();
|
|
}
|
|
|
|
/**
|
|
* Prevent overlapping active score ranges.
|
|
*/
|
|
private function ensureNoOverlap(int $min, int $max, ?int $ignoreId = null, bool $isActive = true): void
|
|
{
|
|
if (!$isActive) {
|
|
return; // allow inactive templates to overlap
|
|
}
|
|
|
|
$query = AttendanceCommentTemplate::query()
|
|
->where('is_active', 1)
|
|
->where(function ($q) use ($min, $max) {
|
|
$q->whereBetween('min_score', [$min, $max])
|
|
->orWhereBetween('max_score', [$min, $max])
|
|
->orWhere(function ($q2) use ($min, $max) {
|
|
$q2->where('min_score', '<=', $min)
|
|
->where('max_score', '>=', $max);
|
|
});
|
|
});
|
|
|
|
if ($ignoreId !== null) {
|
|
$query->where('id', '!=', $ignoreId);
|
|
}
|
|
|
|
if ($query->exists()) {
|
|
abort(response()->json([
|
|
'status' => 'error',
|
|
'message' => 'Score range overlaps with an existing active template.',
|
|
], 422));
|
|
}
|
|
}
|
|
|
|
private function transform($row): array
|
|
{
|
|
return [
|
|
'id' => (int) ($row->id ?? 0),
|
|
'min_score' => (int) ($row->min_score ?? 0),
|
|
'max_score' => (int) ($row->max_score ?? 0),
|
|
'template_text' => (string) ($row->template_text ?? ''),
|
|
'is_active' => (bool) ($row->is_active ?? false),
|
|
];
|
|
}
|
|
} |