Open
Conversation
… model, template apply - Add rlanvin/php-rrule to composer.json for RRULE parsing and expansion - Add migration: schedule_items.schedule_template_uuid, is_exception, exception_for_date columns - Add migration: schedule_exceptions table (time_off, sick, holiday, swap, training, other types) - Add migration: schedules.last_materialized_at, materialization_horizon columns - Rewrite Schedule model: add exceptions(), appliedTemplates(), activeShiftFor(), isDriverAvailableAt() - Rewrite ScheduleItem model: add scheduleTemplate(), scopeForDate(), scopeActiveOn(), isException() - Rewrite ScheduleTemplate model: add schedule(), items(), expandOccurrences(), generateItems() - Add ScheduleException model: polymorphic subject, approve/reject workflow, overlapping/coveringDate scopes - Rewrite ScheduleService: full RRULE materialization engine with exception-aware shift generation - materializeTemplate(): expand RRULE, skip exception-covered dates, upsert ScheduleItems - applyTemplateToSchedule(): copy library template to driver schedule and materialize - approveException()/rejectException(): workflow transitions + cancel covered shifts on approval - getExceptionsForSubject(): filtered query helper - Add MaterializeSchedulesJob: daily rolling 60-day window materialization for all active schedules - Add ScheduleExceptionController: approve, reject, forSubject endpoints - Rewrite ScheduleTemplateController: add apply and materialize endpoints - Add ScheduleException and ScheduleTemplate HTTP resource classes - Register schedule-exceptions routes with approve/reject/for-subject actions - Register schedule-templates apply/materialize routes - Register MaterializeSchedulesJob as daily:01:00 scheduled job in CoreServiceProvider
The schedule_templates migration was missing two columns that the model
already referenced in $fillable and applyToSchedule():
- schedule_uuid: links an applied template copy to its parent Schedule
(NULL for library templates, set when applyToSchedule() is called)
The absence of this column caused:
SQLSTATE[42S22]: Unknown column 'schedule_uuid' in 'field list'
when POST /schedule-templates/{id}/apply was called.
- color: hex colour string used by the frontend calendar to render
shift blocks (e.g. #6366f1). Frontend was already sending this field.
Changes:
- migrations/2026_04_05_000001_add_schedule_uuid_color_to_schedule_templates_table.php
New migration that adds both columns to the existing table.
- src/Models/ScheduleTemplate.php
Added 'color' to $fillable array, applyToSchedule() copy, and @Property docblock.
(schedule_uuid was already in $fillable — only the column was missing.)
- ScheduleService::applyTemplateToSchedule() now returns an array
{template, items_created} instead of just the ScheduleTemplate model,
so the apply endpoint can report the actual count from materializeTemplate()
rather than a post-hoc items()->count() which could be stale or zero
- ScheduleTemplateController::apply() updated to destructure the new return
and pass items_created directly from the materialization result
- Docblock updated to reflect the new return type signature
…y returning null
Previously getRruleInstance() caught all \Exception types, which meant a
'Class RRule\RRule not found' Error (not Exception) would still bubble up
but the catch block would silently return null, causing materializeTemplate()
to produce 0 items with no indication of the root cause.
Changes:
- Add class_exists('RRule\RRule') guard that throws a clear RuntimeException
with an actionable message: 'Run composer require rlanvin/php-rrule'
- Narrow the catch to \RRule\RRuleException only (invalid RRULE strings)
so legitimate missing-dependency errors are never swallowed
- Add \Log::warning() for invalid RRULE strings to aid debugging
…el/isPending on ScheduleException - Add PolymorphicType cast to Schedule.subject_type, ScheduleItem.assignee_type, ScheduleTemplate.subject_type so frontend 'fleet-ops:driver' strings are stored/resolved as the full PHP class name in the database - Create ScheduleItemFilter with scheduleUuid() that resolves public_id to UUID and startAtBetween()/endAtBetween() for range queries from the frontend - Create ScheduleExceptionFilter with scheduleUuid() that resolves public_id to UUID - Add typeLabel and isPending appended attributes to ScheduleException model - Add debug logging to materializeTemplate for easier diagnosis
…dule relationship)
The php-rrule library requires the RFC 5545 property format: DTSTART:<date> (colon separator, not equals sign) RRULE:<rule> (RRULE: prefix required) Previous code was generating: DTSTART=20260405T080000 <- wrong: equals sign FREQ=WEEKLY;BYDAY=MO,TU <- wrong: missing RRULE: prefix This caused InvalidArgumentException: 'Failed to parse RFC line, missing property name followed by ":"' in RfcParser.php. Also: - Use DTSTART;TZID=<tz>:<date> for named timezones (not UTC) - Use DTSTART:<date>Z for UTC - Strip any existing RRULE: prefix from stored value to avoid doubling - Catch InvalidArgumentException (RFC parse errors) in addition to RRuleException
…ve polymorphic type aliases The GET /schedules?subject_type=fleet-ops:driver query was returning empty because the DB stores the full PHP class name (Fleetbase\FleetOps\Models\Driver) via the PolymorphicType cast, but no filter class existed to translate the short alias 'fleet-ops:driver' into the FQCN before applying the WHERE clause. This caused loadDriverSchedule() to always create a new duplicate Schedule instead of finding the existing one, so materialized ScheduleItems were never visible in the calendar. Changes: - Add ScheduleFilter: resolves subject_type alias, filters by subject_uuid/status - Add ScheduleTemplateFilter: resolves subject_type alias, filters by subject_uuid/schedule_uuid - Update ScheduleItemFilter: add assigneeType() + assigneeUuid() methods with alias resolution - Update ScheduleExceptionFilter: add subjectType() + subjectUuid() methods with alias resolution All four filters use Utils::getMutationType() which handles: 'fleet-ops:driver' -> 'Fleetbase\FleetOps\Models\Driver' 'fleet-ops:order' -> 'Fleetbase\FleetOps\Models\Order' etc.
…edule on first item - materializeTemplate: change default status from 'pending' to 'scheduled' for future shifts (clearer semantics — pending implies awaiting approval, scheduled means the shift is confirmed and upcoming) - applyTemplateToSchedule: activate the schedule (draft → active) after the first template is successfully applied and items are materialized - createScheduleItem: activate the parent schedule (draft → active) when the first standalone shift item is created directly
The status column was defined as ENUM('pending','confirmed','in_progress',
'completed','cancelled','no_show') — 'scheduled' was not a valid value, causing
MySQL to throw SQLSTATE[01000] Data truncated when materializeTemplate() tried
to insert items with status='scheduled'.
Adds a new migration that:
- Adds 'scheduled' to the ENUM (between 'pending' and 'confirmed')
- Changes the column DEFAULT from 'pending' to 'scheduled'
- Retains 'pending' for backwards compatibility
The down() migration reverts 'scheduled' rows to 'pending' before shrinking
the ENUM back to its original definition.
…hedules table - New migration adds per-schedule HOS limit columns (nullable, fallback to global defaults) - hos_source column allows future extensibility (schedule | telematics | manual) - Schedule model fillable and casts updated accordingly
- New migration adds company_uuid column to schedule_items table and backfills from parent schedule - ScheduleItem model: company_uuid added to fillable/filterParams, boot() auto-populates from parent schedule or session on creating - ScheduleService::materializeTemplate: explicitly sets company_uuid from schedule.company_uuid on each created item - ScheduleItemFilter::queryForInternal: uses company_uuid OR schedule join so items without a schedule_uuid (standalone shifts) are still included in company-scoped queries
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.