docs: [finance] 경조사비 API 명세 추가 (FE 전달용)
- 6개 엔드포인트 + TypeScript 타입 정의 - 화면 구성 가이드 + Server Actions 예시 - INDEX.md에 문서 등록
This commit is contained in:
1
INDEX.md
1
INDEX.md
@@ -319,6 +319,7 @@ DB 도메인별:
|
||||
| [usage-subscription-api.md](frontend/api-specs/usage-subscription-api.md) | 이용현황(구독관리 통합) API 명세 (API 완료, 화면 가이드, 타입 정의, 피드백 반영) |
|
||||
| [nonconforming-api.md](frontend/api-specs/nonconforming-api.md) | 부적합관리 API 명세 (7개 엔드포인트 + 화면 가이드 + Server Actions 예시) |
|
||||
| [account-ledger-income-statement-api.md](frontend/api-specs/account-ledger-income-statement-api.md) | 계정별원장·손익계산서 API 명세 (2개 엔드포인트 + TypeScript 타입 + 화면 가이드) |
|
||||
| [condolence-expense-api.md](frontend/api-specs/condolence-expense-api.md) | 경조사비 관리 API 명세 (6개 엔드포인트 + TypeScript 타입 + 화면 가이드) |
|
||||
| [vehicle-react-implementation.md](plans/vehicle-react-implementation.md) | 차량관리 React 구현 요청서 (3개 메뉴, 컴포넌트 구조, 타입 정의) |
|
||||
| [stock-production-react-request.md](plans/stock-production-react-request.md) | 재고생산관리 React 구현 요청서 (수주 화면 단순화, API 스펙 포함) |
|
||||
| [bending-lot-react-request.md](plans/bending-lot-react-request.md) | 절곡품 LOT 재고생산 React 구현 요청서 (캐스케이딩 드롭다운, LOT 자동생성, 취소 복원) |
|
||||
|
||||
492
frontend/api-specs/condolence-expense-api.md
Normal file
492
frontend/api-specs/condolence-expense-api.md
Normal file
@@ -0,0 +1,492 @@
|
||||
# 경조사비 관리 API 명세
|
||||
|
||||
> **작성일**: 2026-03-19
|
||||
> **상태**: API 구현 완료
|
||||
> **대상**: React 프론트엔드 개발자
|
||||
> **API 기본 경로**: `/api/v1/condolence-expenses`
|
||||
> **React 페이지 경로**: `/accounting/condolence-expenses`
|
||||
> **메뉴 위치**: 회계관리 > 경조사비
|
||||
|
||||
---
|
||||
|
||||
## 1. 개요
|
||||
|
||||
거래처/임직원 경조사비를 관리하는 CRUD API.
|
||||
축의(congratulation)와 부조(condolence)를 구분하며, 부조금과 선물을 각각 관리한다.
|
||||
|
||||
---
|
||||
|
||||
## 2. API 엔드포인트
|
||||
|
||||
| Method | Path | 설명 |
|
||||
|--------|------|------|
|
||||
| GET | `/` | 목록 조회 (페이지네이션) |
|
||||
| POST | `/` | 신규 등록 |
|
||||
| GET | `/summary` | 통계 조회 |
|
||||
| GET | `/{id}` | 상세 조회 |
|
||||
| PUT | `/{id}` | 수정 |
|
||||
| DELETE | `/{id}` | 삭제 (소프트) |
|
||||
|
||||
---
|
||||
|
||||
## 3. 목록 조회
|
||||
|
||||
### `GET /api/v1/condolence-expenses`
|
||||
|
||||
**요청 파라미터** (Query String):
|
||||
|
||||
| 파라미터 | 타입 | 필수 | 설명 | 기본값 |
|
||||
|---------|------|:---:|------|--------|
|
||||
| `year` | number | N | 연도 필터 (event_date 기준) | - |
|
||||
| `category` | string | N | `congratulation` / `condolence` / `all` | 전체 |
|
||||
| `search` | string | N | 거래처명/내역/비고 통합 검색 | - |
|
||||
| `sort_by` | string | N | 정렬 기준 | `event_date` |
|
||||
| `sort_order` | string | N | `asc` / `desc` | `desc` |
|
||||
| `per_page` | number | N | 페이지 크기 | 50 |
|
||||
| `page` | number | N | 페이지 번호 | 1 |
|
||||
|
||||
**응답**:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "조회되었습니다.",
|
||||
"data": [
|
||||
{
|
||||
"id": 1,
|
||||
"tenant_id": 1,
|
||||
"event_date": "2026-03-15",
|
||||
"expense_date": "2026-03-16",
|
||||
"partner_name": "ABC 회사",
|
||||
"description": "김과장 결혼축의금",
|
||||
"category": "congratulation",
|
||||
"category_label": "축의",
|
||||
"has_cash": true,
|
||||
"cash_method": "transfer",
|
||||
"cash_method_label": "계좌이체",
|
||||
"cash_amount": 50000,
|
||||
"has_gift": true,
|
||||
"gift_type": "화환",
|
||||
"gift_amount": 30000,
|
||||
"total_amount": 80000,
|
||||
"options": null,
|
||||
"memo": "사원 본인 결혼",
|
||||
"created_by": 5,
|
||||
"updated_by": 5,
|
||||
"created_at": "2026-03-16T10:30:00.000000Z",
|
||||
"updated_at": "2026-03-16T10:30:00.000000Z",
|
||||
"deleted_at": null
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"current_page": 1,
|
||||
"last_page": 1,
|
||||
"per_page": 50,
|
||||
"total": 12
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 통계 조회
|
||||
|
||||
### `GET /api/v1/condolence-expenses/summary`
|
||||
|
||||
**요청 파라미터** (Query String):
|
||||
|
||||
| 파라미터 | 타입 | 필수 | 설명 |
|
||||
|---------|------|:---:|------|
|
||||
| `year` | number | N | 연도 필터 |
|
||||
| `category` | string | N | `congratulation` / `condolence` / `all` |
|
||||
|
||||
**응답**:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"total_count": 12,
|
||||
"total_amount": 1250000,
|
||||
"cash_total": 750000,
|
||||
"gift_total": 500000,
|
||||
"congratulation_count": 7,
|
||||
"condolence_count": 5,
|
||||
"congratulation_amount": 800000,
|
||||
"condolence_amount": 450000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 등록
|
||||
|
||||
### `POST /api/v1/condolence-expenses`
|
||||
|
||||
**요청 Body** (JSON):
|
||||
|
||||
```json
|
||||
{
|
||||
"event_date": "2026-03-15",
|
||||
"expense_date": "2026-03-16",
|
||||
"partner_name": "ABC 회사",
|
||||
"description": "김과장 결혼축의금",
|
||||
"category": "congratulation",
|
||||
"has_cash": true,
|
||||
"cash_method": "transfer",
|
||||
"cash_amount": 50000,
|
||||
"has_gift": true,
|
||||
"gift_type": "화환",
|
||||
"gift_amount": 30000,
|
||||
"memo": "사원 본인 결혼"
|
||||
}
|
||||
```
|
||||
|
||||
**검증 규칙**:
|
||||
|
||||
| 필드 | 타입 | 필수 | 규칙 |
|
||||
|------|------|:---:|------|
|
||||
| `event_date` | string (date) | N | `YYYY-MM-DD` |
|
||||
| `expense_date` | string (date) | N | `YYYY-MM-DD` |
|
||||
| `partner_name` | string | **Y** | max 100자 |
|
||||
| `description` | string | N | max 200자 |
|
||||
| `category` | string | **Y** | `congratulation` / `condolence` |
|
||||
| `has_cash` | boolean | N | default: false |
|
||||
| `cash_method` | string | `has_cash`=true일 때 필수 | `cash` / `transfer` / `card` |
|
||||
| `cash_amount` | number | `has_cash`=true일 때 필수 | 0 이상 정수 |
|
||||
| `has_gift` | boolean | N | default: false |
|
||||
| `gift_type` | string | N | max 50자 |
|
||||
| `gift_amount` | number | `has_gift`=true일 때 필수 | 0 이상 정수 |
|
||||
| `memo` | string | N | - |
|
||||
|
||||
> **`total_amount`는 서버에서 자동 계산** (cash_amount + gift_amount)
|
||||
|
||||
**응답** (201):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "등록되었습니다.",
|
||||
"data": { /* 생성된 객체 */ }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 상세 조회
|
||||
|
||||
### `GET /api/v1/condolence-expenses/{id}`
|
||||
|
||||
**응답**: 목록 조회의 data 항목과 동일 구조 + `creator` 관계 포함
|
||||
|
||||
---
|
||||
|
||||
## 7. 수정
|
||||
|
||||
### `PUT /api/v1/condolence-expenses/{id}`
|
||||
|
||||
등록과 동일한 Body 구조. `partner_name`, `category`는 `sometimes|required`.
|
||||
|
||||
**응답**:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "수정되었습니다.",
|
||||
"data": { /* 수정된 객체 */ }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 삭제
|
||||
|
||||
### `DELETE /api/v1/condolence-expenses/{id}`
|
||||
|
||||
소프트 삭제 (`deleted_at` 기록).
|
||||
|
||||
**응답**:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "삭제되었습니다.",
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. TypeScript 타입 정의
|
||||
|
||||
```typescript
|
||||
/** 경조사비 카테고리 */
|
||||
type CondolenceCategory = 'congratulation' | 'condolence';
|
||||
|
||||
/** 지출방법 */
|
||||
type CashMethod = 'cash' | 'transfer' | 'card';
|
||||
|
||||
/** 경조사비 항목 */
|
||||
interface CondolenceExpense {
|
||||
id: number;
|
||||
tenant_id: number;
|
||||
event_date: string | null; // "YYYY-MM-DD"
|
||||
expense_date: string | null; // "YYYY-MM-DD"
|
||||
partner_name: string;
|
||||
description: string | null;
|
||||
category: CondolenceCategory;
|
||||
category_label: string; // "축의" | "부조"
|
||||
has_cash: boolean;
|
||||
cash_method: CashMethod | null;
|
||||
cash_method_label: string | null; // "현금" | "계좌이체" | "카드"
|
||||
cash_amount: number;
|
||||
has_gift: boolean;
|
||||
gift_type: string | null;
|
||||
gift_amount: number;
|
||||
total_amount: number;
|
||||
options: Record<string, unknown> | null;
|
||||
memo: string | null;
|
||||
created_by: number | null;
|
||||
updated_by: number | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
deleted_at: string | null;
|
||||
}
|
||||
|
||||
/** 통계 */
|
||||
interface CondolenceExpenseSummary {
|
||||
total_count: number;
|
||||
total_amount: number;
|
||||
cash_total: number;
|
||||
gift_total: number;
|
||||
congratulation_count: number;
|
||||
condolence_count: number;
|
||||
congratulation_amount: number;
|
||||
condolence_amount: number;
|
||||
}
|
||||
|
||||
/** 등록/수정 요청 */
|
||||
interface CondolenceExpenseForm {
|
||||
event_date?: string | null;
|
||||
expense_date?: string | null;
|
||||
partner_name: string;
|
||||
description?: string | null;
|
||||
category: CondolenceCategory;
|
||||
has_cash?: boolean;
|
||||
cash_method?: CashMethod | null;
|
||||
cash_amount?: number;
|
||||
has_gift?: boolean;
|
||||
gift_type?: string | null;
|
||||
gift_amount?: number;
|
||||
memo?: string | null;
|
||||
}
|
||||
|
||||
/** 목록 조회 파라미터 */
|
||||
interface CondolenceExpenseListParams {
|
||||
year?: number;
|
||||
category?: CondolenceCategory | 'all';
|
||||
search?: string;
|
||||
sort_by?: string;
|
||||
sort_order?: 'asc' | 'desc';
|
||||
per_page?: number;
|
||||
page?: number;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 화면 구성 가이드
|
||||
|
||||
### 10.1 메뉴 위치
|
||||
|
||||
```
|
||||
회계관리 (accounting)
|
||||
└── 경조사비 (/accounting/condolence-expenses)
|
||||
```
|
||||
|
||||
### 10.2 페이지 레이아웃
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ 경조사비 관리 [+ 등록] │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │
|
||||
│ │총 건수 │ │총 금액 │ │부조금 │ │선물 │ │
|
||||
│ │ 12건 │ │125만원 │ │ 75만원 │ │50만원 │ │
|
||||
│ └───────┘ └───────┘ └───────┘ └───────┘ │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ 연도 [2026▾] 구분 [전체▾] 검색 [________] │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ No│경조사일│지출일│거래처│내역│구분│부조금│...│
|
||||
│ 1│03-15 │03-16 │ABC │결혼│축의│50,000│...│
|
||||
│ 2│03-10 │03-11 │DEF │상 │부조│100K │...│
|
||||
│───┼───────┼──────┼─────┼────┼────┼──────┼───│
|
||||
│ │ │ │ │합계│ │150K │...│
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 10.3 통계 카드 (상단)
|
||||
|
||||
| 카드 | API 필드 | 포맷 |
|
||||
|------|---------|------|
|
||||
| 총 건수 | `total_count` | `N건` |
|
||||
| 총 금액 | `total_amount` | 통화 (예: `1,250,000원`) |
|
||||
| 부조금 합계 | `cash_total` | 통화 |
|
||||
| 선물 합계 | `gift_total` | 통화 |
|
||||
|
||||
추가로 축의/부조 건수 표시: `congratulation_count` / `condolence_count`
|
||||
|
||||
### 10.4 필터
|
||||
|
||||
| 필터 | 컴포넌트 | 옵션 |
|
||||
|------|---------|------|
|
||||
| 연도 | Select | 당해연도 ~ 5년 전 |
|
||||
| 구분 | Select | 전체 / 축의 / 부조 |
|
||||
| 검색 | Input | debounce 300ms, placeholder: "거래처명, 내역, 비고" |
|
||||
|
||||
> 필터 변경 시 목록 + 통계 동시 조회
|
||||
|
||||
### 10.5 테이블 컬럼
|
||||
|
||||
| No | 컬럼명 | 필드 | 정렬 | 비고 |
|
||||
|----|--------|------|:---:|------|
|
||||
| 1 | 경조사일자 | `event_date` | 좌 | YYYY-MM-DD |
|
||||
| 2 | 지출일자 | `expense_date` | 좌 | YYYY-MM-DD |
|
||||
| 3 | 거래처명 | `partner_name` | 좌 | |
|
||||
| 4 | 내역 | `description` | 좌 | |
|
||||
| 5 | 구분 | `category_label` | 중앙 | Badge: 축의=red, 부조=gray |
|
||||
| 6 | 부조금 | `has_cash` | 중앙 | 여/부 표시 |
|
||||
| 7 | 지출방법 | `cash_method_label` | 좌 | |
|
||||
| 8 | 부조금액 | `cash_amount` | 우 | 통화 포맷 |
|
||||
| 9 | 선물 | `has_gift` | 중앙 | 여/부 표시 |
|
||||
| 10 | 선물종류 | `gift_type` | 좌 | |
|
||||
| 11 | 선물금액 | `gift_amount` | 우 | 통화 포맷 |
|
||||
| 12 | 총금액 | `total_amount` | 우 | **굵게**, 통화 포맷 |
|
||||
| 13 | 비고 | `memo` | 좌 | |
|
||||
|
||||
**하단 합계 행**: 부조금액 합계, 선물금액 합계, 총금액 합계 (클라이언트 계산)
|
||||
|
||||
### 10.6 등록/수정 모달 (Dialog)
|
||||
|
||||
**필드 구성**:
|
||||
|
||||
| 섹션 | 필드 | 컴포넌트 | 필수 |
|
||||
|------|------|---------|:---:|
|
||||
| 날짜 | 경조사일자 | DatePicker | N |
|
||||
| 날짜 | 지출일자 | DatePicker | N |
|
||||
| 기본 | 거래처명/대상자 | Input | **Y** |
|
||||
| 기본 | 내역 | Input | N |
|
||||
| 기본 | 구분 | Select (축의/부조) | **Y** |
|
||||
| 부조금 | 부조금 여부 | Checkbox (토글) | N |
|
||||
| 부조금 | 지출방법 | Select (현금/계좌이체/카드) | 조건부 |
|
||||
| 부조금 | 금액 | NumberInput (통화 포맷) | 조건부 |
|
||||
| 선물 | 선물 여부 | Checkbox (토글) | N |
|
||||
| 선물 | 종류 | Input | N |
|
||||
| 선물 | 금액 | NumberInput (통화 포맷) | 조건부 |
|
||||
| 합계 | 총금액 | 읽기 전용 (자동 계산) | - |
|
||||
| 메모 | 비고 | Textarea | N |
|
||||
|
||||
**동작**:
|
||||
- 부조금 체크 해제 시 → 지출방법/금액 숨김 + 값 초기화
|
||||
- 선물 체크 해제 시 → 종류/금액 숨김 + 값 초기화
|
||||
- 총금액 = 부조금액 + 선물금액 (실시간 계산)
|
||||
- 등록 성공 시 → 모달 닫기 + 목록 + 통계 새로고침
|
||||
|
||||
### 10.7 행 액션
|
||||
|
||||
| 액션 | 동작 |
|
||||
|------|------|
|
||||
| 행 클릭 또는 수정 버튼 | 수정 모달 열기 (데이터 로드) |
|
||||
| 삭제 버튼 | 확인 다이얼로그 → DELETE API 호출 |
|
||||
|
||||
---
|
||||
|
||||
## 11. Server Actions 예시
|
||||
|
||||
```typescript
|
||||
// actions.ts
|
||||
'use server';
|
||||
|
||||
import { buildApiUrl } from '@/lib/api/query-params';
|
||||
import { executeServerAction, executePaginatedAction } from '@/lib/api/server-action-utils';
|
||||
|
||||
export async function getCondolenceExpenses(params: CondolenceExpenseListParams) {
|
||||
return executePaginatedAction({
|
||||
url: buildApiUrl('/api/v1/condolence-expenses', {
|
||||
year: params.year,
|
||||
category: params.category !== 'all' ? params.category : undefined,
|
||||
search: params.search,
|
||||
sort_by: params.sort_by,
|
||||
sort_order: params.sort_order,
|
||||
per_page: params.per_page,
|
||||
page: params.page,
|
||||
}),
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
export async function getCondolenceExpenseSummary(params: { year?: number; category?: string }) {
|
||||
return executeServerAction({
|
||||
url: buildApiUrl('/api/v1/condolence-expenses/summary', {
|
||||
year: params.year,
|
||||
category: params.category !== 'all' ? params.category : undefined,
|
||||
}),
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
export async function createCondolenceExpense(data: CondolenceExpenseForm) {
|
||||
return executeServerAction({
|
||||
url: buildApiUrl('/api/v1/condolence-expenses'),
|
||||
method: 'POST',
|
||||
body: data,
|
||||
});
|
||||
}
|
||||
|
||||
export async function updateCondolenceExpense(id: number, data: CondolenceExpenseForm) {
|
||||
return executeServerAction({
|
||||
url: buildApiUrl(`/api/v1/condolence-expenses/${id}`),
|
||||
method: 'PUT',
|
||||
body: data,
|
||||
});
|
||||
}
|
||||
|
||||
export async function deleteCondolenceExpense(id: number) {
|
||||
return executeServerAction({
|
||||
url: buildApiUrl(`/api/v1/condolence-expenses/${id}`),
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. 카테고리/지출방법 라벨 매핑
|
||||
|
||||
```typescript
|
||||
const CATEGORY_OPTIONS = [
|
||||
{ value: 'congratulation', label: '축의' },
|
||||
{ value: 'condolence', label: '부조' },
|
||||
];
|
||||
|
||||
const CASH_METHOD_OPTIONS = [
|
||||
{ value: 'cash', label: '현금' },
|
||||
{ value: 'transfer', label: '계좌이체' },
|
||||
{ value: 'card', label: '카드' },
|
||||
];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 관련 문서
|
||||
|
||||
| 문서 | 경로 |
|
||||
|------|------|
|
||||
| 기획서 | `dev/dev_plans/condolence-expense-service-plan.md` |
|
||||
| MNG 기존 구현 | `mng/app/Http/Controllers/Finance/CondolenceExpenseController.php` |
|
||||
| MNG Blade 뷰 | `mng/resources/views/finance/condolence-expenses.blade.php` |
|
||||
|
||||
---
|
||||
|
||||
**최종 업데이트**: 2026-03-19
|
||||
Reference in New Issue
Block a user