feat: 매입관리 품의서/지출결의서 연동 UI 구현
- PurchaseRecord 타입에 approvalId 필드 추가 - API 응답에서 approval 데이터를 sourceDocument로 변환 - 매입 목록에 '연결문서' 컬럼 추가 (품의서/지출결의서 표시) - 모바일 카드 뷰에 연결문서 정보 표시
This commit is contained in:
@@ -31,6 +31,18 @@ interface PurchaseApiData {
|
||||
status: string;
|
||||
purchase_type?: string;
|
||||
withdrawal_id?: number;
|
||||
approval_id?: number;
|
||||
approval?: {
|
||||
id: number;
|
||||
document_number: string;
|
||||
title: string;
|
||||
content?: Record<string, unknown>;
|
||||
form?: {
|
||||
id: number;
|
||||
name: string;
|
||||
category: string;
|
||||
};
|
||||
};
|
||||
tax_invoice_received: boolean;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
@@ -60,6 +72,23 @@ function transformApiToFrontend(data: PurchaseApiData): PurchaseRecord {
|
||||
? (data.purchase_type as PurchaseType)
|
||||
: 'unset';
|
||||
|
||||
// 품의서/지출결의서 연결 정보 변환
|
||||
let sourceDocument: PurchaseRecord['sourceDocument'] = undefined;
|
||||
if (data.approval) {
|
||||
// form.category로 문서 유형 결정 (proposal=품의서, expense_report=지출결의서)
|
||||
const docType = data.approval.form?.category === 'expense_report' ? 'expense_report' : 'proposal';
|
||||
// content에서 예상금액 추출 (품의서 양식에 따라 다를 수 있음)
|
||||
const expectedCost = (data.approval.content?.expected_cost as number) ||
|
||||
(data.approval.content?.total_amount as number) || 0;
|
||||
|
||||
sourceDocument = {
|
||||
type: docType,
|
||||
documentNo: data.approval.document_number,
|
||||
title: data.approval.title,
|
||||
expectedCost,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
id: String(data.id),
|
||||
purchaseNo: data.purchase_number,
|
||||
@@ -72,6 +101,8 @@ function transformApiToFrontend(data: PurchaseApiData): PurchaseRecord {
|
||||
purchaseType,
|
||||
evidenceType: 'tax_invoice',
|
||||
status: data.status === 'confirmed' ? 'completed' : 'pending',
|
||||
approvalId: data.approval_id ? String(data.approval_id) : undefined,
|
||||
sourceDocument,
|
||||
items: [],
|
||||
taxInvoiceReceived: data.tax_invoice_received ?? false,
|
||||
createdAt: data.created_at || '',
|
||||
@@ -90,6 +121,7 @@ function transformFrontendToApi(data: Partial<PurchaseRecord>): Record<string, u
|
||||
if (data.totalAmount !== undefined) result.total_amount = data.totalAmount;
|
||||
if (data.purchaseType !== undefined) result.purchase_type = data.purchaseType;
|
||||
if (data.taxInvoiceReceived !== undefined) result.tax_invoice_received = data.taxInvoiceReceived;
|
||||
if (data.approvalId !== undefined) result.approval_id = data.approvalId ? parseInt(data.approvalId, 10) : null;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ const tableColumns = [
|
||||
{ key: 'purchaseNo', label: '매입번호' },
|
||||
{ key: 'purchaseDate', label: '매입일' },
|
||||
{ key: 'vendorName', label: '거래처' },
|
||||
{ key: 'sourceDocument', label: '연결문서', className: 'text-center' },
|
||||
{ key: 'supplyAmount', label: '공급가액', className: 'text-right' },
|
||||
{ key: 'vat', label: '부가세', className: 'text-right' },
|
||||
{ key: 'totalAmount', label: '합계금액', className: 'text-right' },
|
||||
@@ -388,6 +389,7 @@ export function PurchaseManagement() {
|
||||
<TableCell className="font-bold">합계</TableCell>
|
||||
<TableCell></TableCell>
|
||||
<TableCell></TableCell>
|
||||
<TableCell></TableCell>
|
||||
<TableCell className="text-right font-bold">{tableTotals.totalSupplyAmount.toLocaleString()}</TableCell>
|
||||
<TableCell className="text-right font-bold">{tableTotals.totalVat.toLocaleString()}</TableCell>
|
||||
<TableCell className="text-right font-bold">{tableTotals.totalAmount.toLocaleString()}</TableCell>
|
||||
@@ -424,6 +426,15 @@ export function PurchaseManagement() {
|
||||
<TableCell className="text-sm font-medium">{item.purchaseNo}</TableCell>
|
||||
<TableCell>{item.purchaseDate}</TableCell>
|
||||
<TableCell>{item.vendorName}</TableCell>
|
||||
<TableCell className="text-center">
|
||||
{item.sourceDocument ? (
|
||||
<Badge variant="outline" className="text-xs border-blue-300 text-blue-600 bg-blue-50">
|
||||
{item.sourceDocument.type === 'proposal' ? '품의서' : '지출결의서'}
|
||||
</Badge>
|
||||
) : (
|
||||
<span className="text-gray-400 text-xs">-</span>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">{item.supplyAmount.toLocaleString()}</TableCell>
|
||||
<TableCell className="text-right">{item.vat.toLocaleString()}</TableCell>
|
||||
<TableCell className="text-right font-medium">{item.totalAmount.toLocaleString()}</TableCell>
|
||||
@@ -489,6 +500,7 @@ export function PurchaseManagement() {
|
||||
onClick={() => handleRowClick(item)}
|
||||
details={[
|
||||
{ label: '매입일', value: item.purchaseDate },
|
||||
{ label: '연결문서', value: item.sourceDocument ? (item.sourceDocument.type === 'proposal' ? '품의서' : '지출결의서') : '-' },
|
||||
{ label: '공급가액', value: `${item.supplyAmount.toLocaleString()}원` },
|
||||
{ label: '합계금액', value: `${item.totalAmount.toLocaleString()}원` },
|
||||
]}
|
||||
|
||||
@@ -54,7 +54,9 @@ export interface PurchaseRecord {
|
||||
purchaseType: PurchaseType; // 매입유형
|
||||
evidenceType: EvidenceType; // 증빙유형
|
||||
status: PurchaseStatus; // 상태
|
||||
// 근거 문서
|
||||
// 연결된 결재문서 ID (품의서/지출결의서)
|
||||
approvalId?: string;
|
||||
// 근거 문서 (API에서 조회됨)
|
||||
sourceDocument?: {
|
||||
type: 'proposal' | 'expense_report'; // 품의서 | 지출결의서
|
||||
documentNo: string;
|
||||
|
||||
Reference in New Issue
Block a user