join('spare_part_orders', 'spare_part_order_shipments.spare_part_order_id', '=', 'spare_part_orders.id') ->select([ 'spare_part_order_shipments.*', 'spare_part_orders.spare_part_id', 'spare_part_orders.with_documents', ]) ->get(); foreach ($shipments as $shipment) { DB::table('inventory_movements')->insert([ 'spare_part_order_id' => $shipment->spare_part_order_id, 'spare_part_id' => $shipment->spare_part_id, 'qty' => $shipment->quantity, 'movement_type' => 'issue', 'source_type' => $shipment->reclamation_id ? 'reclamation' : 'manual', 'source_id' => $shipment->reclamation_id, 'with_documents' => $shipment->with_documents, 'user_id' => $shipment->user_id, 'note' => $shipment->note ?? ($shipment->is_automatic ? 'Автоматическое списание (мигрировано)' : 'Ручное списание (мигрировано)'), 'created_at' => $shipment->created_at, 'updated_at' => $shipment->updated_at, ]); } // 2. Находим "виртуальные заказы" с отрицательным остатком (до рефакторинга) // Примечание: колонка уже переименована в available_qty и обнулена в предыдущей миграции // Но нам нужно создать shortages на основе данных в pivot таблице, // где quantity есть, но не было реальной партии // Получаем записи из pivot где запчасть привязана к рекламации $pivotRecords = DB::table('reclamation_spare_part') ->join('spare_parts', 'reclamation_spare_part.spare_part_id', '=', 'spare_parts.id') ->select([ 'reclamation_spare_part.*', 'spare_parts.article', ]) ->get(); foreach ($pivotRecords as $pivot) { // Проверяем, есть ли достаточно резервов/списаний для этой привязки $totalIssued = DB::table('inventory_movements') ->where('source_type', 'reclamation') ->where('source_id', $pivot->reclamation_id) ->where('spare_part_id', $pivot->spare_part_id) ->where('with_documents', $pivot->with_documents) ->where('movement_type', 'issue') ->sum('qty'); $missing = $pivot->quantity - $totalIssued; if ($missing > 0) { // Создаём shortage для недостающего количества DB::table('shortages')->insert([ 'spare_part_id' => $pivot->spare_part_id, 'reclamation_id' => $pivot->reclamation_id, 'with_documents' => $pivot->with_documents, 'required_qty' => $pivot->quantity, 'reserved_qty' => $totalIssued, 'missing_qty' => $missing, 'status' => 'open', 'note' => 'Создано при миграции данных', 'created_at' => $pivot->created_at ?? now(), 'updated_at' => now(), ]); } // Обновляем pivot с новыми полями DB::table('reclamation_spare_part') ->where('id', $pivot->id) ->update([ 'status' => $totalIssued >= $pivot->quantity ? 'issued' : ($totalIssued > 0 ? 'reserved' : 'pending'), 'reserved_qty' => 0, // Старые данные были issue, не reserve 'issued_qty' => $totalIssued, ]); } // 3. Удаляем виртуальные заказы с нулевым ordered_quantity // (они были созданы для учёта недостач) DB::table('spare_part_orders') ->where('ordered_quantity', 0) ->delete(); } /** * Reverse the migrations. */ public function down(): void { // Удаляем созданные при миграции данные DB::table('inventory_movements') ->where('note', 'like', '%мигрировано%') ->delete(); DB::table('shortages') ->where('note', 'Создано при миграции данных') ->delete(); // Сбрасываем новые поля в pivot DB::table('reclamation_spare_part')->update([ 'status' => 'pending', 'reserved_qty' => 0, 'issued_qty' => 0, ]); } };