2026-02-23 20:59:25 +09:00
|
|
|
|
/**
|
|
|
|
|
|
* 월 예상 지출 (MonthlyExpense) + 카드/가지급금 (CardManagement) 변환
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
import type {
|
|
|
|
|
|
ExpectedExpenseApiResponse,
|
|
|
|
|
|
CardTransactionApiResponse,
|
|
|
|
|
|
LoanDashboardApiResponse,
|
|
|
|
|
|
TaxSimulationApiResponse,
|
|
|
|
|
|
} from '../types';
|
|
|
|
|
|
import type {
|
|
|
|
|
|
MonthlyExpenseData,
|
|
|
|
|
|
CardManagementData,
|
|
|
|
|
|
CheckPoint,
|
|
|
|
|
|
CheckPointType,
|
|
|
|
|
|
} from '@/components/business/CEODashboard/types';
|
2026-03-04 22:19:10 +09:00
|
|
|
|
import { formatAmount } from './common';
|
2026-02-23 20:59:25 +09:00
|
|
|
|
|
|
|
|
|
|
// ============================================
|
|
|
|
|
|
// 월 예상 지출 (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),
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ============================================
|
2026-03-04 22:19:10 +09:00
|
|
|
|
// 카드/가지급금 (CardManagement) — D1.7 5장 카드 구조
|
2026-02-23 20:59:25 +09:00
|
|
|
|
// ============================================
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2026-03-04 22:19:10 +09:00
|
|
|
|
* 카드/가지급금 CheckPoints 생성 (D1.7)
|
|
|
|
|
|
*
|
|
|
|
|
|
* CP1: 법인카드 → 가지급금 전환 경고
|
|
|
|
|
|
* CP2: 인정이자 발생 현황
|
|
|
|
|
|
* CP3: 접대비 불인정 항목 감지
|
|
|
|
|
|
* CP4: 주말 카드 사용 감지 (향후 확장)
|
2026-02-23 20:59:25 +09:00
|
|
|
|
*/
|
2026-03-04 22:19:10 +09:00
|
|
|
|
function generateCardManagementCheckPoints(
|
|
|
|
|
|
loanApi?: LoanDashboardApiResponse | null,
|
|
|
|
|
|
taxApi?: TaxSimulationApiResponse | null,
|
|
|
|
|
|
cardApi?: CardTransactionApiResponse | null,
|
|
|
|
|
|
): CheckPoint[] {
|
2026-02-23 20:59:25 +09:00
|
|
|
|
const checkPoints: CheckPoint[] = [];
|
|
|
|
|
|
|
2026-03-04 22:19:10 +09:00
|
|
|
|
const totalOutstanding = loanApi?.summary?.total_outstanding ?? 0;
|
|
|
|
|
|
const interestRate = taxApi?.loan_summary?.interest_rate ?? 4.6;
|
|
|
|
|
|
const recognizedInterest = taxApi?.loan_summary?.recognized_interest ?? 0;
|
|
|
|
|
|
|
|
|
|
|
|
// CP1: 법인카드 사용 중 가지급금 전환 경고
|
|
|
|
|
|
if (totalOutstanding > 0) {
|
2026-02-23 20:59:25 +09:00
|
|
|
|
checkPoints.push({
|
2026-03-04 22:19:10 +09:00
|
|
|
|
id: 'cm-cp1',
|
|
|
|
|
|
type: 'success' as CheckPointType,
|
|
|
|
|
|
message: `법인카드 사용 중 ${formatAmount(totalOutstanding)}이 가지급금으로 전환되었습니다. 연 ${interestRate}% 인정이자가 발생합니다.`,
|
2026-02-23 20:59:25 +09:00
|
|
|
|
highlights: [
|
2026-03-04 22:19:10 +09:00
|
|
|
|
{ text: formatAmount(totalOutstanding), color: 'red' as const },
|
|
|
|
|
|
{ text: '가지급금', color: 'red' as const },
|
|
|
|
|
|
{ text: `연 ${interestRate}% 인정이자`, color: 'red' as const },
|
2026-02-23 20:59:25 +09:00
|
|
|
|
],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-04 22:19:10 +09:00
|
|
|
|
// CP2: 인정이자 발생 현황
|
|
|
|
|
|
if (totalOutstanding > 0 && recognizedInterest > 0) {
|
|
|
|
|
|
checkPoints.push({
|
|
|
|
|
|
id: 'cm-cp2',
|
|
|
|
|
|
type: 'success' as CheckPointType,
|
|
|
|
|
|
message: `현재 가지급금 ${formatAmount(totalOutstanding)} × ${interestRate}% = 연간 약 ${formatAmount(recognizedInterest)}의 인정이자가 발생 중입니다.`,
|
|
|
|
|
|
highlights: [
|
|
|
|
|
|
{ text: `연간 약 ${formatAmount(recognizedInterest)}의 인정이자`, color: 'red' as const },
|
|
|
|
|
|
],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CP3: 접대비 불인정 항목 감지
|
|
|
|
|
|
const entertainmentCount = loanApi?.category_breakdown?.entertainment?.unverified_count ?? 0;
|
|
|
|
|
|
if (entertainmentCount > 0) {
|
|
|
|
|
|
checkPoints.push({
|
|
|
|
|
|
id: 'cm-cp3',
|
|
|
|
|
|
type: 'success' as CheckPointType,
|
|
|
|
|
|
message: '상품권/귀금속 등 접대비 불인정 항목 결제 감지. 가지급금 처리 예정입니다.',
|
|
|
|
|
|
highlights: [
|
|
|
|
|
|
{ text: '불인정 항목 결제 감지', color: 'red' as const },
|
|
|
|
|
|
],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CP4: 주말 카드 사용 감지 (향후 card-transactions API 확장 시)
|
|
|
|
|
|
// 현재는 cardApi 데이터에서 주말 사용 정보가 없으므로 placeholder
|
|
|
|
|
|
if (cardApi && cardApi.current_month_total > 0) {
|
|
|
|
|
|
// 향후 weekend_amount 필드 추가 시 활성화
|
|
|
|
|
|
}
|
2026-02-23 20:59:25 +09:00
|
|
|
|
|
|
|
|
|
|
return checkPoints;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* CardTransaction API 응답 → Frontend 타입 변환
|
2026-03-04 22:19:10 +09:00
|
|
|
|
* D1.7 5장 카드 구조:
|
|
|
|
|
|
* - cm1: 카드 (loans category_breakdown.card)
|
|
|
|
|
|
* - cm2: 경조사 (loans category_breakdown.congratulatory)
|
|
|
|
|
|
* - cm3: 상품권 (loans category_breakdown.gift_certificate)
|
|
|
|
|
|
* - cm4: 접대비 (loans category_breakdown.entertainment)
|
|
|
|
|
|
* - cm_total: 총 가지급금 합계 (loans summary.total_outstanding)
|
2026-02-23 20:59:25 +09:00
|
|
|
|
*/
|
|
|
|
|
|
export function transformCardManagementResponse(
|
|
|
|
|
|
summaryApi: CardTransactionApiResponse,
|
|
|
|
|
|
loanApi?: LoanDashboardApiResponse | null,
|
|
|
|
|
|
taxApi?: TaxSimulationApiResponse | null,
|
|
|
|
|
|
fallbackData?: CardManagementData
|
|
|
|
|
|
): CardManagementData {
|
2026-03-04 22:19:10 +09:00
|
|
|
|
const breakdown = loanApi?.category_breakdown;
|
|
|
|
|
|
const totalOutstanding = loanApi?.summary?.total_outstanding ?? 0;
|
2026-02-23 20:59:25 +09:00
|
|
|
|
|
2026-03-04 22:19:10 +09:00
|
|
|
|
// 카테고리별 금액 추출
|
|
|
|
|
|
const cardAmount = breakdown?.card?.outstanding_amount ?? fallbackData?.cards[0]?.amount ?? 0;
|
|
|
|
|
|
const congratulatoryAmount = breakdown?.congratulatory?.outstanding_amount ?? fallbackData?.cards[1]?.amount ?? 0;
|
|
|
|
|
|
const giftCertificateAmount = breakdown?.gift_certificate?.outstanding_amount ?? fallbackData?.cards[2]?.amount ?? 0;
|
|
|
|
|
|
const entertainmentAmount = breakdown?.entertainment?.outstanding_amount ?? fallbackData?.cards[3]?.amount ?? 0;
|
2026-02-23 20:59:25 +09:00
|
|
|
|
|
2026-03-04 22:19:10 +09:00
|
|
|
|
// 카테고리별 미증빙/미정리 건수
|
|
|
|
|
|
const cardUnverified = breakdown?.card?.unverified_count ?? 0;
|
|
|
|
|
|
const congratulatoryUnverified = breakdown?.congratulatory?.unverified_count ?? 0;
|
|
|
|
|
|
const giftCertificateUnverified = breakdown?.gift_certificate?.unverified_count ?? 0;
|
|
|
|
|
|
const entertainmentUnverified = breakdown?.entertainment?.unverified_count ?? 0;
|
2026-02-23 20:59:25 +09:00
|
|
|
|
|
2026-03-04 22:19:10 +09:00
|
|
|
|
// 총 합계 (API summary 또는 카테고리 합산)
|
|
|
|
|
|
const totalAmount = totalOutstanding > 0
|
|
|
|
|
|
? totalOutstanding
|
|
|
|
|
|
: cardAmount + congratulatoryAmount + giftCertificateAmount + entertainmentAmount;
|
2026-02-23 20:59:25 +09:00
|
|
|
|
|
2026-03-04 22:19:10 +09:00
|
|
|
|
// 가지급금 경고 배너 표시 여부 (가지급금 잔액 > 0이면 표시)
|
|
|
|
|
|
const hasLoanWarning = totalAmount > 0;
|
2026-02-23 20:59:25 +09:00
|
|
|
|
|
|
|
|
|
|
return {
|
2026-03-04 22:19:10 +09:00
|
|
|
|
warningBanner: hasLoanWarning
|
|
|
|
|
|
? (fallbackData?.warningBanner ?? '가지급금 인정이자 4.6%, 법인세 및 연말정산 시 대표자 종합세 가중 주의')
|
|
|
|
|
|
: undefined,
|
2026-02-23 20:59:25 +09:00
|
|
|
|
cards: [
|
2026-03-04 22:19:10 +09:00
|
|
|
|
// cm1: 카드
|
2026-02-23 20:59:25 +09:00
|
|
|
|
{
|
|
|
|
|
|
id: 'cm1',
|
|
|
|
|
|
label: '카드',
|
2026-03-04 22:19:10 +09:00
|
|
|
|
amount: cardAmount,
|
|
|
|
|
|
previousLabel: cardUnverified > 0 ? `미정리 ${cardUnverified}건` : undefined,
|
2026-02-23 20:59:25 +09:00
|
|
|
|
},
|
2026-03-04 22:19:10 +09:00
|
|
|
|
// cm2: 경조사
|
2026-02-23 20:59:25 +09:00
|
|
|
|
{
|
|
|
|
|
|
id: 'cm2',
|
2026-03-04 22:19:10 +09:00
|
|
|
|
label: '경조사',
|
|
|
|
|
|
amount: congratulatoryAmount,
|
|
|
|
|
|
previousLabel: congratulatoryUnverified > 0 ? `미증빙 ${congratulatoryUnverified}건` : undefined,
|
2026-02-23 20:59:25 +09:00
|
|
|
|
},
|
2026-03-04 22:19:10 +09:00
|
|
|
|
// cm3: 상품권
|
2026-02-23 20:59:25 +09:00
|
|
|
|
{
|
|
|
|
|
|
id: 'cm3',
|
2026-03-04 22:19:10 +09:00
|
|
|
|
label: '상품권',
|
|
|
|
|
|
amount: giftCertificateAmount,
|
|
|
|
|
|
previousLabel: giftCertificateUnverified > 0 ? `미증빙 ${giftCertificateUnverified}건` : undefined,
|
2026-02-23 20:59:25 +09:00
|
|
|
|
},
|
2026-03-04 22:19:10 +09:00
|
|
|
|
// cm4: 접대비
|
2026-02-23 20:59:25 +09:00
|
|
|
|
{
|
|
|
|
|
|
id: 'cm4',
|
2026-03-04 22:19:10 +09:00
|
|
|
|
label: '접대비',
|
|
|
|
|
|
amount: entertainmentAmount,
|
|
|
|
|
|
previousLabel: entertainmentUnverified > 0 ? `미증빙 ${entertainmentUnverified}건` : undefined,
|
|
|
|
|
|
},
|
|
|
|
|
|
// cm_total: 총 가지급금 합계
|
|
|
|
|
|
{
|
|
|
|
|
|
id: 'cm_total',
|
|
|
|
|
|
label: '총 가지급금 합계',
|
|
|
|
|
|
amount: totalAmount,
|
2026-02-23 20:59:25 +09:00
|
|
|
|
},
|
|
|
|
|
|
],
|
2026-03-04 22:19:10 +09:00
|
|
|
|
checkPoints: generateCardManagementCheckPoints(loanApi, taxApi, summaryApi),
|
2026-02-23 20:59:25 +09:00
|
|
|
|
};
|
|
|
|
|
|
}
|