# 급여관리 (Payroll) > **작성일**: 2026-02-27 > **상태**: 운영 중 > **최종 갱신**: 2026-03-11 --- ## 1. 개요 ### 1.1 목적 MNG 관리자 페이지(`/hr/payrolls`)에서 월별 급여를 등록/확정/지급하고, 일반전표로 자동 변환하는 시스템이다. ### 1.2 핵심 원칙 - **Payroll 모델** 중심 운영 (Salary 모델은 React 연동용으로 별도 존재) - 급여 데이터는 MNG에서 관리, DB 마이그레이션은 API에서 관리 - 법정공제는 자동 계산, 기타공제(`deductions` JSON)는 수기 입력 --- ## 2. 상태 워크플로우 ``` draft(작성중) ──확정──→ confirmed(확정) ──지급──→ paid(지급완료) ↑ │ │ │ 확정취소 지급취소* │ │ │ └───────────────────────┘ │ └───────────────────────────────────────────────┘ * 슈퍼관리자 전용 ``` ### 2.1 상태별 가능한 작업 | 상태 | 일반 사용자 | 슈퍼관리자 | |------|-----------|-----------| | `draft` (작성중) | 수정, 삭제, 확정 | 동일 | | `confirmed` (확정) | 확정취소, 지급처리, 이메일발송 | + **수정** | | `paid` (지급완료) | 상세보기만 | + **수정**, **지급취소** | ### 2.2 슈퍼관리자 예외 (2026-03-11 추가) - `confirmed`/`paid` 상태에서도 급여 데이터 직접 수정 가능 - `paid` → `draft` 지급취소: 확정/지급 이력(`confirmed_at`, `paid_at`) 초기화 - 용도: 수기 입력 오류(기타공제 항목명 오타 등) 수정 후 전표 재생성 --- ## 3. 데이터 구조 ### 3.1 payrolls 테이블 주요 필드 | 구분 | 필드 | 설명 | |------|------|------| | **식별** | `tenant_id`, `user_id`, `pay_year`, `pay_month` | 테넌트/사원/귀속연월 | | **지급** | `base_salary`, `overtime_pay`, `bonus` | 기본급, 고정연장근로수당, 식대(비과세) | | **수당** | `allowances` (JSON) | `[{name, amount}, ...]` | | **총액** | `gross_salary` | 기본급 + 수당 + 식대 합계 | | **법정공제** | `pension`, `health_insurance`, `long_term_care`, `employment_insurance`, `income_tax`, `resident_tax` | 자동 계산 (수동 override 가능) | | **기타공제** | `deductions` (JSON) | `[{name, amount}, ...]` 수기 입력 | | **결과** | `total_deductions`, `net_salary` | 총공제액, 실수령액 | | **상태** | `status`, `confirmed_at`, `paid_at` | draft/confirmed/paid | ### 3.2 기타공제 (deductions JSON) > **경고: `deductions`의 `name`은 수기 입력 데이터다. 오타에 주의해야 한다.** ```json [ {"name": "연말정산 소득세", "amount": -564120}, {"name": "연말정산 지방소득세", "amount": -120650}, {"name": "건강보험 퇴직정산", "amount": -41600} ] ``` - 양수: 공제 (급여에서 차감) - 음수: 환급 (급여에 추가) - **이름이 다르면 전표 변환 시 별도 항목으로 처리됨** (예: "소득세" vs "소득제" → 그룹핑 실패) --- ## 4. 일반전표 변환 ### 4.1 개요 해당 월의 전체 급여를 합산하여 일반전표 1건을 자동 생성한다. - 메서드: `PayrollController::generateJournalEntry()` - `source_type`: `payroll` - `source_key`: `payroll-{year}-{month}` (중복 생성 불가) - 전표일자: 해당 월 말일 ### 4.2 분개 구조 | 차/대 | 계정코드 | 계정명 | 거래처 | 금액 | 적요 | |-------|---------|--------|--------|------|------| | 차변 | 801 | 급여 | 임직원 | 총지급액 합산 | N월분 급여 | | 대변 | 207 | 예수금 | 건강보험연금 | 국민연금 합산 | 국민연금 | | 대변 | 207 | 예수금 | 건강보험건강 | 건강보험 합산 | 건강보험 | | 대변 | 207 | 예수금 | 건강보험건강 | 장기요양보험 합산 | 장기요양보험 | | 대변 | 207 | 예수금 | 건강보험고용 | 고용보험 합산 | 고용보험 | | 대변 | 207 | 예수금 | 강서세무서 | 근로소득세 합산 | N월분 근로소득세 | | 대변 | 207 | 예수금 | 강서구청 | 지방소득세 합산 | N월분 지방소득세 | | 대변 | 207 | 예수금 | 임직원 | 기타공제 항목별 | 항목명 | | 대변 | 205 | 미지급비용 | 임직원 | 실수령액 합산 | N월분 급여 | ### 4.3 거래처 매핑 (현재 하드코딩) | 공제 항목 | 거래처명 | |----------|---------| | 국민연금 | 건강보험연금 | | 건강보험, 장기요양보험 | 건강보험건강 | | 고용보험 | 건강보험고용 | | 근로소득세 | 강서세무서 | | 지방소득세 | 강서구청 | | 기타공제, 실수령액 | 임직원 | ### 4.4 음수 공제(환급) 처리 - `amount < 0`: 적요에 `"(환급)"` 접미사 추가 - 대변에 음수 금액으로 표기 (예수금 감소) - 동일 `거래처+적요` 조합은 병합: `mergeKey = "{partnerName}|{description}"` ### 4.5 차대 균형 검증 전표 저장 전 `총 차변 === 총 대변` 검증. 불일치 시 상세 내역과 함께 에러 반환. ### 4.6 전표 수정/삭제 생성된 전표의 수정/삭제는 **회계관리 > 일반전표입력** 메뉴에서 처리한다. 급여관리에서 전표를 삭제하면 동일 월에 대해 재생성 가능하다. --- ## 5. 권한 체계 ### 5.1 접근 제어 ```php private const ALLOWED_PAYROLL_USERS = ['이의찬', '전진선', '김보곤']; ``` 급여관리 메뉴 접근은 위 사용자로 제한된다 (`auth()->user()->name` 기준). ### 5.2 슈퍼관리자 권한 `users.is_super_admin = true`인 사용자: - `confirmed`/`paid` 상태에서 급여 데이터 수정 - `paid` → `draft` 지급취소 (`unpay`) --- ## 6. MNG API 엔드포인트 | Method | URI | 설명 | |--------|-----|------| | GET | `/api/admin/hr/payrolls` | 급여 목록 (HTMX 테이블) | | GET | `/api/admin/hr/payrolls/stats` | 월간 통계 카드 | | GET | `/api/admin/hr/payrolls/export` | 엑셀 내보내기 | | POST | `/api/admin/hr/payrolls` | 급여 등록 | | PUT | `/api/admin/hr/payrolls/{id}` | 급여 수정 | | DELETE | `/api/admin/hr/payrolls/{id}` | 급여 삭제 | | POST | `/api/admin/hr/payrolls/{id}/confirm` | 확정 | | POST | `/api/admin/hr/payrolls/{id}/unconfirm` | 확정 취소 | | POST | `/api/admin/hr/payrolls/{id}/pay` | 지급 처리 | | POST | `/api/admin/hr/payrolls/{id}/unpay` | 지급 취소 (슈퍼관리자) | | POST | `/api/admin/hr/payrolls/bulk-generate` | 재직사원 일괄 생성 | | POST | `/api/admin/hr/payrolls/copy-from-previous` | 전월 복사 | | POST | `/api/admin/hr/payrolls/calculate` | 공제 자동 계산 | | POST | `/api/admin/hr/payrolls/generate-journal-entry` | 일반전표 생성 | | POST | `/api/admin/hr/payrolls/{id}/send-payslip` | 급여명세서 이메일 (PDF) | | GET | `/api/admin/hr/payroll-settings` | 급여 설정 조회 | | PUT | `/api/admin/hr/payroll-settings` | 급여 설정 수정 | --- ## 7. 멀티테넌트 확장 계획 > 현재 `tenant_id=1`에서만 운영. 추후 전체 테넌트에 확장 예정. ### 7.1 확장 시 변경 필요 항목 | 항목 | 현재 | 확장 후 | |------|------|--------| | 거래처 매핑 | 하드코딩 (`건강보험연금` 등) | 테넌트별 설정 테이블 | | 계정과목 코드 | 하드코딩 (`801`/`207`/`205`) | 테넌트별 설정 | | `AccountCode` 조회 | `tenant_id` 필터 없음 | `tenant_id` 필터 추가 필수 | | 접근 권한 | `ALLOWED_PAYROLL_USERS` (이름 기반) | 역할(Role) 기반 권한 | | `PayrollSetting` | 이미 테넌트별 분리 가능 | 변경 불필요 | ### 7.2 거래처/계정과목 설정 방안 `PayrollSetting` 또는 별도 설정에 테넌트별 매핑 저장: ```json { "journal_accounts": { "salary": "801", "withholding": "207", "accrued": "205" }, "journal_partners": { "pension": "건강보험연금", "health": "건강보험건강", "employment": "건강보험고용", "income_tax": "강서세무서", "resident_tax": "강서구청", "employee": "임직원" } } ``` --- ## 8. 관련 코드 | 프로젝트 | 경로 | 설명 | |---------|------|------| | MNG | `app/Http/Controllers/Api/Admin/HR/PayrollController.php` | API 컨트롤러 (전표 생성 포함) | | MNG | `app/Services/HR/PayrollService.php` | 비즈니스 로직 | | MNG | `app/Models/HR/Payroll.php` | 모델 (상태 헬퍼) | | MNG | `resources/views/hr/payrolls/` | Blade 뷰 | | API | `database/migrations/2025_12_18_100001_create_payrolls_table.php` | 테이블 정의 | --- ## 관련 문서 - [재무관리 개요](README.md) - [DB 스키마 — 인사](../../system/database/hr.md) - [DB 스키마 — 재무](../../system/database/finance.md) --- **최종 업데이트**: 2026-03-11