@php $isEdit = $plan !== null; $checkerEditMode = $checkerEditMode ?? false; $planParticipantViewMode = $planParticipantViewMode ?? false; $participantHasEditableScheme = $participantHasEditableScheme ?? false; $planIsConsolidatedForSchemeCap = $isEdit && $plan && count($plan->consolidatedSourcePlanIds()) > 0; // Do not use `old() ? old() : …` — Laravel's old() with no args returns [] when empty, and [] is truthy in PHP, // so visit-plan defaults were never merged on first paint. $draftPayload = $errors->any() ? (array) old() : ($plan?->draft_payload ?? []); if (! is_array($draftPayload)) { $draftPayload = []; } if (! $isEdit && $errors->any()) { $overlay = array_merge( is_array($visitPlanDefaults ?? null) ? $visitPlanDefaults : [], is_array(session('plan_visit_meta')) ? session('plan_visit_meta') : [] ); foreach (['plan_type', 'month', 'year'] as $__k) { $__cur = $draftPayload[$__k] ?? null; if ($__cur === null || $__cur === '') { if (isset($overlay[$__k]) && $overlay[$__k] !== '' && $overlay[$__k] !== null) { $draftPayload[$__k] = $__k === 'plan_type' ? (string) $overlay[$__k] : (int) $overlay[$__k]; } } } if (empty($draftPayload['plan_type'] ?? null) && session()->has('plan_create_plan_type')) { $draftPayload['plan_type'] = (string) session('plan_create_plan_type'); } if (! isset($draftPayload['month']) || $draftPayload['month'] === '' || $draftPayload['month'] === null) { if (session()->has('plan_create_month')) { $draftPayload['month'] = (int) session('plan_create_month'); } } if (! isset($draftPayload['year']) || $draftPayload['year'] === '' || $draftPayload['year'] === null) { if (session()->has('plan_create_year')) { $draftPayload['year'] = (int) session('plan_create_year'); } } } if (! $isEdit && ! empty($visitPlanDefaults ?? []) && is_array($visitPlanDefaults)) { $draftPayload = array_merge($visitPlanDefaults, $draftPayload); if (empty($draftPayload['plan_type'] ?? null) && ! empty($visitPlanDefaults['plan_type'] ?? null)) { $draftPayload['plan_type'] = $visitPlanDefaults['plan_type']; } } if (! $isEdit && ! empty($visitPlanDefaults['plan_type'] ?? null)) { $draftPayload['plan_type'] = $visitPlanDefaults['plan_type']; $draftPayload['month'] = (int) ($visitPlanDefaults['month'] ?? ($draftPayload['month'] ?? now()->month)); $draftPayload['year'] = (int) ($visitPlanDefaults['year'] ?? ($draftPayload['year'] ?? now()->year)); } if (! $isEdit) { $sessPt = session('plan_create_plan_type'); if (! filled($draftPayload['plan_type'] ?? null) && is_string($sessPt) && in_array($sessPt, \App\Support\PlanningWing::allPlanTypes(), true)) { $draftPayload['plan_type'] = $sessPt; } if (empty($draftPayload['month'] ?? null) && session()->has('plan_create_month')) { $draftPayload['month'] = (int) session('plan_create_month'); } if (empty($draftPayload['year'] ?? null) && session()->has('plan_create_year')) { $draftPayload['year'] = (int) session('plan_create_year'); } $pvm = session('plan_visit_meta'); if (is_array($pvm)) { if (! filled($draftPayload['plan_type'] ?? null) && filled($pvm['plan_type'] ?? null)) { $draftPayload['plan_type'] = (string) $pvm['plan_type']; } if (empty($draftPayload['month'] ?? null) && isset($pvm['month'])) { $draftPayload['month'] = (int) $pvm['month']; } if (empty($draftPayload['year'] ?? null) && isset($pvm['year'])) { $draftPayload['year'] = (int) $pvm['year']; } } } $effectivePlanTypeForSchemeCap = ($isEdit && $plan) ? (string) ($plan->plan_type ?? 'RVP') : (string) ($draftPayload['plan_type'] ?? 'RVP'); if (! in_array($effectivePlanTypeForSchemeCap, \App\Support\PlanningWing::allPlanTypes(), true)) { $effectivePlanTypeForSchemeCap = 'RVP'; } $planPermissionSubject = $isEdit ? $plan : ($draftPayload['plan_type'] ?? null); $enforcesRvpSixSchemeRowCap = \App\Services\PC\PlanService::planTypeEnforcesSchemeSelectionCap($effectivePlanTypeForSchemeCap); $enforcesMoCrossPlanActivePlanCap = $enforcesRvpSixSchemeRowCap; $planVisitLocationNormalizer = app(\App\Services\PC\PlanService::class); $planCrudSchemeSnapshotsByProjectId = $planCrudSchemeSnapshotsByProjectId ?? []; $schemeDetailDefaults = $planVisitLocationNormalizer->planCrudSchemeDetailSnapshotDefaults(); $planAdpDisplayMonth = (int) ($isEdit && $plan ? ($plan->month ?? now()->month) : ($draftPayload['month'] ?? now()->month)); $planAdpDisplayYear = (int) ($isEdit && $plan ? ($plan->year ?? now()->year) : ($draftPayload['year'] ?? now()->year)); $declinedSchemesEditMode = $declinedSchemesEditMode ?? false; $canEditDeclinedSchemes = $canEditDeclinedSchemes ?? false; $partialDeclinedCorrectionMode = $partialDeclinedCorrectionMode ?? false; $isDeclinedSchemeCorrectionDraft = $isDeclinedSchemeCorrectionDraft ?? false; $pendingNewDeclinedSchemeAlerts = $pendingNewDeclinedSchemeAlerts ?? []; $declinedCorrectionSubmitBlockedReason = $declinedCorrectionSubmitBlockedReason ?? null; $schemeRowCapUnlimited = ! $enforcesRvpSixSchemeRowCap || (($checkerEditMode || $declinedSchemesEditMode) && $planIsConsolidatedForSchemeCap); if (!empty($mergedSchemesFromSelection ?? null) && is_array($mergedSchemesFromSelection)) { // Must run before declined snapshot / checker snapshot: returning from scheme picker merges schemes for edit. $initialSchemes = $mergedSchemesFromSelection; if ($declinedSchemesEditMode && $isEdit && $plan?->latestVersion) { $lvSchemesBySid = $plan->latestVersion->schemes->keyBy('scheme_id'); foreach ($initialSchemes as $idx => $row) { $sid = (int) ($row['scheme_id'] ?? 0); $scheme = $lvSchemesBySid->get($sid); if ($scheme) { $isDeclined = filled($scheme->rd_rejected_at ?? null); $initialSchemes[$idx]['plan_scheme_id'] = (int) $scheme->id; $rdNote = ''; if ($isDeclined) { $rdNote = trim((string) ($scheme->rd_rejection_remarks ?? '')); if ($rdNote === '') { $rdNote = 'This scheme was declined from active RD review. Update it and return it to the active plan.'; } } $initialSchemes[$idx]['rd_return_note'] = $rdNote; $initialSchemes[$idx]['scheme_rd_correction_locked'] = $partialDeclinedCorrectionMode && ! $isDeclined; $initialSchemes[$idx]['mo_assignment_banner'] = (string) ($scheme->mo_assignment_banner ?? ''); $initialSchemes[$idx]['mo_participant_readonly'] = (string) ($plan->status ?? '') === 'rd_review' && $scheme->isFormerMonitoringOfficerReadonly((int) login_user_id(), $plan); } else { $initialSchemes[$idx]['scheme_rd_correction_locked'] = false; $initialSchemes[$idx]['rd_return_note'] = ''; $initialSchemes[$idx]['mo_assignment_banner'] = $initialSchemes[$idx]['mo_assignment_banner'] ?? ''; $initialSchemes[$idx]['mo_participant_readonly'] = false; } } } } elseif ($declinedSchemesEditMode && $isEdit && $plan?->latestVersion && $isDeclinedSchemeCorrectionDraft && is_array($plan->draft_payload['schemes'] ?? null)) { $projectsMapForDeclinedDraft = isset($projects) ? $projects->keyBy('project_id') : collect(); $draftByPlanSchemeId = collect($plan->draft_payload['schemes']) ->filter(fn ($row) => is_array($row) && (int) ($row['plan_scheme_id'] ?? 0) > 0) ->keyBy(fn ($row) => (int) $row['plan_scheme_id']); $initialSchemes = $plan->latestVersion->schemes->map(function ($scheme) use ($projectsMapForDeclinedDraft, $plan, $planVisitLocationNormalizer, $partialDeclinedCorrectionMode, $canAssignMonitoringOfficers, $planCrudSchemeSnapshotsByProjectId, $schemeDetailDefaults, $planAdpDisplayMonth, $planAdpDisplayYear, $draftByPlanSchemeId) { $p = $projectsMapForDeclinedDraft->get($scheme->scheme_id); $schemeName = $p ? (trim($p->code ?? '') ? $p->code . ' - ' . $p->name : $p->name) : ''; $__locNorm = $p ? $planVisitLocationNormalizer->normalizedSchemeLocationPayloadForProject($p) : ['scheme_locations' => [], 'scheme_visit_location_options' => []]; $isDeclined = filled($scheme->rd_rejected_at ?? null); $draftRow = $isDeclined ? $draftByPlanSchemeId->get((int) $scheme->id) : null; $rdNote = ''; if ($isDeclined) { $rdNote = trim((string) ($scheme->rd_rejection_remarks ?? '')); if ($rdNote === '') { $rdNote = 'This scheme was declined from active RD review. Update it and return it to the active plan.'; } } if ($canAssignMonitoringOfficers ?? false) { $rawMo = (int) ($draftRow['monitoring_officer_id'] ?? $scheme->monitoring_officer_id ?? 0); $creatorId = (int) ($plan->created_by ?? 0); $moForForm = ($rawMo > 0 && $rawMo !== $creatorId) ? $rawMo : null; } else { $moForForm = (int) ($draftRow['monitoring_officer_id'] ?? $scheme->monitoring_officer_id ?? $plan->created_by); } return array_merge([ 'plan_scheme_id' => (int) $scheme->id, 'scheme_id' => $scheme->scheme_id, 'scheme_name' => $schemeName, 'scheme_code' => $p ? ($p->code ?? '') : '', 'scheme_description' => $p ? ($p->name ?? '') : '', 'scheme_locations' => $__locNorm['scheme_locations'], 'scheme_visit_location_options' => $__locNorm['scheme_visit_location_options'], 'monitoring_officer_id' => $moForForm, 'visit_location' => (string) ($draftRow['visit_location'] ?? $scheme->visit_location ?? ''), 'visit_date' => $draftRow['visit_date'] ?? optional($scheme->visit_date)->format('Y-m-d'), 'additional_visit_dates' => is_array($draftRow['additional_visit_dates'] ?? null) ? $draftRow['additional_visit_dates'] : $scheme->dates->pluck('visit_date')->map(fn ($d) => $d->format('Y-m-d'))->values()->all(), 'visiting_team' => is_array($draftRow['visiting_team'] ?? null) ? $draftRow['visiting_team'] : $scheme->visitingTeams->pluck('user_id')->values()->all(), 'physical_progress' => $draftRow['physical_progress'] ?? ($scheme->physical_progress ?? '0'), 'financial_progress' => (string) ($draftRow['financial_progress'] ?? $scheme->financial_progress ?? '0'), 'remarks' => (string) ($draftRow['remarks'] ?? $scheme->remarks ?? ''), 'scheme_adp_display' => $p ? plan_scheme_adp_display($p, $planAdpDisplayMonth, $planAdpDisplayYear) : '', 'rd_return_note' => $rdNote, 'scheme_rd_correction_locked' => $partialDeclinedCorrectionMode && ! $isDeclined, 'mo_assignment_banner' => (string) ($scheme->mo_assignment_banner ?? ''), 'mo_participant_readonly' => false, ], $p ? ($planCrudSchemeSnapshotsByProjectId[(int) $p->project_id] ?? $schemeDetailDefaults) : $schemeDetailDefaults); })->values()->toArray(); } elseif ($declinedSchemesEditMode && $isEdit && $plan?->latestVersion) { $projectsMapForDeclined = isset($projects) ? $projects->keyBy('project_id') : collect(); $initialSchemes = $plan->latestVersion->schemes->map(function ($scheme) use ($projectsMapForDeclined, $plan, $planVisitLocationNormalizer, $partialDeclinedCorrectionMode, $canAssignMonitoringOfficers, $planCrudSchemeSnapshotsByProjectId, $schemeDetailDefaults, $planAdpDisplayMonth, $planAdpDisplayYear) { $p = $projectsMapForDeclined->get($scheme->scheme_id); $schemeName = $p ? (trim($p->code ?? '') ? $p->code . ' - ' . $p->name : $p->name) : ''; $__locNorm = $p ? $planVisitLocationNormalizer->normalizedSchemeLocationPayloadForProject($p) : ['scheme_locations' => [], 'scheme_visit_location_options' => []]; $schemeLocations = $__locNorm['scheme_locations']; $schemeVisitLocationOptions = $__locNorm['scheme_visit_location_options']; $isDeclined = filled($scheme->rd_rejected_at ?? null); $schemeRdCorrectionLocked = $partialDeclinedCorrectionMode && ! $isDeclined; $rdNote = ''; if ($isDeclined) { $rdNote = trim((string) ($scheme->rd_rejection_remarks ?? '')); if ($rdNote === '') { $rdNote = 'This scheme was declined from active RD review. Update it and return it to the active plan.'; } } if ($canAssignMonitoringOfficers ?? false) { $rawMo = (int) ($scheme->monitoring_officer_id ?? 0); $creatorId = (int) ($plan->created_by ?? 0); $moForForm = ($rawMo > 0 && $rawMo !== $creatorId) ? $rawMo : null; } else { $moForForm = (int) ($scheme->monitoring_officer_id ?? $plan->created_by); } return array_merge([ 'plan_scheme_id' => (int) $scheme->id, 'scheme_id' => $scheme->scheme_id, 'scheme_name' => $schemeName, 'scheme_code' => $p ? ($p->code ?? '') : '', 'scheme_description' => $p ? ($p->name ?? '') : '', 'scheme_locations' => $schemeLocations, 'scheme_visit_location_options' => $schemeVisitLocationOptions, 'monitoring_officer_id' => $moForForm, 'visit_location' => $scheme->visit_location, 'visit_date' => optional($scheme->visit_date)->format('Y-m-d'), 'additional_visit_dates' => $scheme->dates->pluck('visit_date')->map(fn ($d) => $d->format('Y-m-d'))->values()->all(), 'visiting_team' => $scheme->visitingTeams->pluck('user_id')->values()->all(), 'physical_progress' => $scheme->physical_progress ?? '0', 'financial_progress' => (string) ($scheme->financial_progress ?? '0'), 'remarks' => (string) ($scheme->remarks ?? ''), 'scheme_adp_display' => $p ? plan_scheme_adp_display($p, $planAdpDisplayMonth, $planAdpDisplayYear) : '', 'rd_return_note' => $rdNote, 'scheme_rd_correction_locked' => $schemeRdCorrectionLocked, 'mo_assignment_banner' => (string) ($scheme->mo_assignment_banner ?? ''), 'mo_participant_readonly' => (string) ($plan->status ?? '') === 'rd_review' && $scheme->isFormerMonitoringOfficerReadonly((int) login_user_id(), $plan), ], $p ? ($planCrudSchemeSnapshotsByProjectId[(int) $p->project_id] ?? $schemeDetailDefaults) : $schemeDetailDefaults); })->values()->toArray(); } elseif ($checkerEditMode && $isEdit && $plan?->latestVersion) { $projectsMapForRd = isset($projects) ? $projects->keyBy('project_id') : collect(); $initialSchemes = $plan->latestVersion->schemes->map(function ($scheme) use ($projectsMapForRd, $plan, $planVisitLocationNormalizer, $canAssignMonitoringOfficers, $planCrudSchemeSnapshotsByProjectId, $schemeDetailDefaults, $planAdpDisplayMonth, $planAdpDisplayYear) { $p = $projectsMapForRd->get($scheme->scheme_id); $schemeName = $p ? (trim($p->code ?? '') ? $p->code . ' - ' . $p->name : $p->name) : ''; $__locNorm = $p ? $planVisitLocationNormalizer->normalizedSchemeLocationPayloadForProject($p) : ['scheme_locations' => [], 'scheme_visit_location_options' => []]; $schemeLocations = $__locNorm['scheme_locations']; $schemeVisitLocationOptions = $__locNorm['scheme_visit_location_options']; $rdNote = ''; if (filled($scheme->rd_rejected_at ?? null)) { $rdNote = trim((string) ($scheme->rd_rejection_remarks ?? '')); if ($rdNote === '') { $rdNote = 'The Regional Director returned this scheme for revision.'; } } if ($canAssignMonitoringOfficers ?? false) { $rawMo = (int) ($scheme->monitoring_officer_id ?? 0); $creatorId = (int) ($plan->created_by ?? 0); $moForForm = ($rawMo > 0 && $rawMo !== $creatorId) ? $rawMo : null; } else { $moForForm = (int) ($scheme->monitoring_officer_id ?? $plan->created_by); } return array_merge([ 'plan_scheme_id' => (int) $scheme->id, 'scheme_id' => $scheme->scheme_id, 'scheme_name' => $schemeName, 'scheme_code' => $p ? ($p->code ?? '') : '', 'scheme_description' => $p ? ($p->name ?? '') : '', 'scheme_locations' => $schemeLocations, 'scheme_visit_location_options' => $schemeVisitLocationOptions, 'monitoring_officer_id' => $moForForm, 'visit_location' => $scheme->visit_location, 'visit_date' => optional($scheme->visit_date)->format('Y-m-d'), 'additional_visit_dates' => $scheme->dates->pluck('visit_date')->map(fn ($d) => $d->format('Y-m-d'))->values()->all(), 'visiting_team' => $scheme->visitingTeams->pluck('user_id')->values()->all(), 'physical_progress' => $scheme->physical_progress ?? '0', 'financial_progress' => (string) ($scheme->financial_progress ?? '0'), 'remarks' => (string) ($scheme->remarks ?? ''), 'scheme_adp_display' => $p ? plan_scheme_adp_display($p, $planAdpDisplayMonth, $planAdpDisplayYear) : '', 'rd_return_note' => $rdNote, 'mo_assignment_banner' => (string) ($scheme->mo_assignment_banner ?? ''), 'mo_participant_readonly' => (string) ($plan->status ?? '') === 'rd_review' && $scheme->isFormerMonitoringOfficerReadonly((int) login_user_id(), $plan), ], $p ? ($planCrudSchemeSnapshotsByProjectId[(int) $p->project_id] ?? $schemeDetailDefaults) : $schemeDetailDefaults); })->toArray(); } if (isset($initialSchemes) && is_array($initialSchemes) && !empty($initialSchemes) && !$checkerEditMode) { // Pre-selected from scheme selection (Create Visit Plan flow). // On validation redirect (e.g. schedule conflict → "Submit anyway"), restore posted // scheme fields from old() — otherwise visit_location/dates are wiped and confirm cannot save. if ($errors->any()) { $oldSchemes = old('schemes'); if (is_array($oldSchemes) && $oldSchemes !== []) { $metaBySchemeId = []; foreach ($initialSchemes as $__row) { if (! is_array($__row)) { continue; } $__sid = (int) ($__row['scheme_id'] ?? 0); if ($__sid <= 0 || isset($metaBySchemeId[$__sid])) { continue; } $metaBySchemeId[$__sid] = [ 'scheme_name' => $__row['scheme_name'] ?? '', 'scheme_code' => $__row['scheme_code'] ?? '', 'scheme_description' => $__row['scheme_description'] ?? '', 'scheme_locations' => $__row['scheme_locations'] ?? [], 'scheme_visit_location_options' => $__row['scheme_visit_location_options'] ?? [], 'scheme_adp_display' => $__row['scheme_adp_display'] ?? '', ]; foreach ($schemeDetailDefaults as $__dk => $__dv) { if (array_key_exists($__dk, $__row)) { $metaBySchemeId[$__sid][$__dk] = $__row[$__dk]; } } } $initialSchemes = collect(array_values($oldSchemes))->map(function ($row) use ($metaBySchemeId, $schemeDetailDefaults) { $row = array_merge($schemeDetailDefaults, is_array($row) ? $row : []); $sid = (int) ($row['scheme_id'] ?? 0); if ($sid > 0 && isset($metaBySchemeId[$sid])) { $row = array_merge($row, $metaBySchemeId[$sid]); } return $row; })->values()->all(); } } } elseif (!isset($initialSchemes) || !is_array($initialSchemes) || empty($initialSchemes)) { $mapVersionSchemesToFormRows = function () use ($isEdit, $plan, $projects, $planVisitLocationNormalizer, $canAssignMonitoringOfficers, $planCrudSchemeSnapshotsByProjectId, $schemeDetailDefaults, $declinedSchemesEditMode, $canEditDeclinedSchemes, $planAdpDisplayMonth, $planAdpDisplayYear) { if (! $isEdit || ! $plan?->latestVersion) { return []; } $projectsMap = isset($projects) ? $projects->keyBy('project_id') : collect(); $schemesForRowMap = $plan->latestVersion->schemes; if ((string) ($plan->status ?? '') === 'rd_review' && empty($declinedSchemesEditMode ?? false) && ! ($canEditDeclinedSchemes ?? false)) { $schemesForRowMap = $schemesForRowMap->filter(fn ($s) => ! filled($s->rd_rejected_at ?? null))->values(); } return $schemesForRowMap->map(function ($scheme) use ($projectsMap, $plan, $planVisitLocationNormalizer, $canAssignMonitoringOfficers, $planCrudSchemeSnapshotsByProjectId, $schemeDetailDefaults, $planAdpDisplayMonth, $planAdpDisplayYear) { $p = $projectsMap->get($scheme->scheme_id); $schemeName = $p ? (trim($p->code ?? '') ? $p->code . ' - ' . $p->name : $p->name) : ''; $__locNorm = $p ? $planVisitLocationNormalizer->normalizedSchemeLocationPayloadForProject($p) : ['scheme_locations' => [], 'scheme_visit_location_options' => []]; $schemeLocations = $__locNorm['scheme_locations']; $schemeVisitLocationOptions = $__locNorm['scheme_visit_location_options']; $rdNote = ''; if (filled($scheme->rd_rejected_at ?? null)) { $rdNote = trim((string) ($scheme->rd_rejection_remarks ?? '')); if ($rdNote === '') { $rdNote = 'The Regional Director returned this scheme for revision.'; } } if ($canAssignMonitoringOfficers ?? false) { $rawMo = (int) ($scheme->monitoring_officer_id ?? 0); $creatorId = (int) ($plan->created_by ?? 0); $moForForm = ($rawMo > 0 && $rawMo !== $creatorId) ? $rawMo : null; } else { $moForForm = (int) ($scheme->monitoring_officer_id ?? $plan->created_by); } return array_merge([ 'plan_scheme_id' => (int) $scheme->id, 'scheme_id' => $scheme->scheme_id, 'scheme_name' => $schemeName, 'scheme_code' => $p ? ($p->code ?? '') : '', 'scheme_description' => $p ? ($p->name ?? '') : '', 'scheme_locations' => $schemeLocations, 'scheme_visit_location_options' => $schemeVisitLocationOptions, 'monitoring_officer_id' => $moForForm, 'visit_location' => $scheme->visit_location, 'visit_date' => optional($scheme->visit_date)->format('Y-m-d'), 'additional_visit_dates' => $scheme->dates->pluck('visit_date')->map(fn ($d) => $d->format('Y-m-d'))->values()->all(), 'visiting_team' => $scheme->visitingTeams->pluck('user_id')->values()->all(), 'physical_progress' => $scheme->physical_progress ?? '0', 'financial_progress' => (string) ($scheme->financial_progress ?? '0'), 'remarks' => (string) ($scheme->remarks ?? ''), 'scheme_adp_display' => $p ? plan_scheme_adp_display($p, $planAdpDisplayMonth, $planAdpDisplayYear) : '', 'rd_return_note' => $rdNote, 'mo_assignment_banner' => (string) ($scheme->mo_assignment_banner ?? ''), 'mo_participant_readonly' => (string) ($plan->status ?? '') === 'rd_review' && $scheme->isFormerMonitoringOfficerReadonly((int) login_user_id(), $plan), ], $p ? ($planCrudSchemeSnapshotsByProjectId[(int) $p->project_id] ?? $schemeDetailDefaults) : $schemeDetailDefaults); })->toArray(); }; if ($errors->any()) { $oldSchemes = old('schemes'); $initialSchemes = is_array($oldSchemes) ? $oldSchemes : ($draftPayload['schemes'] ?? []); } else { // draft_payload is not updated when RD edits the submitted snapshot; prefer latest plan_version rows // so visiting_team matches plan_visiting_teams (same source as the detail modal). $workflowStatusesUseDbSnapshot = ['returned', 'rd_review', 'sdm_review', 'dg_review', 'approved', 'rejected']; $preferDbSnapshot = $isEdit && $plan?->latestVersion && $plan->latestVersion->schemes->isNotEmpty() && ( (int) ($plan->current_version ?? 0) >= 1 || in_array((string) ($plan->status ?? ''), $workflowStatusesUseDbSnapshot, true) ); if ($preferDbSnapshot) { $initialSchemes = $mapVersionSchemesToFormRows(); } else { $initialSchemes = $draftPayload['schemes'] ?? []; } } if (! is_array($initialSchemes)) { $initialSchemes = []; } if ($initialSchemes === [] && $isEdit && $plan?->latestVersion) { $initialSchemes = $mapVersionSchemesToFormRows(); } if (empty($initialSchemes)) { $initialSchemes = [array_merge([ 'plan_scheme_id' => null, 'scheme_id' => '', 'scheme_name' => '', 'scheme_code' => '', 'scheme_description' => '', 'scheme_locations' => [], 'scheme_visit_location_options' => [], 'monitoring_officer_id' => ($canAssignMonitoringOfficers ?? false) ? null : ($defaultMonitoringOfficerId ?? null), 'visit_location' => '', 'visit_date' => '', 'additional_visit_dates' => [], 'visiting_team' => [], 'physical_progress' => '0', 'financial_progress' => '0', 'remarks' => '', 'scheme_adp_display' => '', 'rd_return_note' => '', ], $schemeDetailDefaults)]; } } // On edit, ensure each scheme has display fields (code, description, department, locations) so UI matches Create page if ($isEdit && isset($projects) && !empty($initialSchemes)) { $projectsMap = $projects->keyBy('project_id'); $initialSchemes = collect($initialSchemes)->map(function ($row) use ($projectsMap, $planVisitLocationNormalizer, $planCrudSchemeSnapshotsByProjectId, $schemeDetailDefaults, $planAdpDisplayMonth, $planAdpDisplayYear) { $schemeId = (int) ($row['scheme_id'] ?? 0); if (!$schemeId) { return $row; } $p = $projectsMap->get($schemeId); if (!$p) { return $row; } $schemeName = trim($p->code ?? '') ? $p->code . ' - ' . $p->name : $p->name; $__locNorm = $planVisitLocationNormalizer->normalizedSchemeLocationPayloadForProject($p); $snap = $planCrudSchemeSnapshotsByProjectId[(int) $p->project_id] ?? $schemeDetailDefaults; $merged = array_merge($row, $snap, [ 'scheme_name' => $schemeName, 'scheme_code' => $p->code ?? '', 'scheme_description' => $p->name ?? '', 'scheme_locations' => $__locNorm['scheme_locations'], 'scheme_visit_location_options' => $__locNorm['scheme_visit_location_options'], 'scheme_adp_display' => plan_scheme_adp_display($p, $planAdpDisplayMonth, $planAdpDisplayYear), ]); if (!array_key_exists('monitoring_officer_id', $merged)) { $merged['monitoring_officer_id'] = ($canAssignMonitoringOfficers ?? false) ? null : ($defaultMonitoringOfficerId ?? null); } return $merged; })->values()->all(); } $initialSchemes = collect($initialSchemes ?? [])->map(function ($row) use ($schemeDetailDefaults) { $row = array_merge($schemeDetailDefaults, $row); $schemeType = mb_strtolower(trim((string) ($row['scheme_detail_scheme_type'] ?? ''))); $row['scheme_is_umbrella'] = $schemeType === 'umbrella'; $row['scheme_rd_correction_locked'] = (bool) ($row['scheme_rd_correction_locked'] ?? false); return $row; })->values()->all(); // Avoid merging browser WIP over visiting_team when the DB snapshot is authoritative (RD edits, returns, etc.). // RD checker with scheme picker persists removals/additions to the version row — still merge WIP when sync fails or for unsaved field edits. $planSkipWipSchemeMerge = $isEdit && ! ($declinedSchemesEditMode ?? false) && ($plan ?? null) && ( (int) ($plan->current_version ?? 0) >= 1 || in_array((string) ($plan->status ?? ''), ['returned', 'rd_review', 'sdm_review', 'dg_review', 'approved', 'rejected'], true) ) && ! (($checkerEditMode ?? false) && ! empty($schemeSelectionUrl ?? null)); $legacyPlanRemarks = trim((string) ($draftPayload['remarks'] ?? '')); if ($legacyPlanRemarks !== '' && is_array($initialSchemes) && isset($initialSchemes[0])) { $hasAnySchemeRemarks = collect($initialSchemes)->contains(function ($r) { return is_array($r) && filled(trim((string) ($r['remarks'] ?? ''))); }); if (! $hasAnySchemeRemarks) { $initialSchemes[0]['remarks'] = $legacyPlanRemarks; } } // Visit dates must fall within the plan month (same period as hidden month/year on the form) $__planMonth = (int) old('month', $draftPayload['month'] ?? $plan?->month ?? ($defaultMonth ?? now()->month)); $__planYear = (int) old('year', $draftPayload['year'] ?? $plan?->year ?? ($defaultYear ?? now()->year)); if ($__planMonth < 1 || $__planMonth > 12) { $__planMonth = (int) now()->month; } if ($__planYear < 1970 || $__planYear > 2100) { $__planYear = (int) now()->year; } $visitDateMin = \Carbon\Carbon::createFromDate($__planYear, $__planMonth, 1)->startOfMonth()->format('Y-m-d'); $visitDateMax = \Carbon\Carbon::createFromDate($__planYear, $__planMonth, 1)->endOfMonth()->format('Y-m-d'); $createPlanFixedLayout = ! $isEdit && ! $checkerEditMode; $createPlanMonthLabel = ''; $createPlanTypeCode = ''; $createPlanYearDisplay = 0; if ($createPlanFixedLayout) { $createPlanTypeCode = strtoupper(trim((string) ($draftPayload['plan_type'] ?? ''))); if (! in_array($createPlanTypeCode, \App\Support\PlanningWing::allPlanTypes(), true)) { $createPlanTypeCode = 'RVP'; } $__cm = (int) ($draftPayload['month'] ?? ($defaultMonth ?? now()->month)); $__cy = (int) ($draftPayload['year'] ?? ($defaultYear ?? now()->year)); if ($__cm < 1 || $__cm > 12) { $__cm = (int) now()->month; } if ($__cy < 2000 || $__cy > 2100) { $__cy = (int) now()->year; } $draftPayload['plan_type'] = $createPlanTypeCode; $draftPayload['month'] = $__cm; $draftPayload['year'] = $__cy; $createPlanYearDisplay = $__cy; $createPlanMonthLabel = \Carbon\Carbon::createFromDate($__cy, $__cm, 1)->format('F'); $__planMonth = $__cm; $__planYear = $__cy; $visitDateMin = \Carbon\Carbon::createFromDate($__planYear, $__planMonth, 1)->startOfMonth()->format('Y-m-d'); $visitDateMax = \Carbon\Carbon::createFromDate($__planYear, $__planMonth, 1)->endOfMonth()->format('Y-m-d'); } @endphp @extends('layouts.app') @section('title', $checkerEditMode ? 'Edit scheme data (Checker)' : ($isEdit ? 'Edit Plan' : 'Create Plan')) @push('stylesheets') @endpush @section('contents')
@php $planFormInlineErrors = collect($errors->getMessages()) ->except(['schedule_conflict']) ->reject(fn ($_, $key) => preg_match('/^schemes\.\d+\.visit_date$/', (string) $key)) ->flatten() ->unique() ->filter(fn ($msg) => trim((string) $msg) !== ''); @endphp @if ($planFormInlineErrors->isNotEmpty()) @endif
@csrf @if($isEdit) @method('PUT') @endif @if($declinedSchemesEditMode && $isEdit) @endif @if($checkerEditMode) @endif @if(!empty($planParticipantViewMode) && !empty($participantHasEditableScheme)) @endif @if(empty($declinedSchemesEditMode)) @else @endif @if(empty($declinedSchemesEditMode) && empty($checkerEditMode)) @endif
@php $moWorkspaceNotice = trim((string) ($draftPayload['mo_workspace_notice'] ?? '')); @endphp @if($moWorkspaceNotice !== '')
{{ $moWorkspaceNotice }}
@endif @if($createPlanFixedLayout) @php $visitPeriodChangeQuery = []; foreach ($initialSchemes ?? [] as $__row) { $__sid = (int) ($__row['scheme_id'] ?? 0); if ($__sid > 0) { $visitPeriodChangeQuery['scheme_ids'][] = $__sid; $visitPeriodChangeQuery['locked_scheme_ids'][] = $__sid; } } @endphp

