Files
sam-docs/frontend/api-specs/condolence-expense-api.md
김보곤 95ecc985de docs: [finance] 경조사비 API 명세 추가 (FE 전달용)
- 6개 엔드포인트 + TypeScript 타입 정의
- 화면 구성 가이드 + Server Actions 예시
- INDEX.md에 문서 등록
2026-03-19 15:40:31 +09:00

14 KiB

경조사비 관리 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

응답:

{
  "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

응답:

{
  "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):

{
  "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):

{
  "success": true,
  "message": "등록되었습니다.",
  "data": { /* 생성된 객체 */ }
}

6. 상세 조회

GET /api/v1/condolence-expenses/{id}

응답: 목록 조회의 data 항목과 동일 구조 + creator 관계 포함


7. 수정

PUT /api/v1/condolence-expenses/{id}

등록과 동일한 Body 구조. partner_name, categorysometimes|required.

응답:

{
  "success": true,
  "message": "수정되었습니다.",
  "data": { /* 수정된 객체 */ }
}

8. 삭제

DELETE /api/v1/condolence-expenses/{id}

소프트 삭제 (deleted_at 기록).

응답:

{
  "success": true,
  "message": "삭제되었습니다.",
  "data": null
}

9. 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 예시

// 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. 카테고리/지출방법 라벨 매핑

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