정산 시스템 로직

DPSP (Delivery Partner Settlement Platform) 정산 파이프라인의 전체 로직을 정리한 문서입니다. 쿠팡이츠와 배민 플랫폼의 익일정산/주간정산 계산 로직, 라이더 매칭, 배치 관리, 인센티브 시스템을 포함합니다.

0. 전체 파이프라인 개요

정산 처리는 아래 단계를 순서대로 거칩니다.

┌─────────────────────────────────────────────────────────────────────┐ │ STEP 1: Excel 업로드 │ │ 플랫폼(쿠팡/배민)에서 제공하는 정산서 Excel 파일 업로드 │ │ → settlement_file_uploads 테이블에 기록 (status: pending) │ └───────────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────────▼─────────────────────────────────────┐ │ STEP 2: 파싱 (Parser) │ │ 플랫폼/정산유형별 Parser가 Excel 시트 데이터를 추출 │ │ ├─ 쿠팡: 종합/오더상세/지원금/추가지원금/차감/미션/시간제보험 │ │ └─ 배민: 배달내역상세 (일정산) / 을지시트+프로모션+관리비 (주정산) │ └───────────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────────▼─────────────────────────────────────┐ │ STEP 3: 라이더 매칭 (4단계) │ │ Excel 상의 이름/ID를 DB 라이더에 매핑 │ │ LICENSE_ID(100) → NAME_PHONE(80) → NAME_ONLY_INFERRED(60) │ │ → NAME_ONLY(40) → 실패 시 Dead Letter │ └───────────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────────▼─────────────────────────────────────┐ │ STEP 4: 배치 생성 + 정산 계산 │ │ settlement_batches (status: draft → calculated) │ │ Calculator가 공제/세금/수수료 계산 → settlement_details 저장 │ └───────────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────────▼─────────────────────────────────────┐ │ STEP 5: 검토 → 인센티브 적용 → 승인 │ │ calculated → reviewed → incentive_applied → approved │ │ CINR 규칙에 따라 company_incentive 반영 │ └───────────────────────────────┬─────────────────────────────────────┘ │ ┌───────────────────────────────▼─────────────────────────────────────┐ │ STEP 6: 이체 준비 → 완료 │ │ approved → transfer_ready → completed │ │ transfer_records 생성 (은행 계좌 스냅샷, 이체 금액) │ └─────────────────────────────────────────────────────────────────────┘

1. 익일정산 - 쿠팡

INPUT

쿠팡이츠 일정산서 Excel 파일 (7개 시트)

일정산서 - 종합

일정산서 - 오더별 상세 내역서

일정산서 - 지원금

일정산서 - 추가지원금

일정산서 - 차감내역

일정산서 - 협력사 자체 미션

일정산서 - 시간제보험

로직

데이터 특성

기본 요율 (시스템 기본값)

항목비율비고
고용보험료0.8% (0.008)기사부담분
산재보험료0.88% (0.0088)기사부담분
원천징수세3.3% (0.033)소득세 3% + 지방세 0.3%
운영사 수수료설정값 원/건회사/팀별 DB 설정 (commission_fee_per_case)
DPSP 수수료설정값 원/건위탁(full_service)만 적용, 비위탁은 0 (dpsp_fee_per_case)

항목별 계산

  1. 총 정산금액 = 일정산서 종합 시트 '정산금액' (Z열)
  2. 고용보험 공제액 = ROUND(총 정산금액 × 0.008)
  3. 산재보험 공제액 = ROUND(총 정산금액 × 0.0088)
  4. 시간제보험 공제액 = ABS(시간제보험 시트 금액)
    • Excel에서 음수로 제공될 수 있으므로 절대값 변환
  5. 원천세 공제액 = ROUND(총 정산금액 × 0.033)
  6. 수수료 공제액 = 총 오더수 × (운영사 수수료 + DPSP 수수료)
    • 비위탁(calculation_only) 회사: DPSP 수수료 = 0
  7. 총 공제액 = 고용보험 + 산재보험 + 시간제보험 + 원천세 + 수수료
  8. 실지급액 = 총 정산금액 - 총 공제액
