|
|
@@ -14,6 +14,13 @@
|
|
|
|
|
|
class ClassPackageService
|
|
|
{
|
|
|
+ private const EAGER_LOAD = [
|
|
|
+ 'unitPackages',
|
|
|
+ 'groups',
|
|
|
+ 'pavaoProposal.products.product',
|
|
|
+ 'irrecusableProposal.products.product',
|
|
|
+ ];
|
|
|
+
|
|
|
public function __construct(
|
|
|
protected ClassPackageUnitService $unitService,
|
|
|
protected ProposalPricingService $pricingService,
|
|
|
@@ -21,34 +28,34 @@ public function __construct(
|
|
|
|
|
|
public function getAll(): Collection
|
|
|
{
|
|
|
- return ClassPackage::with('products')->orderBy('created_at', 'desc')->get();
|
|
|
+ return ClassPackage::with(['pavaoProposal', 'irrecusableProposal'])->orderBy('created_at', 'desc')->get();
|
|
|
}
|
|
|
|
|
|
public function findById(int $id): ?ClassPackage
|
|
|
{
|
|
|
- return ClassPackage::with(['products', 'unitPackages', 'groups', 'pavaoProposal.products.product', 'irrecusableProposal.products.product'])->find($id);
|
|
|
+ return ClassPackage::with(self::EAGER_LOAD)->find($id);
|
|
|
}
|
|
|
|
|
|
public function create(array $data): ClassPackage
|
|
|
{
|
|
|
- $materials = $data['materials'] ?? [];
|
|
|
$unitVisibilities = $data['unit_visibilities'] ?? null;
|
|
|
$groupIds = $data['group_ids'] ?? [];
|
|
|
- $pavao = $data['pavao'] ?? [];
|
|
|
- $irrecusavel = $data['irrecusavel'] ?? [];
|
|
|
- unset($data['materials'], $data['unit_visibilities'], $data['group_ids'], $data['pavao'], $data['irrecusavel']);
|
|
|
-
|
|
|
- $data['contract_material_value'] = $this->calcMaterialValue($materials);
|
|
|
+ $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);
|
|
|
|
|
|
- $this->syncMaterials($package, $materials);
|
|
|
+ if ($pavao !== null) {
|
|
|
+ $this->pricingService->upsert(PavaoProposal::class, PavaoProposalProduct::class, 'class_package_id', $package->id, $pavao);
|
|
|
+ }
|
|
|
|
|
|
- $this->pricingService->upsert(PavaoProposal::class, PavaoProposalProduct::class, 'class_package_id', $package->id, $pavao);
|
|
|
- $this->pricingService->upsert(IrrecusableProposal::class, IrrecusableProposalProduct::class, 'class_package_id', $package->id, $irrecusavel, withCondition: true);
|
|
|
+ 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(['products', 'pavaoProposal.products', 'irrecusableProposal.products']));
|
|
|
+ $this->replicateToAllUnits($package->load(['pavaoProposal.products', 'irrecusableProposal.products']));
|
|
|
|
|
|
// Sync selected groups
|
|
|
if (!empty($groupIds)) {
|
|
|
@@ -58,7 +65,7 @@ public function create(array $data): ClassPackage
|
|
|
// Apply visibility overrides
|
|
|
$this->applyVisibilityOverrides($package, $unitVisibilities, $groupIds);
|
|
|
|
|
|
- return $package->load(['products', 'unitPackages', 'groups', 'pavaoProposal.products.product', 'irrecusableProposal.products.product']);
|
|
|
+ return $package->load(self::EAGER_LOAD);
|
|
|
}
|
|
|
|
|
|
public function update(int $id, array $data): ?ClassPackage
|
|
|
@@ -66,16 +73,13 @@ public function update(int $id, array $data): ?ClassPackage
|
|
|
$package = $this->findById($id);
|
|
|
if (!$package) return null;
|
|
|
|
|
|
- $materials = $data['materials'] ?? null;
|
|
|
$unitVisibilities = $data['unit_visibilities'] ?? null;
|
|
|
$groupIds = array_key_exists('group_ids', $data) ? ($data['group_ids'] ?? []) : null;
|
|
|
- $pavao = $data['pavao'] ?? null;
|
|
|
- $irrecusavel = $data['irrecusavel'] ?? null;
|
|
|
- unset($data['materials'], $data['unit_visibilities'], $data['group_ids'], $data['pavao'], $data['irrecusavel']);
|
|
|
-
|
|
|
- if ($materials !== null) {
|
|
|
- $data['contract_material_value'] = $this->calcMaterialValue($materials);
|
|
|
- }
|
|
|
+ $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);
|
|
|
|
|
|
@@ -90,19 +94,21 @@ public function update(int $id, array $data): ?ClassPackage
|
|
|
ClassPackageUnit::where('class_package_id', $package->id)->update($scheduleFields);
|
|
|
}
|
|
|
|
|
|
- if ($materials !== null) {
|
|
|
- $this->syncMaterials($package, $materials);
|
|
|
- // Propagate material changes to unit packages
|
|
|
- $this->syncUnitPackageProducts($package->load('products'));
|
|
|
- }
|
|
|
-
|
|
|
// Pavão/Irrecusável updates never propagate to already-cloned unit copies.
|
|
|
- if ($pavao !== null) {
|
|
|
- $this->pricingService->upsert(PavaoProposal::class, PavaoProposalProduct::class, 'class_package_id', $package->id, $pavao);
|
|
|
+ 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 ($irrecusavel !== null) {
|
|
|
- $this->pricingService->upsert(IrrecusableProposal::class, IrrecusableProposalProduct::class, 'class_package_id', $package->id, $irrecusavel, withCondition: true);
|
|
|
+ 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) {
|
|
|
@@ -116,7 +122,7 @@ public function update(int $id, array $data): ?ClassPackage
|
|
|
$this->applyVisibilityOverrides($package, $unitVisibilities, $currentGroupIds);
|
|
|
}
|
|
|
|
|
|
- return $package->fresh(['products', 'unitPackages', 'groups', 'pavaoProposal.products.product', 'irrecusableProposal.products.product']);
|
|
|
+ return $package->fresh(self::EAGER_LOAD);
|
|
|
}
|
|
|
|
|
|
public function delete(int $id): bool
|
|
|
@@ -179,31 +185,4 @@ private function applyVisibilityOverrides(ClassPackage $package, ?array $unitVis
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- /**
|
|
|
- * When materials are updated, propagate product changes to all ClassPackageUnit records.
|
|
|
- */
|
|
|
- private function syncUnitPackageProducts(ClassPackage $package): void
|
|
|
- {
|
|
|
- ClassPackageUnit::where('class_package_id', $package->id)->each(function (ClassPackageUnit $up) use ($package) {
|
|
|
- $this->unitService->syncProductsFromBasePackage($up, $package);
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- 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);
|
|
|
- }
|
|
|
}
|