- HeaderFavoritesBar 대폭 개선 - Sidebar/AuthenticatedLayout 소폭 수정 - ShipmentCreate, VehicleDispatch 출하 관련 개선 - WorkOrderCreate/Edit, WorkerScreen 생산 관련 개선 - InspectionCreate 자재 입고검사 개선 - DailyReport, VendorDetail 회계 수정 - CEO 대시보드: CardManagement/DailyProduction/DailyAttendance 섹션 개선 - useCEODashboard, expense transformer 정비 - DocumentViewer, PDF generate route 소폭 수정 - bill-prototype 개발 페이지 추가 - mockData 불필요 데이터 제거
240 lines
8.5 KiB
TypeScript
240 lines
8.5 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 } 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) — D1.7 5장 카드 구조
|
||
// ============================================
|
||
|
||
/**
|
||
* 카드/가지급금 CheckPoints 생성 (D1.7)
|
||
*
|
||
* CP1: 법인카드 → 가지급금 전환 경고
|
||
* CP2: 인정이자 발생 현황
|
||
* CP3: 접대비 불인정 항목 감지
|
||
* CP4: 주말 카드 사용 감지 (향후 확장)
|
||
*/
|
||
function generateCardManagementCheckPoints(
|
||
loanApi?: LoanDashboardApiResponse | null,
|
||
taxApi?: TaxSimulationApiResponse | null,
|
||
cardApi?: CardTransactionApiResponse | null,
|
||
): CheckPoint[] {
|
||
const checkPoints: CheckPoint[] = [];
|
||
|
||
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) {
|
||
checkPoints.push({
|
||
id: 'cm-cp1',
|
||
type: 'success' as CheckPointType,
|
||
message: `법인카드 사용 중 ${formatAmount(totalOutstanding)}이 가지급금으로 전환되었습니다. 연 ${interestRate}% 인정이자가 발생합니다.`,
|
||
highlights: [
|
||
{ text: formatAmount(totalOutstanding), color: 'red' as const },
|
||
{ text: '가지급금', color: 'red' as const },
|
||
{ text: `연 ${interestRate}% 인정이자`, color: 'red' as const },
|
||
],
|
||
});
|
||
}
|
||
|
||
// 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 필드 추가 시 활성화
|
||
}
|
||
|
||
return checkPoints;
|
||
}
|
||
|
||
/**
|
||
* CardTransaction API 응답 → Frontend 타입 변환
|
||
* 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)
|
||
*/
|
||
export function transformCardManagementResponse(
|
||
summaryApi: CardTransactionApiResponse,
|
||
loanApi?: LoanDashboardApiResponse | null,
|
||
taxApi?: TaxSimulationApiResponse | null,
|
||
fallbackData?: CardManagementData
|
||
): CardManagementData {
|
||
const breakdown = loanApi?.category_breakdown;
|
||
const totalOutstanding = loanApi?.summary?.total_outstanding ?? 0;
|
||
|
||
// 카테고리별 금액 추출
|
||
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;
|
||
|
||
// 카테고리별 미증빙/미정리 건수
|
||
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;
|
||
|
||
// 총 합계 (API summary 또는 카테고리 합산)
|
||
const totalAmount = totalOutstanding > 0
|
||
? totalOutstanding
|
||
: cardAmount + congratulatoryAmount + giftCertificateAmount + entertainmentAmount;
|
||
|
||
// 가지급금 경고 배너 표시 여부 (가지급금 잔액 > 0이면 표시)
|
||
const hasLoanWarning = totalAmount > 0;
|
||
|
||
return {
|
||
warningBanner: hasLoanWarning
|
||
? (fallbackData?.warningBanner ?? '가지급금 인정이자 4.6%, 법인세 및 연말정산 시 대표자 종합세 가중 주의')
|
||
: undefined,
|
||
cards: [
|
||
// cm1: 카드
|
||
{
|
||
id: 'cm1',
|
||
label: '카드',
|
||
amount: cardAmount,
|
||
subLabel: cardUnverified > 0 ? `미정리 ${cardUnverified}건` : undefined,
|
||
subAmount: cardUnverified > 0 ? cardAmount : undefined,
|
||
isHighlighted: cardUnverified > 0,
|
||
},
|
||
// cm2: 경조사
|
||
{
|
||
id: 'cm2',
|
||
label: '경조사',
|
||
amount: congratulatoryAmount,
|
||
subLabel: congratulatoryUnverified > 0 ? `미증빙 ${congratulatoryUnverified}건` : undefined,
|
||
subAmount: congratulatoryUnverified > 0 ? congratulatoryAmount : undefined,
|
||
isHighlighted: congratulatoryUnverified > 0,
|
||
},
|
||
// cm3: 상품권
|
||
{
|
||
id: 'cm3',
|
||
label: '상품권',
|
||
amount: giftCertificateAmount,
|
||
subLabel: giftCertificateUnverified > 0 ? `미증빙 ${giftCertificateUnverified}건` : undefined,
|
||
subAmount: giftCertificateUnverified > 0 ? giftCertificateAmount : undefined,
|
||
isHighlighted: giftCertificateUnverified > 0,
|
||
},
|
||
// cm4: 접대비
|
||
{
|
||
id: 'cm4',
|
||
label: '접대비',
|
||
amount: entertainmentAmount,
|
||
subLabel: entertainmentUnverified > 0 ? `미증빙 ${entertainmentUnverified}건` : undefined,
|
||
subAmount: entertainmentUnverified > 0 ? entertainmentAmount : undefined,
|
||
isHighlighted: entertainmentUnverified > 0,
|
||
},
|
||
// cm_total: 총 가지급금 합계
|
||
{
|
||
id: 'cm_total',
|
||
label: '총 가지급금 합계',
|
||
amount: totalAmount,
|
||
},
|
||
],
|
||
checkPoints: generateCardManagementCheckPoints(loanApi, taxApi, summaryApi),
|
||
};
|
||
}
|