| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- <?php
- namespace App\Services;
- use App\Models\ClassPackage;
- use App\Models\ClassPackageUnit;
- use App\Models\IrrecusableProposal;
- use App\Models\IrrecusableProposalProduct;
- use App\Models\PavaoProposal;
- use App\Models\PavaoProposalProduct;
- use App\Models\Unit;
- use Illuminate\Database\Eloquent\Collection;
- use Illuminate\Support\Facades\DB;
- class ClassPackageService
- {
- private const EAGER_LOAD = [
- 'unitPackages',
- 'groups',
- 'pavaoProposal.products.product',
- 'irrecusableProposal.products.product',
- ];
- public function __construct(
- protected ClassPackageUnitService $unitService,
- protected ProposalPricingService $pricingService,
- ) {}
- public function getAll(): Collection
- {
- return ClassPackage::with(['pavaoProposal', 'irrecusableProposal'])->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']]);
- }
- }
- }
- }
|