/SimpleHR project
SimpleHR project

급여관리 스펙

conceptedited by Cairni · 방금 · AIv11

개요

급여관리 기능은 급여대장(Payroll Ledger)급여명세서(Payslip) 두 축으로 구성됩니다. 관련 전반적인 프로젝트 맥락은 Simple HR 프로젝트 개요를 참고하세요.

현재 급여 계산은 여러 필드가 하드코딩되어 있으며, 근무 정책 스펙에서 정의한 근로정책 데이터와의 연동이 부분적입니다. 본 문서는 급여 계산 흐름, 미연동 사항, 그리고 개선 방향을 상세히 다룹니다.


기능 현황

급여관리 기능 현황AI · 출처 클릭
완료12
기업 사용자 급여명세서 상세 모달 — PDF 다운로드
기업 사용자 급여명세서 상세 모달 — 인쇄하기
기업 사용자 급여명세서 상세 모달 — 이의 제기 (모달 감춤 개선 + 제출 기능 구현)
급여 대장 자동 생성 실패 시 서버 에러 메시지(detail)를 토스트에 표시
계약형태 OUTSOURCE 표시 오류 수정
4대보험 요율 관리자 설정 기능 — 현재 구현이 이미 요구사항 충족 (엑셀 입력값 우선, fallback만 요율 자동계산). 별도 설정 UI 불필요
회계·급여 정책 UI/CRUD 완비 및 주요 항목 반영 확인 (payroll_service.py:238-254)
중소기업 감면 — 대상여부+감면율 end-to-end 동작 (UI→API→DB→급여계산); 감면기간 날짜 입력 UI 추가; 급여명세서 소득세 항목에 감면율·원래세액·감면액 표시 추가
근로계약서 auto_renew / renewal_method 불일치 수정 — 프론트 조건을 c.renewal_method === 'AUTO_RENEW'로 변경, prod 데이터 보정 1건 완료
fix-task-0713 (26년 07월 13일 수정사항)
도급직(CONTRACT_OUTSOURCE) 계약 생성 시 auto_renew 기본값 — 모든 계약 유형을 auto_renew=False 기본값으로 통일, 도급직 자동연장 기본값 로직 제거(contract_service.py:627-629)
fix-task-0715 수정사항
근로정책 work_days OFF 요일 출근 차단 — _resolve_scheduled_for_day()에 work_days OFF 체크 추가 + get_user_dashboard()에 주휴일 판정 추가로 출근 버튼 비활성화. OT_HOLIDAY 승인 시 출근 허용 흐름 동일 (0e9ac95)
fix-task-0715 수정사항
근로정책 적용시점 반영 안됨 + 이력 덮어쓰기 수정 — 항상 신규 EWP INSERT·기존 EWP effective_to 종료, is_primary 대신 날짜 범위 기반 활성 판정, 미래 예약 시 Read 쿼리 자연 전환, EmployeeDetail 응답에 work_policy_effective_from 등 추가, 변경이력 모달 구현
fix-task-0715 수정사항
미완료5
급여대장 (/admin/payroll/ledger) 엑셀 다운로드
fix-task-0623 (26년 06월 23일 수정사항)
나야넷 기본틀 양식 다운로드
fix-task-0623 (26년 06월 23일 수정사항)
급여기초 관리 페이지 — 간이세액 비율(80/100/120%) 선택 UI 미구현. 백엔드 tax_rate_pct 컬럼 및 계산 로직은 있으나 프론트 미반영, 항상 100%로 동작
fix-task-0713 (26년 07월 13일 수정사항)
관리자 설정에서 별도 권한(인사, 급여) 삭제 — 미완료
fix-task-0715 수정사항
급여기초 관리 페이지 — 간이세액 비율(80/100/120%) 선택 UI 미구현. 수정 대상: frontend/src/app/admin/payroll/base/page.tsx — 드롭다운/라디오 추가, 저장 시 tax_rate_pct 전송
fix-task-0715 수정사항

1. 현재 급여 계산 흐름

generate_payslips() 함수의 동작 요약: fix-task-0623 (26년 06월 23일 수정사항)

1. 대상 직원 조회 (퇴직자 제외)
2. 일괄 데이터 로딩 (N+1 제거)
   - 기존 명세서 확인 → 중복 방지
   - EmployeePayBase (급여기초: monthly_work_hours, hourly_wage, standard_wage)
   - EmployeePayDetail + PayItem (급여상세: 각 수당/공제 항목)
   - 근태 데이터 (_attendance_data_map)
