From fde8726e146b559bd567063caf84e8f9727b8992 Mon Sep 17 00:00:00 2001 From: kent Date: Thu, 8 Jan 2026 20:57:49 +0900 Subject: [PATCH] =?UTF-8?q?feat(WEB):=20=EC=88=98=EC=A3=BC=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20Phase=202=20=ED=83=80=EC=9E=85=20=EC=A0=95=EC=9D=98?= =?UTF-8?q?=20=ED=99=95=EC=9E=A5=20=EB=B0=8F=20=EA=B3=B5=EC=A0=95=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EA=B0=9C=EB=B3=84=20=ED=92=88=EB=AA=A9=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Order, OrderItem 인터페이스에 상세 페이지용 필드 추가 - OrderFormData, OrderItemFormData에 수정 페이지용 필드 추가 - 변환 함수에서 새 필드 매핑 처리 - 공정관리 개별 품목을 ID 대신 품목명으로 표시 --- src/components/orders/actions.ts | 45 ++++++++++++++++++- .../process-management/ProcessDetail.tsx | 43 +++++++++--------- src/components/process-management/actions.ts | 20 ++++++--- src/types/process.ts | 8 ++++ 4 files changed, 87 insertions(+), 29 deletions(-) diff --git a/src/components/orders/actions.ts b/src/components/orders/actions.ts index 6083efc7..2f81de08 100644 --- a/src/components/orders/actions.ts +++ b/src/components/orders/actions.ts @@ -156,19 +156,36 @@ export interface Order { remarks?: string; note?: string; items?: OrderItem[]; + // 상세 페이지용 추가 필드 + manager?: string; // 담당자 + contact?: string; // 연락처 (client_contact) + deliveryRequestDate?: string; // 납품요청일 + shippingCost?: string; // 운임비용 + receiver?: string; // 수신자 + receiverContact?: string; // 수신처 연락처 + address?: string; // 수신처 주소 + addressDetail?: string; // 상세주소 + subtotal?: number; // 소계 (supply_amount와 동일) + discountRate?: number; // 할인율 + totalAmount?: number; // 총금액 (amount와 동일하지만 명시적) } export interface OrderItem { id: string; itemId?: number; + itemCode?: string; // 품목코드 itemName: string; specification?: string; + spec?: string; // specification alias + type?: string; // 층 (layer) + symbol?: string; // 부호 quantity: number; unit?: string; unitPrice: number; supplyAmount: number; taxAmount: number; totalAmount: number; + amount?: number; // totalAmount alias sortOrder: number; } @@ -191,10 +208,20 @@ export interface OrderFormData { remarks?: string; note?: string; items?: OrderItemFormData[]; + // 수정 페이지용 추가 필드 + expectedShipDate?: string; // 출고예정일 + deliveryRequestDate?: string; // 납품요청일 + deliveryMethod?: string; // 배송방식 (deliveryMethodCode alias) + shippingCost?: string; // 운임비용 + receiver?: string; // 수신자 + receiverContact?: string; // 수신처 연락처 + address?: string; // 수신처 주소 + addressDetail?: string; // 상세주소 } export interface OrderItemFormData { itemId?: number; + itemCode?: string; // 품목코드 itemName: string; specification?: string; quantity: number; @@ -302,7 +329,18 @@ function transformApiToFrontend(apiData: ApiOrder): Order { memo: apiData.memo ?? undefined, remarks: apiData.remarks ?? undefined, note: apiData.note ?? undefined, - items: apiData.items?.map(transformItemApiToFrontend), + items: apiData.items?.map(transformItemApiToFrontend), // 상세 페이지용 추가 필드 (API에서 매핑) + manager: apiData.client?.representative ?? undefined, + contact: apiData.client_contact ?? apiData.client?.phone ?? undefined, + deliveryRequestDate: apiData.delivery_date ?? undefined, // delivery_date를 공유 + shippingCost: undefined, // API에 해당 필드 없음 - 추후 구현 + receiver: undefined, // API에 해당 필드 없음 - 추후 구현 + receiverContact: undefined, // API에 해당 필드 없음 - 추후 구현 + address: undefined, // API에 해당 필드 없음 - 추후 구현 + addressDetail: undefined, // API에 해당 필드 없음 - 추후 구현 + subtotal: apiData.supply_amount, + discountRate: apiData.discount_rate, + totalAmount: apiData.total_amount, }; } @@ -310,14 +348,19 @@ function transformItemApiToFrontend(apiItem: ApiOrderItem): OrderItem { return { id: String(apiItem.id), itemId: apiItem.item_id ?? undefined, + itemCode: apiItem.item_id ? `ITEM-${apiItem.item_id}` : undefined, // 임시: 실제 item_code는 API에서 제공 필요 itemName: apiItem.item_name, specification: apiItem.specification ?? undefined, + spec: apiItem.specification ?? undefined, // specification alias + type: undefined, // 층 - API에 해당 필드 없음 + symbol: undefined, // 부호 - API에 해당 필드 없음 quantity: apiItem.quantity, unit: apiItem.unit ?? undefined, unitPrice: apiItem.unit_price, supplyAmount: apiItem.supply_amount, taxAmount: apiItem.tax_amount, totalAmount: apiItem.total_amount, + amount: apiItem.total_amount, // totalAmount alias sortOrder: apiItem.sort_order, }; } diff --git a/src/components/process-management/ProcessDetail.tsx b/src/components/process-management/ProcessDetail.tsx index bb8ba47e..a370e09f 100644 --- a/src/components/process-management/ProcessDetail.tsx +++ b/src/components/process-management/ProcessDetail.tsx @@ -178,39 +178,36 @@ export function ProcessDetail({ process }: ProcessDetailProps) { 개별 품목 + {individualItems.length > 0 && individualItems[0].items && ( + + {individualItems[0].items.length}개 + + )} - {individualItems.length === 0 ? ( + {individualItems.length === 0 || !individualItems[0].items?.length ? (

등록된 개별 품목이 없습니다

) : ( -
- {individualItems.map((rule) => ( -
-
- - {rule.isActive ? '활성' : '비활성'} - -
-
- {rule.conditionValue} -
- {rule.description && ( -
- {rule.description} -
- )} +
+
+ {individualItems[0].items.map((item) => ( +
+
+ + {item.code} + + {item.name}
- 우선순위: {rule.priority} -
- ))} + ))} +
)} diff --git a/src/components/process-management/actions.ts b/src/components/process-management/actions.ts index 95cdef04..e52ae0fb 100644 --- a/src/components/process-management/actions.ts +++ b/src/components/process-management/actions.ts @@ -3,7 +3,7 @@ import { isNextRedirectError } from '@/lib/utils/redirect-error'; import { serverFetch } from '@/lib/api/fetch-wrapper'; -import type { Process, ProcessFormData, ClassificationRule } from '@/types/process'; +import type { Process, ProcessFormData, ClassificationRule, IndividualItem } from '@/types/process'; // ============================================================================ // API 타입 정의 @@ -107,13 +107,22 @@ function transformApiToFrontend(apiData: ApiProcess): Process { function transformProcessItemsToRules(processItems: ApiProcessItem[]): ClassificationRule[] { if (processItems.length === 0) return []; + const activeItems = processItems.filter(pi => pi.is_active); + if (activeItems.length === 0) return []; + // 모든 품목 ID를 쉼표로 구분하여 하나의 규칙으로 통합 - const itemIds = processItems - .filter(pi => pi.is_active) + const itemIds = activeItems .map(pi => String(pi.item_id)) .join(','); - if (!itemIds) return []; + // 품목 상세 정보 추출 (code, name 포함) + const items: IndividualItem[] = activeItems + .filter(pi => pi.item) // item 정보가 있는 것만 + .map(pi => ({ + id: String(pi.item!.id), + code: pi.item!.code, + name: pi.item!.name, + })); return [{ id: `individual-${Date.now()}`, @@ -122,9 +131,10 @@ function transformProcessItemsToRules(processItems: ApiProcessItem[]): Classific matchingType: 'equals', conditionValue: itemIds, priority: 0, - description: `개별 품목 ${processItems.length}개`, + description: `개별 품목 ${activeItems.length}개`, isActive: true, createdAt: new Date().toISOString(), + items, // 품목 상세 정보 추가 }]; } diff --git a/src/types/process.ts b/src/types/process.ts index 16aad75f..3f35861d 100644 --- a/src/types/process.ts +++ b/src/types/process.ts @@ -17,6 +17,13 @@ export type RuleType = '품목코드' | '품목명' | '품목구분'; // 매칭 방식 export type MatchingType = 'startsWith' | 'endsWith' | 'contains' | 'equals'; +// 개별 품목 정보 +export interface IndividualItem { + id: string; + code: string; + name: string; +} + // 자동 분류 규칙 export interface ClassificationRule { id: string; @@ -28,6 +35,7 @@ export interface ClassificationRule { description?: string; isActive: boolean; createdAt: string; + items?: IndividualItem[]; // 개별 품목인 경우 품목 정보 } // 자동 분류 규칙 입력용 (id, createdAt 제외)