급여대장 데이터 프로비넌스
원천 엔티티는 관측값만 보관합니다.
OvertimeRecord,FixedIncentive,EducationSubsidy,LeaveRequest,ResignationRecord,YearEndSettlement에는 계산된 금액 필드가 없습니다. 모든 금액은AllowanceRecord/DeductionRecord에서만 관리되며, 이 레코드들은 시트의 "✓ 커밋" 작업 결과로만 생성되어 시트 계보(sourceSheetId/sourceSheetRowId/sourceSheetColumnKey,NOT NULL)를 가집니다. 보험/세금/수당 금액은 컬럼별 계산기가 산출하며, 그 파라미터는 시트 컬럼 메타데이터 + 조직 파라미터 저장소에 보관됩니다. 참고: Payroll Schema Refactor
급여대장(PayrollRecord) 생성에 관여하는 모든 테이블의 컬럼 정의, 데이터 흐름, AllowanceRecord-as-atom 아키텍처를 기록합니다.
아키텍처 원칙
AllowanceRecord가 모든 지급의 원자(atom)입니다. 기본급, 초과근무수당, 각종 수당, 인센티브 등 모든 지급 항목은 개별 AllowanceRecord로 생성됩니다. 보험료, 세금, 정산 등 모든 공제 항목은 개별 DeductionRecord로 생성됩니다. PayrollRecord는 이 원자 레코드들을 FK로 연결하는 헤더이며, 캐시된 합계를 저장합니다.
추가전용(Append-Only) 메타 테이블
모든 메타 테이블(EmploymentContract, OvertimeRecord, FixedIncentive, YearEndSettlement, EducationSubsidy, ResignationRecord)은 추가전용입니다. 내용을 직접 수정하지 않고, 새 버전 행을 삽입하며 이전 행에 supersededAt를 설정합니다. 이를 통해 전체 변경 이력이 보존됩니다.
| 컬럼 | 타입 | 용도 |
|---|---|---|
chainId | uuid | 동일 논리 엔티티의 모든 버전을 그룹화 |
version | integer | 체인 내 단조 증가 (1부터 시작) |
supersededAt | timestamp, nullable | NULL = 현재 버전; 새 버전 삽입 시 설정됨 |
- 내용 변경 (금액, 날짜, 요율): 새 버전 생성 (
version + 1, 동일chainId) - 상태 변경 (pending → approved → paid): 동일 행에 직접 메타데이터 업데이트
- 조회 패턴: 현재 버전만 조회 시
WHERE supersededAt IS NULL - 이력 조회:
WHERE chainId = :chainId ORDER BY version DESC로 전체 감사 추적
프로비넌스 추적
AllowanceRecord와 DeductionRecord는 어떤 메타 테이블 행이 자신을 생성했는지 추적합니다:
| 컬럼 | 타입 | 용도 |
|---|---|---|
sourceType | enum (PayrollSourceType) | 어떤 메타 테이블이 이 레코드를 생성했는지 |
sourceId | uuid, nullable | 특정 메타 테이블 행 ID (집계된 원천의 경우 null) |
PayrollSourceType 값 (packages/core/src/enums/payroll.enum.ts): employment_contract, overtime_record, fixed_incentive, education_subsidy, year_end_settlement, resignation_record, payroll_rate_config, tax_bracket_config, manual
전체 데이터 흐름도
핵심 불변식 (2026-08-13 검증): 금액 원자
AllowanceRecord/DeductionRecord는 오직 시트 커밋(commitSheet)에서만 생성된다.generateForPeriod는 원자를 만들지도 지우지도 않고,PayrollRecord헤더 스냅샷을 만들어 기존 원자를payrollRecordId로 링크만 한다. (이 문서의 이전 버전은generateForPeriod가isAutoGenerated로 필터해 원자를 생성·삭제한다고 기술했으나 이는 틀렸고 위험하다 — 아래 흐름 참조.)
흐름: 시트 커밋 vs 스냅샷 생성
금액 원자 생성 = 시트 커밋 (commitSheet)
AllowanceRecord/DeductionRecord는 오직 시트 "✓ 커밋"에서 생성된다.compute.ts가 원천 관측을 승인 상태 게이트(예: 초과근무status IN ('approved','report_pending','report_approved','report_rejected'))로 SQL 집계하고,commitSheet가 그 결과를 AR/DR로 기록한다(isAutoGenerated = true).- 재커밋: 해당
sourceSheetId의 기존 AR/DR을deletedAt으로 soft-delete한 뒤 재삽입한다(전부isAutoGenerated = true). - 정산 라이터(연말정산·퇴직정산)만
isAutoGenerated = false로 AR/DR을 쓴다 — 이는 "수동 입력"이 아니라 "정산 계열 출력"이라는 뜻이며, 자체 cancel-cleanup 게이트로 쓰인다.
generateForPeriod (PayrollRecord 스냅샷 전용 — 원자 삭제 안 함)
- 해당 기간이 이미
CONFIRMED면 차단(PRECONDITION_FAILED). - 기간의 낡은 PayrollRecord만 삭제. AR/DR은 삭제하지 않음 —
payrollRecordId = NULL로 unlink만. PayrollRecord헤더(캐시 요약 합계) 재생성.- 기간의 모든 AR/DR을
payrollRecordId로 재링크.
⚠️ 하지 말 것:
isAutoGenerated = true필터로 AR/DR을 삭제·재생성하는 로직을generateForPeriod에 되살리지 말 것. 그 필터는 의도적으로 제거됐다 — AR/DR은 시트 커밋 산출물이라 여기서 지우면 시트가 커밋한 급여 데이터가 소실된다. 근거:packages/api/src/routers/payroll.router.ts의generateForPeriod인라인 주석 +.claude/rules/payroll/korean-payroll-compliance.md.
⚠️ 구현 모호점 · 하드닝 후보 (2026-08-13 감사)
- 초과근무 집계 이중 경로(SSOT 미정) — 실 급여 경로는
sheet-rows/compute.ts(SQL, 상태 게이트)이나, 별도OvertimeRecordCalculator(packages/api/src/calculators/overtime-record.calculator.ts)는 status 필터 없이supersededAt IS NULL만으로 합산한다. 현재는 Module Manager 상태 조회에서만 생성되어 급여를 만들지 않지만, 급여 경로로 재배선하면 대기·취소 초과근무가 새어든다 → 재배선 시status게이트 필수. compute.ts가report_rejected(보고서반려)를 급여에 포함 — 주석("pending/rejected/cancelled 제외")과 IN 목록이 불일치. 정책 문서("보고서 승인 시점 반영")와 어긋남 → 반영 기준 확정 필요.isAutoGenerated = false= "정산 라이터 출력"(수동 아님) — cancel-cleanup 분기 수정 시 오해 주의.- 휴일 마스터 ↔ 휴일수당 계산 미연결 —
OrganizationHoliday는 존재(연차·출근율 소비)하나 휴일수당 계산 경로는 미소비 — 수동HOLIDAY/Shift.treatAsHoliday로만 발생. 연결 여부 판단 필요. - NIGHT/HOLIDAY_NIGHT 유효 2.0x 이중 버킷 — 버킷 누락 시 조용한 과소지급(과거 2회 재발). 모듈 레벨 회귀 가드는 신설됨(
packages/api/src/calculators/payroll-correctness.test.ts) — 계산기 레벨 카테고리→버킷 매핑과 국민연금 상·하한(cap/floor)은 여전히 미커버.
1. Employee (직원)
테이블: employees
| 컬럼 | 타입 | 급여대장 사용 |
|---|---|---|
id | uuid (PK) | AllowanceRecord.employeeId FK |
employeeNumber | string, unique | UI 표시, eCount name 조회 |
firstName / lastName | string | eCount export: ${lastName}${firstName} |
status | enum | 급여 생성 대상 필터 (ACTIVE만) |
organizationId | uuid (FK) | 멀티테넌시 필터 |
2. EmploymentContract (근로계약)
테이블: employment_contracts — 메타 테이블. AllowanceRecord 생성의 입력 데이터.
| 컬럼 | 타입 | 급여대장 사용 |
|---|---|---|
baseSalary | decimal(15,2) | → AllowanceRecord (itemCode 01 월급여) |
allowances | jsonb | → AllowanceRecords (식대→19, 교통비→14, 주거비→14) |
salaryGradeId | uuid (FK) | SalaryGrade 참조 |
isActive | boolean | 활성 계약만 사용 |
3. OvertimeRecord (초과근무 기록)
테이블: overtime_records — 원시 관측 테이블. 금액은 OvertimeRecordCalculator가 계산(overtimeHours × Contract.baseSalary/209 × 배수 — 배수는 시트 컬럼/조직 파라미터 저장소에서 가져옴)해 시트 커밋 시 AllowanceRecord에 기록합니다.
| 컬럼 | 타입 | 급여대장 사용 |
|---|---|---|
employeeId | uuid (FK) | 집계 키 |
workDate | date | 기간 필터 |
overtimeHours | decimal(7,2) | → 계산기 입력 |
mealBreakHours | decimal(7,2) | 식사시간 차감 |
category | enum | 카테고리 → AllowanceRecord itemCode 결정 |
status | enum | 시트 집계 게이트: approved / report_pending / report_approved / report_rejected (sheet-rows/compute.ts) |
hourlyRate | decimal(15,2) | (제거예정) — 계산 시 재계산 |
multiplier | decimal(5,2) | (제거된 컬럼) — 값은 이제 시트 컬럼/조직 파라미터 저장소에 보관 |
calculatedPay | decimal(15,2) | (제거예정) — AllowanceRecord.amount에 보관 |
카테고리 → AllowanceRecord ItemCode (레거시 — 마이그레이션 1816 이전)
⚠️ 레거시 매핑. 마이그레이션 1816 이후
AllowanceRecord에는 item-code FK가 없다 — 레코드는targetSheetSlug/targetColumnKey로 시트 컬럼을 가리키며, eCount A/D 코드 분류는 export 시점에 수행된다. 아래 표는 폐기된 고정 매핑 기록이다(HOLIDAY_NIGHT도입 전 표 — HOLIDAY_NIGHT은 휴일 1.5 + 야간 0.5 버킷 합산).
| category | AllowanceRecord itemCode | 항목명 |
|---|---|---|
WEEKDAY | 10 | 연장근무수당1 |
NIGHT | 12 | 연장근무수당2 |
SATURDAY | 13 | 야간근무수당1 |
HOLIDAY | 09 | 휴일근무수당 |
4. AllowanceRecord (수당 기록 — 원자)
테이블: allowance_records — 모든 지급의 원자(atom). 단일 진실 공급원.
| 컬럼 | 타입 | 사용 |
|---|---|---|
id | uuid (PK) | 기본키 |
employeeId | uuid (FK) | 직원 참조 |
year / month | number | 기간 |
amount | decimal(15,2) | 지급 금액 |
type | enum | AllowanceType (자동생성 시 OTHER) |
paymentMethod | enum | SALARY: 급여 포함 |
reason | string | 사람이 읽을 수 있는 설명 |
status | enum | APPROVED / PAID |
itemCodeId | uuid (FK) | AllowanceItemCode FK (eCount 코드) |
payrollRecordId | uuid (FK) | PayrollRecord FK (generate 시 연결) |
isAutoGenerated | boolean | true = 시트 커밋 출력(commitSheet); false = 정산 라이터(연말/퇴직), "수동"이 아님 |
sourceType | enum | PayrollSourceType — 어떤 메타 테이블이 생성했는지 |
sourceId | uuid, nullable | 특정 메타 행 ID (집계 원천의 경우 null) |
organizationId | uuid (FK) | 멀티테넌시 |
시트 커밋 AllowanceRecords (commitSheet)
| 데이터 원천 | itemCode | reason | 금액 | sourceType | sourceId |
|---|---|---|---|---|---|
| Contract.baseSalary | 01 | 월급여 | baseSalary | employment_contract | contract.id |
| OvertimeRecord (WEEKDAY) | 10 | 연장근무수당1 | Σ calculatedPay | overtime_record | null |
| OvertimeRecord (NIGHT) | 12 | 연장근무수당2 | Σ calculatedPay | overtime_record | null |
| OvertimeRecord (SATURDAY) | 13 | 야간근무수당1 | Σ calculatedPay | overtime_record | null |
| OvertimeRecord (HOLIDAY) | 09 | 휴일근무수당 | Σ calculatedPay | overtime_record | null |
| Contract.allowances.meal | 19 | 식대 | 식대 금액 | employment_contract | contract.id |
| Contract.allowances.transportation | 14 | 교통비 | 교통비 금액 | employment_contract | contract.id |
| Contract.allowances.housing | 14 | 주거비 | 주거비 금액 | employment_contract | contract.id |
| FixedIncentive | 23 | 간호간병평가인센티브 | Σ totalAmount | fixed_incentive | null |
5. DeductionRecord (공제 기록 — 원자)
테이블: deduction_records — 모든 공제의 원자(atom). 단일 진실 공급원.
| 컬럼 | 타입 | 사용 |
|---|---|---|
id | uuid (PK) | 기본키 |
employeeId | uuid (FK) | 직원 참조 |
year / month | number | 기간 |
amount | decimal(15,2) | 공제 금액 |
reason | string | 사람이 읽을 수 있는 설명 |
status | enum | APPROVED / APPLIED |
itemCodeId | uuid (FK) | DeductionItemCode FK (eCount 코드) |
payrollRecordId | uuid (FK) | PayrollRecord FK (generate 시 연결) |
isAutoGenerated | boolean | true = 시트 커밋 출력(commitSheet); false = 정산 라이터(연말/퇴직), "수동"이 아님 |
sourceType | enum | PayrollSourceType — 어떤 메타 테이블이 생성했는지 |
sourceId | uuid, nullable | 특정 메타 행 ID (집계 원천의 경우 null) |
organizationId | uuid (FK) | 멀티테넌시 |
시트 커밋 DeductionRecords (commitSheet)
보험 요율은
InsuranceCalculator에 바인딩된 조직 파라미터 저장소/시트 컬럼에서 가져오며, 행은 시트 커밋 시 기록됩니다.
| 데이터 원천 | itemCode | reason | 계산 공식 |
|---|---|---|---|
| InsuranceCalculator | 03 | 국민연금 | round(clamp(base, floor, cap) × rate) |
| InsuranceCalculator | 04 | 건강보험 | round(baseSalary × rate) |
| InsuranceCalculator | 05 | 고용보험 | round(baseSalary × rate) |
| InsuranceCalculator | 20 | 장기요양보험 | round(baseSalary × rate) |
| TaxBracketConfig | 01 | 소득세 | round((과세소득 × 세율 - 누진공제) / 12) |
| TaxBracketConfig | 02 | 주민세 | round(소득세 × 0.10) |
6. FixedIncentive (고정 인센티브)
테이블: fixed_incentives — 메타 테이블. AllowanceRecord 생성의 입력 데이터.
| 컬럼 | 타입 | 급여대장 사용 |
|---|---|---|
employeeId | uuid (FK) | 집계 키 |
year / month | number | 기간 필터 |
unitPrice | decimal(15,2) | 단가 |
unitCount | int | 단위 수량 |
totalAmount | decimal(15,2) | → AllowanceRecord (itemCode 23) |
category | enum | 인센티브 카테고리 (재활, 간호 등) |
7. YearEndSettlement (연말정산)
테이블: year_end_settlements — 원시 관측/라이프사이클 테이블. 조정 금액은 시트 커밋 시 DeductionRecord 행으로 생성됩니다. 분할 납부 계획은 시트 컬럼/조직 파라미터 저장소에 설정합니다.
| 컬럼 | 타입 | 급여대장 사용 |
|---|---|---|
employeeId | uuid (FK) | 직원 참조 |
settlementYear | number | 정산 연도 |
applicationDate | date, nullable | 조정 적용 일자 |
applicationMonth | number, nullable | 적용 급여 월 |
status | enum | PENDING → CALCULATED → APPROVED → APPLIED → COMPLETED |
adjustmentAmount | decimal(15,2) | (제거예정) — DeductionRecord.amount (itemCode 10)로 이동 |
installmentMonths | number | (제거된 컬럼) — 분할 계획은 이제 시트 컬럼/조직 파라미터 저장소에 보관 |
installmentAmount | decimal(15,2) | (제거예정) — adjustmentAmount / installmentMonths로 파생 |
8. EducationSubsidy (교육보조금)
테이블: education_subsidies — 원시 관측/라이프사이클 테이블. 보조금 금액은 EducationSubsidyCalculator를 통해 시트 커밋 시 AllowanceRecord로 생성됩니다. 단가(교육과정 유형별)는 시트 컬럼/조직 파라미터 저장소에 설정합니다.
| 컬럼 | 타입 | 급여대장 사용 |
|---|---|---|
employeeId | uuid (FK) | 직원 참조 |
courseName | string | 교육과정 식별 |
paymentDate | date | 지급 시점 |
receiptVerified | boolean | 영수증 확인 상태 |
status | enum | PENDING → APPROVED → PAID → CANCELLED |
courseAmount | decimal(15,2) | (제거예정) — AllowanceRecord.amount로 이동 |
9. ResignationRecord (퇴직정산)
테이블: resignation_records — 원시 관측/라이프사이클 테이블. 정산 금액은 ResignationRecordCalculator를 통해 개별 AllowanceRecord / DeductionRecord 행으로 분해됩니다.
| 컬럼 | 타입 | 급여대장 사용 |
|---|---|---|
employeeId | uuid (FK) | 직원 참조 |
resignationDate | date | 퇴직일 |
reason | string, nullable | 퇴직 사유 |
status | enum | PENDING → PROCESSING → SETTLED → COMPLETED |
settlementAmount | decimal(15,2) | (제거예정) — 개별 원장 행으로 분해 |
healthInsuranceRecon | decimal(15,2) | (제거예정) — DeductionRecord itemCode 12 |
yearEndRecon | decimal(15,2) | (제거예정) — DeductionRecord itemCode 10 |
annualLeavePayout | decimal(15,2) | (제거예정) — AllowanceRecord itemCode 17 |
unusedLeaveDays | decimal(5,2) | (제거예정) — 연차 발생 − 사용에서 파생 |
totalSettlement | decimal(15,2) | (제거예정) — 원장 행 합계 |
10. 4대보험 요율
4대보험 요율(국민연금/건강보험/고용보험/장기요양보험 근로자 요율, 국민연금 상·하한)은 InsuranceCalculator가 조직 파라미터 저장소의 payroll_rate_config codeModule 키에서 읽으며, 해당 공제 컬럼을 보험 계산기에 바인딩하는 시트 컬럼 메타데이터와 함께 사용됩니다. 계산된 금액은 시트 커밋("✓ 커밋") 시에만 DeductionRecord로 기록되며 시트 계보 3종을 가집니다. 참고: Payroll Schema Refactor.
11. TaxBracketConfig (소득세 구간)
테이블: tax_bracket_configs
| 컬럼 | 타입 | 급여대장 사용 |
|---|---|---|
minIncome / maxIncome | decimal(15,2) | 구간 판별 |
rate | decimal(8,4) | → DeductionRecord 금액 계산 |
deduction | decimal(15,2) | → 누진공제 |
effectiveYear | number | 연도 필터 |
12–16. 참조 테이블
SalaryGrade (salary_grades)
호봉별 급여 정의. EmploymentContract.salaryGradeId를 통한 간접 참조.
AllowanceItemCode (allowance_item_codes)
eCount 수당 항목코드 마스터. AllowanceRecord.itemCodeId FK.
DeductionItemCode (deduction_item_codes)
eCount 공제 항목코드 마스터. DeductionRecord.itemCodeId FK.
17. PayrollRecord (급여대장 헤더)
테이블: payroll_records — AllowanceRecord/DeductionRecord를 연결하는 헤더 레코드. 월별/직원별 1레코드.
관계
| 관계 | 타입 | 설명 |
|---|---|---|
allowanceRecords | OneToMany → AllowanceRecord | 이 급여의 모든 지급 |
deductionRecords | OneToMany → DeductionRecord | 이 급여의 모든 공제 |
details | OneToMany → PayrollDetail | 항목별 상세 (하위호환) |
캐시된 합계 필드
생성 시 연결된 AllowanceRecords/DeductionRecords에서 계산된 값:
| 컬럼 | 타입 | 계산 원천 |
|---|---|---|
baseSalary | decimal(15,2) | AllowanceRecord (itemCode 01) |
overtimePay | decimal(15,2) | AllowanceRecord (itemCode 10) |
nightDifferential | decimal(15,2) | AllowanceRecord (itemCode 12) |
weekendDifferential | decimal(15,2) | AllowanceRecord (itemCode 13) |
holidayDifferential | decimal(15,2) | AllowanceRecord (itemCode 09) |
allowances | jsonb | AllowanceRecords (식대 등) |
totalEarnings | decimal(15,2) | Σ 전체 AllowanceRecords |
nationalPension | decimal(15,2) | DeductionRecord (itemCode 03) |
healthInsurance | decimal(15,2) | DeductionRecord (itemCode 04) |
employmentInsurance | decimal(15,2) | DeductionRecord (itemCode 05) |
longTermCareInsurance | decimal(15,2) | DeductionRecord (itemCode 20) |
incomeTax | decimal(15,2) | DeductionRecord (itemCode 01) |
localIncomeTax | decimal(15,2) | DeductionRecord (itemCode 02) |
totalDeductions | decimal(15,2) | Σ 전체 DeductionRecords |
netPay | decimal(15,2) | totalEarnings - totalDeductions |
상태 및 승인
| 컬럼 | 타입 | 사용처 |
|---|---|---|
status | enum | DRAFT→APPROVED→CONFIRMED→PAID |
paymentDate | date | 생성 시 25일로 설정 |
approvedBy / approvedAt | string / timestamp | 승인 워크플로우 |
confirmedBy / confirmedAt | string / timestamp | 확정 워크플로우 |
paidAt | timestamp | 지급 처리 |
18. PayrollDetail (급여 상세)
테이블: payroll_details — PayrollRecord의 항목별 상세 내역 (하위호환).
| 컬럼 | 타입 | 설명 |
|---|---|---|
payrollRecordId | uuid (FK) | 급여 레코드 |
itemCode | string | 항목 코드 (BASE_SALARY, OVERTIME 등) |
itemName | string | 항목명 (기본급, 초과근무수당 등) |
itemType | enum | EARNING / DEDUCTION / ADJUSTMENT |
category | enum | BASE_SALARY / OVERTIME / ALLOWANCE / TAX / INSURANCE 등 |
amount | decimal(15,2) | 금액 |
19. eCount Export
eCount export는 AllowanceRecord와 DeductionRecord 테이블에서 직접 읽습니다. PayrollRecord 필드가 아닌, (employeeId, itemCodeId) 별 집계를 사용합니다.
A-Codes (수당) — allowance_item_codes
| 코드 | 항목명 | 원천 |
|---|---|---|
| A01 | 월급여 | AllowanceRecord (itemCode 01) |
| A02 | 초과수당 | AllowanceRecord (itemCode 02) |
| A03 | 직책수당 | AllowanceRecord (itemCode 03) |
| A04 | 면허자격수당 | AllowanceRecord (itemCode 04) |
| A05 | 위험수당 | AllowanceRecord (itemCode 05) |
| A06 | 장기근속수당 | AllowanceRecord (itemCode 06) |
| A07 | 나이트수당1 - 간호사 | AllowanceRecord (itemCode 07) |
| A08 | 나이트수당2 - 요양보호사 | AllowanceRecord (itemCode 08) |
| A09 | 휴일근무수당 | AllowanceRecord (itemCode 09) |
| A10 | 연장근무수당1 | AllowanceRecord (itemCode 10) |
| A11 | 특별수당 | AllowanceRecord (itemCode 11) |
| A12 | 연장근무수당2 | AllowanceRecord (itemCode 12) |
| A13 | 야간근무수당1 | AllowanceRecord (itemCode 13) |
| A14 | 기타 | AllowanceRecord (itemCode 14) |
| A16 | 호봉수당 | AllowanceRecord (itemCode 16) |
| A17 | 연차수당 (퇴사자) | AllowanceRecord (itemCode 17) |
| A19 | 식대 | AllowanceRecord (itemCode 19) |
| A20 | 상여 | AllowanceRecord (itemCode 20) |
| A21 | 특별수당1 | AllowanceRecord (itemCode 21) |
| A23 | 간호간병평가인센티브 | AllowanceRecord (itemCode 23) |
| A24 | 내일채움공제 | AllowanceRecord (itemCode 24) |
D-Codes (공제) — deduction_item_codes
| 코드 | 항목명 | 원천 |
|---|---|---|
| D01 | 소득세 | DeductionRecord (itemCode 01) |
| D02 | 주민세 | DeductionRecord (itemCode 02) |
| D03 | 국민연금 | DeductionRecord (itemCode 03) |
| D04 | 건강보험 | DeductionRecord (itemCode 04) |
| D05 | 고용보험 | DeductionRecord (itemCode 05) |
| D06 | 퇴직정산 | DeductionRecord (itemCode 06) |
| D08 | 기타공제 | DeductionRecord (itemCode 08) |
| D10 | 연말정산 | DeductionRecord (itemCode 10) |
| D11 | 건강, 장기연말정산 | DeductionRecord (itemCode 11) |
| D12 | 건강, 장기퇴직정산 | DeductionRecord (itemCode 12) |
| D13 | 고용보험정산 | DeductionRecord (itemCode 13) |
| D20 | 장기요양보험 | DeductionRecord (itemCode 20) |
계산 공식 요약
지급 (AllowanceRecords)
───────────────────────────────────────
계약에서 자동생성:
월급여 (01) = Contract.baseSalary
식대 (19) = Contract.allowances.meal
교통비 (14) = Contract.allowances.transportation
주거비 (14) = Contract.allowances.housing
초과근무에서 자동생성:
연장근무수당1 (10) = Σ OvertimeRecord(WEEKDAY).calculatedPay
연장근무수당2 (12) = Σ OvertimeRecord(NIGHT).calculatedPay
야간근무수당1 (13) = Σ OvertimeRecord(SATURDAY).calculatedPay
휴일근무수당 (09) = Σ OvertimeRecord(HOLIDAY).calculatedPay
인센티브에서 자동생성:
인센티브 (23) = Σ FixedIncentive.totalAmount
수동 AllowanceRecords:
(각종 itemCode, 승인 워크플로우를 통해 생성)
totalEarnings = Σ 전체 AllowanceRecords (자동 + 수동)
공제 (DeductionRecords)
───────────────────────────────────────
자동생성 (보험):
국민연금 (03) = round(clamp(baseSalary, floor, cap) × rate)
건강보험 (04) = round(baseSalary × rate)
고용보험 (05) = round(baseSalary × rate)
장기요양보험 (20) = round(baseSalary × rate)
자동생성 (세금):
과세소득 = totalEarnings - 보험료합계
소득세 (01) = round((과세소득 × 세율 - 누진공제) / 12)
주민세 (02) = round(소득세 × 0.10)
수동 DeductionRecords:
(각종 itemCode, 승인 워크플로우를 통해 생성)
totalDeductions = Σ 전체 DeductionRecords (자동 + 수동)
순지급액
───────────────────────────────────────
netPay = totalEarnings - totalDeductions