3. 직원별 명세서 생성 루프
   a. 급여기초에서 hourly_wage, daily_wage(= hourly_wage × 8) 산출
   b. 고정 수당/공제 항목 순회 (category == "ATTENDANCE"는 스킵)
   c. 근태 연동 수당 자동 계산 (PAY_OVERTIME, PAY_NIGHT, PAY_HOLIDAY, PAY_HOLIDAY_OT)
   d. 연차수당 계산 (daily_wage × 미사용연차일수)
   e. 4대보험 자동 계산
   f. Payslip + PayslipItem INSERT

핵심 데이터 흐름


2. 근로정책 ↔ 급여 연동 현황 매트릭스

항목근로정책 필드급여 계산 참조상태문제점
월 소정근로시간monthly_standard_hours (자동계산)EmployeePayBase.monthly_work_hours (수동, 기본 209)미연동비표준 근로(주 4일 등) 미반영
연장근로 할증률*(별도 필드 없음, 법정 1.5배)*1.5 하드코딩법정 고정
야간근로 할증률night_surcharge_rate (기본 1.5)0.5 하드코딩 (가산분만)미연동배율 정의 불명확
휴일근로 할증률holiday_surcharge_rate (기본 1.5)1.5 하드코딩미연동정책 반영 안 됨
휴일초과 할증률*(별도 필드 없음)*2.0 하드코딩법정 고정
1일 소정근로시간start_time, end_time, break_minutes → 계산 가능8시간 하드코딩미연동비표준 근무시간 미반영
고정연장 vs 실제연장독립 처리 (이중지급 가능)미연동이중지급 위험
근태 데이터 (시간)_attendance_data_map() 자동 연동연동됨
만근수당 판단has_absence_or_late 연동연동됨
미사용연차unused_leave_days 연동연동됨

3. 미연동 항목 상세 분석

3-1. 소정근로시간 하드코딩 (209시간)

현상: EmployeePayBase.monthly_work_hours는 기본값 209시간으로 설정되며, 관리자가 급여기초 저장 시 수동 입력하지 않으면 그대로 사용됩니다. fix-task-0623 (26년 06월 23일 수정사항)

근로정책과의 갭: WorkPolicy.monthly_standard_hourswork_days + start_time/end_time/break_minutes로 자동 계산됩니다. 주 4일 근무(174시간) 등 비표준 정책이 반영되지 않습니다.

영향: 시급 = standard_wage / monthly_work_hours. 소정근로시간이 다르면 시급이 달라지고, 시급 기반 모든 수당(연장·야간·휴일·연차)이 잘못 계산됩니다.

권장사항: 근로정책 변경 시 해당 정책이 적용된 직원의 EmployeePayBase.monthly_work_hours를 자동 갱신하거나, 명세서 생성 시점에 동적으로 조회하도록 개선이 필요합니다.

3-2. 고정연장수당(FIXED_OVERTIME) vs 실제연장수당(PAY_OVERTIME) 이중지급

현상: 급여 상세에 FIXED_OVERTIME(고정연장수당, category=ALLOWANCE)이 등록된 직원의 경우: fix-task-0623 (26년 06월 23일 수정사항)

  1. 1.고정 수당 루프에서 FIXED_OVERTIME 금액이 그대로 포함됨
  2. 2.근태 연동 수당 루프에서 PAY_OVERTIME이 overtime_hours × hourly_wage × 1.5로 별도 추가됨

이중지급 조건: FIXED_OVERTIME이 급여기초에 등록되어 있고, 동시에 해당 월에 실제 연장근로가 발생한 경우 → 둘 다 명세서에 포함됨.

해결 방향:

  • (A) 포괄임금제 해석: FIXED_OVERTIME은 월 고정 연장수당 약정. 실제 연장이 고정분을 초과하면 초과분만 PAY_OVERTIME 지급. 미초과 시 PAY_OVERTIME = 0.
  • (B) 현행 유지: 고정연장은 고정 수당, 실제연장은 근태 기반 별도 수당. 이중지급 허용 (회사 정책에 따라).
  • (C) 관리자 설정: PayItem 또는 근무 정책에 "고정연장 적용 시 근태연장 스킵" 플래그 추가.

3-3. 할증률 하드코딩

현상: 근태 수당 계산 시 할증률이 코드에 고정되어 있습니다. fix-task-0623 (26년 06월 23일 수정사항)

