feat: incar 갭 반영 수수료/운영 14개 도메인 풀스택 + 배치통합 + 신입교육자료

incar CMS(116메뉴) 벤치마킹 갭분석으로 ga-pro에 없던 14개 도메인을 풀스택 추가.

P7 수수료 계산 7종 (V88~V96):
- 수입수수료+수지차, 소개·이관수수료, 정착지원금, 인정실적+환산율,
  시상, 생보운영지원수수료, 지점장수당
- 각 rule/ledger + 공식(보험료×요율, 수입−지급 등) Service 내장

P8 운영/정산 7종 (V97~V105):
- 단계마감, 본사정산, 등급평가, 공동계약, 보증보험, 적립금, 수수료시뮬레이터
- close/reopen/apply/simulate/upsert 등 액션 + 손익·잔액·등급 산정 로직

배치 통합 (V106):
- settle_master.other_commission_total 컬럼 추가(DEFAULT 0, 백필)
- 설계사 지급성 9종 원장 aggregateByAgent → AggregateStep gross 합산
- 빈 원장 0 → 기존 정산결과·무결성 불변(비파괴적)

테스트: P7/P8 Service 공식 단위테스트 21건(ga-api:test 57건 전체 통과)
프론트: 화면 14개 + React.lazy 코드 스플리팅(단일 4MB → 130+ 청크)
문서: DOMAIN_GAP_P7/P8.md, 신입교육_보험과수수료_완전기초.md, DOMAIN_KNOWLEDGE/HANDOFF 갱신

