get(); } public function findById(int $id): ?ClassPackage { return ClassPackage::with(['units', 'products'])->find($id); } public function create(array $data): ClassPackage { $unitVisibilities = $data['unit_visibilities'] ?? []; $materials = $data['materials'] ?? []; unset($data['unit_visibilities'], $data['materials']); $data['contract_material_value'] = $this->calcMaterialValue($materials); $package = ClassPackage::create($data); $this->syncUnitVisibilities($package, $unitVisibilities); $this->syncMaterials($package, $materials); return $package->load(['units', 'products']); } public function update(int $id, array $data): ?ClassPackage { $package = $this->findById($id); if (!$package) return null; $unitVisibilities = $data['unit_visibilities'] ?? null; $materials = $data['materials'] ?? null; unset($data['unit_visibilities'], $data['materials']); if ($materials !== null) { $data['contract_material_value'] = $this->calcMaterialValue($materials); } $package->update($data); if ($unitVisibilities !== null) { $this->syncUnitVisibilities($package, $unitVisibilities); } if ($materials !== null) { $this->syncMaterials($package, $materials); } return $package->fresh(['units', 'products']); } public function delete(int $id): bool { $package = ClassPackage::find($id); if (!$package) return false; return $package->delete(); } public function getAllUnitsWithVisibility(int $packageId): \Illuminate\Support\Collection { $allUnits = Unit::orderBy('fantasy_name')->get(['id', 'fantasy_name']); $package = ClassPackage::with('units')->find($packageId); $visibilityMap = $package ? $package->units->keyBy('id') : collect(); return $allUnits->map(fn($unit) => [ 'id' => $unit->id, 'fantasy_name' => $unit->fantasy_name, 'visible' => $visibilityMap->has($unit->id) ? (bool) $visibilityMap[$unit->id]->pivot->visible : true, ]); } private function syncUnitVisibilities(ClassPackage $package, array $unitVisibilities): void { $syncData = []; foreach ($unitVisibilities as $uv) { $syncData[$uv['unit_id']] = ['visible' => $uv['visible']]; } $package->units()->sync($syncData); } private function syncMaterials(ClassPackage $package, array $materials): void { $syncData = []; foreach ($materials as $m) { $syncData[$m['product_id']] = [ 'quantity' => $m['quantity'], 'price' => $m['price'], ]; } $package->products()->sync($syncData); } private function calcMaterialValue(array $materials): float { return array_reduce($materials, fn($carry, $m) => $carry + ($m['quantity'] * $m['price']), 0.0); } }