PAY_OVERTIME    → 1.5배  (연장근로)
PAY_NIGHT       → 0.5배  (야간근로, 가산분만)
PAY_HOLIDAY     → 1.5배  (휴일근로)
PAY_HOLIDAY_OT  → 2.0배  (휴일초과)

근로정책 필드:

  • WorkPolicy.night_surcharge_rate (기본 1.5) — 전체 배율. 가산분(0.5)과 의미 차이 있음
  • WorkPolicy.holiday_surcharge_rate (기본 1.5) — 전체 배율

법정 고정성: 연장(1.5), 야간 가산(0.5), 휴일(1.5), 휴일초과(2.0)은 근로기준법에 고정되어 있으므로, 정책별로 다르게 설정할 실익이 제한적입니다. 다만, 회사 자체 규정으로 법정 이상 할증을 적용하는 경우에는 정책 참조가 필요합니다.

3-4. 근로정책 변경 시 급여기초 미갱신

현상: 근로정책의 monthly_standard_hours가 변경되어도(work_days·시간 수정 등) 해당 정책이 적용된 직원의 EmployeePayBase.monthly_work_hours는 갱신되지 않습니다. fix-task-0623 (26년 06월 23일 수정사항)

흐름:

  1. 1.update_work_policy()monthly_standard_hours 재계산 후 WorkPolicy 업데이트
  2. 2.끝. 직원별 EmployeePayBase에 대한 후처리 없음.

권장 개선:

  • (A) 자동 갱신: update_work_policy() 후처리로 해당 정책 적용 직원의 EmployeePayBase 일괄 업데이트.
  • (B) 알림만: 관리자에게 "근로정책 변경됨, 급여기초 확인 필요" 알림 발송. 수동 갱신.
  • (C) 동적 조회: EmployeePayBase의 monthly_work_hours를 사용하지 않고, 명세서 생성 시 직원별 유효 근로정책에서 월 소정근로시간을 가져옴.

3-5. 1일 통상임금 8시간 하드코딩

현상: 연차수당 계산의 기초인 daily_wagehourly_wage × 8로 고정되어 있습니다. fix-task-0623 (26년 06월 23일 수정사항)

근로정책과의 갭: 근로정책에서 start_time, end_time, break_minutes로 1일 소정근로시간을 계산할 수 있습니다(예: 09:00~17:00, 휴게 1시간 = 7시간). 7시간 근무자의 연차수당이 8시간 기준으로 과다 지급됩니다.

개선 방향: 연차 자동계산 로직 스펙 참고하여 근로정책의 실제 1일 근로시간을 동적으로 계산하고 적용해야 합니다.


4. 완료된 기능 상세

4-1. 급여명세서 상세 모달 (기업 사용자)

모바일 UI/UX 개선 작업 (기업 사용자)와 연계되는 기능으로, 기업 사용자가 자신의 급여명세서를 열람하는 상세 모달에서 다음 세 가지 기능이 구현되었습니다. fix-task-0619.md

기능설명
PDF 다운로드급여명세서 상세 모달에서 PDF 파일로 내려받기
인쇄하기브라우저 인쇄 기능 연동
이의 제기기존에 모달이 다른 요소에 감춰지던 버그 수정 + 실제 제출 기능 구현

4-2. 급여 대장 자동 생성 — 오류 안내 개선

/admin/payroll/ledger에서 급여 대장 자동 생성 버튼 클릭 시 실패하는 케이스가 있었으며, 실패 원인을 사용자가 인지할 수 없었습니다. fix-task-0619.md

  • 원인 예시: {"detail": "발행/확정된 급여명세서가 없습니다."}
  • 수정 내용: 서버가 반환하는 detail 메시지를 토스트 알림 공통 컴포넌트를 통해 화면에 표시하도록 변경

4-3. 급여 기초관리 — 계약형태 표시 오류 수정

급여관리 > 급여 기초관리 > 급여 기초 페이지에서 계약형태가 OUTSOURCE로 노출되는 버그가 수정되었습니다. fix-task-0622.md

4-4. 4대보험 요율 관리자 설정

4대보험은 세무사에게 급여 서류를 받아 급여 기초에서 엑셀로 등록하는 방식으로 운영됩니다. 별도의 요율 계산 없이 엑셀 입력값 기반으로 계산 및 명세서에 표시됩니다. 현재 구현(엑셀 입력값 우선, fallback만 요율 자동계산)이 이미 요구사항을 충족하므로 별도 설정 UI는 불필요한 것으로 확인되었습니다. fix-task-0629 (26년 06월 29일 수정사항)

