- CEO 대시보드: 섹션별 API 연동 강화 (매출/매입/생산 실데이터 표시) - DashboardSettingsDialog 드래그 정렬 및 설정 UX 개선 - dashboard transformers 모듈 분리 (파일 분할) - DocumentTable/DocumentWrapper 공통 문서 컴포넌트 추출 - LineItemsTable organisms 컴포넌트 추가 - PurchaseOrderDocument/InspectionRequestDocument 문서 컴포넌트 리팩토링 - PermissionContext → permissionStore(Zustand) 전환 - useUIStore, stores/utils/userStorage 추가 - favoritesStore/useTableColumnStore 사용자별 저장 지원 - DepositDetail/WithdrawalDetail 삭제 (통합) - PurchaseDetail/SalesDetail 간소화 - amount.ts/formatters.ts 유틸 확장 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
178 lines
5.6 KiB
TypeScript
178 lines
5.6 KiB
TypeScript
/**
|
|
* 월 예상 지출 (MonthlyExpense) + 카드/가지급금 (CardManagement) 변환
|
|
*/
|
|
|
|
import type {
|
|
ExpectedExpenseApiResponse,
|
|
CardTransactionApiResponse,
|
|
LoanDashboardApiResponse,
|
|
TaxSimulationApiResponse,
|
|
} from '../types';
|
|
import type {
|
|
MonthlyExpenseData,
|
|
CardManagementData,
|
|
CheckPoint,
|
|
CheckPointType,
|
|
} from '@/components/business/CEODashboard/types';
|
|
import { formatAmount, calculateChangeRate } from './common';
|
|
|
|
// ============================================
|
|
// 월 예상 지출 (MonthlyExpense)
|
|
// ============================================
|
|
|
|
/**
|
|
* 당월 예상 지출 CheckPoints 생성
|
|
*/
|
|
function generateMonthlyExpenseCheckPoints(api: ExpectedExpenseApiResponse): CheckPoint[] {
|
|
const checkPoints: CheckPoint[] = [];
|
|
|
|
// 총 예상 지출
|
|
checkPoints.push({
|
|
id: 'me-total',
|
|
type: 'info' as CheckPointType,
|
|
message: `이번 달 예상 지출은 ${formatAmount(api.total_amount)}입니다.`,
|
|
highlights: [
|
|
{ text: formatAmount(api.total_amount), color: 'blue' as const },
|
|
],
|
|
});
|
|
|
|
return checkPoints;
|
|
}
|
|
|
|
/**
|
|
* ExpectedExpense API 응답 → Frontend 타입 변환
|
|
* 주의: 실제 API는 상세 분류(매입/카드/어음 등)를 제공하지 않음
|
|
* by_transaction_type에서 추출하거나 기본값 사용
|
|
*/
|
|
export function transformMonthlyExpenseResponse(api: ExpectedExpenseApiResponse): MonthlyExpenseData {
|
|
// transaction_type별 금액 추출
|
|
const purchaseTotal = api.by_transaction_type['purchase']?.total ?? 0;
|
|
const cardTotal = api.by_transaction_type['card']?.total ?? 0;
|
|
const billTotal = api.by_transaction_type['bill']?.total ?? 0;
|
|
|
|
return {
|
|
cards: [
|
|
{
|
|
id: 'me1',
|
|
label: '매입',
|
|
amount: purchaseTotal,
|
|
},
|
|
{
|
|
id: 'me2',
|
|
label: '카드',
|
|
amount: cardTotal,
|
|
},
|
|
{
|
|
id: 'me3',
|
|
label: '발행어음',
|
|
amount: billTotal,
|
|
},
|
|
{
|
|
id: 'me4',
|
|
label: '총 예상 지출 합계',
|
|
amount: api.total_amount,
|
|
},
|
|
],
|
|
checkPoints: generateMonthlyExpenseCheckPoints(api),
|
|
};
|
|
}
|
|
|
|
// ============================================
|
|
// 카드/가지급금 (CardManagement)
|
|
// ============================================
|
|
|
|
/**
|
|
* 카드/가지급금 CheckPoints 생성
|
|
*/
|
|
function generateCardManagementCheckPoints(api: CardTransactionApiResponse): CheckPoint[] {
|
|
const checkPoints: CheckPoint[] = [];
|
|
|
|
// 전월 대비 변화
|
|
const changeRate = calculateChangeRate(api.current_month_total, api.previous_month_total);
|
|
if (Math.abs(changeRate) > 10) {
|
|
const type: CheckPointType = changeRate > 0 ? 'warning' : 'info';
|
|
checkPoints.push({
|
|
id: 'cm-change',
|
|
type,
|
|
message: `당월 카드 사용액이 전월 대비 ${changeRate > 0 ? '+' : ''}${changeRate.toFixed(1)}% 변동했습니다.`,
|
|
highlights: [
|
|
{ text: `${changeRate > 0 ? '+' : ''}${changeRate.toFixed(1)}%`, color: changeRate > 0 ? 'red' as const : 'green' as const },
|
|
],
|
|
});
|
|
}
|
|
|
|
// 당월 사용액
|
|
checkPoints.push({
|
|
id: 'cm-current',
|
|
type: 'info' as CheckPointType,
|
|
message: `당월 카드 사용 총 ${formatAmount(api.current_month_total)}입니다.`,
|
|
highlights: [
|
|
{ text: formatAmount(api.current_month_total), color: 'blue' as const },
|
|
],
|
|
});
|
|
|
|
return checkPoints;
|
|
}
|
|
|
|
/**
|
|
* CardTransaction API 응답 → Frontend 타입 변환
|
|
* 4개 카드 구조:
|
|
* - cm1: 카드 사용액 (CardTransaction API)
|
|
* - cm2: 가지급금 (LoanDashboard API)
|
|
* - cm3: 법인세 예상 가중 (TaxSimulation API - corporate_tax.difference)
|
|
* - cm4: 대표자 종합세 예상 가중 (TaxSimulation API - income_tax.difference)
|
|
*/
|
|
export function transformCardManagementResponse(
|
|
summaryApi: CardTransactionApiResponse,
|
|
loanApi?: LoanDashboardApiResponse | null,
|
|
taxApi?: TaxSimulationApiResponse | null,
|
|
fallbackData?: CardManagementData
|
|
): CardManagementData {
|
|
const changeRate = calculateChangeRate(summaryApi.current_month_total, summaryApi.previous_month_total);
|
|
|
|
// cm2: 가지급금 금액 (LoanDashboard API 또는 fallback)
|
|
const loanAmount = loanApi?.summary?.total_outstanding ?? fallbackData?.cards[1]?.amount ?? 0;
|
|
|
|
// cm3: 법인세 예상 가중 (TaxSimulation API 또는 fallback)
|
|
const corporateTaxDifference = taxApi?.corporate_tax?.difference ?? fallbackData?.cards[2]?.amount ?? 0;
|
|
|
|
// cm4: 대표자 종합세 예상 가중 (TaxSimulation API 또는 fallback)
|
|
const incomeTaxDifference = taxApi?.income_tax?.difference ?? fallbackData?.cards[3]?.amount ?? 0;
|
|
|
|
// 가지급금 경고 배너 표시 여부 결정 (가지급금 잔액 > 0이면 표시)
|
|
const hasLoanWarning = loanAmount > 0;
|
|
|
|
return {
|
|
// 가지급금 관련 경고 배너 (가지급금 있을 때만 표시)
|
|
warningBanner: hasLoanWarning ? fallbackData?.warningBanner : undefined,
|
|
cards: [
|
|
// cm1: 카드 사용액 (CardTransaction API)
|
|
{
|
|
id: 'cm1',
|
|
label: '카드',
|
|
amount: summaryApi.current_month_total,
|
|
previousLabel: `전월 대비 ${changeRate > 0 ? '+' : ''}${changeRate.toFixed(1)}%`,
|
|
},
|
|
// cm2: 가지급금 (LoanDashboard API)
|
|
{
|
|
id: 'cm2',
|
|
label: '가지급금',
|
|
amount: loanAmount,
|
|
},
|
|
// cm3: 법인세 예상 가중 (TaxSimulation API)
|
|
{
|
|
id: 'cm3',
|
|
label: '법인세 예상 가중',
|
|
amount: corporateTaxDifference,
|
|
},
|
|
// cm4: 대표자 종합세 예상 가중 (TaxSimulation API)
|
|
{
|
|
id: 'cm4',
|
|
label: '대표자 종합세 예상 가중',
|
|
amount: incomeTaxDifference,
|
|
},
|
|
],
|
|
checkPoints: generateCardManagementCheckPoints(summaryApi),
|
|
};
|
|
}
|