|
|
@@ -3,8 +3,10 @@
|
|
|
namespace App\Services;
|
|
|
|
|
|
use App\Models\ClassPackage;
|
|
|
+use App\Models\ClassPackageUnit;
|
|
|
use App\Models\Unit;
|
|
|
use Illuminate\Database\Eloquent\Collection;
|
|
|
+use Illuminate\Support\Facades\DB;
|
|
|
|
|
|
class ClassPackageService
|
|
|
{
|
|
|
@@ -19,13 +21,15 @@ public function getAll(): Collection
|
|
|
|
|
|
public function findById(int $id): ?ClassPackage
|
|
|
{
|
|
|
- return ClassPackage::with('products')->find($id);
|
|
|
+ return ClassPackage::with(['products', 'unitPackages', 'groups'])->find($id);
|
|
|
}
|
|
|
|
|
|
public function create(array $data): ClassPackage
|
|
|
{
|
|
|
- $materials = $data['materials'] ?? [];
|
|
|
- unset($data['materials']);
|
|
|
+ $materials = $data['materials'] ?? [];
|
|
|
+ $unitVisibilities = $data['unit_visibilities'] ?? null;
|
|
|
+ $groupIds = $data['group_ids'] ?? [];
|
|
|
+ unset($data['materials'], $data['unit_visibilities'], $data['group_ids']);
|
|
|
|
|
|
$data['contract_material_value'] = $this->calcMaterialValue($materials);
|
|
|
|
|
|
@@ -33,9 +37,18 @@ public function create(array $data): ClassPackage
|
|
|
|
|
|
$this->syncMaterials($package, $materials);
|
|
|
|
|
|
+ // Replicate to all units (all start visible = true)
|
|
|
$this->replicateToAllUnits($package->load('products'));
|
|
|
|
|
|
- return $package->load('products');
|
|
|
+ // Sync selected groups
|
|
|
+ if (!empty($groupIds)) {
|
|
|
+ $package->groups()->sync($groupIds);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Apply visibility overrides
|
|
|
+ $this->applyVisibilityOverrides($package, $unitVisibilities, $groupIds);
|
|
|
+
|
|
|
+ return $package->load(['products', 'unitPackages', 'groups']);
|
|
|
}
|
|
|
|
|
|
public function update(int $id, array $data): ?ClassPackage
|
|
|
@@ -43,8 +56,10 @@ public function update(int $id, array $data): ?ClassPackage
|
|
|
$package = $this->findById($id);
|
|
|
if (!$package) return null;
|
|
|
|
|
|
- $materials = $data['materials'] ?? null;
|
|
|
- unset($data['materials']);
|
|
|
+ $materials = $data['materials'] ?? null;
|
|
|
+ $unitVisibilities = $data['unit_visibilities'] ?? null;
|
|
|
+ $groupIds = array_key_exists('group_ids', $data) ? ($data['group_ids'] ?? []) : null;
|
|
|
+ unset($data['materials'], $data['unit_visibilities'], $data['group_ids']);
|
|
|
|
|
|
if ($materials !== null) {
|
|
|
$data['contract_material_value'] = $this->calcMaterialValue($materials);
|
|
|
@@ -54,9 +69,22 @@ public function update(int $id, array $data): ?ClassPackage
|
|
|
|
|
|
if ($materials !== null) {
|
|
|
$this->syncMaterials($package, $materials);
|
|
|
+ // Propagate material changes to unit packages
|
|
|
+ $this->syncUnitPackageProducts($package->load('products'));
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($groupIds !== null) {
|
|
|
+ $package->groups()->sync($groupIds);
|
|
|
}
|
|
|
|
|
|
- return $package->fresh('products');
|
|
|
+ // 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(['products', 'unitPackages', 'groups']);
|
|
|
}
|
|
|
|
|
|
public function delete(int $id): bool
|
|
|
@@ -70,7 +98,63 @@ public function delete(int $id): bool
|
|
|
public function replicateToAllUnits(ClassPackage $package): void
|
|
|
{
|
|
|
Unit::all()->each(function (Unit $unit) use ($package) {
|
|
|
- $this->unitService->replicateFromBasePackage($unit->id, $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']]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 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);
|
|
|
});
|
|
|
}
|
|
|
|