4-5. 회계·급여 정책

기본설정 > 회계·급여 정책 메뉴의 UI/CRUD가 완비되었으며, 주요 항목이 payroll_service.py:238-254에 이미 반영된 것을 확인하였습니다. 반영된 항목: salary_calc_start_day / salary_calc_end_day, salary_pay_day, salary_holiday_rule, annual_leave_basis. fix-task-0629 (26년 06월 29일 수정사항)

4-6. 중소기업 감면

중소기업 소득세 감면 기능이 UI→API→DB→급여계산까지 end-to-end로 동작합니다. fix-task-0629 (26년 06월 29일 수정사항)

항목내용
대상 여부 + 감면율UI·API·DB·급여계산 전 구간 연동 완료
감면기간 날짜 입력 UI시작일/종료일 date picker + 백엔드 필드 추가
급여명세서 표시소득세 항목에 감면율·원래세액·감면액 표시 추가
연간 한도 200만원 누적 체크미구현 (대부분 직원 한도 미도달, 추후 필요 시 구현)

5. 미완료 항목

급여대장 엑셀 다운로드 및 나야넷 양식

/admin/payroll/ledger 페이지에서 다음 두 가지 기능은 아직 미구현 상태입니다. fix-task-0623 (26년 06월 23일 수정사항)

  1. 1.엑셀 다운로드 — 급여대장 전체 데이터를 엑셀 파일로 내려받는 기능
  2. 2.나야넷 기본틀 양식 다운로드 — 나야넷 연동을 위한 표준 양식 파일 제공 기능

간이세액 비율 선택 UI 미구현

백엔드에 tax_rate_pct 컬럼(기본값 100)과 소득세 계산 시 비율 적용 로직은 구현되어 있으나, 프론트엔드 급여기초 페이지(/admin/payroll/base)의 "간이세액 (부양가족)" 영역에 비율 선택 입력이 없어 항상 100%로만 동작합니다. fix-task-0713 (26년 07월 13일 수정사항)

수정 대상: frontend/src/app/admin/payroll/base/page.tsx — "간이세액 (부양가족)" 영역에 80/100/120% 선택 드롭다운 또는 라디오 추가, 저장 시 tax_rate_pct 값 전송

도급직 auto_renew 기본값 수정 완료

도급직(CONTRACT_OUTSOURCE) 계약 생성 시 auto_renew=true가 기본값이었으나 법적 근거가 없어, 모든 계약 유형에서 auto_renew=False 기본값으로 통일되었습니다. 관리자가 명시적으로 선택한 경우에만 자동연장이 적용됩니다. 관련 내용은 근로계약서 스펙 참고. fix-task-0715 수정사항

수정 완료: backend/app/services/contract_service.py:627-629 — 도급직 자동연장 기본값 로직 제거

급여기초 관리 — 간이세액 비율 선택 UI 미구현 (07-14·07-15 재확인)

fix-task-0714 (26년 07월 14일 수정사항)fix-task-0715 수정사항에서도 동일 이슈가 재확인되었습니다. 백엔드 tax_rate_pct 컬럼 및 비율 적용 로직은 구현되어 있으나, 프론트엔드 /admin/payroll/base 페이지의 "간이세액 (부양가족)" 영역에 80/100/120% 선택 드롭다운 또는 라디오 입력이 없어 항상 100%로만 동작합니다. fix-task-0714 (26년 07월 14일 수정사항)


6. 개발자 의사결정 사항 (4가지)

Q1. 고정연장수당 + 실제연장수당 처리 정책

고정연장수당(FIXED_OVERTIME)이 있는 직원에게 실제 연장수당(PAY_OVERTIME)도 지급해야 하는 케이스가 있는가? 아니면 둘 중 하나만? fix-task-0623 (26년 06월 23일 수정사항)

선택지:

  • (A) 포괄임금제 해석: FIXED_OVERTIME은 월 고정 연장수당 약정. 실제 연장이 고정분을 초과하면 초과분만 PAY_OVERTIME 지급. 미초과 시 PAY_OVERTIME = 0.
  • (B) 현행 유지: 고정연장은 고정 수당, 실제연장은 근태 기반 별도 수당. 이중지급 허용 (회사 정책에 따라).
  • (C) 관리자 설정: PayItem 또는 근무 정책에 "고정연장 적용 시 근태연장 스킵" 플래그 추가.

Q2. 근로정책 변경 시 급여기초 자동갱신 vs 알림