검증: 전체 ./gradlew build(test 포함) SUCCESSFUL, Flyway V88~V106 success,
GET+액션POST smoke 5xx 0건, 9개 집계쿼리 SQL 유효성 확인, 공식 런타임 실측.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
GA Pro
2026-05-31 15:45:10 +09:00
parent 70620463b4
commit bfc724669b
231 changed files with 13325 additions and 189 deletions
+277
View File
@@ -144,6 +144,173 @@ export interface OverrideLedgerSearchParam {
pageSize?: number;
}
// ── P7: IncomeCommission ──────────────────────────
export interface IncomeLedgerRow extends Record<string, unknown> {
incomeId: number;
contractId: number;
contractNo: string;
carrierId: number;
carrierName: string;
settleMonth: string;
premiumAmount: number;
companyRate: number;
incomeAmount: number;
commissionType: string;
status: string;
}
export interface MarginSummaryRow extends Record<string, unknown> {
marginId: number;
settleMonth: string;
agentId?: number;
agentName?: string;
incomeTotal: number;
payoutTotal: number;
marginAmount: number;
marginRate?: number;
}
// ── P7: ReferralCommission ────────────────────────
export interface ReferralRuleRow extends Record<string, unknown> {
ruleId: number;
referralType: string;
calcType: string;
commissionRate?: number;
fixedAmount?: number;
effectiveFrom: string;
effectiveTo?: string;
}
export interface ReferralLedgerRow extends Record<string, unknown> {
ledgerId: number;
contractId: number;
contractNo: string;
referrerAgentId: number;
referrerAgentName: string;
settleMonth: string;
referralType: string;
baseAmount: number;
commissionRate?: number;
commissionAmount: number;
status: string;
}
// ── P7: SettlingSupport ───────────────────────────
export interface SettlingSupportRuleRow extends Record<string, unknown> {
ruleId: number;
agentGrade: string;
supportAmount: number;
durationMonths: number;
clawbackMonths: number;
effectiveFrom: string;
effectiveTo?: string;
}
export interface SettlingSupportLedgerRow extends Record<string, unknown> {
ledgerId: number;
agentId: number;
agentName: string;
settleMonth: string;
supportAmount: number;
clawbackAmount: number;
netAmount: number;
status: string;
}
// ── P7: RecognizedPerformance ─────────────────────
export interface ConversionRateRow extends Record<string, unknown> {
rateId: number;
productId: number;
productName: string;
conversionRate: number;
effectiveFrom: string;
effectiveTo?: string;
}
export interface RecognizedLedgerRow extends Record<string, unknown> {
ledgerId: number;
agentId: number;
agentName: string;
contractId: number;
contractNo: string;
settleMonth: string;
premiumAmount: number;
conversionRate: number;
convertedPremium: number;
recognitionRate: number;
recognizedAmount: number;
status: string;
}
// ── P7: Award ─────────────────────────────────────
export interface AwardRuleRow extends Record<string, unknown> {
ruleId: number;
awardType: string;
calcType: string;
thresholdAmount?: number;
awardRate?: number;
awardFixed?: number;
effectiveFrom: string;
effectiveTo?: string;
}
export interface AwardLedgerRow extends Record<string, unknown> {
ledgerId: number;
agentId: number;
agentName: string;
settleMonth: string;
awardType: string;
baseAmount: number;
awardAmount: number;
status: string;
}
// ── P7: LifeSupport ───────────────────────────────
export interface LifeSupportRuleRow extends Record<string, unknown> {
ruleId: number;
agentGrade: string;
supportRate: number;
effectiveFrom: string;
effectiveTo?: string;
}
export interface LifeSupportLedgerRow extends Record<string, unknown> {
ledgerId: number;
agentId: number;
agentName: string;
settleMonth: string;
baseAmount: number;
supportRate: number;
supportAmount: number;
clawbackAmount: number;
netAmount: number;
status: string;
}
// ── P7: BranchAllowance ───────────────────────────
export interface BranchAllowanceRuleRow extends Record<string, unknown> {
ruleId: number;
positionCode: string;
allowanceRate: number;
capAmount?: number;
effectiveFrom: string;
effectiveTo?: string;
}
export interface BranchAllowanceLedgerRow extends Record<string, unknown> {
ledgerId: number;
managerAgentId: number;
managerAgentName: string;
orgId: number;
orgName: string;
settleMonth: string;
baseAmount: number;
allowanceRate: number;
allowanceAmount: number;
clawbackAmount: number;
status: string;
}
// ── API ───────────────────────────────────────────
export const commissionApi = {
// CommissionMaster
@@ -227,4 +394,114 @@ export const commissionApi = {
unwrap<PageResponse<OverrideLedgerRow>>(
api.get('/api/override-ledgers', { params: p }),
),
// ── P7: IncomeCommission ──────────────────────────
incomeLedgers: (p: CommissionSearchParam) =>
unwrap<PageResponse<IncomeLedgerRow>>(
api.get('/api/income-commissions/ledgers', { params: p }),
),
incomeMargins: (p: CommissionSearchParam) =>
unwrap<PageResponse<MarginSummaryRow>>(
api.get('/api/income-commissions/margins', { params: p }),
),
incomeMarginRecalc: (settleMonth: string) =>
unwrap<void>(
api.post('/api/income-commissions/margin/recalc', null, { params: { settleMonth } }),
),
// ── P7: ReferralCommission ────────────────────────
referralRules: (p?: Partial<CommissionSearchParam>) =>
unwrap<PageResponse<ReferralRuleRow>>(
api.get('/api/referral-commissions/rules', { params: p }),
),
referralRuleCreate: (body: Partial<ReferralRuleRow>) =>
unwrap<ReferralRuleRow>(api.post('/api/referral-commissions/rules', body)),
referralRuleUpdate: (id: number, body: Partial<ReferralRuleRow>) =>
unwrap<ReferralRuleRow>(api.put(`/api/referral-commissions/rules/${id}`, body)),
referralRuleDelete: (id: number) =>
unwrap<void>(api.delete(`/api/referral-commissions/rules/${id}`)),
referralLedgers: (p: CommissionSearchParam) =>
unwrap<PageResponse<ReferralLedgerRow>>(
api.get('/api/referral-commissions/ledgers', { params: p }),
),
// ── P7: SettlingSupport ───────────────────────────
settlingRules: (p?: Partial<CommissionSearchParam>) =>
unwrap<PageResponse<SettlingSupportRuleRow>>(
api.get('/api/settling-supports/rules', { params: p }),
),
settlingRuleCreate: (body: Partial<SettlingSupportRuleRow>) =>
unwrap<SettlingSupportRuleRow>(api.post('/api/settling-supports/rules', body)),
settlingRuleUpdate: (id: number, body: Partial<SettlingSupportRuleRow>) =>
unwrap<SettlingSupportRuleRow>(api.put(`/api/settling-supports/rules/${id}`, body)),
settlingRuleDelete: (id: number) =>
unwrap<void>(api.delete(`/api/settling-supports/rules/${id}`)),
settlingLedgers: (p: CommissionSearchParam) =>
unwrap<PageResponse<SettlingSupportLedgerRow>>(
api.get('/api/settling-supports/ledgers', { params: p }),
),
// ── P7: RecognizedPerformance ─────────────────────
conversionRates: (p?: Partial<CommissionSearchParam>) =>
unwrap<PageResponse<ConversionRateRow>>(
api.get('/api/recognized-performances/rates', { params: p }),
),
conversionRateCreate: (body: Partial<ConversionRateRow>) =>
unwrap<ConversionRateRow>(api.post('/api/recognized-performances/rates', body)),
conversionRateUpdate: (id: number, body: Partial<ConversionRateRow>) =>
unwrap<ConversionRateRow>(api.put(`/api/recognized-performances/rates/${id}`, body)),
conversionRateDelete: (id: number) =>
unwrap<void>(api.delete(`/api/recognized-performances/rates/${id}`)),
recognizedLedgers: (p: CommissionSearchParam) =>
unwrap<PageResponse<RecognizedLedgerRow>>(
api.get('/api/recognized-performances/ledgers', { params: p }),
),
// ── P7: Award ─────────────────────────────────────
awardRules: (p?: Partial<CommissionSearchParam>) =>
unwrap<PageResponse<AwardRuleRow>>(
api.get('/api/awards/rules', { params: p }),
),
awardRuleCreate: (body: Partial<AwardRuleRow>) =>
unwrap<AwardRuleRow>(api.post('/api/awards/rules', body)),
awardRuleUpdate: (id: number, body: Partial<AwardRuleRow>) =>
unwrap<AwardRuleRow>(api.put(`/api/awards/rules/${id}`, body)),
awardRuleDelete: (id: number) =>
unwrap<void>(api.delete(`/api/awards/rules/${id}`)),
awardLedgers: (p: CommissionSearchParam) =>
unwrap<PageResponse<AwardLedgerRow>>(
api.get('/api/awards/ledgers', { params: p }),
),
// ── P7: LifeSupport ───────────────────────────────
lifeSupportRules: (p?: Partial<CommissionSearchParam>) =>
unwrap<PageResponse<LifeSupportRuleRow>>(
api.get('/api/life-supports/rules', { params: p }),
),
lifeSupportRuleCreate: (body: Partial<LifeSupportRuleRow>) =>
unwrap<LifeSupportRuleRow>(api.post('/api/life-supports/rules', body)),
lifeSupportRuleUpdate: (id: number, body: Partial<LifeSupportRuleRow>) =>
unwrap<LifeSupportRuleRow>(api.put(`/api/life-supports/rules/${id}`, body)),
lifeSupportRuleDelete: (id: number) =>
unwrap<void>(api.delete(`/api/life-supports/rules/${id}`)),
lifeSupportLedgers: (p: CommissionSearchParam) =>
unwrap<PageResponse<LifeSupportLedgerRow>>(
api.get('/api/life-supports/ledgers', { params: p }),
),
// ── P7: BranchAllowance ───────────────────────────
branchAllowanceRules: (p?: Partial<CommissionSearchParam>) =>
unwrap<PageResponse<BranchAllowanceRuleRow>>(
api.get('/api/branch-allowances/rules', { params: p }),
),
branchAllowanceRuleCreate: (body: Partial<BranchAllowanceRuleRow>) =>
unwrap<BranchAllowanceRuleRow>(api.post('/api/branch-allowances/rules', body)),
branchAllowanceRuleUpdate: (id: number, body: Partial<BranchAllowanceRuleRow>) =>
unwrap<BranchAllowanceRuleRow>(api.put(`/api/branch-allowances/rules/${id}`, body)),
branchAllowanceRuleDelete: (id: number) =>
unwrap<void>(api.delete(`/api/branch-allowances/rules/${id}`)),
branchAllowanceLedgers: (p: CommissionSearchParam) =>
unwrap<PageResponse<BranchAllowanceLedgerRow>>(
api.get('/api/branch-allowances/ledgers', { params: p }),
),
};