반올림 규칙: 익일정산은 각 공제 항목별로 Math.round() (사사오입) 적용

OUTPUT

명세서 항목


2. 익일정산 - 배민

INPUT

배민 일정산서 - 배달 내역 상세 (단일 시트)

로직

데이터 특성

기본 요율 (시스템 기본값)

항목비율비고
고용보험료0.8% (0.008)기사부담분
산재보험료0.9% (0.009)기사부담분 (쿠팡 0.88%와 다름)
원천징수세3.3% (0.033)소득세 3% + 지방세 0.3%
일정산 수수료기본값 77원/건commission_fee_per_case (DB 설정)
DPSP 수수료설정값 원/건위탁(full_service)만 적용, 비위탁은 0
시간제보험료기본값 5,000원시간제보험 가입자만 적용 (boolean flag)
주의: 배민 산재보험료는 0.9% (0.009)로, 쿠팡의 0.88% (0.0088)와 다릅니다. 통합 비율(0.0498)은 주간정산 익일정산자에만 사용됩니다.

항목별 계산

  1. 원배달료 = SUM(각 배달건의 '배달처리비')
  2. 총 건수 = 배달 데이터 행 수
  3. 고용보험 공제액 = ROUND(원배달료 × 0.008)
  4. 산재보험 공제액 = ROUND(원배달료 × 0.009)
  5. 원천세 공제액 = ROUND(원배달료 × 0.033)
  6. 시간제보험 공제액 = 시간제보험 가입자 ? 5,000원 : 0원
    • 라이더 정보의 시간제보험 가입 여부(boolean flag)로 판정
  7. 수수료 = 총 건수 × (일정산 수수료 + DPSP 수수료)
    • 비위탁(calculation_only) 회사: DPSP 수수료 = 0
  8. 실지급액 = 원배달료 - 고용보험 - 산재보험 - 원천세 - 시간제보험 - 수수료
반올림 규칙: 익일정산은 각 공제 항목별로 Math.round() (사사오입) 적용. 통합 비율(0.0498)로 한꺼번에 계산하지 않음.

OUTPUT

명세서 항목


3. 주간정산 - 쿠팡

INPUT

주정산서 - 종합 (일자별 정산내역)

주정산서 - 지원금 상세 내역서

주정산서 - 추가지원금 상세 내역서

주정산서 - 차감내역

주정산서 - 협력사 자체미션

주정산서 - 시간제 보험료 내역

주정산서 - 보험료 소급 내역

로직

주정산자 계산

주정산(weekly_only) 라이더에 대한 전체 정산을 수행합니다.

기본 요율

항목비율비고
원천징수세3.3% (0.033)반올림: Math.floor() (절삭)
주간정산 반올림 규칙: 주간정산에서는 Math.floor() (소수점 이하 절삭)을 사용합니다. 익일정산의 Math.round()와 다릅니다.

항목별 계산

  1. 정산서 합계 = 정산금액(Z열) + 총 지원금(AA열) + 차감내역(AB열)
    • 차감내역은 음수로 제공되므로 덧셈으로 처리
  2. 프로모션 합계 = 건별 인센티브 + 팀 미션 금액 + 추가 지원금
    • 건별 인센티브: 인센티브 규칙(CINR)에 따라 자동 계산
    • 팀 미션: 협력사 자체미션에서 달성(isAchieved=true) + 선택된 미션의 금액 합산
    • 추가 지원금: 수동 입력
  3. 과세 금액 = 정산서 합계 + 프로모션 합계
  4. 원천세 = FLOOR(과세 금액 × 0.033)
    • 정산서 금액과 프로모션 금액이 통합되어 한 번에 과세
  5. 보험 공제 합계 = |고용보험(AE열)| + |산재보험(AG열)| + |시간제보험(AH열)| + |보험소급(AI열)|
    • 모든 보험료는 Excel 원본 값의 절대값을 사용
  6. 추가 공제 = 수동 입력된 추가 공제 금액 (세후 차감)
  7. 정산 합계 = 과세 금액 - 보험 공제 합계 - 원천세 - 추가 공제
  8. 실입금액 = 정산 합계 - 기지급 익일정산액
    • 해당 주 중 익일정산으로 이미 지급된 금액을 차감

