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