Files
sam-api/database/migrations/2025_09_24_000003_create_estimates_table.php
hskwon 2d9217c9b4 feat: 견적 시스템 API
- 5130의 71개 하드코딩 컬럼을 동적 카테고리 필드 시스템으로 전환
- 모터 브라켓 계산 등 핵심 비즈니스 로직 FormulaParser에 통합
- 파라미터 기반 동적 견적 폼 시스템 구축
- 견적 상태 워크플로 (DRAFT → SENT → APPROVED/REJECTED/EXPIRED)
- 모델셋 관리 API: 카테고리+제품+BOM 통합 관리
- 견적 관리 API: 생성/수정/복제/상태변경/미리보기 기능

주요 구현 사항:
- EstimateController/EstimateService: 견적 비즈니스 로직
- ModelSetController/ModelSetService: 모델셋 관리 로직
- Estimate/EstimateItem 모델: 견적 데이터 구조
- 동적 견적 필드 마이그레이션: 스크린/철재 제품 구조
- API 라우트 17개 엔드포인트 추가
- 다국어 메시지 지원 (성공/에러 메시지)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-24 17:43:29 +09:00

103 lines
4.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('estimates', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id')->comment('테넌트 ID');
$table->unsignedBigInteger('model_set_id')->comment('모델셋(카테고리) ID');
$table->string('estimate_no', 50)->comment('견적번호 (자동생성)');
$table->string('estimate_name')->comment('견적명');
$table->string('customer_name')->nullable()->comment('고객명');
$table->string('project_name')->nullable()->comment('프로젝트명');
// 견적 파라미터 (사용자 입력값들)
$table->json('parameters')->comment('견적 파라미터 (W0, H0, 수량 등)');
// 계산 결과 (W1, H1, 중량, 면적 등)
$table->json('calculated_results')->nullable()->comment('계산 결과값들');
// BOM 데이터 (계산된 BOM 정보)
$table->json('bom_data')->nullable()->comment('BOM 계산 결과');
$table->decimal('total_amount', 15, 2)->nullable()->comment('총 견적금액');
$table->enum('status', ['DRAFT', 'SENT', 'APPROVED', 'REJECTED', 'EXPIRED'])
->default('DRAFT')->comment('견적 상태');
$table->text('notes')->nullable()->comment('비고');
$table->date('valid_until')->nullable()->comment('견적 유효기간');
// 공통 감사 필드
$table->unsignedBigInteger('created_by')->nullable()->comment('생성자 ID');
$table->unsignedBigInteger('updated_by')->nullable()->comment('수정자 ID');
$table->unsignedBigInteger('deleted_by')->nullable()->comment('삭제자 ID');
$table->timestamps();
$table->softDeletes();
// 인덱스
$table->index(['tenant_id', 'status']);
$table->index(['tenant_id', 'created_at']);
$table->index(['tenant_id', 'model_set_id']);
$table->unique(['tenant_id', 'estimate_no']);
// 외래키
$table->foreign('tenant_id')->references('id')->on('tenants')->onDelete('cascade');
$table->foreign('model_set_id')->references('id')->on('categories')->onDelete('restrict');
});
Schema::create('estimate_items', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tenant_id')->comment('테넌트 ID');
$table->unsignedBigInteger('estimate_id')->comment('견적 ID');
$table->integer('sequence')->default(1)->comment('항목 순번');
$table->string('item_name')->comment('항목명');
$table->text('item_description')->nullable()->comment('항목 설명');
// 항목별 파라미터 (개별 제품 파라미터)
$table->json('parameters')->comment('항목별 파라미터');
// 항목별 계산 결과
$table->json('calculated_values')->nullable()->comment('항목별 계산값');
$table->decimal('unit_price', 12, 2)->default(0)->comment('단가');
$table->decimal('quantity', 8, 2)->default(1)->comment('수량');
$table->decimal('total_price', 15, 2)->default(0)->comment('총 가격 (단가 × 수량)');
// BOM 구성품 정보
$table->json('bom_components')->nullable()->comment('BOM 구성품 목록');
$table->text('notes')->nullable()->comment('항목별 비고');
// 공통 감사 필드
$table->unsignedBigInteger('created_by')->nullable()->comment('생성자 ID');
$table->unsignedBigInteger('updated_by')->nullable()->comment('수정자 ID');
$table->unsignedBigInteger('deleted_by')->nullable()->comment('삭제자 ID');
$table->timestamps();
$table->softDeletes();
// 인덱스
$table->index(['tenant_id', 'estimate_id']);
$table->index(['estimate_id', 'sequence']);
// 외래키
$table->foreign('tenant_id')->references('id')->on('tenants')->onDelete('cascade');
$table->foreign('estimate_id')->references('id')->on('estimates')->onDelete('cascade');
});
}
public function down(): void
{
Schema::dropIfExists('estimate_items');
Schema::dropIfExists('estimates');
}
};