labor_ledger 스키마
월별 노임대장 문서의 전체 스키마. 각 현장의 월별 근로자 출역/공수/임금/수수료를 집계 관리합니다.
저장 위치
doc_id는 연월을"YYYYMM"형식으로 고정 (예:"202601").- 문서는 현장의 출역(attendance_logs) 트리거 또는 출역 수정 시
init_labor_ledger()에 의해 자동 생성됩니다. companies/{company_id}/settings/tags문서에서labor_suppliers,commission설정을 초기값으로 복사해옵니다.
생성/갱신 흐름
출역 생성(attendance_logs)
→ init_labor_ledger (문서 없으면 생성)
→ add_labor_ledger_attendance_data (data[].attendance[day] += man_days)
→ 수수료(commission) 자동 계산 (auto_commission=True일 때)
출역 삭제(attendance_logs delete)
→ delete_labor_ledger_attendance_data (attendance[day] -= man_days)
→ attendance_id 전 일자가 모두 비면 해당 사용자 엔트리 pop
출역 수정(attendance_logs update)
→ 이전 데이터 delete → 새 데이터 add 2단계로 진행
→ 현장 변경(before_site_id != after_site_id) 시 두 현장 labor_ledger 모두 갱신
수동 수정 엔드포인트(change_labor_ledger_*) 는 전체 문서를 get → in-memory 수정 → update로 덮어쓰는 방식입니다.
문서 필드
| 필드 | 타입 | 설명 |
|---|---|---|
company_name |
string | 노임대장 생성 시점의 회사명 (엑셀 헤더용) |
site_name |
string | 현장명 |
supervisor_name |
string | 현장 대리인 이름 |
tag_settings |
object | 업체/수수료 설정 — 아래 TagSettings 참조 |
custom_commissions |
array | (예약 필드) 사용자별 커스텀 수수료 |
fields |
string[] | 이 대장에 등장한 field(직종) 목록 (중복 제거) |
tags |
string[] | 이 대장에 등장한 labor_supplier(업체) 목록 (중복 제거) |
data |
UserEntry[] | 근로자별 엔트리 배열 |
field_sum |
object | 직종별 일자별 공수 합계 — 아래 FieldSum / TagSum 참조 |
tag_sum |
object | 업체별 일자별 공수 합계 |
TagSettings
{
"labor_suppliers": ["A업체", "B업체"],
"commission": [
{ "type": "amount", "value": 10000 },
{ "type": "percent", "value": 0.05 }
]
}
| 필드 | 타입 | 설명 |
|---|---|---|
labor_suppliers |
string[] | 인력 공급업체 태그 배열. 인덱스 기준으로 commission과 매칭 |
commission |
object[] | 각 업체별 수수료 규칙 (길이는 labor_suppliers와 동일) |
commission[].type |
string | "amount"(고정 금액) | "percent"(비율) |
commission[].value |
number | type=amount이면 원 단위, type=percent이면 비율(0~1) |
수수료 계산식 (calculate_commission):
- type=amount: value × man_days_sum (원)
- type=percent: value × man_days_sum × wage_rate (= 비율 × 총 인건비)
- 업체가 labor_suppliers에 없거나 "없음"이면 0원
UserEntry
data[] 배열의 각 엔트리로, 한 근로자의 월 단위 출역/임금/수수료 레코드.
{
"UID": "uid_worker_1",
"field": "철근",
"labor_supplier": "A업체",
"name": "홍길동",
"birth": "1985-03-15T00:00:00Z",
"sex": "male",
"main_address": "서울특별시 강남구",
"sub_address_enc": "AES(...)",
"phone_enc": "AES(...)",
"phone_masked": "010-****-5678",
"wage_rate": 180000,
"attendance_source": "company",
"attendance": [0, 1, 1, 0.5, 0, ...],
"attendance_id": {
"0": [],
"1": ["log_id_1", "log_id_2"],
...
},
"man_days_sum": 2.5,
"commission": 25000,
"auto_commission": true,
"field_sum": {},
"tag_sum": {}
}
| 필드 | 타입 | 단위 | 설명 |
|---|---|---|---|
UID |
string | - | 근로자 UID (매칭 키) |
field |
string | - | 직종 (예: "철근", "형틀", "없음") |
labor_supplier |
string | - | 공급 업체명 (없으면 "없음") |
name |
string | - | 근로자 이름 (당시 값 스냅샷) |
birth |
timestamp? | - | 생년월일 (엑셀 주민번호 생성에 사용) |
sex |
string? | - | "male" | "female" |
main_address |
string? | - | 주소 (평문) |
sub_address_enc |
string? | - | 상세주소 AES 암호화 |
phone_enc |
string? | - | 전화번호 AES 암호화 |
phone_masked |
string? | - | "010-****-XXXX" 마스킹 표시용 |
wage_rate |
int | 원/공수 | 단가 (1공수 기준 금액) |
attendance_source |
string | - | "company"(회사 attendance_logs) | "site"(현장 attendance_logs) |
attendance |
number[31] | 공수 | 일자별 공수 배열. 인덱스 i = 그 달 i+1일 |
attendance_id |
map | - | 일자별 원본 attendance_log id 배열. 키는 "0"~"30" 문자열 |
man_days_sum |
number | 공수 | sum(attendance) (월 총공수) |
commission |
int | 원 | 수수료 금액. auto_commission=true이면 자동 계산 |
auto_commission |
bool | - | true: calculate_commission으로 자동 갱신 / false: 수동 입력값 유지 |
field_sum |
object | - | (과거 필드, 현재 미사용 — 문서 최상위 field_sum에 집계) |
tag_sum |
object | - | (과거 필드, 현재 미사용) |
매칭 규칙: find_matching_index는 현재 UID 단독으로 비교합니다(기존 field/tags까지 비교하던 로직은 주석 처리됨). 즉 한 UID는 labor_ledger 당 1개 엔트리.
FieldSum / TagSum
{
"field_sum": {
"철근": [0, 2, 3, 0, ...],
"형틀": [1, 1, 0, 0, ...],
"없음": [0, 0, 0, 0, ...]
},
"tag_sum": {
"A업체": [1, 3, 2, 0, ...],
"B업체": [0, 0, 1, 0, ...],
"없음": [0, 0, 0, 0, ...]
}
}
- 문서 최상위 필드.
- 키: 직종명 / 업체명. 값: 길이 31의 공수 합계 배열.
calculate_tag_field_sum이data[]를 순회하여 일자별 합계를 재계산 후 저장.
수동 수정 엔드포인트 매트릭스
| 엔드포인트 | 수정 대상 필드 |
|---|---|
change_labor_ledger_meta_data |
company_name, site_name, supervisor_name |
change_labor_ledger_user_data |
data[].field, labor_supplier, phone_enc, sub_address_enc, main_address, phone_masked (+ 자동 수수료 재계산 + field_sum/tag_sum 재집계) |
change_labor_ledger_user_wage |
data[].wage_rate, commission, auto_commission (new_commission == -1이면 자동계산 모드로 전환) |
change_labor_ledger_tag_data |
tag_settings.labor_suppliers, tag_settings.commission (+ 모든 auto_commission=true 사용자의 수수료 재계산) |
엑셀 출력
create_labor_ledger_excel 엔드포인트는 labor_ledger 문서를 읽어 업체(tags)별로 시트를 분리한 엑셀(.xlsx)을 생성하고 Firebase Storage에 업로드한 뒤 signed URL을 반환합니다.
- 저장 경로:
companies/{company_id}/sites/{site_id}/labor_ledger/{site_name}_{YYYYMM}.xlsx - signed URL 유효기간: 10분
예시 문서
{
"company_name": "건설24 주식회사",
"site_name": "판교 오피스 신축",
"supervisor_name": "김대리",
"tag_settings": {
"labor_suppliers": ["A업체", "B업체"],
"commission": [
{ "type": "amount", "value": 10000 },
{ "type": "percent", "value": 0.05 }
]
},
"custom_commissions": [],
"fields": ["철근", "형틀"],
"tags": ["A업체", "B업체"],
"data": [
{
"UID": "uid_worker_1",
"field": "철근",
"labor_supplier": "A업체",
"name": "홍길동",
"wage_rate": 180000,
"attendance_source": "company",
"attendance": [0, 1, 1, 0.5, 0, "... (31 길이)"],
"attendance_id": { "0": [], "1": ["log_1"], "2": ["log_2"], "3": ["log_3"] },
"man_days_sum": 2.5,
"commission": 25000,
"auto_commission": true
}
],
"field_sum": {
"철근": [0, 1, 1, 0.5, 0, "..."],
"형틀": [0, 0, 0, 0, 0, "..."]
},
"tag_sum": {
"A업체": [0, 1, 1, 0.5, 0, "..."],
"B업체": [0, 0, 0, 0, 0, "..."]
}
}