익일정산자 계산

익일정산(daily_settlement) 라이더는 기본 배달료가 이미 익일정산으로 지급 완료되었으므로, 주간정산에서는 프로모션 항목만 정산합니다.

항목별 계산

  1. 기본 배달료: 이미 익일정산으로 지급 완료 → 제외
  2. 건별 인센티브 = 인센티브 규칙(CINR)에 따라 자동 계산
  3. 팀 미션 금액 = 달성 + 선택된 미션의 금액 합산
  4. 추가 지원금 = 수동 입력
  5. 프로모션 합계 = 건별 인센티브 + 팀 미션 + 추가 지원금
  6. 원천세 = FLOOR(프로모션 합계 × 0.033)
  7. 추가 공제 = 수동 입력 (세후 차감)
  8. 실입금액 = 프로모션 합계 - 원천세 - 추가 공제

OUTPUT

주정산자 명세서 항목 (20개 필드)

익일정산자 명세서 항목

톡방 업로드용 이미지

이체 파일

상세 정산서 (엑셀)


4. 주간정산 - 배민

INPUT

주정산서 - 을지_협력사 소속 라이더 정산 확인용

주정산서 - 관리비

주정산서 - 프로모션

주정산서 - 추가배달료

주정산서 - 고용보험 소급정산

로직

데이터 특성

주정산자 계산

주정산(weekly_only) 라이더의 정산입니다.

항목별 계산

  1. 주정산서 지급금액 = 을지 시트 '지급금액' 항목
    • 이미 팀 프로모션, 보험료, 원천세가 반영된 최종 금액
  2. 지사 프로모션 계산
    • 지사 프로모션 금액 = 협력사 자체 계산
    • 지사 프로모션 원천세 공제 = FLOOR(지사 프로모션 금액 × 0.033)
    • 지사 프로모션 지급액 = 지사 프로모션 금액 - 지사 프로모션 원천세 공제
  3. 최종 지급액 = 주정산서 지급금액 + 지사 프로모션 지급액
반올림 규칙: 주간정산은 모든 공제에 Math.floor() (절삭) 사용

익일정산자 계산

익일정산(daily_settlement) 라이더는 기본 배달료가 이미 지급되었으므로, 프로모션 항목만 정산합니다.

요율

항목비율적용 대상
통합 공제 비율4.98% (0.0498)익일정산자의 모든 프로모션 항목
왜 4.98%인가: 고용보험(0.8%) + 산재보험(0.9%) + 원천세(3.3%) = 5.0%이지만, 시스템은 0.0498을 통합 비율로 사용합니다. 주정산자는 이미 을지 시트에서 보험/세금이 반영되어 있으므로 지사 프로모션에만 3.3% 적용하지만, 익일정산자는 프로모션이 새로운 소득이므로 전체 공제가 필요합니다.

항목별 계산

  1. 팀 프로모션 계산 (배민 제공)
    • 팀 프로모션 금액 = 주정산서 '프로모션' 항목
    • 팀 프로모션 공제액 = FLOOR(팀 프로모션 금액 × 0.0498)
    • 팀 프로모션 지급액 = 팀 프로모션 금액 - 팀 프로모션 공제액
  2. 지사 프로모션 계산 (협력사 자체)
    • 지사 프로모션 금액 = 협력사 자체 계산
    • 지사 프로모션 공제액 = FLOOR(지사 프로모션 금액 × 0.0498)
    • 지사 프로모션 지급액 = 지사 프로모션 금액 - 지사 프로모션 공제액
  3. 과적할증 계산 (있는 경우)
    • 과적할증 금액 = 주정산서 '과적할증' 항목
    • 과적할증 공제액 = FLOOR(과적할증 금액 × 0.0498)
    • 과적할증 지급액 = 과적할증 금액 - 과적할증 공제액
  4. 최종 지급액 = 팀 프로모션 지급액 + 지사 프로모션 지급액 + 과적할증 지급액

