diff --git a/src/components/production/WorkOrders/documents/SlatWorkLogContent.tsx b/src/components/production/WorkOrders/documents/SlatWorkLogContent.tsx
index 1da4edff..8a6e61ec 100644
--- a/src/components/production/WorkOrders/documents/SlatWorkLogContent.tsx
+++ b/src/components/production/WorkOrders/documents/SlatWorkLogContent.tsx
@@ -50,6 +50,9 @@ export function SlatWorkLogContent({ data: order, materialLots = [] }: SlatWorkL
// 숫자 천단위 콤마 포맷
const fmt = (v?: number) => v != null ? formatNumber(v) : '-';
+ // 소수점: 정수면 소수점 없이, 소수면 소수점 1자리까지
+ const fmtDec = (v: number) => Number.isInteger(v) ? String(v) : v.toFixed(1);
+
// floorCode에서 부호 추출: "1층/FSS-01" → "FSS-01"
const getSymbolCode = (floorCode?: string) => {
if (!floorCode || floorCode === '-') return '-';
@@ -176,7 +179,7 @@ export function SlatWorkLogContent({ data: order, materialLots = [] }: SlatWorkL
제작사이즈(mm) - 미미제외 |
조인트바 수량 |
코일 사용량 |
- 설치홈/ 부호 |
+ 층/ 부호 |
| 가로 |
@@ -201,7 +204,7 @@ export function SlatWorkLogContent({ data: order, materialLots = [] }: SlatWorkL
{fmt(item.height)} |
{slatCount > 0 ? fmt(slatCount) : '-'} |
{jointBar > 0 ? fmt(jointBar) : '-'} |
- {coilUsage > 0 ? coilUsage.toFixed(1) : '-'} |
+ {coilUsage > 0 ? fmtDec(coilUsage) : '-'} |
{getSymbolCode(item.floorCode)} |
);
@@ -221,7 +224,7 @@ export function SlatWorkLogContent({ data: order, materialLots = [] }: SlatWorkL
| 생산량 합계 [m²] |
- {totalCoilUsage > 0 ? totalCoilUsage.toFixed(1) : ''} |
+ {totalCoilUsage > 0 ? fmtDec(totalCoilUsage) : ''} |
조인트바 합계 |
{totalJointBar > 0 ? fmt(totalJointBar) : ''} |
diff --git a/src/components/quotes/LocationDetailPanel.tsx b/src/components/quotes/LocationDetailPanel.tsx
index 95423246..8589b573 100644
--- a/src/components/quotes/LocationDetailPanel.tsx
+++ b/src/components/quotes/LocationDetailPanel.tsx
@@ -337,6 +337,7 @@ export function LocationDetailPanel({
onUpdateLocation(location.id, {
productCode: value,
productName: product?.item_name || value,
+ itemCategory: product?.item_category,
});
}}
disabled={disabled}
diff --git a/src/components/quotes/LocationListPanel.tsx b/src/components/quotes/LocationListPanel.tsx
index ebb5a7ca..080601aa 100644
--- a/src/components/quotes/LocationListPanel.tsx
+++ b/src/components/quotes/LocationListPanel.tsx
@@ -152,6 +152,7 @@ export function LocationListPanel({
openHeight: parseFloat(formData.openHeight) || 0,
productCode: formData.productCode,
productName: product?.item_name || formData.productCode,
+ itemCategory: product?.item_category,
quantity: parseInt(formData.quantity) || 1,
guideRailType: formData.guideRailType,
motorPower: formData.motorPower,
diff --git a/src/components/quotes/QuoteRegistration.tsx b/src/components/quotes/QuoteRegistration.tsx
index fce69942..e8ea1501 100644
--- a/src/components/quotes/QuoteRegistration.tsx
+++ b/src/components/quotes/QuoteRegistration.tsx
@@ -68,6 +68,7 @@ export interface LocationItem {
openHeight: number; // 세로 (오픈사이즈 H)
productCode: string; // 제품코드
productName: string; // 제품명
+ itemCategory?: string; // 품목 카테고리 (스크린/철재)
quantity: number; // 수량
guideRailType: string; // 가이드레일 설치 유형
motorPower: string; // 모터 전원
diff --git a/src/components/quotes/types.ts b/src/components/quotes/types.ts
index 373de7b7..96506679 100644
--- a/src/components/quotes/types.ts
+++ b/src/components/quotes/types.ts
@@ -36,13 +36,28 @@ export const QUOTE_STATUS_COLORS: Record = {
};
// ===== 제품 카테고리 =====
-export type ProductCategory = 'screen' | 'steel';
+export type ProductCategory = 'SCREEN' | 'STEEL';
-export const PRODUCT_CATEGORY_LABELS: Record = {
+export const PRODUCT_CATEGORY_LABELS: Record = {
+ SCREEN: '스크린',
+ STEEL: '철재',
screen: '스크린',
steel: '철재',
};
+/** item_category(한글) → product_category 변환 (DB는 대문자) */
+export function itemCategoryToProductCategory(itemCategory?: string): ProductCategory {
+ if (itemCategory === '철재') return 'STEEL';
+ return 'SCREEN';
+}
+
+/** 개소 목록에서 견적 전체의 product_category 결정 */
+function deriveProductCategory(locations: LocationItem[]): ProductCategory {
+ const categories = new Set(locations.map(loc => itemCategoryToProductCategory(loc.itemCategory)));
+ if (categories.size === 1) return categories.values().next().value!;
+ return itemCategoryToProductCategory(locations[0]?.itemCategory);
+}
+
// ===== 견적 품목 =====
export interface QuoteItem {
id: string;
@@ -104,6 +119,8 @@ export interface Quote {
// 자동산출 입력값 타입
export interface CalculationInputItem {
productCategory?: string;
+ itemCategory?: string; // 품목 카테고리 원본 (스크린/철재) - round-trip용
+ productCode?: string; // 제품코드
productName?: string;
openWidth?: string;
openHeight?: string;
@@ -246,7 +263,7 @@ export function transformApiToFrontend(apiData: QuoteApiData): Quote {
// API 실제 필드명(manager, contact) 우선, 레거시 필드명(manager_name, manager_contact) 폴백
managerName: apiData.manager || apiData.manager_name || undefined,
managerContact: apiData.contact || apiData.manager_contact || undefined,
- productCategory: apiData.product_category,
+ productCategory: (apiData.product_category?.toUpperCase() || 'SCREEN') as ProductCategory,
quantity: apiData.quantity || 0,
unitSymbol: apiData.unit_symbol || undefined,
supplyAmount: parseFloat(String(apiData.supply_amount)) || 0,
@@ -669,6 +686,7 @@ export interface LocationItem {
openHeight: number; // 세로 (오픈사이즈 H)
productCode: string; // 제품코드
productName: string; // 제품명
+ itemCategory?: string; // 품목 카테고리 (스크린/철재)
quantity: number; // 수량
guideRailType: string; // 가이드레일 설치 유형
motorPower: string; // 모터 전원
@@ -734,7 +752,8 @@ export function transformV2ToApi(
const calculationInputs: CalculationInputs & { bomResults?: BomCalculationResult[] } = {
items: data.locations.map(loc => ({
- productCategory: 'screen', // TODO: 동적으로 결정
+ productCategory: itemCategoryToProductCategory(loc.itemCategory),
+ itemCategory: loc.itemCategory, // round-trip용
productCode: loc.productCode, // BOM 재계산용
productName: loc.productName,
openWidth: String(loc.openWidth),
@@ -876,7 +895,7 @@ export function transformV2ToApi(
contact: data.contact || null,
completion_date: data.dueDate || null,
remarks: data.remarks || null,
- product_category: 'screen', // TODO: 동적으로 결정
+ product_category: deriveProductCategory(data.locations),
quantity: data.locations.reduce((sum, loc) => sum + loc.quantity, 0),
unit_symbol: '개소',
total_amount: grandTotal,
@@ -948,6 +967,7 @@ export function transformApiToV2(apiData: QuoteApiData): QuoteFormDataV2 {
openHeight: parseInt(ci.openHeight || '0', 10),
productCode: (ci as { productCode?: string }).productCode || bomResult?.finished_goods?.code || '',
productName: ci.productName || '',
+ itemCategory: ci.itemCategory,
quantity: qty,
guideRailType: ci.guideRailType || 'wall',
motorPower: ci.motorPower || 'single',
@@ -1129,7 +1149,7 @@ export function transformFormDataToApi(formData: QuoteFormData): Record sum + item.quantity, 0),
unit_symbol: formData.unitSymbol || '개소', // 선택한 제품의 단위 또는 기본값
total_amount: grandTotal,