VACATION SYSTEM - REVISED IMPLEMENTATION PLAN V2 ================================================ Document purpose ---------------- This document replaces the lifecycle assumptions in the original vacation-system implementation plan. It incorporates the following approved changes: 1. Weekly days off are employee-specific rather than globally defined. 2. Work-week types must be managed through a new CRUD module. 3. Every employee must be assigned a work-week type. 4. Official holidays remain part of vacation-day calculation and may or may not deduct from the employee balance. 5. The default for a newly created official holiday is that it does not deduct from the vacation balance. 6. A configurable connected-leave rule can add the consecutive weekly days off immediately following a leave request. 7. Vacation request status "archived" is replaced by "completed", displayed in Arabic as "منتهي". 8. Request-day generation, balance reservation, daily consumption, cancellation, and completion must use auditable vacation_request_days records. This plan is intentionally divided into implementation phases that can be copied into separate working chats. CURRENT SYSTEM AUDIT ==================== The following items already exist in the project: - week_days migration, seed data, model, routes, permissions, and CRUD views. - official_holidays migration, model, routes, permissions, and CRUD views. - vacation_request_days migration, model, routes, permissions, and administrative views. - vacation_requests CRUD, printing, approval, rejection, and cancellation actions. - vacation_balances and vacation_years logic. - A singleton hr_settings row used for vacation-year start and end dates. - The HR vacation submenu. Important current behavior that must be replaced: - week_days.is_weekend is currently global for all employees. - Employees do not have a work_week_type_id. - Vacation requests accept working_days from the browser. - Request creation currently increases reserved_days immediately. - Approval currently removes reserved days and immediately increases used_days. - No dedicated request-day generator, balance service, workflow service, or daily processor exists. - Official holidays currently have affects_vacation_calculation with a database default of true. - The request status enum currently contains archived instead of completed. All related migrations have already run on MySQL. Therefore: - Never edit an already-run migration to deploy these changes. - Create new additive migrations. - Use an expand, backfill, switch, and contract approach for renamed or removed fields. - Preserve existing requests and balances until a reconciliation phase explicitly handles them. REVISED BUSINESS RULES ====================== 1. WEEK-DAY DICTIONARY ---------------------- The week_days table remains the fixed dictionary of the seven calendar weekdays: - 0: Sunday - 1: Monday - 2: Tuesday - 3: Wednesday - 4: Thursday - 5: Friday - 6: Saturday The table supplies names and display order only. The global week_days.is_weekend value must no longer determine whether a date is a working day or a weekly day off for an employee. 2. EMPLOYEE-SPECIFIC WORK WEEKS ------------------------------- Every employee is assigned one work-week type. Examples: - Administrative week: Friday and Saturday are off. - Six-day week: Friday is off only. - Another operational week: different days may be configured as off. Each work-week type must contain exactly seven day configurations, one for every week_days record. At least one day must be a working day. This prevents an invalid all-off schedule and prevents an endless connected-day calculation. The working-day and off-day counts are calculated from the seven day configurations. They must not be independently trusted user values. 3. OFFICIAL HOLIDAY POLICY -------------------------- Official holidays remain part of vacation calculation. Each official holiday has its own balance policy: - If the holiday is configured to affect the vacation balance, the date deducts from the balance when included in the calculated request dates. - If the holiday is configured not to affect the vacation balance, the date does not deduct. - The default for every newly created official holiday is no balance deduction. The existing affects_vacation_calculation field may remain the authoritative field, but its meaning must be made explicit everywhere: - true: the official holiday date deducts from the vacation balance. - false: the official holiday date does not deduct from the vacation balance. The database default must be changed to false through a new migration. The Arabic CRUD label should clearly describe the behavior, for example: "تخصم العطلة من رصيد الإجازة" Do not silently update existing official holiday rows. Existing values must be reviewed because the old default was true. Official holidays only classify dates already included in the requested or connected date set. An official holiday outside that date set does not extend a vacation request by itself. 4. CONNECTED WEEKLY-OFF POLICY ------------------------------ Add a singleton vacation setting: count_connected_weekly_off_days The UI value is Yes or No, and the recommended database default is false. Recommended interpretation based on the supplied examples: - When disabled, consecutive weekly days off after the requested end date are not added. - When enabled, start with the day after request.end_date. - Add consecutive weekly-off dates according to the employee's work-week type. - Stop at the first configured working day. - Do not add days before request.start_date. Example A: - Employee weekly days off: Friday and Saturday. - Requested leave: Thursday only. - Connected setting enabled. - Calculated dates: Thursday, Friday, Saturday. Example B: - Employee weekly days off: Friday and Saturday. - Requested leave: Sunday through Thursday. - Connected setting enabled. - Calculated dates: Sunday through Saturday. The phrase "connected leave" must not be implemented as both leading and trailing weekly days off unless management later requests that change. Adding the preceding Friday and Saturday to a request starting Sunday would contradict the supplied example. 5. POLICY PRECEDENCE FOR EACH DATE ---------------------------------- Use this precedence order so the calculation is deterministic: 1. If the vacation type does not affect balance: - deducts_balance = false for every generated date. 2. Otherwise, if the date is an enabled official holiday applicable to the request's vacation year: - deducts_balance equals the holiday's affects_vacation_calculation value. - The holiday policy overrides the employee work-week classification for balance deduction. 3. Otherwise, if the date is a configured employee working day: - deducts_balance = true. 4. Otherwise, the date is a configured weekly day off: - deducts_balance = true only when connected weekly-off calculation is enabled and the date is included by that policy. - deducts_balance = false when connected calculation is disabled. 5. day_value is 1.00 for a full deductible day and 0.00 for a non-deductible day. Future half-day support may use day_value = 0.50, but it is outside the current scope. 6. POLICY SNAPSHOTS ------------------- Changing an employee's work-week type or the global connected setting must not silently reinterpret approved or completed requests. At request creation, snapshot: - work_week_type_id on vacation_requests. - count_connected_weekly_off_days on vacation_requests. Every vacation_request_days row also stores the calculated result for audit purposes. Recommended rule: - Settings and employee schedule changes apply to newly created requests. - Existing approved, rejected, cancelled, or completed requests never regenerate automatically. - Submitted or under-review requests may be regenerated only through an explicit safe action. 7. REQUEST TOTALS ----------------- Do not trust a working_days value from the browser. Maintain separate concepts: - requested_calendar_days: number of calendar dates explicitly selected by the user. - working_days: scheduled employee working days inside the explicit requested range. - deductible_days: sum of day_value where deducts_balance is true, including connected weekly-off dates. All balance approval checks must use deductible_days derived from vacation_request_days. The Arabic UI should emphasize "الأيام المحتسبة من الرصيد" for deductible_days so users do not confuse it with scheduled working days. 8. COMPLETED STATUS ------------------- Replace the vacation request status value archived with completed. Arabic label: منتهي This change applies to vacation requests only. Do not rename the archived status of vacation years. A vacation year may still be archived because that term describes a closed historical year. TARGET DATABASE DESIGN ====================== 1. work_week_types ------------------ Recommended columns: - id - name - working_days_count, unsigned tiny integer - off_days_count, unsigned tiny integer - is_default, boolean, default false - status, enabled or disabled - notes, nullable text - created_by, nullable user foreign key - updated_by, nullable user foreign key - timestamps - soft deletes Rules: - name is required. - working_days_count + off_days_count must equal 7. - Counts are synchronized from child day rows inside the same transaction. - Exactly one active default type should exist. - A type assigned to employees or snapshotted by requests cannot be hard deleted. - A default type cannot be disabled until another default is selected. 2. work_week_type_days ---------------------- Recommended columns: - id - work_week_type_id - week_day_id - is_working_day, boolean - timestamps Constraints: - Unique work_week_type_id plus week_day_id. - Exactly seven rows for each work-week type. - work_week_type_id references work_week_types. - week_day_id references week_days. 3. employees changes -------------------- Add: - work_week_type_id, initially nullable, indexed, foreign key with restrict-on-delete. Deployment sequence: 1. Add nullable field. 2. Create the default work-week type from existing week_days.is_weekend values. 3. Assign the default type to all existing employees. 4. Validate that no employee remains unassigned. 5. Make the field required in a later contract migration if deployment policy allows it. 4. hr_settings changes ---------------------- Add: - count_connected_weekly_off_days, boolean, default false. Keep the existing singleton row and vacation-year date settings. The setting page must always edit the singleton record rather than insert multiple rows. 5. vacation_requests changes ---------------------------- Add: - work_week_type_id, nullable during transition, later required for new requests. - count_connected_weekly_off_days, boolean snapshot. - requested_calendar_days, unsigned integer or suitable decimal if future partial days require it. - deductible_days, decimal(6,2), default 0. - completed_at, nullable timestamp. Status transition: 1. Expand the enum to temporarily allow archived and completed. 2. Migrate existing archived requests to completed. 3. Update application code and filters. 4. Remove archived from the request enum in a later contract migration. 6. vacation_request_days changes -------------------------------- Recommended additive fields: - source, enum or string: requested or connected_weekly_off. - is_weekly_off, boolean snapshot. - is_scheduled_working_day, boolean snapshot. - work_week_type_id, nullable snapshot/reference during transition. - calculation_reason, optional string or enum for audit reporting. Keep: - date - week_day_id - is_holiday - official_holiday_id - day_value - deducts_balance - reserved_at - processed_at - released_at - notes The old is_weekend column becomes legacy after is_weekly_off is introduced. Remove it only in a later contract migration after all code has switched. Recommended calculation_reason values: - requested_working_day - requested_weekly_off - requested_official_holiday - connected_weekly_off - non_balance_vacation_type The existing unique vacation_request_id plus date constraint remains valid. Do not add a global unique employee_id plus date constraint because rejected, cancelled, and historical requests may share dates. Active overlap is enforced transactionally during approval. REVISED REQUEST LIFECYCLE ========================= Main path: Create request -> Snapshot employee work week and connected setting -> Generate request-day rows -> Submitted -> Under review -> Approved -> Reserve deductible days -> Process each finished day -> Completed Alternative paths: - Submitted or under review -> Rejected. - Submitted or under review -> Cancelled. - Approved -> Cancelled, releasing only unprocessed reserved days. 1. CREATE AND SUBMIT -------------------- In one transaction: 1. Validate employee, vacation type, current vacation year, and requested dates. 2. Require the employee to have an enabled work-week type with seven configured days. 3. Create the request number. 4. Snapshot employee.work_week_type_id onto the request. 5. Snapshot hr_settings.count_connected_weekly_off_days onto the request. 6. Generate requested and connected request-day rows. 7. Calculate requested_calendar_days, working_days, and deductible_days from those rows. 8. Set status to submitted. 9. Set approval_status to pending. 10. Set submitted_at. Balance effect: - No reservation. - No used-day increase. - No remaining balance change. 2. UNDER REVIEW --------------- Printing or explicitly starting review changes submitted to under_review through the workflow service. Balance effect: - None. 3. REJECT BEFORE APPROVAL ------------------------- Allowed from submitted or under_review. Update: - status = rejected - approval_status = rejected - rejected_at = now Balance effect: - None. 4. CANCEL BEFORE APPROVAL ------------------------- Allowed from submitted or under_review. Update: - status = cancelled - cancelled_at = now Balance effect: - None. 5. APPROVE ---------- Approval must run in one transaction: 1. Lock the request. 2. Lock its generated request-day rows. 3. Lock the matching employee vacation balance. 4. Recalculate requested total from request-day rows rather than request input: SUM(day_value) WHERE deducts_balance = true AND processed_at IS NULL AND released_at IS NULL 5. Calculate: available_days = remaining_days - reserved_days 6. Reject approval if deductible_days exceeds available_days. 7. Reject approval if another approved request for the same employee overlaps any deductible generated date, including connected weekly-off dates. 8. Increase reserved_days by the exact deductible total. 9. Set reserved_at on each deductible request-day row. 10. Set request status and approval status to approved. 11. Set approved_at. Do not increase used_days at approval. Do not reduce remaining_days at approval. 6. DAILY PROCESSING ------------------- Create a scheduled command such as: hr:process-vacation-days Recommended schedule: - Daily at 00:10. - withoutOverlapping(). - onOneServer() when the application runs on multiple servers. Process request-day rows where: - Request status is approved. - Date is before today. - deducts_balance is true. - reserved_at is not null. - processed_at is null. - released_at is null. For each eligible day, in one transaction: 1. Lock the day. 2. Lock the request. 3. Lock the balance. 4. Decrease reserved_days by day_value. 5. Increase used_days by day_value. 6. Recalculate remaining_days: opening_balance - (used_days + adjusted_days) 7. Set processed_at. Use chunkById or another bounded iteration strategy. Idempotency: - A row with processed_at is never processed again. - Never reset all reserved_days to zero. - Never affect reservations belonging to other requests. 7. COMPLETE REQUEST ------------------- After daily processing, mark an approved request completed when: - Every deductible request-day row has either processed_at or released_at. - The latest generated deductible date is before today. Use the generated date set, not only request.end_date, because connected weekly-off rows may extend past the explicit end date. Update: - status = completed - completed_at = now Non-deductible dates do not block completion. 8. CANCEL AFTER APPROVAL ------------------------ In one transaction: 1. Lock the request. 2. Lock the request-day rows. 3. Lock the balance. 4. Sum deductible rows where reserved_at is set, processed_at is null, and released_at is null. 5. Decrease reserved_days by that exact total. 6. Set released_at on those rows. 7. Keep processed rows in used_days. 8. Set status = cancelled and cancelled_at = now. Processed days are not returned automatically. Any return of used balance must use a separate audited balance adjustment. IMPLEMENTATION PHASES ===================== PHASE 0 - BUSINESS POLICY CONFIRMATION -------------------------------------- Objective: Confirm the calculation rules before schema and service implementation. Decisions to approve: 1. Connected weekly days off are added only after end_date, not before start_date. 2. The extension stops at the first configured working day. 3. An official holiday uses its own balance-deduction flag. 4. The default official holiday flag is no deduction. 5. If a date is both an official holiday and a weekly day off, the official-holiday flag determines deduction. 6. Global settings and employee schedule changes do not change approved historical requests. 7. Employee schedule and connected policy are snapshotted on request creation. 8. Vacation types with affects_balance = false override all date-level deduction rules. 9. Requests cannot be approved when their deductible date sets overlap. 10. Cross-vacation-year requests and connected days crossing year boundaries are either blocked or handled by a separately approved allocation policy. Recommended cross-year rule for the first implementation: - Require every explicit and connected deductible date to remain inside the selected vacation year. - Block the request with a clear validation message otherwise. Deliverable: - Signed or confirmed policy decisions. Do not start the generator phase until these rules are accepted. PHASE 1 - ADDITIVE DATABASE FOUNDATION -------------------------------------- Objective: Add the new schema without breaking current code. Implement new migrations for: 1. work_week_types. 2. work_week_type_days. 3. employees.work_week_type_id as nullable. 4. hr_settings.count_connected_weekly_off_days default false. 5. vacation_requests snapshot, deductible total, and completed fields. 6. vacation_request_days source and schedule snapshot fields. 7. official_holidays.affects_vacation_calculation default false. 8. Request status enum expansion to include completed while temporarily retaining archived. 9. Permissions for work-week types and vacation settings. Important: - Do not drop week_days.is_weekend yet. - Do not drop vacation_request_days.is_weekend yet. - Do not remove request status archived yet. - Do not overwrite existing official-holiday values. - Do not alter balances in schema migrations. Acceptance criteria: - Migrations are reversible. - Current pages continue to load before later phases switch behavior. - New official holidays default to no balance deduction at the database level. - Existing data remains unchanged. PHASE 2 - MODELS, RELATIONSHIPS, AND DOMAIN CONSTANTS ---------------------------------------------------- Objective: Build the Eloquent foundation without adding workflow behavior. Create: - WorkWeekType model. - WorkWeekTypeDay model. Add relationships: - WorkWeekType hasMany days. - WorkWeekType hasMany employees. - WorkWeekType hasMany vacation requests. - WorkWeekTypeDay belongsTo work-week type and weekday. - Employee belongsTo work-week type. - VacationRequest belongsTo snapshotted work-week type. - VacationRequestDay belongsTo work-week type when the field exists. - WeekDay hasMany work-week type days. Add: - Casts for booleans, counts, decimals, and timestamps. - Status and source constants or enums matching project conventions. - Query scopes for enabled/default work-week types. - Request-day scopes for requested, connected, deductible, reserved, processed, and released rows. - Helpers that determine whether a request or request day is editable. Refactor official-holiday labels so the balance field clearly means deduction from vacation balance. Acceptance criteria: - Relationships reflect the new schema. - No lifecycle changes are made yet. - No duplicate status or source strings are scattered through pages. PHASE 3 - WORK-WEEK TYPES CRUD ------------------------------ Objective: Allow administrators to manage employee schedule types. Create full-page Livewire CRUD views matching the existing Week Days CRUD style and layout. Arabic title and submenu item: أنواع أسابيع الدوام Index requirements: - Search by name. - Filter by status. - Display working-days count, off-days count, default status, and active status. - Display edit, activate/deactivate, and safe-delete actions. Create/update form: - Name. - Status. - Default type selection. - Notes using the general textarea component. - Seven weekday rows ordered through week_days. - Each day must select either working day or weekly day off. - Show live derived counts. Save rules: - Save type and all seven child rows in one transaction. - Require exactly seven unique weekday configurations. - Require at least one working day. - Derive and store both counts. - Enforce one active default type. Deletion restrictions: - Block deletion when assigned to employees. - Block deletion when referenced by requests. - Block deletion of the default type until another default exists. Navigation: - Add the index page to the existing الإجازات submenu. - Add route active-state and permission checks. Do not assign employees or generate request days in this phase. PHASE 4 - DEFAULT WORK WEEK AND EMPLOYEE ASSIGNMENT -------------------------------------------------- Objective: Assign an employee-specific work week safely. Data backfill: 1. Create a default work-week type from the current week_days.is_weekend values. 2. Create its seven day rows. 3. Assign it to every employee without a work-week type. 4. Verify that all 90 existing employees are assigned in the current environment. Employee form changes: - Add a required "نوع أسبوع الدوام" general select field to employee create and update pages. - Load enabled work-week types only, while still displaying the employee's selected disabled type during editing if necessary. - Validate that the selected type exists and is not deleted. - Update EmployeeController create and update payloads. - Display the work-week type on the employee index or details page if useful. Server rules: - New employees must have a work-week type. - Do not allow removal of the assignment while vacation logic depends on it. Contract step: - After backfill verification, optionally make employees.work_week_type_id non-nullable through a new migration. Do not change request calculation in this phase. PHASE 5 - VACATION LOGIC SETTINGS PAGE -------------------------------------- Objective: Create a dedicated page for vacation calculation settings. Arabic page and submenu title: إعدادات الإجازات First setting: احتساب أيام العطلة الأسبوعية المتصلة: نعم / لا Implementation: - Reuse the existing singleton hr_settings record. - Add a full-page Livewire settings view matching existing HR CRUD cards and layout. - Use the general select or switch component. - Validate boolean input server-side. - Use a transaction and existing toast notifications. - Add view/edit permissions. - Add the page under the الإجازات submenu. - Never create a second hr_settings row. Behavior: - The setting applies to new requests. - Changing it does not regenerate approved or completed requests. - Display a clear Arabic note explaining the non-retroactive behavior. Do not implement the connected-date generator yet. PHASE 6 - OFFICIAL HOLIDAY POLICY UPDATE ---------------------------------------- Objective: Make the official-holiday balance behavior explicit and default it to no deduction. Update the existing Official Holidays CRUD: - Replace ambiguous Arabic text with "تخصم العطلة من رصيد الإجازة". - Default the create form value to No. - Keep the current saved value during editing. - Update index filters and badges to show deducts / does not deduct. - Keep attendance calculation settings separate. Data handling: - Do not bulk change existing holiday values. - Provide an administrative review list or filter for existing rows. - Confirm the current existing official holiday value before enabling generation. Model handling: - Keep an explicit scope/helper such as deductsVacationBalance(). - Avoid the old ambiguous interpretation where "affects calculation" could mean exclusion. Do not regenerate requests in this phase. PHASE 7 - REQUEST-DAY POLICY ENGINE AND GENERATOR ------------------------------------------------ Objective: Create one authoritative calculation engine. Suggested classes: - VacationRequestDayGenerator - VacationDayCalculationPolicy or VacationDayPolicyResolver - WorkWeekResolver Generation algorithm: 1. Validate that the request has a snapshotted work-week type with seven days. 2. Load all seven work-week day configurations once. 3. Load applicable enabled official holidays for the full possible date window in one query. 4. Iterate from start_date through end_date using CarbonPeriod. 5. For each explicit date: - Resolve week_day_id. - Resolve scheduled working/off status. - Resolve applicable official holiday. - Apply the policy-precedence rules. - Create one source=requested row. 6. When connected calculation is enabled: - Start at end_date plus one day. - Add consecutive configured weekly-off dates. - Stop at the first configured working day. - Apply official-holiday balance policy to every added date. - Use source=connected_weekly_off. - Use a hard safety limit of at most six connected days because every valid week must have at least one working day. 7. Upsert or recreate rows only while the request is editable and no row is reserved, processed, or released. 8. Calculate request totals from persisted rows. 9. Update requested_calendar_days, working_days, and deductible_days. Official holiday matching: - Respect enabled status. - Respect vacation_year_id or global null year according to existing scope. - Define deterministic precedence if overlapping official holidays exist, or prevent overlapping enabled holiday definitions in CRUD validation. Regeneration: - Allow only for submitted, under_review, returned, or draft requests. - Block when any request day is reserved, processed, or released. - Use one transaction. - Never change balances. Performance: - Do not query weekdays or holidays once per date. - Load maps before iteration. - Keep the generator stateless apart from the request transaction. PHASE 8 - REQUEST FORM AND REQUEST-DAY PREVIEW --------------------------------------------- Objective: Integrate generated totals into request creation and editing. Request form changes: - Remove the editable working_days input. - Show read-only calculated values: - Requested calendar days. - Scheduled working days. - Days deducted from balance. - Connected weekly-off days. - Official holidays that deduct. - Official holidays that do not deduct. - Require an employee with a work-week type. - Explain the selected employee schedule in Arabic. Create flow: - Create request and request-day rows in one transaction. - Do not reserve balance at submission. Edit flow: - Permit normal changes only for editable request states. - Regenerate days after employee, vacation type, start date, or end date changes. - Preserve the request snapshot unless an explicit refresh-policy action is approved. Request-day administration: - Update the existing request-day index/details pages to display source, scheduled status, weekly-off status, holiday policy, calculation reason, and deduction result. - Use Arabic badges. - Keep processed rows read-only. Printing: - Update the PDF to show deductible_days instead of trusting working_days. - Display the completed status as منتهي. PHASE 9 - SERVICE-BASED REQUEST WORKFLOW ---------------------------------------- Objective: Remove lifecycle and balance mutations from Livewire pages and controllers. Create: 1. VacationBalanceService - reserve(VacationRequest $request) - consumeDay(VacationRequestDay $day) - release(VacationRequest $request) 2. VacationRequestWorkflowService - submit() - markUnderReview() - approve() - reject() - cancel() - complete() Rules: - Every balance mutation uses a transaction. - Lock request, request days, and balance with lockForUpdate. - Approval uses persisted deductible request-day totals. - Available balance equals remaining_days minus reserved_days. - Approval only reserves; it does not consume. - Reject/cancel before approval does not affect balance. - Approved cancellation releases only unprocessed reserved rows. - Enforce active deductible-date overlap checks. Replace: - The current reservation during request creation. - The current approval behavior that immediately increases used_days. - Direct status changes from Livewire actions. - Direct under-review changes in the print controller. PHASE 10 - DAILY PROCESSING AND COMPLETION ----------------------------------------- Objective: Consume completed vacation days and finish requests automatically. Create Artisan command: hr:process-vacation-days Responsibilities: - Select only eligible approved request-day rows. - Process rows in chunks. - Call VacationBalanceService.consumeDay(). - Remain idempotent through processed_at. - Continue safely after one row failure while logging enough context, according to project logging conventions. - After processing, complete eligible requests through the workflow service. Schedule from routes/console.php: - dailyAt('00:10') - withoutOverlapping() - onOneServer() when supported by deployment cache configuration Completion: - Use the latest deductible generated date. - Set status completed and completed_at. - Use Arabic label منتهي in every UI, filter, badge, print, and notification. PHASE 11 - CANCELLATION, EDITING, AND DELETION HARDENING -------------------------------------------------------- Objective: Enforce lifecycle safety across every entry point. Rules: - Submitted/under-review requests may be edited and regenerated. - Approved requests cannot be edited normally. - Processed request days cannot be edited or deleted. - Reserved or released request days cannot be manually changed in a way that affects balances. - Rejected, cancelled, and completed requests remain historical. - Deleting a request with balance or day history is blocked or soft-deleted according to an explicit policy. - Official holidays referenced by request-day history cannot be hard deleted. - Work-week types referenced by employees or requests cannot be hard deleted. - Weekday dictionary records referenced by schedules or request days cannot be deleted. Update every Livewire action and controller endpoint, not only visible buttons. PHASE 12 - EXISTING DATA RECONCILIATION --------------------------------------- Objective: Bring old requests and balances into the new lifecycle without blind resets. Current environment audit found: - 90 employees. - 1 vacation request. - 0 vacation_request_days rows. - 1 official holiday. These counts must be rechecked at implementation time because data may change. Create an idempotent reconciliation command with dry-run and apply modes. Recommended responsibilities: 1. Report employees without work-week types. 2. Assign the approved default work-week type when explicitly applying the backfill. 3. Report official holidays and their deduction flags for administrative review. 4. Generate request-day rows for legacy requests using an explicitly approved snapshot policy. 5. Recalculate request totals. 6. Compare expected reservations and usage with existing vacation balances. 7. Produce per-balance deltas rather than setting all reserved or used totals to zero. 8. Require an explicit apply option before changing balances. 9. Record enough output for audit and rollback planning. Legacy status handling: - Submitted/under-review: no reservation should remain under the new lifecycle. - Approved future days: should be reserved. - Approved past days: should be processed into used according to the approved cutoff policy. - Rejected/cancelled: no unprocessed reservation should remain. - Archived request records: migrate to completed only after validating their balance history. Do not infer adjustments silently when the previous manual working_days value conflicts with generated request days. Report the conflict for administrative decision. PHASE 13 - LEGACY FIELD CONTRACT CLEANUP ---------------------------------------- Objective: Remove obsolete global fields only after the new logic is active, existing data is reconciled, and the replacement fields are verified. Possible contract migrations: - Drop week_days.is_weekend. - Drop or rename vacation_request_days.is_weekend after is_weekly_off is fully used. - Remove archived from the vacation request status enum. - Make employees.work_week_type_id non-nullable. - Make vacation_requests.work_week_type_id required for all new-system requests, while handling legacy rows safely. Before dropping anything: - Complete Phase 12 reconciliation successfully. - Search the entire codebase for references. - Verify background commands and PDF views. - Verify existing CRUD filters and badges. - Confirm migrated data is complete. PHASE 14 - MANUAL VERIFICATION AND CONTROLLED ROLLOUT ----------------------------------------------------- The project instructions prohibit creating test code, so do not add unit, feature, Pest, or Livewire tests. Perform proportionate non-test verification: - Run Pint on changed PHP files. - Run php -l on changed PHP files. - Inspect route:list for new routes. - Inspect migration status. - Review the Git diff for unrelated changes. - Verify Livewire pages in the browser using an authorized session. - Verify validation, permissions, loading states, and Arabic messages. Manual business scenarios: 1. Employee A uses Friday/Saturday off; employee B uses Friday only. 2. Create the same Thursday request for both employees with connected setting disabled. 3. Enable connected setting and repeat; confirm different generated tails. 4. Create Sunday-through-Thursday for Friday/Saturday employee and confirm Friday/Saturday are added, with no preceding weekend. 5. Include an official holiday configured not to deduct; confirm day_value is zero. 6. Include an official holiday configured to deduct; confirm day_value is one. 7. Confirm a vacation type with affects_balance false deducts nothing. 8. Confirm submission changes no balance. 9. Confirm approval increases only reserved_days. 10. Confirm insufficient available balance blocks approval. 11. Confirm overlapping deductible dates block approval. 12. Run daily processing and confirm reserved decreases while used increases by the same value. 13. Run processing again and confirm no duplicate consumption. 14. Cancel an approved request and confirm only future unprocessed reservations are released. 15. Confirm a request becomes منتهي only after all deductible generated dates finish. 16. Change an employee work-week type and confirm an older approved request retains its snapshot. 17. Change the connected setting and confirm older approved requests remain unchanged. Rollout sequence: 1. Deploy additive schema and models. 2. Create and verify work-week types. 3. Assign every employee a valid type. 4. Configure official-holiday deduction flags. 5. Configure connected-leave setting. 6. Deploy generator and request preview while old balance mutation is disabled in the same release boundary. 7. Deploy workflow services. 8. Reconcile existing data. 9. Enable scheduled processing. 10. Monitor reservations, usage, processing logs, and completed requests. 11. Apply legacy field cleanup only after a stable observation period. MANAGEMENT DECISIONS STILL REQUIRED =================================== The following points must be confirmed before the related implementation phase: 1. Is the connected-weekly-off rule trailing-only as recommended, or should preceding weekly days off ever be counted? 2. Should connected weekly days off be charged when they contain an official holiday configured not to deduct? This plan recommends that the official-holiday flag takes precedence and the date does not deduct. 3. Should editable submitted requests automatically adopt a changed employee schedule, or only through an explicit recalculation action? 4. Should cross-year connected dates be blocked, charged entirely to the request year, or split between yearly balances? This plan recommends blocking them initially. 5. Can specific vacation types permit negative available balance? 6. Who may cancel an approved request? 7. Does approved cancellation require a second approval? 8. How should retroactive vacation requests be processed when their dates are already in the past? 9. Should overlapping official holidays be prohibited or resolved by priority? 10. Should the official-holiday deduction value be stored as the existing affects_vacation_calculation field or renamed in a later contract migration to deducts_vacation_balance? RECOMMENDED IMPLEMENTATION CHAT ORDER ===================================== Use one separate implementation chat per phase in this order: 1. Phase 1: Additive database foundation. 2. Phase 2: Models and relationships. 3. Phase 3: Work-week types CRUD. 4. Phase 4: Employee assignment and default backfill. 5. Phase 5: Vacation settings page. 6. Phase 6: Official holiday policy update. 7. Phase 7: Request-day policy engine and generator. 8. Phase 8: Request form, preview, request-day UI, and PDF updates. 9. Phase 9: Workflow and balance services. 10. Phase 10: Daily processor and completed status. 11. Phase 11: Lifecycle hardening. 12. Phase 12: Existing data reconciliation. 13. Phase 13: Legacy field cleanup. 14. Phase 14: Manual verification and controlled rollout. Every implementation prompt should instruct the working chat to: - Read AGENTS.md and this complete plan first. - Inspect the current implementation before editing. - Implement only the named phase. - Preserve unrelated dirty-tree changes. - Reuse existing HR CRUD styles and shared components. - Add required index pages to the الإجازات submenu when the phase contains a new page. - Use Arabic user-facing labels and validation messages. - Avoid creating or running tests. - Run vendor/bin/pint --dirty --format agent after PHP changes. - Run php -l on changed PHP files. - Inspect routes and the final diff. - Report files, routes, permissions, assumptions, deferred work, and verification results. FINAL ARCHITECTURAL RESULT ========================== After all phases are complete: - Weekdays are a fixed calendar dictionary. - Work-week types define which weekdays are work or off days. - Every employee has a work-week type. - Every request snapshots the employee schedule and connected policy. - Official holidays explicitly decide whether their dates deduct from balance, defaulting to no deduction. - Connected weekly-off dates are generated according to the approved trailing rule. - Request-day rows explain exactly why every date does or does not deduct. - Submission has no balance effect. - Approval reserves the exact deductible total. - Daily processing moves finished days from reserved to used. - Cancellation releases only unprocessed reservations. - Completed requests display as منتهي. - Historical requests remain stable when schedules or settings change. - Balance updates are transactional, locked, idempotent, and auditable.