- db-trigger-audit-system-plan.md - intermediate-inspection-report-plan.md - mng-numbering-rule-management-plan.md - quote-order-sync-improvement-plan.md - tenant-numbering-system-plan.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6.1 KiB
6.1 KiB
견적 수정 → 기존 수주 업데이트 연동 개선 계획
작성일: 2026-02-07 목적: 견적 수정 시 연결된 기존 수주를 자동 업데이트하고, "수주등록" 대신 "수주 보기" 버튼 표시 상태: 🔄 진행중
📍 현재 진행 상태
| 항목 | 내용 |
|---|---|
| 마지막 완료 작업 | 분석 완료 |
| 다음 작업 | Phase 1.1 - API 수정 |
| 진행률 | 0/4 (0%) |
| 마지막 업데이트 | 2026-02-07 |
1. 개요
1.1 배경
사용자가 수주(33) 상세 → 견적(41) 수정 → 저장 후 "수주등록" 버튼이 표시되어 클릭 시 새 수주가 생성됨.
기대 동작: 견적 수정 → 기존 수주(33)에 자동 반영 + "수주 보기" 버튼으로 기존 수주 이동
1.2 근본 원인
Quote.order_id가 null인 상태에서Order.quote_id만 설정된 경우 발생QuoteService::update()는quote->order_id기준으로만 동기화 트리거QuoteService::show()는 역방향 참조(Order.quote_id)를 고려하지 않음- 결과: 프론트에서
orderId = null→ "수주등록" 버튼 표시
1.3 기존 구현 현황 (이미 구현된 부분)
| 기능 | 상태 | 위치 |
|---|---|---|
OrderService::syncFromQuote() |
✅ 완전 구현 | api/app/Services/OrderService.php:561-746 |
QuoteService::update() → syncFromQuote 호출 |
✅ 구현 (order_id 기준) | api/app/Services/Quote/QuoteService.php:448 |
| QuoteFooterBar "수주 보기" / "수주등록" 분기 | ✅ 구현 (orderId 기준) | react/src/components/quotes/QuoteFooterBar.tsx:209 |
transformApiToV2: order_id → orderId 매핑 |
✅ 구현 | react/src/components/quotes/types.ts:275,1008 |
1.4 변경 승인 정책
| 분류 | 예시 | 승인 |
|---|---|---|
| ✅ 즉시 가능 | 기존 메서드에 조건 추가 | 불필요 |
| ⚠️ 컨펌 필요 | API 로직 변경, 데이터 보정 | 필수 |
2. 대상 범위
2.1 Phase 1: API 수정 (백엔드)
| # | 작업 항목 | 상태 | 비고 |
|---|---|---|---|
| 1.1 | QuoteService::show() - 역방향 order 참조 보정 | ⏳ | order_id null이면 orders() 관계로 탐색 |
| 1.2 | QuoteService::update() - 역방향 sync 트리거 | ⏳ | order_id null이어도 orders() 있으면 동기화 |
2.2 Phase 2: 프론트엔드 확인
| # | 작업 항목 | 상태 | 비고 |
|---|---|---|---|
| 2.1 | 견적 수정 후 view 모드 전환 시 데이터 갱신 확인 | ⏳ | orderId가 정상 반영되는지 |
| 2.2 | "수주 보기" 버튼 동작 확인 | ⏳ | 기존 수주로 정상 이동하는지 |
3. 작업 절차
3.1 상세 변경 사항
1.1 QuoteService::show() 수정
파일: api/app/Services/Quote/QuoteService.php (line 168-187)
현재 동작: Quote 모델을 그대로 반환 (order_id가 null이면 null 그대로)
변경: quote.order_id가 null인데 Order.quote_id로 연결된 수주가 있으면 order_id를 보정
// show() 메서드 내, return $quote; 직전에 추가
if (!$quote->order_id) {
$linkedOrder = \App\Models\Orders\Order::where('quote_id', $quote->id)
->where('tenant_id', $tenantId)
->first();
if ($linkedOrder) {
// DB에도 반영 (데이터 정합성 복구)
$quote->update(['order_id' => $linkedOrder->id]);
$quote->refresh();
}
}
1.2 QuoteService::update() 동기화 트리거 확장
파일: api/app/Services/Quote/QuoteService.php (line 447-460)
현재 동작: if ($quote->order_id) 일 때만 syncFromQuote 호출
변경: order_id가 null이어도 orders() 관계로 연결된 수주가 있으면 동기화 실행
// 기존 코드 (line 448)
if ($quote->order_id) {
// 변경 후
$orderId = $quote->order_id;
if (!$orderId) {
// 역방향 참조로 연결된 수주 찾기
$linkedOrder = \App\Models\Orders\Order::where('quote_id', $quote->id)
->where('tenant_id', $tenantId)
->first();
if ($linkedOrder) {
$quote->update(['order_id' => $linkedOrder->id]);
$orderId = $linkedOrder->id;
}
}
if ($orderId) {
3.2 영향 범위
| 영향 받는 부분 | 변경 여부 | 설명 |
|---|---|---|
| QuoteService::show() | ✅ 수정 | 역방향 참조 보정 |
| QuoteService::update() | ✅ 수정 | sync 트리거 확장 |
| OrderService::syncFromQuote() | ❌ 변경 없음 | 이미 완전 구현 |
| QuoteFooterBar.tsx | ❌ 변경 없음 | orderId 기준 분기 이미 구현 |
| QuoteRegistrationV2.tsx | ❌ 변경 없음 | orderId 전달 이미 구현 |
| types.ts (transformApiToV2) | ❌ 변경 없음 | order_id → orderId 매핑 이미 구현 |
4. 검증 방법
4.1 테스트 시나리오
| # | 시나리오 | 예상 결과 |
|---|---|---|
| 1 | 수주(33) 상세 → 견적(41) 수정 → 저장 | 기존 수주(33) 품목 자동 업데이트 |
| 2 | 견적(41) 상세 view 모드 진입 | "수주 보기" 버튼 표시 (수주등록 아님) |
| 3 | "수주 보기" 버튼 클릭 | 수주(33) 상세 페이지로 이동 |
| 4 | 견적 수정 후 금액 변경 | 수주 총금액도 동기화 |
4.2 성공 기준
- 견적 수정 시 연결된 수주가 자동 업데이트됨
- "수주 보기" 버튼이 정상 표시됨
- 기존 수주로 정상 네비게이션됨
- 기존 convertToOrder() 플로우에 영향 없음
5. 참고 파일
| 파일 | 역할 |
|---|---|
api/app/Services/Quote/QuoteService.php |
견적 서비스 (show, update, convertToOrder) |
api/app/Services/OrderService.php |
수주 서비스 (syncFromQuote) |
api/app/Models/Quote/Quote.php |
견적 모델 (orders() 관계) |
api/app/Models/Orders/Order.php |
수주 모델 (quote() 관계) |
react/src/components/quotes/QuoteFooterBar.tsx |
견적 푸터 바 (버튼 분기) |
react/src/components/quotes/QuoteRegistrationV2.tsx |
견적 등록/수정 V2 |
react/src/components/quotes/types.ts |
타입 및 API→V2 변환 |
react/src/app/[locale]/(protected)/sales/quote-management/[id]/page.tsx |
견적 상세 페이지 |
이 문서는 /sc:plan 스킬로 생성되었습니다.