diff --git a/INDEX.md b/INDEX.md index 0db6d78..0ab7723 100644 --- a/INDEX.md +++ b/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 자동생성, 취소 복원) | diff --git a/frontend/api-specs/condolence-expense-api.md b/frontend/api-specs/condolence-expense-api.md new file mode 100644 index 0000000..e6a5152 --- /dev/null +++ b/frontend/api-specs/condolence-expense-api.md @@ -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 | 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