OUTPUT

주정산자 명세서 항목

익일정산자 명세서 항목

톡방 업로드용 이미지

이체 파일

상세 정산서 (엑셀)


5. 라이더 매칭 시스템

Excel 정산서의 라이더 식별 정보(이름, 라이선스ID 등)를 DB에 등록된 라이더(users)에 매핑하는 시스템입니다. 4단계 우선순위로 매칭을 시도하며, 매칭 실패 시 Dead Letter로 격리합니다.

4단계 매칭 우선순위

단계 매칭 방법 신뢰도 안정성 적용 조건
1단계 LICENSE_ID (라이선스 ID) 100 STABLE 쿠팡: license_id → rider_platform_credentials
배민: rider_id/user_id → platform_rider_id / platform_user_id
2단계 NAME_PHONE (이름 + 전화번호 뒷 4자리) 80 STABLE 이름과 전화번호 뒷 4자리 동시 일치
3단계 NAME_ONLY_INFERRED (이름만, 유일자) 60 FRAGILE 동명이인 없음 (requires_phone = FALSE) + 플랫폼 활성 소속 필터
4단계 NAME_ONLY (이름만, 최후 수단) 40 FRAGILE 동명이인 정확히 1명일 때만

매칭 프로세스

  1. Excel에서 라이더 식별 정보 추출 (이름, 라이선스ID, 전화번호 뒷 4자리)
  2. 1단계부터 순서대로 매칭 시도 — 성공 시 해당 신뢰도로 기록
  3. 모든 단계 실패 시 → settlement_dead_letters에 격리
  4. 매칭 결과는 rider_id_mapping 테이블에 기록
    • matched_user_id: 매칭된 라이더 ID
    • match_method: 매칭 방법
    • match_confidence: 신뢰도 점수
    • identifier_stability: STABLE / FRAGILE

동명이인 처리

company_name_uniqueness_registry 테이블이 회사별로 동명이인을 자동 추적합니다.

중요: 완료(completed), 승인(approved), 이체준비(transfer_ready) 상태의 배치는 절대 소급 무효화하지 않습니다.

Dead Letter 처리

매칭 실패 시 settlement_dead_letters에 격리됩니다.

실패 유형

failure_reason설명해결 방법
NO_MATCH라이더 미등록라이더 등록 후 재처리
DUPLICATE_PHONE_SUFFIX동명이인 + 번호 뒷 4자리까지 동일관리자 수동 매칭
AMBIGUOUS_ACTIVE동명이인 다수 + 모두 플랫폼 활성관리자 수동 매칭
NO_MATCH_PLATFORM동명이인 있으나 플랫폼 계정 비활성플랫폼 계정 등록 후 재처리

재처리 프로세스

  1. 관리자가 Dead Letter에 resolved_user_id를 설정 (수동 매칭)
  2. fn_reprocess_dead_letters() 함수가 자동 재처리
  3. SAVEPOINT 기반 — 개별 Dead Letter 실패 시 나머지는 계속 처리
  4. 완료/승인/이체준비 상태의 배치는 재처리 차단

6. 배치 생명주기

정산 배치(settlement_batches)는 정산 프로세스의 단위입니다. 각 배치는 특정 회사/팀/플랫폼/정산유형의 정산 건을 묶어 관리합니다.

상태 전이

draft → calculated → reviewed → incentive_applied → approved → transfer_ready → completed ↓ revoked (취소)
상태설명전이 조건
draft배치 생성됨, 원본 데이터 저장Excel 업로드 시 자동 생성
calculated정산 계산 완료Calculator 실행 완료
reviewed담당자 검토 완료관리자/본사 검토 확인
incentive_applied인센티브 규칙 적용 완료CINR 규칙 실행, company_incentive 반영
approved최종 승인권한자 승인
transfer_ready이체 준비 완료transfer_records 생성
completed이체 완료은행 이체 완료 확인
revoked배치 취소관리자에 의한 취소

전이 권한 분기

위탁(full_service) vs 비위탁(calculation_only) 여부와 정산 유형(일정산/주정산)에 따라 전이 권한이 달라집니다.

