fix(WEB): 기타 버그 수정 및 개선

- CardTransactionInquiry: account_code 'unset' 처리 개선
- WorkOrderCreate: DevFill 공정 옵션 로딩 타이밍 수정
- accountingData: 생성기 개선
- api/errors: 에러 처리 개선
This commit is contained in:
2026-01-22 23:19:54 +09:00
parent c8890c1a85
commit e7fb3b1f96
5 changed files with 51 additions and 13 deletions

View File

@@ -296,7 +296,7 @@ export async function createCardTransaction(data: {
merchant_name: data.merchantName,
amount: data.amount,
description: data.memo,
account_code: data.usageType,
account_code: data.usageType === 'unset' ? null : data.usageType,
}),
});
@@ -349,7 +349,7 @@ export async function updateCardTransaction(
merchant_name: data.merchantName,
amount: data.amount,
description: data.memo,
account_code: data.usageType,
account_code: data.usageType === 'unset' ? null : data.usageType,
}),
});

View File

@@ -164,6 +164,19 @@ export interface Vendor {
}
// ===== API 응답 타입 =====
export interface SaleApiOrderItem {
id: number;
order_id: number;
item_name: string;
quantity: string | number;
unit_price: string | number;
supply_amount: string | number;
tax_amount: string | number;
total_amount: string | number;
note: string | null;
sort_order: number;
}
export interface SaleApiData {
id: number;
sale_number: string;
@@ -173,6 +186,10 @@ export interface SaleApiData {
id: number;
name: string;
};
order?: {
id: number;
items?: SaleApiOrderItem[];
};
supply_amount: string | number;
tax_amount: string | number;
total_amount: string | number;
@@ -197,6 +214,17 @@ export const API_STATUS_MAP: Record<string, SalesStatus> = {
// API 응답 → 프론트엔드 타입 변환
export function transformApiToFrontend(apiData: SaleApiData): SalesRecord {
// 수주(Order)의 품목(items)을 매출 품목으로 변환
const items: SalesItem[] = (apiData.order?.items ?? []).map((item, index) => ({
id: String(item.id),
itemName: item.item_name ?? '',
quantity: parseFloat(String(item.quantity)) || 0,
unitPrice: parseFloat(String(item.unit_price)) || 0,
supplyAmount: parseFloat(String(item.supply_amount)) || 0,
vat: parseFloat(String(item.tax_amount)) || 0,
note: item.note ?? '',
}));
return {
id: String(apiData.id),
salesNo: apiData.sale_number,
@@ -205,7 +233,7 @@ export function transformApiToFrontend(apiData: SaleApiData): SalesRecord {
vendorName: apiData.client?.name ?? '',
salesType: 'other', // API에 없음, 기본값
accountSubject: 'other', // API에 없음, 기본값
items: [], // API에 없음, 빈 배열
items, // 수주 품목에서 가져옴
totalSupplyAmount: parseFloat(String(apiData.supply_amount)) || 0,
totalVat: parseFloat(String(apiData.tax_amount)) || 0,
totalAmount: parseFloat(String(apiData.total_amount)) || 0,

View File

@@ -60,7 +60,7 @@ const DEPOSIT_NOTES = [
export interface DepositFormData {
depositDate: string;
accountName: string;
bankAccountId: string;
depositorName: string;
depositAmount: number;
note: string;
@@ -70,15 +70,17 @@ export interface DepositFormData {
export interface GenerateDepositDataOptions {
vendors?: Array<{ id: string; name: string }>;
bankAccounts?: Array<{ id: string; name: string }>;
}
export function generateDepositData(options: GenerateDepositDataOptions = {}): DepositFormData {
const { vendors = SAMPLE_VENDORS } = options;
const { vendors = SAMPLE_VENDORS, bankAccounts = [] } = options;
const vendor = randomPick(vendors);
const bankAccount = bankAccounts.length > 0 ? randomPick(bankAccounts) : null;
return {
depositDate: today(),
accountName: randomPick(ACCOUNT_NAMES),
bankAccountId: bankAccount?.id || '',
depositorName: randomPick(DEPOSITOR_NAMES),
depositAmount: randomInt(100000, 10000000),
note: randomPick(DEPOSIT_NOTES),
@@ -119,7 +121,7 @@ const WITHDRAWAL_NOTES = [
export interface WithdrawalFormData {
withdrawalDate: string;
accountName: string;
bankAccountId: string;
recipientName: string;
withdrawalAmount: number;
note: string;
@@ -129,15 +131,17 @@ export interface WithdrawalFormData {
export interface GenerateWithdrawalDataOptions {
vendors?: Array<{ id: string; name: string }>;
bankAccounts?: Array<{ id: string; name: string }>;
}
export function generateWithdrawalData(options: GenerateWithdrawalDataOptions = {}): WithdrawalFormData {
const { vendors = SAMPLE_VENDORS } = options;
const { vendors = SAMPLE_VENDORS, bankAccounts = [] } = options;
const vendor = randomPick(vendors);
const bankAccount = bankAccounts.length > 0 ? randomPick(bankAccounts) : null;
return {
withdrawalDate: today(),
accountName: randomPick(ACCOUNT_NAMES),
bankAccountId: bankAccount?.id || '',
recipientName: randomPick(RECIPIENT_NAMES),
withdrawalAmount: randomInt(50000, 5000000),
note: randomPick(WITHDRAWAL_NOTES),
@@ -264,6 +268,7 @@ export function generatePurchaseApprovalData(options: GeneratePurchaseApprovalDa
approvalLine: [currentUser],
references: [randomReference],
proposalData: {
vendorId: vendor.id,
vendor: vendor.name,
vendorPaymentDate: today(),
title: randomPick(PROPOSAL_TITLES),

View File

@@ -119,8 +119,12 @@ export function WorkOrderCreate() {
// DevToolbar 자동 채우기
useDevFill(
'workOrder',
useCallback(() => {
const sampleData = generateWorkOrderData({ processOptions });
useCallback(async () => {
// 공정 옵션 직접 가져오기 (state가 아직 로딩 전일 수 있음)
const processResult = await getProcessOptions();
const processes = processResult.success ? processResult.data : [];
const sampleData = generateWorkOrderData({ processOptions: processes });
// 수동 등록 모드로 변경
setMode('manual');
@@ -139,7 +143,7 @@ export function WorkOrderCreate() {
}));
toast.success('[Dev] 작업지시 폼이 자동으로 채워졌습니다.');
}, [processOptions])
}, [])
);
// 수주 선택 핸들러

View File

@@ -48,13 +48,14 @@ export function createAuthErrorResponse(message?: string): ApiErrorResponse {
/**
* 일반 API 에러 응답 생성 헬퍼
* - 디버깅을 위해 상태 코드를 메시지에 포함
*/
export function createErrorResponse(status: number, message: string, code?: string): ApiErrorResponse {
return {
__error: true,
__authError: status === 401,
status,
message,
message: `[${status}] ${message}`,
code,
};
}