add projet

This commit is contained in:
root
2026-03-05 12:29:37 -05:00
parent 8d1eef8ba8
commit 23b7db1107
9109 changed files with 1106501 additions and 73 deletions
@@ -0,0 +1,141 @@
<?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),
];
}
}