구분일정산 (daily)주정산 (weekly)
비위탁 (calculation_only) 본사 전이 가능 (전 구간) 본사 전이 가능 (전 구간)
위탁 (full_service) calculated 이후 전이 차단
(admin만 가능)
본사도 직접 전이 가능
admin 전 구간 통과
프론트엔드 표시: 위탁 일정산만 전이 버튼 비활성 + "DPSP 관리자 처리 대기" 표시. 나머지는 동일한 진행 바 사용.

배치 보호 규칙


7. 인센티브 시스템 (CINR)

CINR (Company INcentive Results)은 회사별 인센티브 규칙을 정의하고 정산에 자동 적용하는 시스템입니다. INDIVIDUAL(개인)과 TEAM(팀) 두 가지 유형이 있습니다.

INDIVIDUAL 인센티브

라이더 개인의 배달 건수에 따라 보상을 지급합니다.

계산 방식 (calc_method)

방식설명계산
tiered 단계별 누적 각 구간(min_count ~ 다음 구간) × rate_per_delivery 합산
최대 금액(max_amount) 제한 가능
simple 목표 달성 시 건당 금액 target_count 달성 시 → (달성건수 - from_count) × rate_per_delivery
fixed 목표 달성 시 고정 보너스 target_count 달성 시 → bonus_amount 지급

건수 집계 범위 (count_scope)

TEAM 인센티브

팀 단위 조건과 개인 조건을 동시에 충족해야 보상이 지급됩니다.

조건

  1. 팀 전체 최소 건수 (team_min_total_count): 팀 전체 배달 건수가 기준 이상
  2. 개인 최소 건수 (individual_min_count): 팀원 각자의 배달 건수가 기준 이상
  3. 두 조건 모두 충족 시 → reward_amount를 팀원 1인당 지급

적용 시점

  1. 배치 상태가 reviewed → incentive_applied로 전이될 때 실행
  2. 인센티브 규칙을 평가하여 조건 충족 여부 판정
  3. 결과가 company_incentive_results 테이블에 저장
    • rule_id: 적용된 규칙
    • rider_id: 대상 라이더
    • delivery_count_used: 실제 집계된 배달 건수
    • reward_amount: 지급 보상 금액
  4. settlement_details.company_incentive 필드에 reward_amount 합산 반영
  5. 최종 실지급액(net_payment)에 인센티브 금액이 추가됨
IRUL 참고: 이전 시스템(IRUL)은 2026-02에 deprecated되었으며, CINR로 완전 전환 완료 후 제거 예정입니다.

8. 요율 설정

시스템 기본값

각 계산기(Calculator)가 사용하는 기본 요율입니다. DB의 settlement_rate_settings 테이블에서 조회하며, 미설정 시 아래 기본값을 사용합니다.

항목쿠팡 익일쿠팡 주간배민 익일배민 주간
고용보험료0.8%Excel 값0.8%Excel 값
산재보험료0.88%Excel 값0.9%Excel 값
원천징수세3.3%3.3%3.3%3.3%
통합 공제 비율---4.98% (익일정산자)
수수료/건설정값-77원-
시간제보험Excel 값Excel 값5,000원-
반올림round()floor()round()floor()
현재 상태: settlement_rate_settings DB 테이블이 존재하지만, Calculator에서는 아직 하드코딩된 기본값을 사용 중입니다. DB 조회 연결은 향후 구현 예정입니다.

회사/팀별 설정

수수료는 회사/팀 단위로 설정 가능합니다.

설정 항목설명조회 경로
commission_fee_per_case운영사 수수료 (원/건)TeamService.getSettlementSettings(companyId, teamId)
dpsp_fee_per_caseDPSP 수수료 (원/건)위탁(full_service)만 적용, 비위탁은 0

서비스 타입별 수수료 적용

요율 조회 우선순위

  1. TeamService.getSettlementSettings(companyId, teamId) → 회사/팀 특정 설정
  2. TeamService.getDefaultSettings() → 시스템 기본값 (fallback)
  3. Calculator 내부 하드코딩 기본값 (최후 fallback)