diff --git a/src/app/.DS_Store b/src/app/.DS_Store new file mode 100644 index 00000000..e26ff0f2 Binary files /dev/null and b/src/app/.DS_Store differ diff --git a/src/app/[locale]/(protected)/sales/order-management-sales/[id]/page.tsx b/src/app/[locale]/(protected)/sales/order-management-sales/[id]/page.tsx index b680f045..4b9d6295 100644 --- a/src/app/[locale]/(protected)/sales/order-management-sales/[id]/page.tsx +++ b/src/app/[locale]/(protected)/sales/order-management-sales/[id]/page.tsx @@ -775,31 +775,35 @@ export default function OrderDetailPage() { /> {/* 문서 모달 */} - + {order && ( + + )} - {/* 취소 확인 다이얼로그 */} + {/* 다이얼로그들 */} + {order && ( + <> @@ -1097,6 +1101,8 @@ export default function OrderDetailPage() { + + )} ); } \ No newline at end of file diff --git a/src/app/[locale]/(protected)/sales/order-management-sales/page.tsx b/src/app/[locale]/(protected)/sales/order-management-sales/page.tsx index 519bfc5d..c8cfb6df 100644 --- a/src/app/[locale]/(protected)/sales/order-management-sales/page.tsx +++ b/src/app/[locale]/(protected)/sales/order-management-sales/page.tsx @@ -71,9 +71,12 @@ function getOrderStatusBadge(status: OrderStatus) { order_confirmed: { label: "수주확정", variant: "default", className: "bg-gray-100 text-gray-700 border-gray-200" }, production_ordered: { label: "생산지시완료", variant: "default", className: "bg-blue-100 text-blue-700 border-blue-200" }, in_production: { label: "생산중", variant: "default", className: "bg-green-100 text-green-700 border-green-200" }, + produced: { label: "생산완료", variant: "default", className: "bg-blue-100 text-blue-700 border-blue-200" }, rework: { label: "재작업중", variant: "default", className: "bg-orange-100 text-orange-700 border-orange-200" }, work_completed: { label: "작업완료", variant: "default", className: "bg-blue-600 text-white border-blue-600" }, + shipping: { label: "출하중", variant: "default", className: "bg-purple-100 text-purple-700 border-purple-200" }, shipped: { label: "출하완료", variant: "default", className: "bg-gray-500 text-white border-gray-500" }, + completed: { label: "완료", variant: "default", className: "bg-gray-500 text-white border-gray-500" }, cancelled: { label: "취소", variant: "default", className: "bg-red-100 text-red-700 border-red-200" }, }; diff --git a/src/components/.DS_Store b/src/components/.DS_Store new file mode 100644 index 00000000..81805e17 Binary files /dev/null and b/src/components/.DS_Store differ diff --git a/src/components/business/CEODashboard/CEODashboard.tsx b/src/components/business/CEODashboard/CEODashboard.tsx index c72bd8a3..93ef4880 100644 --- a/src/components/business/CEODashboard/CEODashboard.tsx +++ b/src/components/business/CEODashboard/CEODashboard.tsx @@ -83,9 +83,9 @@ export function CEODashboard() { debtCollection: apiData.debtCollection.data ?? mockData.debtCollection, monthlyExpense: apiData.monthlyExpense.data ?? mockData.monthlyExpense, cardManagement: apiData.cardManagement.data ?? mockData.cardManagement, - // Phase 2 섹션들 - todayIssue: apiData.statusBoard.data ?? mockData.todayIssue, - todayIssueList: todayIssueData.data?.items ?? mockData.todayIssueList, + // Phase 2 섹션들 (API 연동 완료 - 목업 fallback 제거) + todayIssue: apiData.statusBoard.data ?? [], + todayIssueList: todayIssueData.data?.items ?? [], calendarSchedules: calendarData.data?.items ?? mockData.calendarSchedules, vat: vatData.data ?? mockData.vat, entertainment: entertainmentData.data ?? mockData.entertainment, diff --git a/src/components/business/CEODashboard/mockData.ts b/src/components/business/CEODashboard/mockData.ts index b25cb398..decf1a2c 100644 --- a/src/components/business/CEODashboard/mockData.ts +++ b/src/components/business/CEODashboard/mockData.ts @@ -5,308 +5,9 @@ import type { CEODashboardData } from './types'; * TODO: API 연동 시 이 파일을 API 호출로 대체 */ export const mockData: CEODashboardData = { - todayIssue: [ - { id: '1', label: '수주', count: 3, path: '/sales/order-management-sales', isHighlighted: false }, - { id: '2', label: '채권 추심', count: 3, path: '/accounting/bad-debt-collection', isHighlighted: false }, - { id: '3', label: '안전 재고', count: 3, path: '/material/stock-status', isHighlighted: true }, - { id: '4', label: '세금 신고', count: '부가세 신고 D-15', path: '/accounting/tax', isHighlighted: false }, - { id: '5', label: '신규 업체 등록', count: 3, path: '/accounting/vendors', isHighlighted: false }, - { id: '6', label: '연차', count: 3, path: '/hr/vacation-management', isHighlighted: false }, - { id: '7', label: '발주', count: 3, path: '/construction/order/order-management', isHighlighted: false }, - { id: '8', label: '결재 요청', count: 3, path: '/approval/inbox', isHighlighted: false }, - ], - todayIssueList: [ - { - id: 'til1', - badge: '수주 성공', - content: 'A전자 신규 수주 450,000,000원 확정', - time: '10분 전', - date: '2026-01-16', - needsApproval: false, - path: '/sales/order-management-sales', - }, - { - id: 'til2', - badge: '주식 이슈', - content: 'B물산 미수금 15,000,000원 연체 15일', - time: '1시간 전', - date: '2026-01-16', - needsApproval: false, - path: '/accounting/receivables-status', - }, - { - id: 'til3', - badge: '직정 제고', - content: '원자재 3종 안전재고 미달', - time: '20시간 전', - date: '2026-01-16', - needsApproval: false, - path: '/material/stock-status', - }, - { - id: 'til4', - badge: '지출예상내역서', - content: '품의서명 외 5건 (2,500,000원)', - time: '20시간 전', - date: '2026-01-16', - needsApproval: true, - path: '/approval/inbox', - }, - { - id: 'til5', - badge: '세금 신고', - content: '4분기 부가세 신고 D-15', - time: '20시간 전', - date: '2026-01-16', - needsApproval: false, - path: '/accounting/tax', - }, - { - id: 'til6', - badge: '결재 요청', - content: '법인카드 사용 내역 승인 요청 (김철수)', - time: '30분 전', - date: '2026-01-16', - needsApproval: true, - path: '/approval/inbox', - }, - { - id: 'til7', - badge: '수주 성공', - content: 'C건설 추가 발주 120,000,000원 확정', - time: '2시간 전', - date: '2026-01-16', - needsApproval: false, - path: '/sales/order-management-sales', - }, - { - id: 'til8', - badge: '기타', - content: '신규 거래처 D산업 등록 완료', - time: '3시간 전', - date: '2026-01-16', - needsApproval: false, - path: '/accounting/vendors', - }, - { - id: 'til9', - badge: '결재 요청', - content: '출장비 정산 승인 요청 (이영희)', - time: '4시간 전', - date: '2026-01-16', - needsApproval: true, - path: '/approval/inbox', - }, - { - id: 'til10', - badge: '주식 이슈', - content: 'E물류 미수금 8,500,000원 연체 7일', - time: '5시간 전', - date: '2026-01-16', - needsApproval: false, - path: '/accounting/receivables-status', - }, - { - id: 'til11', - badge: '직정 제고', - content: '부품 A-102 재고 부족 경고', - time: '6시간 전', - date: '2026-01-16', - needsApproval: false, - path: '/material/stock-status', - }, - { - id: 'til12', - badge: '지출예상내역서', - content: '장비 구매 품의서 (15,000,000원)', - time: '8시간 전', - date: '2026-01-16', - needsApproval: true, - path: '/approval/inbox', - }, - { - id: 'til13', - badge: '수주 성공', - content: 'F테크 유지보수 계약 연장 85,000,000원', - time: '어제', - date: '2026-01-15', - needsApproval: false, - path: '/sales/order-management-sales', - }, - { - id: 'til14', - badge: '세금 신고', - content: '원천세 신고 완료', - time: '어제', - date: '2026-01-15', - needsApproval: false, - path: '/accounting/tax', - }, - { - id: 'til15', - badge: '결재 요청', - content: '연차 사용 승인 요청 (박지민 외 2명)', - time: '어제', - date: '2026-01-15', - needsApproval: true, - path: '/hr/vacation-management', - }, - // 추가 데이터 (스크롤 테스트용) - { - id: 'til16', - badge: '수주 성공', - content: 'G산업 신규 계약 250,000,000원 확정', - time: '2일 전', - date: '2026-01-14', - needsApproval: false, - path: '/sales/order-management-sales', - }, - { - id: 'til17', - badge: '주식 이슈', - content: 'H물류 미수금 12,000,000원 연체 30일', - time: '2일 전', - date: '2026-01-14', - needsApproval: false, - path: '/accounting/receivables-status', - }, - { - id: 'til18', - badge: '직정 제고', - content: '원자재 B-205 안전재고 미달 경고', - time: '2일 전', - date: '2026-01-14', - needsApproval: false, - path: '/material/stock-status', - }, - { - id: 'til19', - badge: '지출예상내역서', - content: '사무용품 구매 품의서 (500,000원)', - time: '2일 전', - date: '2026-01-14', - needsApproval: true, - path: '/approval/inbox', - }, - { - id: 'til20', - badge: '세금 신고', - content: '법인세 중간예납 D-30', - time: '2일 전', - date: '2026-01-14', - needsApproval: false, - path: '/accounting/tax', - }, - { - id: 'til21', - badge: '결재 요청', - content: '해외출장 경비 승인 요청 (최민수)', - time: '3일 전', - date: '2026-01-13', - needsApproval: true, - path: '/approval/inbox', - }, - { - id: 'til22', - badge: '수주 성공', - content: 'I테크 추가 발주 80,000,000원 확정', - time: '3일 전', - date: '2026-01-13', - needsApproval: false, - path: '/sales/order-management-sales', - }, - { - id: 'til23', - badge: '기타', - content: '신규 거래처 J전자 등록 완료', - time: '3일 전', - date: '2026-01-13', - needsApproval: false, - path: '/accounting/vendors', - }, - { - id: 'til24', - badge: '주식 이슈', - content: 'K상사 미수금 5,000,000원 연체 45일', - time: '3일 전', - date: '2026-01-13', - needsApproval: false, - path: '/accounting/receivables-status', - }, - { - id: 'til25', - badge: '직정 제고', - content: '완제품 C-301 재고 부족 경고', - time: '4일 전', - date: '2026-01-12', - needsApproval: false, - path: '/material/stock-status', - }, - { - id: 'til26', - badge: '지출예상내역서', - content: '마케팅 비용 품의서 (3,000,000원)', - time: '4일 전', - date: '2026-01-12', - needsApproval: true, - path: '/approval/inbox', - }, - { - id: 'til27', - badge: '결재 요청', - content: '복리후생비 사용 승인 요청 (정영수)', - time: '4일 전', - date: '2026-01-12', - needsApproval: true, - path: '/approval/inbox', - }, - { - id: 'til28', - badge: '수주 성공', - content: 'L건설 유지보수 계약 연장 45,000,000원', - time: '5일 전', - date: '2026-01-11', - needsApproval: false, - path: '/sales/order-management-sales', - }, - { - id: 'til29', - badge: '기타', - content: '사내 시스템 업데이트 완료', - time: '5일 전', - date: '2026-01-11', - needsApproval: false, - path: '/settings', - }, - { - id: 'til30', - badge: '세금 신고', - content: '지방세 납부 완료', - time: '5일 전', - date: '2026-01-11', - needsApproval: false, - path: '/accounting/tax', - }, - // 1월 6일 (기획서 스크린샷 날짜) 이슈 데이터 - { - id: 'til31', - badge: '직정 제고', - content: '원자재 3종 안전재고 미달', - time: '10일 전', - date: '2026-01-06', - needsApproval: false, - path: '/material/stock-status', - }, - { - id: 'til32', - badge: '결재 요청', - content: '출장비 정산 승인 요청', - time: '10일 전', - date: '2026-01-06', - needsApproval: true, - path: '/approval/inbox', - }, - ], + // TodayIssue: API 연동 완료 - 목업 데이터 제거됨 + todayIssue: [], + todayIssueList: [], dailyReport: { date: '2026년 1월 5일 월요일', cards: [ diff --git a/src/components/business/CEODashboard/sections/TodayIssueSection.tsx b/src/components/business/CEODashboard/sections/TodayIssueSection.tsx index 9dae9f72..65b1b53d 100644 --- a/src/components/business/CEODashboard/sections/TodayIssueSection.tsx +++ b/src/components/business/CEODashboard/sections/TodayIssueSection.tsx @@ -155,9 +155,9 @@ export function TodayIssueSection({ items }: TodayIssueSectionProps) { {item.time} - {/* 버튼 */} + {/* TODO: 버튼 - API 구현 후 활성화
e.stopPropagation()}> - {item.needsApproval ? ( + {item.needsApproval && ( <>
+ */} )) )} diff --git a/src/components/orders/actions.ts b/src/components/orders/actions.ts index 14588f69..7a0f170d 100644 --- a/src/components/orders/actions.ts +++ b/src/components/orders/actions.ts @@ -197,10 +197,13 @@ export type OrderStatus = | 'order_registered' // DRAFT | 'order_confirmed' // CONFIRMED | 'production_ordered' // IN_PROGRESS - | 'in_production' // IN_PROGRESS (세부) - | 'rework' // IN_PROGRESS (세부) - | 'work_completed' // IN_PROGRESS (세부) - | 'shipped' // COMPLETED + | 'in_production' // IN_PRODUCTION + | 'produced' // PRODUCED + | 'shipping' // SHIPPING + | 'shipped' // SHIPPED + | 'completed' // COMPLETED + | 'rework' // (세부 - 레거시) + | 'work_completed' // (세부 - 레거시) | 'cancelled'; // CANCELLED export interface Order { @@ -401,7 +404,11 @@ const API_TO_FRONTEND_STATUS: Record = { 'DRAFT': 'order_registered', 'CONFIRMED': 'order_confirmed', 'IN_PROGRESS': 'production_ordered', - 'COMPLETED': 'shipped', + 'IN_PRODUCTION': 'in_production', + 'PRODUCED': 'produced', + 'SHIPPING': 'shipping', + 'SHIPPED': 'shipped', + 'COMPLETED': 'completed', 'CANCELLED': 'cancelled', }; @@ -409,10 +416,13 @@ const FRONTEND_TO_API_STATUS: Record = { 'order_registered': 'DRAFT', 'order_confirmed': 'CONFIRMED', 'production_ordered': 'IN_PROGRESS', - 'in_production': 'IN_PROGRESS', + 'in_production': 'IN_PRODUCTION', + 'produced': 'PRODUCED', + 'shipping': 'SHIPPING', + 'shipped': 'SHIPPED', + 'completed': 'COMPLETED', 'rework': 'IN_PROGRESS', 'work_completed': 'IN_PROGRESS', - 'shipped': 'COMPLETED', 'cancelled': 'CANCELLED', }; diff --git a/src/lib/.DS_Store b/src/lib/.DS_Store new file mode 100644 index 00000000..f346b798 Binary files /dev/null and b/src/lib/.DS_Store differ diff --git a/src/lib/api/dashboard/transformers.ts b/src/lib/api/dashboard/transformers.ts index f8bc53db..360c2d68 100644 --- a/src/lib/api/dashboard/transformers.ts +++ b/src/lib/api/dashboard/transformers.ts @@ -75,6 +75,59 @@ function calculateChangeRate(current: number, previous: number): number { // 1. DailyReport 변환 // ============================================ +/** + * 운영자금 안정성에 따른 색상 반환 + * 참조: AI 리포트 색상 체계 가이드 - 섹션 2.3 + */ +function getStabilityColor(stability: string): 'red' | 'green' | 'blue' { + switch (stability) { + case 'stable': + return 'blue'; // 6개월 이상 - 안정적 + case 'caution': + return 'green'; // 3-6개월 - 주의 (주황 대신 green 사용, 기존 타입 호환) + case 'warning': + return 'red'; // 3개월 미만 - 경고 + default: + return 'blue'; + } +} + +/** + * 운영자금 안정성 메시지 생성 + * - 음수: 현금성 자산 적자 상태 + * - 0~3개월: 자금 부족 우려 + * - 3~6개월: 자금 관리 필요 + * - 6개월 이상: 안정적 + */ +function getStabilityMessage(months: number | null, stability: string, cashAsset: number): string { + if (months === null) { + return '월 운영비 데이터가 없어 안정성을 판단할 수 없습니다.'; + } + + // 현금성 자산이 음수인 경우 (적자 상태) + if (cashAsset < 0 || months < 0) { + return '현금성 자산이 부족한 상태입니다. 긴급 자금 확보가 필요합니다.'; + } + + // 운영 가능 기간이 거의 없는 경우 (1개월 미만) + if (months < 1) { + return '운영 자금이 거의 소진된 상태입니다. 즉시 자금 확보가 필요합니다.'; + } + + const monthsText = `${months}개월분`; + + switch (stability) { + case 'stable': + return `월 운영비용 대비 ${monthsText}이 확보되어 안정적입니다.`; + case 'caution': + return `월 운영비용 대비 ${monthsText}이 확보되어 있습니다. 자금 관리가 필요합니다.`; + case 'warning': + return `월 운영비용 대비 ${monthsText}만 확보되어 자금 부족 우려가 있습니다.`; + default: + return `월 운영비용 대비 ${monthsText}이 확보되어 있습니다.`; + } +} + /** * 일일 일보 CheckPoints 생성 * 참조: AI 리포트 색상 체계 가이드 - 섹션 2 @@ -109,15 +162,37 @@ function generateDailyReportCheckPoints(api: DailyReportApiResponse): CheckPoint }); } - // 현금성 자산 현황 + // 현금성 자산 + 운영자금 안정성 현황 const cashAsset = api.cash_asset_total; + const operatingMonths = api.operating_months; + const operatingStability = api.operating_stability; + const stabilityColor = getStabilityColor(operatingStability); + const stabilityMessage = getStabilityMessage(operatingMonths, operatingStability, cashAsset); + + // 하이라이트 생성 (음수/적자 상태일 때는 "X개월분" 대신 다른 메시지) + const isDeficit = cashAsset < 0 || (operatingMonths !== null && operatingMonths < 0); + const isAlmostEmpty = operatingMonths !== null && operatingMonths >= 0 && operatingMonths < 1; + + const highlights: Array<{ text: string; color: 'red' | 'green' | 'blue' }> = []; + + if (isDeficit) { + highlights.push({ text: '긴급 자금 확보 필요', color: 'red' }); + } else if (isAlmostEmpty) { + highlights.push({ text: '즉시 자금 확보 필요', color: 'red' }); + } else if (operatingMonths !== null && operatingMonths >= 1) { + highlights.push({ text: `${operatingMonths}개월분`, color: stabilityColor }); + if (operatingStability === 'stable') { + highlights.push({ text: '안정적', color: 'blue' }); + } else if (operatingStability === 'warning') { + highlights.push({ text: '자금 부족 우려', color: 'red' }); + } + } + checkPoints.push({ id: 'dr-cash-asset', - type: 'info' as CheckPointType, - message: `총 현금성 자산이 ${formatAmount(cashAsset)}입니다.`, - highlights: [ - { text: formatAmount(cashAsset), color: 'blue' as const }, - ], + type: isDeficit || isAlmostEmpty ? 'warning' as CheckPointType : 'info' as CheckPointType, + message: `총 현금성 자산이 ${formatAmount(cashAsset)}입니다. ${stabilityMessage}`, + highlights, }); return checkPoints; diff --git a/src/lib/api/dashboard/types.ts b/src/lib/api/dashboard/types.ts index 2cddb9c1..1f3d6555 100644 --- a/src/lib/api/dashboard/types.ts +++ b/src/lib/api/dashboard/types.ts @@ -16,6 +16,9 @@ export interface CurrencyTotals { balance: number; // 잔액 } +/** 운영자금 안정성 상태 */ +export type OperatingStability = 'stable' | 'caution' | 'warning' | 'unknown'; + /** GET /api/proxy/daily-report/summary 응답 */ export interface DailyReportApiResponse { date: string; // "2026-01-20" @@ -25,6 +28,10 @@ export interface DailyReportApiResponse { cash_asset_total: number; // 현금성 자산 합계 krw_totals: CurrencyTotals; // 원화 합계 usd_totals: CurrencyTotals; // 달러 합계 + // 운영자금 안정성 지표 + monthly_operating_expense: number; // 월 운영비 (직전 3개월 평균) + operating_months: number | null; // 운영 가능 개월 수 + operating_stability: OperatingStability; // 안정성 상태 } // ============================================