Order.php 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. <?php
  2. namespace App\Models;
  3. use App\Helpers\Price;
  4. use App\Models\Dictionary\Area;
  5. use App\Models\Dictionary\District;
  6. use App\Models\Scopes\YearScope;
  7. use Illuminate\Database\Eloquent\Attributes\ScopedBy;
  8. use Illuminate\Database\Eloquent\Casts\Attribute;
  9. use Illuminate\Database\Eloquent\Model;
  10. use Illuminate\Database\Eloquent\Relations\BelongsTo;
  11. use Illuminate\Database\Eloquent\Relations\BelongsToMany;
  12. use Illuminate\Database\Eloquent\Relations\HasMany;
  13. use Illuminate\Database\Eloquent\Relations\HasManyThrough;
  14. use Illuminate\Database\Eloquent\SoftDeletes;
  15. use Illuminate\Support\Facades\DB;
  16. #[ScopedBy([YearScope::class])]
  17. class Order extends Model
  18. {
  19. use SoftDeletes;
  20. const DEFAULT_SORT_BY = 'created_at';
  21. const STATUS_NEW = 1;
  22. const STATUS_NOT_READY = 2;
  23. const STATUS_READY_NO_MAF = 3;
  24. const STATUS_READY_TO_MOUNT = 4;
  25. const STATUS_IN_MOUNT = 5;
  26. const STATUS_DUTY = 6;
  27. const STATUS_READY_TO_HAND_OVER = 7;
  28. const STATUS_NOT_HANDED_OVER_WITH_NOTES = 8;
  29. const STATUS_HANDED_OVER_WITH_NOTES = 9;
  30. const STATUS_HANDED_OVER = 10;
  31. const STATUS_NO_MAF = 11;
  32. const STATUS_PROBLEM = 12;
  33. //ПЛ не готова; ПЛ готова нет МАФ; Готов к монтажу; В монтаже; Долг;Готов к сдаче;Не сдан, замечания;Сдан с замечаниями;Сдан;Проблема
  34. const STATUS_NAMES = [
  35. self::STATUS_NEW => 'Новая',
  36. self::STATUS_NOT_READY => 'Не готова',
  37. self::STATUS_READY_NO_MAF => 'Готова, нет МАФ',
  38. self::STATUS_READY_TO_MOUNT => 'Готова к монтажу',
  39. self::STATUS_IN_MOUNT => 'В монтаже',
  40. self::STATUS_DUTY => 'Долг',
  41. self::STATUS_READY_TO_HAND_OVER => 'Готова к сдаче',
  42. self::STATUS_NOT_HANDED_OVER_WITH_NOTES => 'Не сдана, замечания',
  43. self::STATUS_HANDED_OVER_WITH_NOTES => 'Сдана с замечаниями',
  44. self::STATUS_HANDED_OVER => 'Сдана',
  45. self::STATUS_NO_MAF => 'Отсутствуют МАФ',
  46. self::STATUS_PROBLEM => 'Проблема',
  47. ];
  48. // set year attribute to current selected year
  49. protected static function boot(): void
  50. {
  51. parent::boot();
  52. static::creating(function($attributes) {
  53. if(!isset($attributes->year)) {
  54. $attributes->year = year();
  55. }
  56. });
  57. }
  58. protected $fillable = [
  59. 'year',
  60. 'name',
  61. 'user_id',
  62. 'district_id',
  63. 'area_id',
  64. 'object_address',
  65. 'object_type_id',
  66. 'comment',
  67. 'installation_date',
  68. 'ready_date',
  69. 'brigadier_id',
  70. 'order_status_id',
  71. 'tg_group_name',
  72. 'tg_group_link',
  73. 'ready_to_mount',
  74. ];
  75. public $appends = ['common_name', 'products_with_count'];
  76. public function products_sku(): HasMany
  77. {
  78. return $this->hasMany(ProductSKU::class, 'order_id', 'id');
  79. }
  80. public function products(): HasManyThrough
  81. {
  82. return $this->hasManyThrough(
  83. Product::class,
  84. ProductSKU::class,
  85. 'order_id',
  86. 'id',
  87. 'id',
  88. 'product_id');
  89. }
  90. public function user(): BelongsTo
  91. {
  92. return $this->belongsTo(User::class, 'user_id', 'id');
  93. }
  94. public function district(): BelongsTo
  95. {
  96. return $this->belongsTo(District::class);
  97. }
  98. public function area(): BelongsTo
  99. {
  100. return $this->belongsTo(Area::class);
  101. }
  102. public function objectType(): BelongsTo
  103. {
  104. return $this->belongsTo(ObjectType::class);
  105. }
  106. public function brigadier(): BelongsTo
  107. {
  108. return $this->belongsTo(User::class, 'brigadier_id', 'id');
  109. }
  110. public function orderStatus(): BelongsTo
  111. {
  112. return $this->belongsTo(OrderStatus::class);
  113. }
  114. public function photos(): BelongsToMany
  115. {
  116. return $this->belongsToMany(File::class, 'order_file', 'order_id', 'file_id');
  117. }
  118. public function documents(): BelongsToMany
  119. {
  120. return $this->belongsToMany(File::class, 'order_file', 'order_id', 'file_id');
  121. }
  122. public function statements(): BelongsToMany
  123. {
  124. return $this->belongsToMany(File::class, 'order_file', 'order_id', 'file_id');
  125. }
  126. public function getNeeds(): array
  127. {
  128. $needs = [];
  129. foreach ($this->products_sku as $sku) {
  130. if($sku->maf_order) continue;
  131. $needs[$sku->product_id]['needs'] = (isset($needs[$sku->product_id])) ? $needs[$sku->product_id]['needs'] + 1 : 1;
  132. }
  133. foreach ($needs as $productId => $quantity) {
  134. $needs[$productId]['sku'] = MafOrder::query()
  135. ->where('maf_orders.product_id', $productId)
  136. ->sum('maf_orders.in_stock');
  137. }
  138. return $needs;
  139. }
  140. public function recalculateReadyToMount(): void
  141. {
  142. $result = true;
  143. foreach ($this->getNeeds() as $need) {
  144. if($need['sku'] < $need['needs']) {
  145. $result = false;
  146. break;
  147. }
  148. }
  149. $this->update(['ready_to_mount' => ($result) ? 'Да' : 'Нет']);
  150. }
  151. public function autoChangeStatus(): void
  152. {
  153. if(($this->products_sku->count() < 1)
  154. && ($this->order_status_id !== self::STATUS_NEW)
  155. ) {
  156. $this->update(['order_status_id' => self::STATUS_NO_MAF]);
  157. return;
  158. }
  159. if(($this->order_status_id === self::STATUS_READY_TO_MOUNT)
  160. && ($this->brigadier_id !== null)
  161. && ($this->installation_date !== null)
  162. ) {
  163. $allMafConnected = true;
  164. foreach ($this->products_sku as $sku) {
  165. if($sku->maf_order) continue;
  166. $allMafConnected = false;
  167. }
  168. if($allMafConnected) {
  169. $this->update(['order_status_id' => self::STATUS_IN_MOUNT]);
  170. }
  171. }
  172. }
  173. public function commonName(): Attribute
  174. {
  175. return Attribute::make(
  176. get: fn($value) => (string) $this->object_address . ', ' . $this->area->name . ', ' . $this->district->shortname,
  177. );
  178. }
  179. public function productsWithCount(): Attribute
  180. {
  181. $products = $this->products_sku;
  182. $ret = [];
  183. foreach ($products as $product) {
  184. if(isset($ret[$product->product->id])) {
  185. $ret[$product->product->id]['count'] += 1;
  186. } else {
  187. $ret[$product->product->id] = [
  188. 'name' => $product->product->article,
  189. 'count' => 1,
  190. ];
  191. }
  192. if($product->maf_order?->order_number) {
  193. $ret[$product->product->id]['order_numbers'][] = $product->maf_order?->order_number;
  194. }
  195. }
  196. $s = '';
  197. foreach ($ret as $product) {
  198. ;
  199. $order_numbers = (isset($product['order_numbers'])) ? ' (' . implode(', ', array_unique($product['order_numbers'])) . ')' : '';
  200. $s .= '<div>' . $product['name'] . ' - ' . $product['count'] . $order_numbers . '</div>';
  201. }
  202. return Attribute::make(
  203. get: fn($value) => (string) $s,
  204. );
  205. }
  206. }