New visit plan Type {{ $createPlanTypeCode }} · Month {{ $createPlanMonthLabel }} · Year {{ $createPlanYearDisplay }} @if (! empty($planFormSelectedMecRegion['show'])) · Region {{ $planFormSelectedMecRegion['name'] }} @endif

@if (! empty($planFormSelectedMecRegion['id'])) @endif @endif @if($checkerEditMode || $isEdit)
@if($checkerEditMode)

{{ $plan?->plan_type ?? '—' }}

@elseif($isEdit && empty($declinedSchemesEditMode)) @php $planTypeValue = old('plan_type', $draftPayload['plan_type'] ?? $plan?->plan_type); $planTypeLabels = [ 'RVP' => 'Regular Visit Plan (RVP)', 'CVP' => 'Compliance Visit Plan (CVP)', 'SVP' => 'Special Visit Plan (SVP)', 'DRP' => 'Desk Review Plan (DRP)', 'ERP' => 'Evaluation Report Plan (ERP)', 'PMP' => 'Project Monitoring Plan (PMP)', ]; $editPlanPeriodTypeCode = strtoupper(trim((string) $planTypeValue)); if (! in_array($editPlanPeriodTypeCode, \App\Support\PlanningWing::allPlanTypes(), true)) { $editPlanPeriodTypeCode = 'RVP'; } $editPlanPeriodMonthNum = (int) old('month', $draftPayload['month'] ?? $plan?->month ?? ($defaultMonth ?? now()->month)); $editPlanPeriodYearNum = (int) old('year', $draftPayload['year'] ?? $plan?->year ?? ($defaultYear ?? now()->year)); if ($editPlanPeriodMonthNum < 1 || $editPlanPeriodMonthNum > 12) { $editPlanPeriodMonthNum = (int) now()->month; } if ($editPlanPeriodYearNum < 2000 || $editPlanPeriodYearNum > 2100) { $editPlanPeriodYearNum = (int) now()->year; } $editPlanPeriodMonthLabel = \Carbon\Carbon::createFromDate($editPlanPeriodYearNum, $editPlanPeriodMonthNum, 1)->format('F'); $editPlanPeriodTypeLabel = $planTypeLabels[$editPlanPeriodTypeCode] ?? $editPlanPeriodTypeCode; $periodEditQuery = [ 'return_plan_id' => $plan->id, 'plan_type' => $editPlanPeriodTypeCode, 'month' => $editPlanPeriodMonthNum, 'year' => $editPlanPeriodYearNum, ]; foreach (collect($initialSchemes ?? [])->pluck('scheme_id')->map(fn ($id) => (int) $id)->filter()->unique()->values()->all() as $__sid) { $periodEditQuery['scheme_ids'][] = $__sid; $periodEditQuery['locked_scheme_ids'][] = $__sid; } $planPeriodEditUrl = route('plan.visit.period', $periodEditQuery); @endphp

