orderBy('created_at', 'desc')->get(); } public function findById(int $id): ?ClassPackage { return ClassPackage::with(self::EAGER_LOAD)->find($id); } public function create(array $data): ClassPackage { $unitVisibilities = $data['unit_visibilities'] ?? null; $groupIds = $data['group_ids'] ?? []; $pavao = array_key_exists('pavao', $data) ? $data['pavao'] : null; $irrecusavel = array_key_exists('irrecusavel', $data) ? $data['irrecusavel'] : null; unset($data['unit_visibilities'], $data['group_ids'], $data['pavao'], $data['irrecusavel']); $package = ClassPackage::create($data); if ($pavao !== null) { $this->pricingService->upsert(PavaoProposal::class, PavaoProposalProduct::class, 'class_package_id', $package->id, $pavao); } if ($irrecusavel !== null) { $this->pricingService->upsert(IrrecusableProposal::class, IrrecusableProposalProduct::class, 'class_package_id', $package->id, $irrecusavel, withCondition: true); } // Replicate to all units (all start visible = true) $this->replicateToAllUnits($package->load(['pavaoProposal.products', 'irrecusableProposal.products'])); // Sync selected groups if (!empty($groupIds)) { $package->groups()->sync($groupIds); } // Apply visibility overrides $this->applyVisibilityOverrides($package, $unitVisibilities, $groupIds); return $package->load(self::EAGER_LOAD); } public function update(int $id, array $data): ?ClassPackage { $package = $this->findById($id); if (!$package) return null; $unitVisibilities = $data['unit_visibilities'] ?? null; $groupIds = array_key_exists('group_ids', $data) ? ($data['group_ids'] ?? []) : null; $pavaoProvided = array_key_exists('pavao', $data); $irrecusavelProvided = array_key_exists('irrecusavel', $data); $pavao = $data['pavao'] ?? null; $irrecusavel = $data['irrecusavel'] ?? null; unset($data['unit_visibilities'], $data['group_ids'], $data['pavao'], $data['irrecusavel']); $package->update($data); $scheduleFields = array_intersect_key($data, array_flip([ 'class_duration_minutes', 'weekday', 'start_time', 'second_weekday', 'second_start_time', ])); if (!empty($scheduleFields)) { ClassPackageUnit::where('class_package_id', $package->id)->update($scheduleFields); } // Pavão/Irrecusável updates never propagate to already-cloned unit copies. if ($pavaoProvided) { if ($pavao !== null) { $this->pricingService->upsert(PavaoProposal::class, PavaoProposalProduct::class, 'class_package_id', $package->id, $pavao); } else { $this->pricingService->deleteFor(PavaoProposal::class, 'class_package_id', $package->id); } } if ($irrecusavelProvided) { if ($irrecusavel !== null) { $this->pricingService->upsert(IrrecusableProposal::class, IrrecusableProposalProduct::class, 'class_package_id', $package->id, $irrecusavel, withCondition: true); } else { $this->pricingService->deleteFor(IrrecusableProposal::class, 'class_package_id', $package->id); } } if ($groupIds !== null) { $package->groups()->sync($groupIds); } // Determine current group IDs (after sync) $currentGroupIds = $package->groups()->pluck('groups.id')->toArray(); if ($unitVisibilities !== null || $groupIds !== null) { $this->applyVisibilityOverrides($package, $unitVisibilities, $currentGroupIds); } return $package->fresh(self::EAGER_LOAD); } public function delete(int $id): bool { $package = ClassPackage::find($id); if (!$package) return false; return $package->delete(); } public function replicateToAllUnits(ClassPackage $package): void { Unit::all()->each(function (Unit $unit) use ($package) { // Skip if ClassPackageUnit already exists for this package/unit combo $exists = ClassPackageUnit::withTrashed() ->where('class_package_id', $package->id) ->where('unit_id', $unit->id) ->exists(); if (!$exists) { $this->unitService->replicateFromBasePackage($unit->id, $package); } }); } /** * Apply visibility overrides: * - Units in selected groups → forced visible = true * - Other units → use explicit unit_visibilities (if provided) */ private function applyVisibilityOverrides(ClassPackage $package, ?array $unitVisibilities, array $groupIds): void { // Get all unit IDs that belong to the selected groups $groupUnitIds = []; if (!empty($groupIds)) { $groupUnitIds = DB::table('group_units') ->whereIn('group_id', $groupIds) ->pluck('unit_id') ->unique() ->toArray(); } // Force group units to visible = true if (!empty($groupUnitIds)) { ClassPackageUnit::where('class_package_id', $package->id) ->whereIn('unit_id', $groupUnitIds) ->update(['visible' => true]); } // Apply explicit visibility for non-group units if (!empty($unitVisibilities)) { foreach ($unitVisibilities as $uv) { if (in_array($uv['unit_id'], $groupUnitIds)) { continue; // group units cannot be hidden } ClassPackageUnit::where('class_package_id', $package->id) ->where('unit_id', $uv['unit_id']) ->update(['visible' => $uv['visible']]); } } } }