feat(WEB): 부실채권, 재고, 입고, 수주 UI 개선
- BadDebtCollection 액션/타입 리팩토링 - ReceivingProcessDialog 입고처리 개선 - StockStatusList 재고현황 UI 개선 - OrderSalesDetailView 수주 상세 수정 - UniversalListPage 범용 리스트 개선 - production-order 페이지 수정
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
import { isNextRedirectError } from '@/lib/utils/redirect-error';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { serverFetch } from '@/lib/api/fetch-wrapper';
|
||||
import type { BadDebtRecord, CollectionStatus } from './types';
|
||||
import type { BadDebtRecord, BadDebtItem, CollectionStatus } from './types';
|
||||
|
||||
// ============================================
|
||||
// API 응답 타입 정의
|
||||
@@ -37,69 +37,47 @@ interface PaginatedResponse<T> {
|
||||
last_page: number;
|
||||
}
|
||||
|
||||
// API 악성채권 데이터 타입
|
||||
interface BadDebtApiData {
|
||||
// API 개별 악성채권 타입
|
||||
interface BadDebtItemApiData {
|
||||
id: number;
|
||||
tenant_id: number;
|
||||
client_id: number;
|
||||
debt_amount: string;
|
||||
debt_amount: number;
|
||||
status: 'collecting' | 'legal_action' | 'recovered' | 'bad_debt';
|
||||
overdue_days: number;
|
||||
occurred_at: string;
|
||||
closed_at: string | null;
|
||||
assigned_manager_id: number | null;
|
||||
is_active: boolean;
|
||||
note: string | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
deleted_at: string | null;
|
||||
client?: {
|
||||
id: number;
|
||||
code: string;
|
||||
name: string;
|
||||
business_number: string | null;
|
||||
representative_name: string | null;
|
||||
client_type: string | null;
|
||||
business_type: string | null;
|
||||
business_category: string | null;
|
||||
zip_code: string | null;
|
||||
address1: string | null;
|
||||
address2: string | null;
|
||||
phone: string | null;
|
||||
mobile: string | null;
|
||||
fax: string | null;
|
||||
email: string | null;
|
||||
contact_name: string | null;
|
||||
contact_phone: string | null;
|
||||
};
|
||||
assigned_manager?: {
|
||||
occurred_at: string | null;
|
||||
assigned_user?: {
|
||||
id: number;
|
||||
name: string;
|
||||
department?: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
position: string | null;
|
||||
phone: string | null;
|
||||
};
|
||||
documents?: Array<{
|
||||
} | null;
|
||||
}
|
||||
|
||||
// API 악성채권 데이터 타입 (거래처 기준)
|
||||
interface BadDebtApiData {
|
||||
id: number;
|
||||
client_id: number;
|
||||
client_code: string;
|
||||
client_name: string;
|
||||
business_no: string | null;
|
||||
contact_person: string | null;
|
||||
phone: string | null;
|
||||
mobile: string | null;
|
||||
email: string | null;
|
||||
address: string | null;
|
||||
client_type: string | null;
|
||||
// 집계 데이터
|
||||
total_debt_amount: number;
|
||||
max_overdue_days: number;
|
||||
bad_debt_count: number;
|
||||
// 대표 상태
|
||||
status: 'collecting' | 'legal_action' | 'recovered' | 'bad_debt';
|
||||
is_active: boolean;
|
||||
// 담당자
|
||||
assigned_user?: {
|
||||
id: number;
|
||||
file_name: string;
|
||||
file_path: string;
|
||||
file_size: number;
|
||||
mime_type: string;
|
||||
created_at: string;
|
||||
}>;
|
||||
memos?: Array<{
|
||||
id: number;
|
||||
content: string;
|
||||
created_at: string;
|
||||
created_by: number;
|
||||
created_by_user?: {
|
||||
id: number;
|
||||
name: string;
|
||||
};
|
||||
}>;
|
||||
name: string;
|
||||
} | null;
|
||||
// 개별 악성채권 목록
|
||||
bad_debts: BadDebtItemApiData[];
|
||||
}
|
||||
|
||||
// 통계 API 응답 타입
|
||||
@@ -165,61 +143,66 @@ function mapClientTypeToVendorType(clientType?: string | null): 'sales' | 'purch
|
||||
}
|
||||
|
||||
/**
|
||||
* API 데이터 → 프론트엔드 타입 변환
|
||||
* API 데이터 → 프론트엔드 타입 변환 (거래처 기준)
|
||||
*/
|
||||
function transformApiToFrontend(apiData: BadDebtApiData): BadDebtRecord {
|
||||
const client = apiData.client;
|
||||
const manager = apiData.assigned_manager;
|
||||
const manager = apiData.assigned_user;
|
||||
const firstBadDebt = apiData.bad_debts?.[0];
|
||||
|
||||
return {
|
||||
id: String(apiData.id),
|
||||
id: String(apiData.id), // Client ID
|
||||
vendorId: String(apiData.client_id),
|
||||
vendorCode: client?.code || '',
|
||||
vendorName: client?.name || '거래처 없음',
|
||||
businessNumber: client?.business_number || '',
|
||||
representativeName: client?.representative_name || '',
|
||||
vendorType: mapClientTypeToVendorType(client?.client_type),
|
||||
businessType: client?.business_type || '',
|
||||
businessCategory: client?.business_category || '',
|
||||
zipCode: client?.zip_code || '',
|
||||
address1: client?.address1 || '',
|
||||
address2: client?.address2 || '',
|
||||
phone: client?.phone || '',
|
||||
mobile: client?.mobile || '',
|
||||
fax: client?.fax || '',
|
||||
email: client?.email || '',
|
||||
contactName: client?.contact_name || '',
|
||||
contactPhone: client?.contact_phone || '',
|
||||
vendorCode: apiData.client_code || '',
|
||||
vendorName: apiData.client_name || '거래처 없음',
|
||||
businessNumber: apiData.business_no || '',
|
||||
representativeName: '',
|
||||
vendorType: mapClientTypeToVendorType(apiData.client_type),
|
||||
businessType: '',
|
||||
businessCategory: '',
|
||||
zipCode: '',
|
||||
address1: apiData.address || '',
|
||||
address2: '',
|
||||
phone: apiData.phone || '',
|
||||
mobile: apiData.mobile || '',
|
||||
fax: '',
|
||||
email: apiData.email || '',
|
||||
contactName: apiData.contact_person || '',
|
||||
contactPhone: '',
|
||||
systemManager: '',
|
||||
debtAmount: parseFloat(apiData.debt_amount) || 0,
|
||||
// 집계 데이터
|
||||
debtAmount: apiData.total_debt_amount || 0,
|
||||
badDebtCount: apiData.bad_debt_count || 0,
|
||||
status: mapApiStatusToFrontend(apiData.status),
|
||||
overdueDays: apiData.overdue_days || 0,
|
||||
overdueDays: apiData.max_overdue_days || 0,
|
||||
overdueToggle: apiData.is_active,
|
||||
occurrenceDate: apiData.occurred_at,
|
||||
endDate: apiData.closed_at,
|
||||
assignedManagerId: apiData.assigned_manager_id ? String(apiData.assigned_manager_id) : null,
|
||||
occurrenceDate: firstBadDebt?.occurred_at || '',
|
||||
endDate: null,
|
||||
assignedManagerId: manager ? String(manager.id) : null,
|
||||
assignedManager: manager ? {
|
||||
id: String(manager.id),
|
||||
departmentName: manager.department?.name || '',
|
||||
departmentName: '',
|
||||
name: manager.name,
|
||||
position: manager.position || '',
|
||||
phone: manager.phone || '',
|
||||
position: '',
|
||||
phone: '',
|
||||
} : null,
|
||||
settingToggle: apiData.is_active,
|
||||
files: apiData.documents?.map(doc => ({
|
||||
id: String(doc.id),
|
||||
name: doc.file_name,
|
||||
url: doc.file_path,
|
||||
type: 'additional' as const,
|
||||
})) || [],
|
||||
memos: apiData.memos?.map(memo => ({
|
||||
id: String(memo.id),
|
||||
content: memo.content,
|
||||
createdAt: memo.created_at,
|
||||
createdBy: memo.created_by_user?.name || `User ${memo.created_by}`,
|
||||
})) || [],
|
||||
createdAt: apiData.created_at,
|
||||
updatedAt: apiData.updated_at,
|
||||
// 개별 악성채권 목록
|
||||
badDebts: (apiData.bad_debts || []).map(bd => ({
|
||||
id: String(bd.id),
|
||||
debtAmount: bd.debt_amount || 0,
|
||||
status: mapApiStatusToFrontend(bd.status),
|
||||
overdueDays: bd.overdue_days || 0,
|
||||
isActive: bd.is_active,
|
||||
occurredAt: bd.occurred_at,
|
||||
assignedManager: bd.assigned_user ? {
|
||||
id: String(bd.assigned_user.id),
|
||||
name: bd.assigned_user.name,
|
||||
} : null,
|
||||
})),
|
||||
files: [],
|
||||
memos: [],
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,18 @@ export interface AttachedFile {
|
||||
type: 'businessRegistration' | 'taxInvoice' | 'additional';
|
||||
}
|
||||
|
||||
// 악성채권 레코드
|
||||
// 개별 악성채권 항목 (거래처별 하위 목록)
|
||||
export interface BadDebtItem {
|
||||
id: string;
|
||||
debtAmount: number;
|
||||
status: CollectionStatus;
|
||||
overdueDays: number;
|
||||
isActive: boolean;
|
||||
occurredAt: string | null;
|
||||
assignedManager: { id: string; name: string } | null;
|
||||
}
|
||||
|
||||
// 악성채권 레코드 (거래처 기준)
|
||||
export interface BadDebtRecord {
|
||||
id: string;
|
||||
// 거래처 기본 정보
|
||||
@@ -55,16 +66,19 @@ export interface BadDebtRecord {
|
||||
contactName: string;
|
||||
contactPhone: string;
|
||||
systemManager: string;
|
||||
// 악성채권 정보
|
||||
debtAmount: number;
|
||||
status: CollectionStatus;
|
||||
overdueDays: number;
|
||||
// 악성채권 집계 정보 (거래처 기준)
|
||||
debtAmount: number; // 총 미수금액
|
||||
badDebtCount: number; // 악성채권 건수
|
||||
status: CollectionStatus; // 대표 상태 (가장 최근)
|
||||
overdueDays: number; // 최대 연체일수
|
||||
overdueToggle: boolean;
|
||||
occurrenceDate: string;
|
||||
endDate: string | null;
|
||||
assignedManagerId: string | null;
|
||||
assignedManager: Manager | null;
|
||||
settingToggle: boolean;
|
||||
// 개별 악성채권 목록
|
||||
badDebts: BadDebtItem[];
|
||||
// 첨부 파일
|
||||
files: AttachedFile[];
|
||||
// 메모
|
||||
|
||||
Reference in New Issue
Block a user