Plan period Type {{ $editPlanPeriodTypeCode }} · Month {{ $editPlanPeriodMonthLabel }} · Year {{ $editPlanPeriodYearNum }} @if (! empty($planFormSelectedMecRegion['show'])) · Region {{ $planFormSelectedMecRegion['name'] }} @endif ({{ $editPlanPeriodTypeLabel }})

Change plan period
@elseif(!empty($declinedSchemesEditMode) && $isEdit)
@if(!empty($partialDeclinedCorrectionMode)) Declined schemes. Correct or remove only the schemes marked below. Other schemes stay in RD review and are read-only until you return the corrected declined schemes to the active plan. @else Declined schemes. Update the schemes below, save a draft, then submit so they rejoin RD review on this same plan. @endif
@if(!empty($pendingNewDeclinedSchemeAlerts))
    @foreach($pendingNewDeclinedSchemeAlerts as $alert)
  • {{ $alert['scheme_label'] ?? 'Scheme' }}: {{ $alert['message'] ?? '' }}
  • @endforeach
@endif @endif
@endif
@if(!empty($planParticipantViewMode))
@if(!empty($participantHasEditableScheme))

Update visit details for schemes assigned to you. Schemes reassigned to another monitoring officer are read-only.

@else

You have no schemes assigned to you for editing on this plan.

@endif
@endif
Schemes
@if(!empty($schemeSelectionUrl ?? null)) Add Schemes @endif
@if(!empty($schemeSelectionUrl ?? null)) @endif
@endsection @push('scripts') @php $__wipSigIds = collect($initialSchemes ?? [])->pluck('scheme_id')->map(fn ($id) => (int) $id)->filter()->sort()->values()->all(); $planInitialSchemesSignatureForWip = hash('sha256', implode(',', $__wipSigIds)); @endphp @endpush