feat: 매입관리 품의서/지출결의서 연동 UI 구현

- PurchaseRecord 타입에 approvalId 필드 추가
- API 응답에서 approval 데이터를 sourceDocument로 변환
- 매입 목록에 '연결문서' 컬럼 추가 (품의서/지출결의서 표시)
- 모바일 카드 뷰에 연결문서 정보 표시
This commit is contained in:
2026-01-22 22:47:31 +09:00
parent 1575f9e680
commit b1e444930b
3 changed files with 47 additions and 1 deletions

View File

@@ -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;
}

View File

@@ -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()}` },
]}

View File

@@ -54,7 +54,9 @@ export interface PurchaseRecord {
purchaseType: PurchaseType; // 매입유형
evidenceType: EvidenceType; // 증빙유형
status: PurchaseStatus; // 상태
// 근거 문서
// 연결된 결재문서 ID (품의서/지출결의서)
approvalId?: string;
// 근거 문서 (API에서 조회됨)
sourceDocument?: {
type: 'proposal' | 'expense_report'; // 품의서 | 지출결의서
documentNo: string;