근로정책이 변경되면 기존 직원의 급여기초(monthly_work_hours, hourly_wage)를 어떻게 처리할 것인가? fix-task-0623 (26년 06월 23일 수정사항)

선택지:

  • (A) 자동 갱신: update_work_policy() 후처리로 해당 정책 적용 직원의 EmployeePayBase 일괄 업데이트.
  • (B) 알림만: 관리자에게 "근로정책 변경됨, 급여기초 확인 필요" 알림 발송. 수동 갱신.
  • (C) 명세서 생성 시점 동적 조회: EmployeePayBase의 monthly_work_hours를 사용하지 않고, 명세서 생성 시 직원별 유효 근로정책에서 월 소정근로시간을 동적으로 가져옴.

Q3. 야간수당 배율 해석

야간수당 0.5배는 "추가 가산"의 의미이며, 근로정책의 night_surcharge_rate는 1.5(전체 배율)를 저장합니다. fix-task-0623 (26년 06월 23일 수정사항)

해석 혼동:

  • 일반 직원 야간근로: 기본급에 야간 미포함 → 가산분 0.5배만 지급 (현행)
  • 야간 전용 근무자: 기본급에 야간 미포함 → 1.5배 지급? 아니면 현행과 동일하게 0.5배?
  • night_surcharge_rate를 급여 계산에 사용할 경우, 가산분 = night_surcharge_rate - 1.0으로 변환해야 하는지?

검토 필요: 근무 정책 스펙에서 night_surcharge_rate의 의미 정의와 급여 계산 로직 간 일관성 확보.


Q4. 근로정책 할증률 직접 사용 여부

근로정책의 holiday_surcharge_rate, night_surcharge_rate를 급여 계산에 직접 사용할 것인가? fix-task-0623 (26년 06월 23일 수정사항)

현황:

  • 이 필드들은 근로정책 UI 표시용으로만 사용되고, 급여 계산에는 참조되지 않음.
  • 법정 할증률(연장 1.5, 야간 0.5 가산, 휴일 1.5, 휴일초과 2.0)은 근로기준법에 고정이므로, 정책별로 다르게 설정할 실익이 제한적.
  • 다만, 회사 자체 규정으로 법정 이상 할증을 적용하는 경우(예: 휴일 2.0배)에는 정책 참조가 필요.

결정 기준:

  1. 1.법정 최저 할증 보장 필수인가? (예: 휴일은 최소 1.5배)
  2. 2.회사 정책이 법정 이상 할증을 설정할 수 있도록 지원할 것인가?
  3. 3.근로정책 변경 → 급여 계산 자동 영향 범위는 어디까지인가?

7. 관련 페이지 및 스펙


8. E2E 테스트 시나리오 — 급여 정산·명세서 흐름

관리자(허빈)↔직원(김소민) 연계 시나리오 중 급여 관련 흐름입니다. 전체 시나리오는 E2E 테스트 시나리오 명세를 참고하세요. E2E 테스트 시나리오 - Part 3. 관리자↔사용자 연계 시나리오

5-1. 급여 정산 및 명세서 발행

#액터시나리오기대 결과비고
1허빈급여관리 > 급여기초에서 김소민의 급여 항목을 설정한다EmployeePayBase + EmployeePayDetail이 저장된다
2허빈급여관리 > 명세서에서 해당 월 명세서를 생성한다 (정산 기간, 지급일 설정)비동기 생성 잡이 실행되고, 김소민의 Payslip이 PAY_DRAFT 상태로 생성된다
3허빈명세서를 확정(confirm)한다PAY_CONFIRMED 상태로 변경된다
4허빈명세서를 발행(issue)한다PAY_ISSUED 상태로 변경되고, 김소민에게 "명세서 발행" 알림이 전송된다

5-2. 직원 명세서 확인 및 이의제기

#액터시나리오기대 결과비고
5김소민급여관리에서 해당 월 명세서를 조회한다급여 항목, 공제 항목, 실수령액이 표시된다PAY_ISSUED 상태부터 조회 가능
6김소민명세서 수신 확인 서명을 한다AuditSignature가 기록된다근기법 48조 교부 입증
7김소민명세서에 이의를 제기한다 (사유 입력)PayslipObjection이 생성되고, 관리자에게 알림이 전송된다
8허빈급여관리 > 이의제기에서 김소민의 이의를 확인하고 응답한다이의가 처리 완료된다
Made with CairniExplore public wikis →