ClassPackageService.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. <?php
  2. namespace App\Services;
  3. use App\Models\ClassPackage;
  4. use App\Models\Unit;
  5. use Illuminate\Database\Eloquent\Collection;
  6. class ClassPackageService
  7. {
  8. public function getAll(): Collection
  9. {
  10. return ClassPackage::orderBy('created_at', 'desc')->get();
  11. }
  12. public function getByUnit(int $unitId): Collection
  13. {
  14. return ClassPackage::with('products')
  15. ->whereHas('units', fn($q) => $q->where('units.id', $unitId)->where('visible', true))
  16. ->orderBy('name')
  17. ->get();
  18. }
  19. public function findById(int $id): ?ClassPackage
  20. {
  21. return ClassPackage::with(['units', 'products'])->find($id);
  22. }
  23. public function create(array $data): ClassPackage
  24. {
  25. $unitVisibilities = $data['unit_visibilities'] ?? [];
  26. $materials = $data['materials'] ?? [];
  27. unset($data['unit_visibilities'], $data['materials']);
  28. $data['contract_material_value'] = $this->calcMaterialValue($materials);
  29. $package = ClassPackage::create($data);
  30. $this->syncUnitVisibilities($package, $unitVisibilities);
  31. $this->syncMaterials($package, $materials);
  32. return $package->load(['units', 'products']);
  33. }
  34. public function update(int $id, array $data): ?ClassPackage
  35. {
  36. $package = $this->findById($id);
  37. if (!$package) return null;
  38. $unitVisibilities = $data['unit_visibilities'] ?? null;
  39. $materials = $data['materials'] ?? null;
  40. unset($data['unit_visibilities'], $data['materials']);
  41. if ($materials !== null) {
  42. $data['contract_material_value'] = $this->calcMaterialValue($materials);
  43. }
  44. $package->update($data);
  45. if ($unitVisibilities !== null) {
  46. $this->syncUnitVisibilities($package, $unitVisibilities);
  47. }
  48. if ($materials !== null) {
  49. $this->syncMaterials($package, $materials);
  50. }
  51. return $package->fresh(['units', 'products']);
  52. }
  53. public function delete(int $id): bool
  54. {
  55. $package = ClassPackage::find($id);
  56. if (!$package) return false;
  57. return $package->delete();
  58. }
  59. public function getAllUnitsWithVisibility(int $packageId): \Illuminate\Support\Collection
  60. {
  61. $allUnits = Unit::orderBy('fantasy_name')->get(['id', 'fantasy_name']);
  62. $package = ClassPackage::with('units')->find($packageId);
  63. $visibilityMap = $package
  64. ? $package->units->keyBy('id')
  65. : collect();
  66. return $allUnits->map(fn($unit) => [
  67. 'id' => $unit->id,
  68. 'fantasy_name' => $unit->fantasy_name,
  69. 'visible' => $visibilityMap->has($unit->id)
  70. ? (bool) $visibilityMap[$unit->id]->pivot->visible
  71. : true,
  72. ]);
  73. }
  74. private function syncUnitVisibilities(ClassPackage $package, array $unitVisibilities): void
  75. {
  76. $syncData = [];
  77. foreach ($unitVisibilities as $uv) {
  78. $syncData[$uv['unit_id']] = ['visible' => $uv['visible']];
  79. }
  80. $package->units()->sync($syncData);
  81. }
  82. private function syncMaterials(ClassPackage $package, array $materials): void
  83. {
  84. $syncData = [];
  85. foreach ($materials as $m) {
  86. $syncData[$m['product_id']] = [
  87. 'quantity' => $m['quantity'],
  88. 'price' => $m['price'],
  89. ];
  90. }
  91. $package->products()->sync($syncData);
  92. }
  93. private function calcMaterialValue(array $materials): float
  94. {
  95. return array_reduce($materials, fn($carry, $m) => $carry + ($m['quantity'] * $m['price']), 0.0);
  96. }
  97. }