where('unit_id', $unitId) ->where('visible', true) ->orderBy('name') ->get(); } public function getAllByUnit(int $unitId): Collection { return ClassPackageUnit::with('products.product', 'variations.products.product') ->where('unit_id', $unitId) ->orderBy('name') ->get(); } public function findByIdForUnit(int $id, int $unitId): ClassPackageUnit { return ClassPackageUnit::with('products.product', 'variations.products.product') ->where('unit_id', $unitId) ->findOrFail($id); } public function create(array $data): ClassPackageUnit { $materials = $data['materials'] ?? []; $variations = $data['variations'] ?? []; unset($data['materials'], $data['variations']); $data['contract_material_value'] = $this->calcMaterialValue($materials); $packageUnit = ClassPackageUnit::create($data); $this->syncProducts($packageUnit, $materials); $this->syncVariations($packageUnit, $variations, $materials); return $packageUnit->load('products.product', 'variations.products.product'); } public function update(int $id, int $unitId, array $data): ClassPackageUnit { $packageUnit = $this->findByIdForUnit($id, $unitId); $materials = $data['materials'] ?? null; $variations = $data['variations'] ?? null; unset($data['materials'], $data['variations']); if ($materials !== null) { $data['contract_material_value'] = $this->calcMaterialValue($materials); } $packageUnit->update($data); if ($materials !== null) { $this->syncProducts($packageUnit, $materials); } if ($variations !== null) { $this->syncVariations($packageUnit, $variations, $this->currentMaterials($packageUnit)); } return $packageUnit->fresh('products.product', 'variations.products.product'); } public function toggleVisibility(int $id, int $unitId): ClassPackageUnit { $packageUnit = $this->findByIdForUnit($id, $unitId); $packageUnit->update(['visible' => !$packageUnit->visible]); return $packageUnit->fresh(); } public function delete(int $id, int $unitId): bool { $packageUnit = $this->findByIdForUnit($id, $unitId); return $packageUnit->delete(); } // Sync products on an existing ClassPackageUnit from the base package. public function syncProductsFromBasePackage(ClassPackageUnit $packageUnit, \App\Models\ClassPackage $basePackage): void { $packageUnit->products()->delete(); $basePackage->products->each(function ($product) use ($packageUnit) { ClassPackageUnitProduct::create([ 'class_package_unit_id' => $packageUnit->id, 'product_id' => $product->id, 'quantity' => $product->pivot->quantity, 'price' => $product->pivot->price, ]); }); } public function replicateFromBasePackage(int $unitId, \App\Models\ClassPackage $basePackage): ClassPackageUnit { $packageUnit = ClassPackageUnit::create([ 'unit_id' => $unitId, 'class_package_id' => $basePackage->id, 'name' => $basePackage->name, 'quantity_classes' => $basePackage->quantity_classes, 'contract_material_value' => $basePackage->contract_material_value, 'class_duration_minutes' => $basePackage->class_duration_minutes, 'weekday' => $basePackage->weekday, 'start_time' => $basePackage->start_time, 'second_weekday' => $basePackage->second_weekday, 'second_start_time' => $basePackage->second_start_time, 'visible' => true, ]); $basePackage->products->each(function ($product) use ($packageUnit) { ClassPackageUnitProduct::create([ 'class_package_unit_id' => $packageUnit->id, 'product_id' => $product->id, 'quantity' => $product->pivot->quantity, 'price' => $product->pivot->price, ]); }); return $packageUnit; } // private function calcMaterialValue(array $materials): float { return array_reduce($materials, fn($carry, $m) => $carry + ($m['quantity'] * $m['price']), 0.0); } private function currentMaterials(ClassPackageUnit $packageUnit): array { return $packageUnit->products() ->get() ->map(fn ($product) => [ 'product_id' => $product->product_id, 'quantity' => $product->quantity, 'price' => (float) $product->price, ]) ->all(); } private function syncProducts(ClassPackageUnit $packageUnit, array $materials): void { $packageUnit->products()->delete(); foreach ($materials as $m) { ClassPackageUnitProduct::create([ 'class_package_unit_id' => $packageUnit->id, 'product_id' => $m['product_id'], 'quantity' => $m['quantity'], 'price' => $m['price'], ]); } } private function syncVariations(ClassPackageUnit $packageUnit, array $variations, array $defaultMaterials): void { $packageUnit->variations()->delete(); foreach ($variations as $variation) { // sem lista propria a proposta herda os materiais do pacote da unidade $materials = $variation['materials'] ?? $defaultMaterials; unset($variation['materials']); // o valor do material nao e editavel, ele acompanha a lista $variation['material_value'] = $this->calcMaterialValue($materials); $record = $packageUnit->variations()->create($variation); $this->syncVariationProducts($record, $materials); } } private function syncVariationProducts(ClassPackageUnitVariation $variation, array $materials): void { $variation->products()->delete(); foreach ($materials as $material) { $variation->products()->create([ 'product_id' => $material['product_id'], 'quantity' => $material['quantity'], 'price' => $material['price'], ]); } } }