feat: [demo] 데모 테넌트 운영 자동화 (Phase 2)
- DemoLimitMiddleware: 쇼케이스 읽기전용, 만료 체크, 외부연동 차단 - DemoTenantService: 파트너/체험 테넌트 생성, 기간 연장, 정식 전환 - ResetDemoShowcaseCommand: 매일 자정 데이터 리셋 + 샘플 재시드 - ManufacturingPresetSeeder: 부서/거래처/품목/견적/수주 샘플 데이터 - 스케줄러 등록 (00:00 demo:reset-showcase --seed) - 미들웨어 별칭 등록 (demo.limit)
This commit is contained in:
248
database/seeders/Demo/ManufacturingPresetSeeder.php
Normal file
248
database/seeders/Demo/ManufacturingPresetSeeder.php
Normal file
@@ -0,0 +1,248 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders\Demo;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/**
|
||||
* 제조업 데모 프리셋 시더
|
||||
*
|
||||
* 데모 쇼케이스 테넌트용 샘플 데이터를 생성한다.
|
||||
* DatabaseSeeder에 등록하지 않으며, ResetDemoShowcaseCommand에서만 호출된다.
|
||||
*
|
||||
* 기존 코드/데이터에 영향 없음: 지정된 tenant_id에만 데이터 생성
|
||||
*
|
||||
* @see docs/features/sales/demo-tenant-policy.md
|
||||
*/
|
||||
class ManufacturingPresetSeeder
|
||||
{
|
||||
public function run(int $tenantId): void
|
||||
{
|
||||
$now = now();
|
||||
|
||||
// 1. 부서
|
||||
$this->seedDepartments($tenantId, $now);
|
||||
|
||||
// 2. 거래처
|
||||
$clientIds = $this->seedClients($tenantId, $now);
|
||||
|
||||
// 3. 품목 (원자재, 반제품, 완제품)
|
||||
$this->seedItems($tenantId, $now);
|
||||
|
||||
// 4. 견적
|
||||
$this->seedQuotes($tenantId, $clientIds, $now);
|
||||
|
||||
// 5. 수주
|
||||
$this->seedOrders($tenantId, $clientIds, $now);
|
||||
}
|
||||
|
||||
private function seedDepartments(int $tenantId, $now): void
|
||||
{
|
||||
$parentId = DB::table('departments')->insertGetId([
|
||||
'tenant_id' => $tenantId,
|
||||
'name' => '데모제조(주)',
|
||||
'parent_id' => null,
|
||||
'is_active' => true,
|
||||
'sort_order' => 0,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
|
||||
$departments = [
|
||||
['name' => '경영지원팀', 'sort_order' => 1],
|
||||
['name' => '영업팀', 'sort_order' => 2],
|
||||
['name' => '생산팀', 'sort_order' => 3],
|
||||
['name' => '품질관리팀', 'sort_order' => 4],
|
||||
['name' => '자재팀', 'sort_order' => 5],
|
||||
];
|
||||
|
||||
foreach ($departments as $dept) {
|
||||
DB::table('departments')->insert([
|
||||
'tenant_id' => $tenantId,
|
||||
'name' => $dept['name'],
|
||||
'parent_id' => $parentId,
|
||||
'is_active' => true,
|
||||
'sort_order' => $dept['sort_order'],
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function seedClients(int $tenantId, $now): array
|
||||
{
|
||||
$clients = [
|
||||
['code' => 'C-DEMO-001', 'name' => '(주)한국철강', 'type' => 'SUPPLIER', 'business_no' => '123-45-67890', 'phone' => '02-1234-5678'],
|
||||
['code' => 'C-DEMO-002', 'name' => '삼성전자(주)', 'type' => 'CUSTOMER', 'business_no' => '234-56-78901', 'phone' => '02-2345-6789'],
|
||||
['code' => 'C-DEMO-003', 'name' => '(주)대한물산', 'type' => 'CUSTOMER', 'business_no' => '345-67-89012', 'phone' => '02-3456-7890'],
|
||||
['code' => 'C-DEMO-004', 'name' => '현대부품(주)', 'type' => 'SUPPLIER', 'business_no' => '456-78-90123', 'phone' => '031-4567-8901'],
|
||||
['code' => 'C-DEMO-005', 'name' => '동양기계(주)', 'type' => 'BOTH', 'business_no' => '567-89-01234', 'phone' => '032-5678-9012'],
|
||||
['code' => 'C-DEMO-006', 'name' => '(주)서울유통', 'type' => 'CUSTOMER', 'business_no' => '678-90-12345', 'phone' => '02-6789-0123'],
|
||||
['code' => 'C-DEMO-007', 'name' => '부산산업(주)', 'type' => 'SUPPLIER', 'business_no' => '789-01-23456', 'phone' => '051-7890-1234'],
|
||||
['code' => 'C-DEMO-008', 'name' => '(주)글로벌테크', 'type' => 'CUSTOMER', 'business_no' => '890-12-34567', 'phone' => '02-8901-2345'],
|
||||
['code' => 'C-DEMO-009', 'name' => '인천금속(주)', 'type' => 'SUPPLIER', 'business_no' => '901-23-45678', 'phone' => '032-9012-3456'],
|
||||
['code' => 'C-DEMO-010', 'name' => '(주)한빛전자', 'type' => 'CUSTOMER', 'business_no' => '012-34-56789', 'phone' => '02-0123-4567'],
|
||||
];
|
||||
|
||||
$ids = [];
|
||||
foreach ($clients as $client) {
|
||||
$ids[] = DB::table('clients')->insertGetId([
|
||||
'tenant_id' => $tenantId,
|
||||
'client_code' => $client['code'],
|
||||
'name' => $client['name'],
|
||||
'client_type' => $client['type'],
|
||||
'business_no' => $client['business_no'],
|
||||
'phone' => $client['phone'],
|
||||
'is_active' => true,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
private function seedItems(int $tenantId, $now): void
|
||||
{
|
||||
// 원자재
|
||||
$rawMaterials = [
|
||||
['code' => 'RM-001', 'name' => 'STS304 스테인리스 판재 (1.0t)', 'unit' => 'EA'],
|
||||
['code' => 'RM-002', 'name' => 'STS304 스테인리스 판재 (1.5t)', 'unit' => 'EA'],
|
||||
['code' => 'RM-003', 'name' => '알루미늄 프로파일 40x40', 'unit' => 'M'],
|
||||
['code' => 'RM-004', 'name' => '알루미늄 프로파일 60x60', 'unit' => 'M'],
|
||||
['code' => 'RM-005', 'name' => 'SS400 철판 (3.0t)', 'unit' => 'EA'],
|
||||
['code' => 'RM-006', 'name' => '동파이프 15A', 'unit' => 'M'],
|
||||
['code' => 'RM-007', 'name' => '볼트 M8x20 STS', 'unit' => 'EA'],
|
||||
['code' => 'RM-008', 'name' => '볼트 M10x30 STS', 'unit' => 'EA'],
|
||||
['code' => 'RM-009', 'name' => '고무 패킹 (50mm)', 'unit' => 'EA'],
|
||||
['code' => 'RM-010', 'name' => '에폭시 도료 (20L)', 'unit' => 'CAN'],
|
||||
];
|
||||
|
||||
foreach ($rawMaterials as $rm) {
|
||||
DB::table('items')->insert([
|
||||
'tenant_id' => $tenantId,
|
||||
'code' => $rm['code'],
|
||||
'name' => $rm['name'],
|
||||
'unit' => $rm['unit'],
|
||||
'item_type' => 'MATERIAL',
|
||||
'is_active' => true,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
// 반제품
|
||||
$subAssemblies = [
|
||||
['code' => 'SA-001', 'name' => '프레임 조립체 A', 'unit' => 'EA'],
|
||||
['code' => 'SA-002', 'name' => '프레임 조립체 B', 'unit' => 'EA'],
|
||||
['code' => 'SA-003', 'name' => '구동부 어셈블리', 'unit' => 'SET'],
|
||||
['code' => 'SA-004', 'name' => '제어 패널 유닛', 'unit' => 'EA'],
|
||||
['code' => 'SA-005', 'name' => '하우징 케이스', 'unit' => 'EA'],
|
||||
];
|
||||
|
||||
foreach ($subAssemblies as $sa) {
|
||||
DB::table('items')->insert([
|
||||
'tenant_id' => $tenantId,
|
||||
'code' => $sa['code'],
|
||||
'name' => $sa['name'],
|
||||
'unit' => $sa['unit'],
|
||||
'item_type' => 'SUBASSEMBLY',
|
||||
'is_active' => true,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
// 완제품
|
||||
$finishedProducts = [
|
||||
['code' => 'FP-001', 'name' => '자동화 컨베이어 시스템 (표준형)', 'unit' => 'SET'],
|
||||
['code' => 'FP-002', 'name' => '자동화 컨베이어 시스템 (고속형)', 'unit' => 'SET'],
|
||||
['code' => 'FP-003', 'name' => '산업용 로봇암 (6축)', 'unit' => 'EA'],
|
||||
['code' => 'FP-004', 'name' => '정밀 CNC 가공기', 'unit' => 'EA'],
|
||||
['code' => 'FP-005', 'name' => '유압 프레스 (50톤)', 'unit' => 'EA'],
|
||||
];
|
||||
|
||||
foreach ($finishedProducts as $p) {
|
||||
DB::table('items')->insert([
|
||||
'tenant_id' => $tenantId,
|
||||
'code' => $p['code'],
|
||||
'name' => $p['name'],
|
||||
'unit' => $p['unit'],
|
||||
'item_type' => 'PRODUCT',
|
||||
'is_active' => true,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function seedQuotes(int $tenantId, array $clientIds, $now): void
|
||||
{
|
||||
$quotes = [
|
||||
['no' => 'QT-2026-001', 'client_idx' => 1, 'name' => '컨베이어 시스템 표준형', 'qty' => 2, 'amount' => 45000000, 'status' => 'approved'],
|
||||
['no' => 'QT-2026-002', 'client_idx' => 2, 'name' => '로봇암 6축 3대', 'qty' => 3, 'amount' => 120000000, 'status' => 'sent'],
|
||||
['no' => 'QT-2026-003', 'client_idx' => 5, 'name' => 'CNC 가공기 설치', 'qty' => 1, 'amount' => 85000000, 'status' => 'finalized'],
|
||||
['no' => 'QT-2026-004', 'client_idx' => 7, 'name' => '유압프레스 2대', 'qty' => 2, 'amount' => 60000000, 'status' => 'draft'],
|
||||
['no' => 'QT-2026-005', 'client_idx' => 9, 'name' => '컨베이어 고속형', 'qty' => 1, 'amount' => 55000000, 'status' => 'converted'],
|
||||
];
|
||||
|
||||
foreach ($quotes as $q) {
|
||||
$supplyAmount = $q['amount'];
|
||||
$taxAmount = (int) round($supplyAmount * 0.1);
|
||||
|
||||
DB::table('quotes')->insert([
|
||||
'tenant_id' => $tenantId,
|
||||
'quote_number' => $q['no'],
|
||||
'quote_type' => 'manufacturing',
|
||||
'registration_date' => now()->subDays(rand(10, 60))->toDateString(),
|
||||
'client_id' => $clientIds[$q['client_idx']] ?? $clientIds[0],
|
||||
'product_category' => 'STEEL',
|
||||
'product_name' => $q['name'],
|
||||
'quantity' => $q['qty'],
|
||||
'subtotal' => $supplyAmount,
|
||||
'discount_rate' => 0,
|
||||
'discount_amount' => 0,
|
||||
'total_amount' => $supplyAmount + $taxAmount,
|
||||
'status' => $q['status'],
|
||||
'current_revision' => 1,
|
||||
'is_final' => $q['status'] === 'finalized' || $q['status'] === 'converted',
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function seedOrders(int $tenantId, array $clientIds, $now): void
|
||||
{
|
||||
$orders = [
|
||||
['no' => 'SO-2026-001', 'client_idx' => 1, 'status' => 'CONFIRMED', 'qty' => 2, 'supply' => 45000000],
|
||||
['no' => 'SO-2026-002', 'client_idx' => 2, 'status' => 'IN_PRODUCTION', 'qty' => 3, 'supply' => 120000000],
|
||||
['no' => 'SO-2026-003', 'client_idx' => 5, 'status' => 'COMPLETED', 'qty' => 1, 'supply' => 85000000],
|
||||
['no' => 'SO-2026-004', 'client_idx' => 7, 'status' => 'SHIPPED', 'qty' => 2, 'supply' => 60000000],
|
||||
['no' => 'SO-2026-005', 'client_idx' => 9, 'status' => 'DRAFT', 'qty' => 1, 'supply' => 55000000],
|
||||
['no' => 'SO-2026-006', 'client_idx' => 1, 'status' => 'CONFIRMED', 'qty' => 5, 'supply' => 30000000],
|
||||
['no' => 'SO-2026-007', 'client_idx' => 2, 'status' => 'IN_PRODUCTION', 'qty' => 1, 'supply' => 95000000],
|
||||
['no' => 'SO-2026-008', 'client_idx' => 5, 'status' => 'CONFIRMED', 'qty' => 4, 'supply' => 72000000],
|
||||
];
|
||||
|
||||
foreach ($orders as $o) {
|
||||
$taxAmount = (int) round($o['supply'] * 0.1);
|
||||
|
||||
DB::table('orders')->insert([
|
||||
'tenant_id' => $tenantId,
|
||||
'order_no' => $o['no'],
|
||||
'order_type_code' => 'ORDER',
|
||||
'status_code' => $o['status'],
|
||||
'client_id' => $clientIds[$o['client_idx']] ?? $clientIds[0],
|
||||
'quantity' => $o['qty'],
|
||||
'supply_amount' => $o['supply'],
|
||||
'tax_amount' => $taxAmount,
|
||||
'total_amount' => $o['supply'] + $taxAmount,
|
||||
'received_at' => now()->subDays(rand(5, 45))->toDateString(),
|
||||
'delivery_date' => now()->addDays(rand(10, 60))->toDateString(),
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user