# 급여관리 API 명세 > **작성일**: 2026-03-11 > **상태**: 개발 완료 (API 배포됨) > **Base URL**: `api.codebridge-x.com` (운영) / `api.dev.codebridge-x.com` (개발) --- ## 1. 개요 월별 급여를 등록/확정/지급하고, 4대보험과 근로소득세를 자동 계산하는 급여관리 API이다. ### 1.1 인증 모든 요청에 다음 헤더가 필요하다: ``` X-API-KEY: {api_key} Authorization: Bearer {token} ``` ### 1.2 공통 응답 형식 ```json { "success": true, "message": "조회 성공", "data": { ... } } ``` 에러 시: ```json { "success": false, "message": "에러 메시지" } ``` ### 1.3 엔드포인트 요약 | # | Method | Path | 설명 | |---|--------|------|------| | 1 | GET | `/api/v1/payrolls` | 급여 목록 (페이지네이션) | | 2 | POST | `/api/v1/payrolls` | 급여 등록 | | 3 | GET | `/api/v1/payrolls/summary` | 월간 요약 통계 | | 4 | POST | `/api/v1/payrolls/calculate` | 급여 일괄 계산 (draft 재계산) | | 5 | POST | `/api/v1/payrolls/calculate-preview` | 계산 미리보기 (저장 안 함) | | 6 | POST | `/api/v1/payrolls/bulk-confirm` | 일괄 확정 | | 7 | POST | `/api/v1/payrolls/bulk-generate` | 재직사원 일괄 생성 | | 8 | POST | `/api/v1/payrolls/copy-from-previous` | 전월 급여 복사 | | 9 | GET | `/api/v1/payrolls/{id}` | 급여 상세 | | 10 | PUT | `/api/v1/payrolls/{id}` | 급여 수정 | | 11 | DELETE | `/api/v1/payrolls/{id}` | 급여 삭제 | | 12 | POST | `/api/v1/payrolls/{id}/confirm` | 확정 | | 13 | POST | `/api/v1/payrolls/{id}/unconfirm` | 확정 취소 | | 14 | POST | `/api/v1/payrolls/{id}/pay` | 지급 처리 | | 15 | POST | `/api/v1/payrolls/{id}/unpay` | 지급 취소 (슈퍼관리자) | | 16 | GET | `/api/v1/payrolls/{id}/payslip` | 급여명세서 조회 | | 17 | GET | `/api/v1/payrolls/settings` | 급여 설정 조회 | | 18 | PUT | `/api/v1/payrolls/settings` | 급여 설정 수정 | --- ## 2. 상태 흐름도 ``` ┌────────────────┐ │ draft (작성중) │ └───┬──────┬─────┘ │ ▲ │ confirm │ unconfirm ▼ │ ┌────────────────┐ │confirmed (확정) │ └───┬──────┬─────┘ │ ▲ │ pay │ unpay* ▼ │ ┌────────────────┐ │ paid (지급완료)│ └────────────────┘ * unpay는 슈퍼관리자 전용 (paid → draft 초기화) ``` ### 2.1 상태값 | 상태 | 값 | 설명 | UI 배지 색상 | |------|---|------|-------------| | 작성중 | `draft` | 수정/삭제/확정 가능 | gray | | 확정 | `confirmed` | 확정취소/지급 가능 | blue | | 지급완료 | `paid` | 상세보기만 가능 | green | ### 2.2 상태별 가능한 작업 | 상태 | 일반 사용자 | 슈퍼관리자 | |------|-----------|-----------| | `draft` | 수정, 삭제, 확정, 일괄계산 | 동일 | | `confirmed` | 확정취소, 지급처리 | + **수정** | | `paid` | 상세보기만 | + **수정**, **지급취소** | --- ## 3. 급여 계산 엔진 ### 3.1 과세표준 ``` 과세표준 = 총지급액(gross_salary) - 식대(bonus) ``` - `bonus` 필드는 **식대(비과세)** 항목이다 - 4대보험과 세금은 과세표준 기준으로 계산한다 ### 3.2 4대보험 자동 계산 | 항목 | 계산식 | 기본 요율 | 비고 | |------|--------|----------|------| | 건강보험 | `과세표준 × 3.545%` | 3.545% | 10원 단위 절삭 | | 장기요양보험 | `건강보험료 × 0.9082%` | 0.9082% | 건강보험료 기준, 10원 단위 절삭 | | 국민연금 | `과세표준 × 4.5%` | 4.5% | 상한 590만 / 하한 37만 적용 | | 고용보험 | `과세표준 × 0.9%` | 0.9% | 10원 단위 절삭 | > **모든 보험료는 10원 단위 절삭** (floor to nearest 10) ### 3.3 근로소득세 - **770천원 미만**: 0원 - **770~10,000천원**: 간이세액표(DB) 조회 (연도, 월급여 천원단위, 가족수) - **10,000천원 초과**: 공식 계산 (소득세법 시행령 별표2) ### 3.4 지방소득세 ``` 지방소득세 = 근로소득세 × 10% (10원 단위 절삭) ``` ### 3.5 가족수 (공제대상가족수) - 기본: 본인 1인 - TenantUserProfile의 `json_extra.dependents` 배열에서 `is_dependent: true`인 수만큼 추가 - 범위: 최소 1, 최대 11 ### 3.6 요율 설정 요율은 `payroll_settings` 테이블에서 테넌트별로 관리한다. 기본값은 위 표와 동일하며, 설정 API(17, 18번)를 통해 변경 가능하다. --- ## 4. 데이터 모델 ### 4.1 Payroll 객체 ```json { "id": 1, "tenant_id": 1, "user_id": 5, "pay_year": 2026, "pay_month": 3, "base_salary": "3500000", "overtime_pay": "0", "bonus": "200000", "allowances": [ {"name": "직책수당", "amount": 300000}, {"name": "교통비", "amount": 100000} ], "gross_salary": "4100000", "income_tax": "117750", "resident_tax": "11770", "health_insurance": "138220", "long_term_care": "1250", "pension": "175500", "employment_insurance": "35100", "deductions": [ {"name": "대출상환", "amount": 500000} ], "options": null, "total_deductions": "979590", "net_salary": "3120410", "status": "draft", "confirmed_at": null, "confirmed_by": null, "paid_at": null, "withdrawal_id": null, "note": null, "created_by": 1, "updated_by": 1, "created_at": "2026-03-11T10:00:00.000000Z", "updated_at": "2026-03-11T10:00:00.000000Z", "user": { "id": 5, "name": "홍길동", "email": "hong@example.com" }, "creator": { "id": 1, "name": "관리자" } } ``` ### 4.2 필드 설명 **지급 항목:** | 필드 | 타입 | 설명 | |------|------|------| | `base_salary` | decimal(0) | 기본급 | | `overtime_pay` | decimal(0) | 고정연장근로수당 | | `bonus` | decimal(0) | 식대 (비과세) | | `allowances` | json | 추가 수당 `[{name, amount}]` | | `gross_salary` | decimal(0) | 총지급액 (자동 계산) | **법정 공제 항목 (자동 계산):** | 필드 | 타입 | 설명 | |------|------|------| | `income_tax` | decimal(0) | 근로소득세 | | `resident_tax` | decimal(0) | 지방소득세 | | `health_insurance` | decimal(0) | 건강보험료 | | `long_term_care` | decimal(0) | 장기요양보험료 | | `pension` | decimal(0) | 국민연금 | | `employment_insurance` | decimal(0) | 고용보험료 | **기타 공제:** | 필드 | 타입 | 설명 | |------|------|------| | `deductions` | json | 기타공제 `[{name, amount}]` | **결과:** | 필드 | 타입 | 설명 | |------|------|------| | `total_deductions` | decimal(0) | 총공제액 (법정 + 기타) | | `net_salary` | decimal(0) | 실수령액 = gross - total_deductions | **상태:** | 필드 | 타입 | 설명 | |------|------|------| | `status` | string | `draft` / `confirmed` / `paid` | | `confirmed_at` | datetime | 확정 일시 | | `confirmed_by` | int | 확정자 user_id | | `paid_at` | datetime | 지급 일시 | | `withdrawal_id` | int | 연결된 출금 ID | --- ## 5. API 상세 ### 5.1 급여 목록 조회 ``` GET /api/v1/payrolls ``` **Query Parameters:** | 파라미터 | 타입 | 필수 | 설명 | 예시 | |---------|------|------|------|------| | `year` | int | - | 귀속연도 | `2026` | | `month` | int | - | 귀속월 | `3` | | `user_id` | int | - | 사원 ID | `5` | | `status` | string | - | 상태 필터 | `draft` | | `department_id` | int | - | 부서 필터 | `2` | | `search` | string | - | 사원명 검색 | `홍길동` | | `sort_by` | string | - | 정렬 기준 (기본: `pay_year`) | `net_salary` | | `sort_dir` | string | - | 정렬 방향 (기본: `desc`) | `asc` | | `per_page` | int | - | 페이지당 건수 (기본: 20) | `50` | | `page` | int | - | 페이지 번호 | `1` | **응답 (200):** ```json { "success": true, "message": "조회 성공", "data": { "current_page": 1, "data": [ { "id": 1, "user_id": 5, "pay_year": 2026, "pay_month": 3, "base_salary": "3500000", "gross_salary": "4100000", "total_deductions": "979590", "net_salary": "3120410", "status": "draft", "user": {"id": 5, "name": "홍길동", "email": "hong@example.com"}, "creator": {"id": 1, "name": "관리자"} } ], "per_page": 20, "total": 15, "last_page": 1 } } ``` **프론트엔드 참고:** - 연월을 선택하는 UI를 제공하면 `year` + `month` 필터 사용 - `sort_by=period` 전달 시 `pay_year` + `pay_month` 복합 정렬 --- ### 5.2 급여 등록 ``` POST /api/v1/payrolls ``` **Request Body:** ```json { "user_id": 5, "pay_year": 2026, "pay_month": 3, "base_salary": 3500000, "overtime_pay": 0, "bonus": 200000, "allowances": [ {"name": "직책수당", "amount": 300000} ], "deductions": [ {"name": "대출상환", "amount": 500000} ], "family_count": 3, "deduction_overrides": { "income_tax": 100000, "pension": 170000 }, "note": "메모" } ``` **필드 규칙:** | 필드 | 타입 | 필수 | 설명 | |------|------|------|------| | `user_id` | int | ✅ | 급여 대상 사원 ID | | `pay_year` | int | ✅ | 귀속연도 (2000~2100) | | `pay_month` | int | ✅ | 귀속월 (1~12) | | `base_salary` | numeric | ✅ | 기본급 (0 이상) | | `overtime_pay` | numeric | - | 고정연장근로수당 | | `bonus` | numeric | - | 식대 (비과세) | | `allowances` | array | - | 추가수당 `[{name, amount}]` | | `deductions` | array | - | 기타공제 `[{name, amount}]` | | `family_count` | int | - | 공제대상가족수 (1~11, 미전달 시 자동) | | `deduction_overrides` | object | - | 법정공제 수동 입력 (아래 참고) | | `note` | string | - | 메모 (최대 1000자) | **`deduction_overrides` 필드:** 자동 계산된 법정 공제 항목을 수동으로 덮어쓸 때 사용한다. 지정한 항목만 덮어쓰고, 나머지는 자동 계산값을 유지한다. ```json { "income_tax": 100000, "resident_tax": 10000, "health_insurance": 140000, "long_term_care": 1300, "pension": 170000, "employment_insurance": 35000 } ``` **응답 (201):** ```json { "success": true, "message": "등록 성공", "data": { /* Payroll 객체 (4.1 참고) */ } } ``` **에러:** | 상황 | 응답 코드 | 메시지 | |------|----------|--------| | 동일 연월+사원 중복 | 400 | 해당 연월에 이미 급여가 등록되어 있습니다. | | 검증 실패 | 422 | 요청 데이터 검증에 실패했습니다. | --- ### 5.3 월간 요약 통계 ``` GET /api/v1/payrolls/summary?year=2026&month=3 ``` **Query Parameters:** | 파라미터 | 타입 | 필수 | 기본값 | |---------|------|------|--------| | `year` | int | - | 현재 연도 | | `month` | int | - | 현재 월 | **응답 (200):** ```json { "success": true, "message": "조회 성공", "data": { "year": 2026, "month": 3, "total_count": 15, "draft_count": 3, "confirmed_count": 7, "paid_count": 5, "total_gross": 62500000, "total_deductions": 15800000, "total_net": 46700000 } } ``` **프론트엔드 참고:** - 대시보드 카드에 `total_count`, `total_gross`, `total_net` 표시 - 상태별 카운트로 진행 상태 게이지 표현 가능 --- ### 5.4 급여 일괄 계산 기존 `draft` 상태 급여의 공제 항목을 재계산한다. ``` POST /api/v1/payrolls/calculate ``` **Request Body:** ```json { "year": 2026, "month": 3, "user_ids": [5, 8, 12] } ``` | 필드 | 타입 | 필수 | 설명 | |------|------|------|------| | `year` | int | ✅ | 대상 연도 | | `month` | int | ✅ | 대상 월 | | `user_ids` | array | - | 특정 사원만 지정 (미전달 시 전체) | **응답 (200):** ```json { "success": true, "message": "급여가 일괄 계산되었습니다.", "data": [ { /* 재계산된 Payroll 객체들 */ } ] } ``` > **주의:** `confirmed`/`paid` 상태 급여는 재계산하지 않는다 (draft만 대상). --- ### 5.5 계산 미리보기 급여 데이터를 저장하지 않고 계산 결과만 미리 확인한다. 급여 등록/수정 폼에서 실시간 미리보기용. ``` POST /api/v1/payrolls/calculate-preview ``` **Request Body:** ```json { "user_id": 5, "base_salary": 3500000, "overtime_pay": 0, "bonus": 200000, "allowances": [ {"name": "직책수당", "amount": 300000} ], "deductions": [ {"name": "대출상환", "amount": 500000} ] } ``` **응답 (200):** ```json { "success": true, "message": "계산 완료", "data": { "gross_salary": 4100000, "taxable_base": 3900000, "income_tax": 117750, "resident_tax": 11770, "health_insurance": 138220, "long_term_care": 1250, "pension": 175500, "employment_insurance": 35100, "total_deductions": 979590, "net_salary": 3120410, "family_count": 3 } } ``` **프론트엔드 참고:** - `user_id`를 전달하면 해당 사원의 가족수를 자동 반영 - `user_id` 미전달 시 가족수 1로 계산 - 폼 입력값이 변경될 때마다 호출하여 실시간 계산 결과를 표시 (debounce 300ms 권장) --- ### 5.6 일괄 확정 해당 월의 모든 `draft` 급여를 한 번에 `confirmed`로 변경한다. ``` POST /api/v1/payrolls/bulk-confirm ``` **Request Body:** ```json { "year": 2026, "month": 3 } ``` **응답 (200):** ```json { "success": true, "message": "급여가 일괄 확정되었습니다.", "data": { "count": 12 } } ``` --- ### 5.7 재직사원 일괄 생성 해당 연월에 재직 중인(employee_status=active) 모든 사원의 급여를 자동 생성한다. ``` POST /api/v1/payrolls/bulk-generate ``` **Request Body:** ```json { "year": 2026, "month": 3 } ``` **응답 (200):** ```json { "success": true, "message": "급여가 일괄 생성되었습니다.", "data": { "created": 12, "skipped": 3 } } ``` **동작 설명:** - 사원별 연봉 정보(`json_extra.salary_info.annual_salary`)에서 `÷12`로 월 기본급 산출 - 이미 존재하는 사원은 `skipped` 처리 (중복 생성하지 않음) - 연봉 정보가 없는 사원도 기본급 0으로 생성됨 - 모든 급여는 `draft` 상태로 생성됨 **프론트엔드 참고:** - 매월 초에 "일괄 생성" 버튼을 눌러 해당 월 급여를 초기화 - `created`/`skipped` 결과를 토스트 메시지로 표시 --- ### 5.8 전월 급여 복사 전월 급여 데이터를 현재 월로 복사한다. 매월 동일한 급여 구조를 유지할 때 사용. ``` POST /api/v1/payrolls/copy-from-previous ``` **Request Body:** ```json { "year": 2026, "month": 3 } ``` **응답 (200):** ```json { "success": true, "message": "전월 급여가 복사되었습니다.", "data": { "created": 15, "skipped": 0 } } ``` **동작 설명:** - 지급/공제 항목을 전월 그대로 복사 (`base_salary`, `allowances`, `deductions` 등) - 상태는 `draft`로 초기화 - 이미 존재하는 사원은 `skipped` 처리 - 1월 요청 시 전년 12월 데이터 참조 **에러:** | 상황 | 응답 코드 | 메시지 | |------|----------|--------| | 전월 데이터 없음 | 400 | 전월 급여 데이터가 없습니다. | --- ### 5.9 급여 상세 조회 ``` GET /api/v1/payrolls/{id} ``` **응답 (200):** ```json { "success": true, "message": "조회 성공", "data": { "id": 1, "user": {"id": 5, "name": "홍길동", "email": "hong@example.com"}, "confirmer": {"id": 1, "name": "관리자"}, "withdrawal": null, "creator": {"id": 1, "name": "관리자"}, /* ... 전체 Payroll 필드 */ } } ``` --- ### 5.10 급여 수정 ``` PUT /api/v1/payrolls/{id} ``` **Request Body:** ```json { "base_salary": 3600000, "overtime_pay": 100000, "bonus": 200000, "allowances": [ {"name": "직책수당", "amount": 300000} ], "deductions": [ {"name": "대출상환", "amount": 500000} ], "deduction_overrides": { "pension": 175000 }, "_is_super_admin": false, "note": "기본급 인상 반영" } ``` **필드 규칙:** - `_is_super_admin: true` 전달 시 `confirmed`/`paid` 상태에서도 수정 가능 - `deduction_overrides`로 법정 공제 항목을 수동 변경 가능 - 전달하지 않은 필드는 기존값 유지 **에러:** | 상황 | 응답 코드 | 메시지 | |------|----------|--------| | draft 아닌 상태에서 수정 | 400 | 작성중 상태의 급여만 수정할 수 있습니다. | | 연월/사원 변경 시 중복 | 400 | 해당 연월에 이미 급여가 등록되어 있습니다. | --- ### 5.11 급여 삭제 ``` DELETE /api/v1/payrolls/{id} ``` **응답 (200):** ```json { "success": true, "message": "삭제 성공", "data": null } ``` > `draft` 상태에서만 삭제 가능. Soft delete 처리. --- ### 5.12 확정 ``` POST /api/v1/payrolls/{id}/confirm ``` **Request Body:** 없음 **응답 (200):** ```json { "success": true, "message": "급여가 확정되었습니다.", "data": { "id": 1, "status": "confirmed", "confirmed_at": "2026-03-11T14:30:00.000000Z", "confirmer": {"id": 1, "name": "관리자"} } } ``` --- ### 5.13 확정 취소 ``` POST /api/v1/payrolls/{id}/unconfirm ``` **Request Body:** 없음 **응답 (200):** ```json { "success": true, "message": "급여 확정이 취소되었습니다.", "data": { "id": 1, "status": "draft", "confirmed_at": null, "confirmed_by": null } } ``` > `confirmed` 상태에서만 가능. `draft`로 되돌린다. --- ### 5.14 지급 처리 ``` POST /api/v1/payrolls/{id}/pay ``` **Request Body:** ```json { "withdrawal_id": 42 } ``` | 필드 | 타입 | 필수 | 설명 | |------|------|------|------| | `withdrawal_id` | int | - | 연결할 출금 내역 ID | **응답 (200):** ```json { "success": true, "message": "급여가 지급 처리되었습니다.", "data": { "id": 1, "status": "paid", "paid_at": "2026-03-25T09:00:00.000000Z", "withdrawal": { "id": 42, "..." : "..." } } } ``` --- ### 5.15 지급 취소 ``` POST /api/v1/payrolls/{id}/unpay ``` **Request Body:** 없음 > **슈퍼관리자 전용.** `paid` → `draft`로 초기화. 확정/지급 이력 모두 제거. **응답 (200):** ```json { "success": true, "message": "급여 지급이 취소되었습니다.", "data": { "id": 1, "status": "draft", "confirmed_at": null, "paid_at": null, "withdrawal_id": null } } ``` --- ### 5.16 급여명세서 조회 ``` GET /api/v1/payrolls/{id}/payslip ``` **응답 (200):** ```json { "success": true, "message": "조회 성공", "data": { "payroll": { /* 전체 Payroll 객체 */ }, "period": "2026년 03월", "employee": { "id": 5, "name": "홍길동", "email": "hong@example.com" }, "earnings": { "base_salary": 3500000, "overtime_pay": 0, "bonus": 200000, "allowances": [ {"name": "직책수당", "amount": 300000}, {"name": "교통비", "amount": 100000} ], "allowances_total": 400000, "gross_total": 4100000 }, "deductions": { "income_tax": 117750, "resident_tax": 11770, "health_insurance": 138220, "long_term_care": 1250, "pension": 175500, "employment_insurance": 35100, "other_deductions": [ {"name": "대출상환", "amount": 500000} ], "other_total": 500000, "total": 979590 }, "net_salary": 3120410, "status": "confirmed", "status_label": "확정", "paid_at": null } } ``` **프론트엔드 참고:** - `earnings` 구조로 지급 항목 테이블 구성 - `deductions` 구조로 공제 항목 테이블 구성 - `period`, `employee`, `net_salary`로 명세서 헤더 구성 - 인쇄용 레이아웃은 A4 세로 기준 권장 --- ### 5.17 급여 설정 조회 ``` GET /api/v1/payrolls/settings ``` **응답 (200):** ```json { "success": true, "message": "조회 성공", "data": { "id": 1, "tenant_id": 1, "income_tax_rate": "0.00", "resident_tax_rate": "10.00", "health_insurance_rate": "3.545", "long_term_care_rate": "0.9082", "pension_rate": "4.500", "employment_insurance_rate": "0.900", "pension_max_salary": "5900000.00", "pension_min_salary": "370000.00", "pay_day": 25, "auto_calculate": false, "allowance_types": [ {"code": "meal", "name": "식대", "is_taxable": false}, {"code": "transport", "name": "교통비", "is_taxable": false}, {"code": "position", "name": "직책수당", "is_taxable": true}, {"code": "skill", "name": "기술수당", "is_taxable": true}, {"code": "family", "name": "가족수당", "is_taxable": true}, {"code": "housing", "name": "주거수당", "is_taxable": true} ], "deduction_types": [ {"code": "loan", "name": "대출상환"}, {"code": "union", "name": "조합비"}, {"code": "savings", "name": "저축"}, {"code": "etc", "name": "기타공제"} ] } } ``` **프론트엔드 참고:** - `allowance_types`로 수당 입력 폼의 드롭다운 구성 - `deduction_types`로 공제 입력 폼의 드롭다운 구성 - `pay_day`를 급여 지급일 표시에 활용 --- ### 5.18 급여 설정 수정 ``` PUT /api/v1/payrolls/settings ``` **Request Body:** ```json { "health_insurance_rate": 3.545, "pension_rate": 4.5, "pay_day": 25, "allowance_types": [ {"code": "meal", "name": "식대", "is_taxable": false}, {"code": "transport", "name": "교통비", "is_taxable": false} ] } ``` > 전달한 필드만 업데이트. 미전달 필드는 기존값 유지. --- ## 6. 에러 코드 정리 | 에러 키 | 메시지 | 발생 상황 | |---------|--------|----------| | `error.payroll.not_found` | 급여 정보를 찾을 수 없습니다. | 존재하지 않는 ID | | `error.payroll.already_exists` | 해당 연월에 이미 급여가 등록되어 있습니다. | 동일 사원+연월 중복 | | `error.payroll.not_editable` | 작성중 상태의 급여만 수정할 수 있습니다. | draft 외 수정 시도 | | `error.payroll.not_deletable` | 작성중 상태의 급여만 삭제할 수 있습니다. | draft 외 삭제 시도 | | `error.payroll.not_confirmable` | 작성중 상태의 급여만 확정할 수 있습니다. | draft 외 확정 시도 | | `error.payroll.not_unconfirmable` | 확정된 급여만 확정 취소할 수 있습니다. | confirmed 외 확정취소 | | `error.payroll.not_payable` | 확정된 급여만 지급 처리할 수 있습니다. | confirmed 외 지급 | | `error.payroll.not_unpayable` | 지급완료된 급여만 지급 취소할 수 있습니다. | paid 외 지급취소 | | `error.payroll.no_previous_month` | 전월 급여 데이터가 없습니다. | 전월 복사 시 데이터 없음 | | `error.payroll.invalid_withdrawal` | 유효하지 않은 출금 내역입니다. | 존재하지 않는 withdrawal_id | --- ## 7. 프론트엔드 구현 가이드 ### 7.1 추천 화면 구성 ``` ┌─────────────────────────────────────────────────────┐ │ 급여관리 [2026년 03월 ▼] │ ├─────────────────────────────────────────────────────┤ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐│ │ │ 총 인원 │ │ 총 지급액 │ │ 총 공제액 │ │ 실수령액 ││ │ │ 15명 │ │ 62,500천원│ │ 15,800천원│ │46,700천원││ │ └──────────┘ └──────────┘ └──────────┘ └─────────┘│ │ │ │ [일괄생성] [전월복사] [일괄계산] [일괄확정] [+ 등록] │ │ │ │ ┌───┬──────┬──────┬──────┬──────┬──────┬────┬────┐│ │ │ # │ 사원 │ 기본급│총지급액│총공제액│실수령액│상태 │ 작업││ │ ├───┼──────┼──────┼──────┼──────┼──────┼────┼────┤│ │ │ 1 │홍길동│ 350만│ 410만│ 98만 │ 312만│작성│ ⋮ ││ │ │ 2 │김철수│ 300만│ 350만│ 85만 │ 265만│확정│ ⋮ ││ │ └───┴──────┴──────┴──────┴──────┴──────┴────┴────┘│ └─────────────────────────────────────────────────────┘ ``` ### 7.2 급여 등록/수정 폼 ``` ┌─────────────────────────────────────────────────────┐ │ 급여 등록 │ ├─────────────────────────────────────────────────────┤ │ 사원: [홍길동 ▼] 연도: [2026] 월: [3 ▼] │ │ │ │ ── 지급 항목 ──────────────────────────────────── │ │ 기본급: [ 3,500,000 ] │ │ 연장근로수당: [ 0 ] │ │ 식대(비과세): [ 200,000 ] │ │ 수당: │ │ 직책수당 [ 300,000 ] [삭제] │ │ 교통비 [ 100,000 ] [삭제] │ │ [+ 수당 추가] │ │ ────────────────────────── 총 지급액: 4,100,000 │ │ │ │ ── 공제 항목 (자동 계산) ──────────────────────── │ │ 근로소득세: [ 117,750 ] ← 자동 (수정 가능) │ │ 지방소득세: [ 11,770 ] ← 자동 (수정 가능) │ │ 건강보험: [ 138,220 ] ← 자동 (수정 가능) │ │ 장기요양보험: [ 1,250 ] ← 자동 (수정 가능) │ │ 국민연금: [ 175,500 ] ← 자동 (수정 가능) │ │ 고용보험: [ 35,100 ] ← 자동 (수정 가능) │ │ 기타 공제: │ │ 대출상환 [ 500,000 ] [삭제] │ │ [+ 기타 공제 추가] │ │ ────────────────────────── 총 공제액: 979,590 │ │ │ │ ═════════════════════════ 실수령액: 3,120,410 │ │ │ │ 메모: [ ] │ │ │ │ [취소] [미리보기] [저장]│ └─────────────────────────────────────────────────────┘ ``` **구현 포인트:** - 지급 항목 변경 시 `calculate-preview` API 호출하여 공제 항목 자동 갱신 - 법정 공제 필드는 기본 readonly + "수정" 토글로 수동 입력 허용 - 수동 입력된 공제 항목은 `deduction_overrides`로 전달 - `allowance_types`, `deduction_types`는 설정 API에서 조회하여 드롭다운 제공 ### 7.3 급여명세서 (인쇄용) `payslip` API 응답의 `earnings`/`deductions` 구조를 활용: ``` ┌─────────────────────────────────────────────┐ │ 급 여 명 세 서 │ │ │ │ 사원명: 홍길동 귀속기간: 2026년 03월 │ │ │ │ ┌──── 지급 내역 ────┬── 공제 내역 ────┐ │ │ │ 기본급 3,500,000│ 소득세 117,750│ │ │ │ 식대 200,000│ 지방소득세 11,770│ │ │ │ 직책수당 300,000│ 건강보험 138,220│ │ │ │ 교통비 100,000│ 장기요양 1,250│ │ │ │ │ 국민연금 175,500│ │ │ │ │ 고용보험 35,100│ │ │ │ │ 대출상환 500,000│ │ │ ├───────────────────┼─────────────────┤ │ │ │ 지급합계 4,100,000│ 공제합계 979,590│ │ │ └───────────────────┴─────────────────┘ │ │ │ │ 실수령액: 3,120,410원 │ └─────────────────────────────────────────────┘ ``` ### 7.4 월간 워크플로우 ``` 1. 월초 → [일괄생성] 또는 [전월복사] 실행 2. 개별 급여 데이터 확인/수정 3. [일괄계산] 실행 (공제 항목 최신 요율로 재계산) 4. 데이터 확인 완료 → [일괄확정] 5. 급여 지급일 → 개별 [지급처리] (출금과 연결) 6. 급여명세서 조회/인쇄 ``` ### 7.5 금액 표시 규칙 - 모든 금액은 **원(KRW)** 단위 정수 - 천 단위 콤마 필수: `3,500,000` - 음수 금액(환급): 빨간색 + `-` 부호 --- ## 관련 문서 - [급여관리 기능 상세](../../features/finance/payroll.md) — 전표 변환, 권한, 멀티테넌트 - [DB 스키마 — 인사](../../system/database/hr.md) - [결재관리 API 명세](approval-api.md) --- **최종 업데이트**: 2026-03-11