| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- <?php
- namespace App\Console\Commands;
- use App\Models\Contract;
- use App\Models\File;
- use App\Models\MafOrder;
- use App\Models\Order;
- use App\Models\Product;
- use App\Models\ProductSKU;
- use App\Models\Reclamation;
- use App\Models\Schedule;
- use App\Models\Ttn;
- use Illuminate\Console\Command;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Storage;
- class ClearYearData extends Command
- {
- protected $signature = 'app:clear-year-data
- {year : Год для очистки данных}
- {--force : Выполнить без подтверждения}';
- protected $description = 'Очистка всех данных CRM за указанный год и связанных зависимостей';
- public function handle(): int
- {
- $year = (int) $this->argument('year');
- if ($year < 2020 || $year > 2100) {
- $this->error("Некорректный год: {$year}");
- return self::FAILURE;
- }
- $stats = $this->collectStats($year);
- $this->info("Данные для удаления за {$year} год:");
- $this->table(
- ['Сущность', 'Количество'],
- collect($stats)->map(fn($count, $name) => [$name, $count])->toArray()
- );
- if (!$this->option('force')) {
- if (!$this->confirm('Вы уверены, что хотите удалить все эти данные? Это действие необратимо!')) {
- $this->info('Операция отменена.');
- return self::SUCCESS;
- }
- }
- $this->info('Начинаю удаление данных...');
- DB::beginTransaction();
- try {
- $this->clearData($year);
- DB::commit();
- $this->info('Все данные за ' . $year . ' год успешно удалены.');
- return self::SUCCESS;
- } catch (\Exception $e) {
- DB::rollBack();
- $this->error('Ошибка при удалении данных: ' . $e->getMessage());
- return self::FAILURE;
- }
- }
- private function collectStats(int $year): array
- {
- $orderIds = Order::withoutGlobalScopes()->withTrashed()->where('year', $year)->pluck('id');
- $productIds = Product::withoutGlobalScopes()->withTrashed()->where('year', $year)->pluck('id');
- $mafOrderIds = MafOrder::withoutGlobalScopes()->withTrashed()->where('year', $year)->pluck('id');
- $productSkuIds = ProductSKU::withoutGlobalScopes()->withTrashed()->where('year', $year)->pluck('id');
- $reclamationCount = Reclamation::whereIn('order_id', $orderIds)->count();
- // Собираем ID файлов для удаления
- $fileIds = $this->collectFileIds($year, $orderIds, $productIds, $productSkuIds);
- return [
- 'Заказы (Orders)' => $orderIds->count(),
- 'Заказы МАФ (MafOrders)' => $mafOrderIds->count(),
- 'Продукты (Products)' => $productIds->count(),
- 'SKU продуктов (ProductSKU)' => $productSkuIds->count(),
- 'Рекламации (Reclamations)' => $reclamationCount,
- 'Расписания (Schedules)' => Schedule::whereIn('order_id', $orderIds)->count(),
- 'ТТН (Ttns)' => Ttn::where('year', $year)->count(),
- 'Контракты (Contracts)' => Contract::where('year', $year)->count(),
- 'Файлы (Files)' => $fileIds->count(),
- ];
- }
- private function collectFileIds(int $year, $orderIds, $productIds, $productSkuIds): \Illuminate\Support\Collection
- {
- $fileIds = collect();
- // Файлы заказов (фото, документы, ведомости)
- $fileIds = $fileIds->merge(
- DB::table('order_photo')->whereIn('order_id', $orderIds)->pluck('file_id')
- );
- $fileIds = $fileIds->merge(
- DB::table('order_document')->whereIn('order_id', $orderIds)->pluck('file_id')
- );
- $fileIds = $fileIds->merge(
- DB::table('order_statement')->whereIn('order_id', $orderIds)->pluck('file_id')
- );
- // Рекламации связанных заказов
- $reclamationIds = Reclamation::whereIn('order_id', $orderIds)->pluck('id');
- $fileIds = $fileIds->merge(
- DB::table('reclamation_photo_before')->whereIn('reclamation_id', $reclamationIds)->pluck('file_id')
- );
- $fileIds = $fileIds->merge(
- DB::table('reclamation_photo_after')->whereIn('reclamation_id', $reclamationIds)->pluck('file_id')
- );
- $fileIds = $fileIds->merge(
- DB::table('reclamation_document')->whereIn('reclamation_id', $reclamationIds)->pluck('file_id')
- );
- $fileIds = $fileIds->merge(
- DB::table('reclamation_act')->whereIn('reclamation_id', $reclamationIds)->pluck('file_id')
- );
- // Сертификаты продуктов
- $fileIds = $fileIds->merge(
- Product::withoutGlobalScopes()->withTrashed()
- ->whereIn('id', $productIds)
- ->whereNotNull('certificate_id')
- ->pluck('certificate_id')
- );
- // Паспорта SKU
- $fileIds = $fileIds->merge(
- ProductSKU::withoutGlobalScopes()->withTrashed()
- ->whereIn('id', $productSkuIds)
- ->whereNotNull('passport_id')
- ->pluck('passport_id')
- );
- // Файлы ТТН
- $fileIds = $fileIds->merge(
- Ttn::where('year', $year)->whereNotNull('file_id')->pluck('file_id')
- );
- return $fileIds->unique();
- }
- private function clearData(int $year): void
- {
- $orderIds = Order::withoutGlobalScopes()->withTrashed()->where('year', $year)->pluck('id');
- $productIds = Product::withoutGlobalScopes()->withTrashed()->where('year', $year)->pluck('id');
- $mafOrderIds = MafOrder::withoutGlobalScopes()->withTrashed()->where('year', $year)->pluck('id');
- $productSkuIds = ProductSKU::withoutGlobalScopes()->withTrashed()->where('year', $year)->pluck('id');
- $reclamationIds = Reclamation::whereIn('order_id', $orderIds)->pluck('id');
- // Собираем файлы до удаления связей
- $fileIds = $this->collectFileIds($year, $orderIds, $productIds, $productSkuIds);
- $this->info('Удаление рекламаций и связанных данных...');
- // Детали рекламаций (cascadeOnDelete, но удаляем явно для уверенности)
- DB::table('reclamation_details')->whereIn('reclamation_id', $reclamationIds)->delete();
- DB::table('reclamation_product_sku')->whereIn('reclamation_id', $reclamationIds)->delete();
- DB::table('reclamation_photo_before')->whereIn('reclamation_id', $reclamationIds)->delete();
- DB::table('reclamation_photo_after')->whereIn('reclamation_id', $reclamationIds)->delete();
- DB::table('reclamation_document')->whereIn('reclamation_id', $reclamationIds)->delete();
- DB::table('reclamation_act')->whereIn('reclamation_id', $reclamationIds)->delete();
- Reclamation::whereIn('id', $reclamationIds)->delete();
- $this->info('Удаление связей заказов с файлами...');
- DB::table('order_photo')->whereIn('order_id', $orderIds)->delete();
- DB::table('order_document')->whereIn('order_id', $orderIds)->delete();
- DB::table('order_statement')->whereIn('order_id', $orderIds)->delete();
- $this->info('Удаление расписаний...');
- Schedule::whereIn('order_id', $orderIds)->delete();
- $this->info('Удаление SKU продуктов...');
- ProductSKU::withoutGlobalScopes()->withTrashed()->where('year', $year)->forceDelete();
- $this->info('Удаление заказов...');
- Order::withoutGlobalScopes()->withTrashed()->where('year', $year)->forceDelete();
- $this->info('Удаление заказов МАФ...');
- MafOrder::withoutGlobalScopes()->withTrashed()->where('year', $year)->forceDelete();
- $this->info('Удаление продуктов...');
- // Сначала обнуляем certificate_id чтобы избежать проблем с FK
- Product::withoutGlobalScopes()->withTrashed()
- ->whereIn('id', $productIds)
- ->update(['certificate_id' => null]);
- Product::withoutGlobalScopes()->withTrashed()->where('year', $year)->forceDelete();
- $this->info('Удаление ТТН...');
- // Обнуляем file_id перед удалением
- Ttn::where('year', $year)->update(['file_id' => null]);
- Ttn::where('year', $year)->delete();
- $this->info('Удаление контрактов...');
- Contract::where('year', $year)->delete();
- $this->info('Удаление файлов...');
- $this->deleteFiles($fileIds);
- }
- private function deleteFiles($fileIds): void
- {
- $files = File::whereIn('id', $fileIds)->get();
- foreach ($files as $file) {
- // Удаляем физический файл
- if ($file->path && Storage::disk('public')->exists($file->path)) {
- Storage::disk('public')->delete($file->path);
- }
- }
- // Удаляем записи из БД
- File::whereIn('id', $fileIds)->delete();
- }
- }
|