Files
sam-react-prod/src/lib/api/dashboard/transformers/expense.ts
유병철 8f4a7ee842 refactor(WEB): CEO 대시보드 대규모 개선 및 문서/권한/스토어 리팩토링
- 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>
2026-02-23 20:59:25 +09:00

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),
};
}