175 lines
4.9 KiB
PHP
175 lines
4.9 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Console\Commands;
|
||
|
|
|
||
|
|
use App\Models\Tenants\Tenant;
|
||
|
|
use Illuminate\Console\Command;
|
||
|
|
use Illuminate\Support\Facades\DB;
|
||
|
|
use Illuminate\Support\Facades\Log;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 데모 쇼케이스 테넌트 데이터 리셋 커맨드
|
||
|
|
*
|
||
|
|
* 매일 자정에 쇼케이스 테넌트의 비즈니스 데이터를 삭제하고
|
||
|
|
* 샘플 데이터를 다시 시드한다.
|
||
|
|
*
|
||
|
|
* 기존 코드 영향 없음: DEMO_SHOWCASE 테넌트만 대상
|
||
|
|
*
|
||
|
|
* @see docs/features/sales/demo-tenant-policy.md
|
||
|
|
*/
|
||
|
|
class ResetDemoShowcaseCommand extends Command
|
||
|
|
{
|
||
|
|
protected $signature = 'demo:reset-showcase
|
||
|
|
{--seed : 리셋 후 샘플 데이터 시드}
|
||
|
|
{--dry-run : 실제 삭제 없이 대상만 표시}';
|
||
|
|
|
||
|
|
protected $description = '데모 쇼케이스 테넌트의 비즈니스 데이터를 리셋합니다';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 리셋 대상 테이블 목록 (tenant_id 기반)
|
||
|
|
* 순서 중요: FK 의존성 역순으로 삭제
|
||
|
|
*/
|
||
|
|
private const RESET_TABLES = [
|
||
|
|
// 영업/주문
|
||
|
|
'order_item_components',
|
||
|
|
'order_items',
|
||
|
|
'order_histories',
|
||
|
|
'orders',
|
||
|
|
'quotes',
|
||
|
|
|
||
|
|
// 생산
|
||
|
|
'production_results',
|
||
|
|
'production_plans',
|
||
|
|
|
||
|
|
// 자재/재고
|
||
|
|
'material_inspection_items',
|
||
|
|
'material_inspections',
|
||
|
|
'material_receipts',
|
||
|
|
'lot_sales',
|
||
|
|
'lots',
|
||
|
|
|
||
|
|
// 마스터
|
||
|
|
'price_histories',
|
||
|
|
'product_components',
|
||
|
|
'items',
|
||
|
|
'clients',
|
||
|
|
|
||
|
|
// 파일 (데모 데이터 관련)
|
||
|
|
// files는 morphable이므로 별도 처리 필요
|
||
|
|
|
||
|
|
// 조직
|
||
|
|
'departments',
|
||
|
|
|
||
|
|
// 감사 로그 (데모 데이터)
|
||
|
|
'audit_logs',
|
||
|
|
];
|
||
|
|
|
||
|
|
public function handle(): int
|
||
|
|
{
|
||
|
|
$showcases = Tenant::withoutGlobalScopes()
|
||
|
|
->where('tenant_type', Tenant::TYPE_DEMO_SHOWCASE)
|
||
|
|
->get();
|
||
|
|
|
||
|
|
if ($showcases->isEmpty()) {
|
||
|
|
$this->info('데모 쇼케이스 테넌트가 없습니다.');
|
||
|
|
|
||
|
|
return self::SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach ($showcases as $tenant) {
|
||
|
|
$this->info("리셋 대상: [{$tenant->id}] {$tenant->company_name}");
|
||
|
|
|
||
|
|
if ($this->option('dry-run')) {
|
||
|
|
$this->showStats($tenant);
|
||
|
|
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->resetTenantData($tenant);
|
||
|
|
|
||
|
|
if ($this->option('seed')) {
|
||
|
|
$this->seedSampleData($tenant);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return self::SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
private function showStats(Tenant $tenant): void
|
||
|
|
{
|
||
|
|
foreach (self::RESET_TABLES as $table) {
|
||
|
|
if (! \Schema::hasTable($table)) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (! \Schema::hasColumn($table, 'tenant_id')) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$count = DB::table($table)->where('tenant_id', $tenant->id)->count();
|
||
|
|
if ($count > 0) {
|
||
|
|
$this->line(" - {$table}: {$count}건");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private function resetTenantData(Tenant $tenant): void
|
||
|
|
{
|
||
|
|
$totalDeleted = 0;
|
||
|
|
|
||
|
|
DB::beginTransaction();
|
||
|
|
try {
|
||
|
|
foreach (self::RESET_TABLES as $table) {
|
||
|
|
if (! \Schema::hasTable($table)) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (! \Schema::hasColumn($table, 'tenant_id')) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$deleted = DB::table($table)->where('tenant_id', $tenant->id)->delete();
|
||
|
|
if ($deleted > 0) {
|
||
|
|
$this->line(" 삭제: {$table} → {$deleted}건");
|
||
|
|
$totalDeleted += $deleted;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
DB::commit();
|
||
|
|
$this->info(" 총 {$totalDeleted}건 삭제 완료");
|
||
|
|
|
||
|
|
Log::info('데모 쇼케이스 리셋 완료', [
|
||
|
|
'tenant_id' => $tenant->id,
|
||
|
|
'deleted_count' => $totalDeleted,
|
||
|
|
]);
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
DB::rollBack();
|
||
|
|
$this->error(" 리셋 실패: {$e->getMessage()}");
|
||
|
|
Log::error('데모 쇼케이스 리셋 실패', [
|
||
|
|
'tenant_id' => $tenant->id,
|
||
|
|
'error' => $e->getMessage(),
|
||
|
|
]);
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private function seedSampleData(Tenant $tenant): void
|
||
|
|
{
|
||
|
|
$preset = $tenant->getDemoPreset() ?? 'manufacturing';
|
||
|
|
$this->info(" 샘플 데이터 시드: {$preset}");
|
||
|
|
|
||
|
|
try {
|
||
|
|
$seeder = new \Database\Seeders\Demo\ManufacturingPresetSeeder;
|
||
|
|
$seeder->run($tenant->id);
|
||
|
|
$this->info(' 샘플 데이터 시드 완료');
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
$this->error(" 시드 실패: {$e->getMessage()}");
|
||
|
|
Log::error('데모 샘플 데이터 시드 실패', [
|
||
|
|
'tenant_id' => $tenant->id,
|
||
|
|
'error' => $e->getMessage(),
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|