ClassPackageUnitService.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. <?php
  2. namespace App\Services;
  3. use App\Models\ClassPackageUnit;
  4. use App\Models\ClassPackageUnitProduct;
  5. use App\Models\ClassPackageUnitVariation;
  6. use Illuminate\Database\Eloquent\Collection;
  7. class ClassPackageUnitService
  8. {
  9. public function getByUnit(int $unitId): Collection
  10. {
  11. return ClassPackageUnit::with('products.product', 'variations.products.product')
  12. ->where('unit_id', $unitId)
  13. ->where('visible', true)
  14. ->orderBy('name')
  15. ->get();
  16. }
  17. public function getAllByUnit(int $unitId): Collection
  18. {
  19. return ClassPackageUnit::with('products.product', 'variations.products.product')
  20. ->where('unit_id', $unitId)
  21. ->orderBy('name')
  22. ->get();
  23. }
  24. public function findByIdForUnit(int $id, int $unitId): ClassPackageUnit
  25. {
  26. return ClassPackageUnit::with('products.product', 'variations.products.product')
  27. ->where('unit_id', $unitId)
  28. ->findOrFail($id);
  29. }
  30. public function create(array $data): ClassPackageUnit
  31. {
  32. $materials = $data['materials'] ?? [];
  33. $variations = $data['variations'] ?? [];
  34. unset($data['materials'], $data['variations']);
  35. $data['contract_material_value'] = $this->calcMaterialValue($materials);
  36. $packageUnit = ClassPackageUnit::create($data);
  37. $this->syncProducts($packageUnit, $materials);
  38. $this->syncVariations($packageUnit, $variations, $materials);
  39. return $packageUnit->load('products.product', 'variations.products.product');
  40. }
  41. public function update(int $id, int $unitId, array $data): ClassPackageUnit
  42. {
  43. $packageUnit = $this->findByIdForUnit($id, $unitId);
  44. $materials = $data['materials'] ?? null;
  45. $variations = $data['variations'] ?? null;
  46. unset($data['materials'], $data['variations']);
  47. if ($materials !== null) {
  48. $data['contract_material_value'] = $this->calcMaterialValue($materials);
  49. }
  50. $packageUnit->update($data);
  51. if ($materials !== null) {
  52. $this->syncProducts($packageUnit, $materials);
  53. }
  54. if ($variations !== null) {
  55. $this->syncVariations($packageUnit, $variations, $this->currentMaterials($packageUnit));
  56. }
  57. return $packageUnit->fresh('products.product', 'variations.products.product');
  58. }
  59. public function toggleVisibility(int $id, int $unitId): ClassPackageUnit
  60. {
  61. $packageUnit = $this->findByIdForUnit($id, $unitId);
  62. $packageUnit->update(['visible' => !$packageUnit->visible]);
  63. return $packageUnit->fresh();
  64. }
  65. public function delete(int $id, int $unitId): bool
  66. {
  67. $packageUnit = $this->findByIdForUnit($id, $unitId);
  68. return $packageUnit->delete();
  69. }
  70. // Sync products on an existing ClassPackageUnit from the base package.
  71. public function syncProductsFromBasePackage(ClassPackageUnit $packageUnit, \App\Models\ClassPackage $basePackage): void
  72. {
  73. $packageUnit->products()->delete();
  74. $basePackage->products->each(function ($product) use ($packageUnit) {
  75. ClassPackageUnitProduct::create([
  76. 'class_package_unit_id' => $packageUnit->id,
  77. 'product_id' => $product->id,
  78. 'quantity' => $product->pivot->quantity,
  79. 'price' => $product->pivot->price,
  80. ]);
  81. });
  82. }
  83. public function replicateFromBasePackage(int $unitId, \App\Models\ClassPackage $basePackage): ClassPackageUnit
  84. {
  85. $packageUnit = ClassPackageUnit::create([
  86. 'unit_id' => $unitId,
  87. 'class_package_id' => $basePackage->id,
  88. 'name' => $basePackage->name,
  89. 'quantity_classes' => $basePackage->quantity_classes,
  90. 'contract_material_value' => $basePackage->contract_material_value,
  91. 'class_duration_minutes' => $basePackage->class_duration_minutes,
  92. 'weekday' => $basePackage->weekday,
  93. 'start_time' => $basePackage->start_time,
  94. 'second_weekday' => $basePackage->second_weekday,
  95. 'second_start_time' => $basePackage->second_start_time,
  96. 'visible' => true,
  97. ]);
  98. $basePackage->products->each(function ($product) use ($packageUnit) {
  99. ClassPackageUnitProduct::create([
  100. 'class_package_unit_id' => $packageUnit->id,
  101. 'product_id' => $product->id,
  102. 'quantity' => $product->pivot->quantity,
  103. 'price' => $product->pivot->price,
  104. ]);
  105. });
  106. return $packageUnit;
  107. }
  108. //
  109. private function calcMaterialValue(array $materials): float
  110. {
  111. return array_reduce($materials, fn($carry, $m) => $carry + ($m['quantity'] * $m['price']), 0.0);
  112. }
  113. private function currentMaterials(ClassPackageUnit $packageUnit): array
  114. {
  115. return $packageUnit->products()
  116. ->get()
  117. ->map(fn ($product) => [
  118. 'product_id' => $product->product_id,
  119. 'quantity' => $product->quantity,
  120. 'price' => (float) $product->price,
  121. ])
  122. ->all();
  123. }
  124. private function syncProducts(ClassPackageUnit $packageUnit, array $materials): void
  125. {
  126. $packageUnit->products()->delete();
  127. foreach ($materials as $m) {
  128. ClassPackageUnitProduct::create([
  129. 'class_package_unit_id' => $packageUnit->id,
  130. 'product_id' => $m['product_id'],
  131. 'quantity' => $m['quantity'],
  132. 'price' => $m['price'],
  133. ]);
  134. }
  135. }
  136. private function syncVariations(ClassPackageUnit $packageUnit, array $variations, array $defaultMaterials): void
  137. {
  138. $packageUnit->variations()->delete();
  139. foreach ($variations as $variation) {
  140. // sem lista propria a proposta herda os materiais do pacote da unidade
  141. $materials = $variation['materials'] ?? $defaultMaterials;
  142. unset($variation['materials']);
  143. // o valor do material nao e editavel, ele acompanha a lista
  144. $variation['material_value'] = $this->calcMaterialValue($materials);
  145. $record = $packageUnit->variations()->create($variation);
  146. $this->syncVariationProducts($record, $materials);
  147. }
  148. }
  149. private function syncVariationProducts(ClassPackageUnitVariation $variation, array $materials): void
  150. {
  151. $variation->products()->delete();
  152. foreach ($materials as $material) {
  153. $variation->products()->create([
  154. 'product_id' => $material['product_id'],
  155. 'quantity' => $material['quantity'],
  156. 'price' => $material['price'],
  157. ]);
  158. }
  159. }
  160. }