fix logic and tests, update docker CI file
This commit is contained in:
@@ -68,7 +68,7 @@ class AttendanceDay extends BaseModel
|
||||
$q = static::query()
|
||||
->select('id')
|
||||
->where('class_section_id', $classSectionId)
|
||||
->where('date', $date)
|
||||
->whereDate('date', $date)
|
||||
->where(function ($w) {
|
||||
$w->where('status', 'published')
|
||||
->orWhere('status', 'finalized'); // legacy
|
||||
@@ -91,7 +91,7 @@ class AttendanceDay extends BaseModel
|
||||
): ?self {
|
||||
return static::query()
|
||||
->where('class_section_id', $classSectionId)
|
||||
->where('date', $date)
|
||||
->whereDate('date', $date)
|
||||
->where('semester', $semester)
|
||||
->where('school_year', $schoolYear)
|
||||
->first();
|
||||
@@ -112,11 +112,12 @@ class AttendanceDay extends BaseModel
|
||||
if ($row) return $row;
|
||||
|
||||
$now = now();
|
||||
$normalizedDate = Carbon::parse($date)->toDateString();
|
||||
|
||||
try {
|
||||
return static::create([
|
||||
'class_section_id' => $classSectionId,
|
||||
'date' => $date,
|
||||
'date' => $normalizedDate,
|
||||
'status' => 'draft',
|
||||
'submitted_by' => null,
|
||||
'submitted_at' => null,
|
||||
@@ -142,15 +143,15 @@ class AttendanceDay extends BaseModel
|
||||
/**
|
||||
* DEPRECATED legacy finalize => submit (teacher submit).
|
||||
*/
|
||||
public static function finalize(int $id, int $userId): bool
|
||||
public function finalize(int $userId): bool
|
||||
{
|
||||
return static::submit($id, $userId, null);
|
||||
return $this->submit($userId, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Teacher submit: status => submitted (teacher locked, admin editable).
|
||||
*/
|
||||
public static function submit(int $id, int $userId, ?string $autoPublishAt = null): bool
|
||||
public function submit(int $userId, ?string $autoPublishAt = null): bool
|
||||
{
|
||||
$now = now();
|
||||
|
||||
@@ -165,17 +166,17 @@ class AttendanceDay extends BaseModel
|
||||
$payload['auto_publish_at'] = $autoPublishAt;
|
||||
}
|
||||
|
||||
return static::query()->whereKey($id)->update($payload) >= 0;
|
||||
return static::query()->whereKey($this->id)->update($payload) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin publish (hard lock): status => published.
|
||||
*/
|
||||
public static function publish(int $id, int $userId): bool
|
||||
public function publish(int $userId): bool
|
||||
{
|
||||
$now = now();
|
||||
|
||||
return static::query()->whereKey($id)->update([
|
||||
return static::query()->whereKey($this->id)->update([
|
||||
'status' => 'published',
|
||||
'published_by' => $userId,
|
||||
'published_at' => $now,
|
||||
@@ -186,7 +187,7 @@ class AttendanceDay extends BaseModel
|
||||
/**
|
||||
* Admin reopen a day back to 'draft' (default) or 'submitted'.
|
||||
*/
|
||||
public static function reopen(int $id, int $userId, string $toStatus = 'draft', ?string $reason = null): bool
|
||||
public function reopen(int $userId, string $toStatus = 'draft', ?string $reason = null): bool
|
||||
{
|
||||
if (!in_array($toStatus, ['draft', 'submitted'], true)) {
|
||||
throw new \InvalidArgumentException('toStatus must be "draft" or "submitted".');
|
||||
@@ -194,7 +195,7 @@ class AttendanceDay extends BaseModel
|
||||
|
||||
$now = now();
|
||||
|
||||
return static::query()->whereKey($id)->update([
|
||||
return static::query()->whereKey($this->id)->update([
|
||||
'status' => $toStatus,
|
||||
'reopened_by' => $userId,
|
||||
'reopened_at' => $now,
|
||||
@@ -202,4 +203,4 @@ class AttendanceDay extends BaseModel
|
||||
'updated_at' => $now,
|
||||
]) >= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ class AttendanceEmailTemplate extends BaseModel
|
||||
* Fetch a template by code and variant, falling back to 'default' if needed.
|
||||
* Active only.
|
||||
*/
|
||||
public static function getTemplate(string $code, string $variant = 'default'): ?self
|
||||
public static function getTemplate(string $code, string $variant = 'default'): ?array
|
||||
{
|
||||
$row = static::query()
|
||||
->where('code', $code)
|
||||
@@ -39,13 +39,15 @@ class AttendanceEmailTemplate extends BaseModel
|
||||
->first();
|
||||
|
||||
if ($row) {
|
||||
return $row;
|
||||
return $row->toArray();
|
||||
}
|
||||
|
||||
return static::query()
|
||||
$fallback = static::query()
|
||||
->where('code', $code)
|
||||
->where('variant', 'default')
|
||||
->where('is_active', 1)
|
||||
->first();
|
||||
|
||||
return $fallback?->toArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\BaseModel;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ClassSection extends BaseModel
|
||||
{
|
||||
use HasFactory;
|
||||
// CI table name is "classSection"
|
||||
protected $table = 'classSection';
|
||||
|
||||
@@ -28,6 +30,16 @@ class ClassSection extends BaseModel
|
||||
'class_section_id' => 'integer',
|
||||
];
|
||||
|
||||
public function getSectionNameAttribute(): ?string
|
||||
{
|
||||
return $this->attributes['class_section_name'] ?? null;
|
||||
}
|
||||
|
||||
public function setSectionNameAttribute($value): void
|
||||
{
|
||||
$this->attributes['class_section_name'] = $value;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
* Relationships (optional)
|
||||
* ========================= */
|
||||
@@ -136,4 +148,4 @@ class ClassSection extends BaseModel
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,11 @@ class CommunicationLog extends BaseModel
|
||||
'metadata',
|
||||
];
|
||||
|
||||
public function getFillable(): array
|
||||
{
|
||||
return $this->fillable;
|
||||
}
|
||||
|
||||
protected $casts = [
|
||||
'student_id' => 'integer',
|
||||
'family_id' => 'integer',
|
||||
@@ -51,4 +56,4 @@ class CommunicationLog extends BaseModel
|
||||
{
|
||||
return $this->belongsTo(User::class, 'sent_by');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,24 @@ class EmailTemplate extends BaseModel
|
||||
|
||||
protected $casts = [
|
||||
'is_active' => 'boolean',
|
||||
'updated_by' => 'integer',
|
||||
];
|
||||
|
||||
public static function getTemplate(string $code, string $variant = 'default'): ?self
|
||||
{
|
||||
$row = static::query()
|
||||
->where('code', $code)
|
||||
->where('is_active', 1)
|
||||
->where(function ($q) use ($variant) {
|
||||
$q->where('variant', $variant)
|
||||
->orWhere('variant', 'default');
|
||||
})
|
||||
->orderByRaw("CASE WHEN variant = ? THEN 0 ELSE 1 END", [$variant])
|
||||
->first();
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent of CI getActiveTemplates():
|
||||
* is_active=1, orderBy template_key ASC
|
||||
@@ -48,4 +64,4 @@ class EmailTemplate extends BaseModel
|
||||
->where('is_active', 1)
|
||||
->first();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,11 @@ class PurchaseOrder extends BaseModel
|
||||
'deleted_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function getFillable(): array
|
||||
{
|
||||
return $this->fillable;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Status (enum-like)
|
||||
* ============================================================
|
||||
@@ -157,4 +162,4 @@ class PurchaseOrder extends BaseModel
|
||||
'notes' => ['nullable', 'string', 'max:5000'],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,11 @@ class PurchaseOrderItem extends BaseModel
|
||||
'updated_at' => 'datetime',
|
||||
];
|
||||
|
||||
public function getFillable(): array
|
||||
{
|
||||
return $this->fillable;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Relationships (optional but recommended)
|
||||
* ============================================================
|
||||
@@ -84,4 +89,4 @@ class PurchaseOrderItem extends BaseModel
|
||||
'unit_cost' => [$updating ? 'sometimes' : 'required', 'numeric', 'min:0'],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ class Stats extends BaseModel
|
||||
* If your stats table has created_at/updated_at, keep true (default).
|
||||
* If it doesn't, set to false.
|
||||
*/
|
||||
public $timestamps = false;
|
||||
public $timestamps = true;
|
||||
|
||||
protected $fillable = [
|
||||
'students',
|
||||
@@ -28,6 +28,11 @@ class Stats extends BaseModel
|
||||
'users' => 'integer',
|
||||
];
|
||||
|
||||
public function getFillable(): array
|
||||
{
|
||||
return $this->fillable;
|
||||
}
|
||||
|
||||
/**
|
||||
* CI-compatible: getStats()
|
||||
* Returns all rows.
|
||||
|
||||
@@ -4,12 +4,14 @@ namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use App\Models\BaseModel;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class Student extends BaseModel
|
||||
{
|
||||
use HasFactory;
|
||||
protected $table = 'students';
|
||||
|
||||
/**
|
||||
@@ -38,7 +40,7 @@ class Student extends BaseModel
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'school_id' => 'integer',
|
||||
'school_id' => 'string',
|
||||
'age' => 'integer',
|
||||
'photo_consent' => 'boolean',
|
||||
'is_new' => 'boolean',
|
||||
@@ -392,4 +394,4 @@ class Student extends BaseModel
|
||||
'is_active' => ['nullable', 'boolean'],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ class TeacherClass extends BaseModel
|
||||
->join('classSection as cs', 'cs.class_section_id', '=', 'tc.class_section_id')
|
||||
->where('tc.teacher_id', $teacherId)
|
||||
->where('tc.school_year', $schoolYear)
|
||||
->orderByRaw("FIELD(tc.position,'main','ta')")
|
||||
->orderByRaw("CASE tc.position WHEN 'main' THEN 0 WHEN 'ta' THEN 1 ELSE 2 END")
|
||||
->get()
|
||||
->map(fn ($r) => (array) $r)
|
||||
->all();
|
||||
@@ -296,7 +296,7 @@ class TeacherClass extends BaseModel
|
||||
->leftJoin('users as u', 'u.id', '=', 'tc.teacher_id')
|
||||
->where('tc.class_section_id', $sectionCode)
|
||||
->where('tc.school_year', $schoolYear)
|
||||
->orderByRaw("FIELD(tc.position,'main','ta')")
|
||||
->orderByRaw("CASE tc.position WHEN 'main' THEN 0 WHEN 'ta' THEN 1 ELSE 2 END")
|
||||
->orderBy('u.firstname', 'asc')
|
||||
->get()
|
||||
->map(fn ($r) => (array) $r)
|
||||
@@ -324,7 +324,7 @@ class TeacherClass extends BaseModel
|
||||
->leftJoin('users as u', 'u.id', '=', 'tc.teacher_id')
|
||||
->where('tc.school_year', $schoolYear)
|
||||
->orderBy('tc.class_section_id', 'asc')
|
||||
->orderByRaw("FIELD(tc.position,'main','ta')")
|
||||
->orderByRaw("CASE tc.position WHEN 'main' THEN 0 WHEN 'ta' THEN 1 ELSE 2 END")
|
||||
->orderBy('u.firstname', 'asc');
|
||||
|
||||
if (!empty($onlySectionCodes)) {
|
||||
@@ -360,4 +360,4 @@ class TeacherClass extends BaseModel
|
||||
'updated_by' => ['nullable', 'integer'],
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
@@ -14,6 +15,7 @@ use Laravel\Sanctum\HasApiTokens;
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasApiTokens;
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'users';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user