동기화
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
-- V29: 마감 마스터 (period_close) — 정산 월 마감 관리
|
||||
|
||||
-- ============================================================
|
||||
-- 1. period_close — 마감 마스터
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE period_close (
|
||||
close_id BIGSERIAL PRIMARY KEY,
|
||||
close_month CHAR(6) NOT NULL, -- YYYYMM
|
||||
closed_at TIMESTAMP NOT NULL DEFAULT NOW(), -- 마감 처리 일시
|
||||
closed_by BIGINT NOT NULL, -- 마감 처리자 (user_id)
|
||||
reopen_at TIMESTAMP, -- 재오픈 일시 (NULL = 마감 중)
|
||||
reopen_by BIGINT, -- 재오픈 처리자
|
||||
reopen_reason VARCHAR(500), -- 재오픈 사유
|
||||
note VARCHAR(500), -- 마감 비고
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP,
|
||||
UNIQUE (close_month) -- 월별 단 1건
|
||||
);
|
||||
|
||||
COMMENT ON TABLE period_close IS '정산 마감 마스터 — 마감된 월은 수정 불가';
|
||||
COMMENT ON COLUMN period_close.close_month IS '마감 정산년월 (YYYYMM)';
|
||||
COMMENT ON COLUMN period_close.closed_at IS '마감 처리 일시';
|
||||
COMMENT ON COLUMN period_close.closed_by IS '마감 처리자 user_id';
|
||||
COMMENT ON COLUMN period_close.reopen_at IS '재오픈 일시. NULL이면 현재 마감 상태';
|
||||
COMMENT ON COLUMN period_close.reopen_by IS '재오픈 처리자 user_id';
|
||||
COMMENT ON COLUMN period_close.reopen_reason IS '재오픈 사유 (감사 추적용)';
|
||||
|
||||
-- 마감 상태 조회용 인덱스 (재오픈 여부로 현재 마감 여부 판단)
|
||||
CREATE INDEX idx_pc_month ON period_close(close_month);
|
||||
|
||||
-- ============================================================
|
||||
-- 2. 공통코드 CLOSE_STATUS (마감/재오픈 상태 표현용)
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO common_code_group (group_code, group_name, description, is_system, sort_order) VALUES
|
||||
('CLOSE_STATUS', '마감상태', 'CLOSED/REOPENED', 'Y', 290)
|
||||
ON CONFLICT (group_code) DO NOTHING;
|
||||
|
||||
INSERT INTO common_code (group_code, code, code_name, code_desc, sort_order) VALUES
|
||||
('CLOSE_STATUS', 'CLOSED', '마감', '정산월 마감 완료 — 수정 불가', 10),
|
||||
('CLOSE_STATUS', 'REOPENED', '재오픈', '마감 해제 상태 — 수정 가능', 20)
|
||||
ON CONFLICT (group_code, code) DO NOTHING;
|
||||
@@ -0,0 +1,62 @@
|
||||
-- V30: 정산 정정 (settle_correction) — 확정된 정산의 정정 이력 관리
|
||||
|
||||
-- ============================================================
|
||||
-- 1. settle_correction — 정산 정정 이력
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE settle_correction (
|
||||
correction_id BIGSERIAL PRIMARY KEY,
|
||||
original_settle_id BIGINT NOT NULL REFERENCES settle_master(settle_id), -- 원본 정산 참조
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
settle_month CHAR(6) NOT NULL, -- YYYYMM (원본과 동일)
|
||||
diff_amount NUMERIC(15,2) NOT NULL, -- 차액 (양수=추가지급, 음수=환수)
|
||||
before_amount NUMERIC(15,2) NOT NULL, -- 정정 전 순지급액
|
||||
after_amount NUMERIC(15,2) NOT NULL, -- 정정 후 순지급액
|
||||
reason_code VARCHAR(30) NOT NULL, -- 정정 사유 코드 (CORRECTION_REASON)
|
||||
reason_detail VARCHAR(1000), -- 정정 사유 상세
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'DRAFT', -- DRAFT/APPROVED/APPLIED/CANCELLED
|
||||
requested_by BIGINT NOT NULL, -- 정정 신청자
|
||||
requested_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
approved_by BIGINT, -- 정정 승인자
|
||||
approved_at TIMESTAMP,
|
||||
applied_settle_id BIGINT REFERENCES settle_master(settle_id), -- 정정이 반영된 정산 (다음 월 등)
|
||||
cancel_reason VARCHAR(500),
|
||||
cancelled_by BIGINT,
|
||||
cancelled_at TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP
|
||||
);
|
||||
|
||||
COMMENT ON TABLE settle_correction IS '정산 정정 이력 — 확정 정산에 대한 사후 정정';
|
||||
COMMENT ON COLUMN settle_correction.original_settle_id IS '원본 settle_master 참조';
|
||||
COMMENT ON COLUMN settle_correction.diff_amount IS '정정 차액 (양수=추가, 음수=환수)';
|
||||
COMMENT ON COLUMN settle_correction.before_amount IS '정정 전 순지급액';
|
||||
COMMENT ON COLUMN settle_correction.after_amount IS '정정 후 순지급액';
|
||||
COMMENT ON COLUMN settle_correction.reason_code IS '정정 사유 코드 (CORRECTION_REASON 그룹)';
|
||||
COMMENT ON COLUMN settle_correction.status IS 'DRAFT/APPROVED/APPLIED/CANCELLED';
|
||||
COMMENT ON COLUMN settle_correction.applied_settle_id IS '차액이 반영된 정산 settle_id (다음 정산월 등)';
|
||||
|
||||
CREATE INDEX idx_sc_original ON settle_correction(original_settle_id);
|
||||
CREATE INDEX idx_sc_agent ON settle_correction(agent_id, settle_month);
|
||||
CREATE INDEX idx_sc_status ON settle_correction(status, requested_at DESC);
|
||||
|
||||
-- ============================================================
|
||||
-- 2. 공통코드 CORRECTION_REASON / CORRECTION_STATUS
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO common_code_group (group_code, group_name, description, is_system, sort_order) VALUES
|
||||
('CORRECTION_REASON', '정정사유', 'DATA_ERROR/POLICY_CHANGE/LATE_DATA/MANUAL_ADJ/OTHER', 'Y', 300),
|
||||
('CORRECTION_STATUS', '정정상태', 'DRAFT/APPROVED/APPLIED/CANCELLED', 'Y', 310)
|
||||
ON CONFLICT (group_code) DO NOTHING;
|
||||
|
||||
INSERT INTO common_code (group_code, code, code_name, code_desc, sort_order) VALUES
|
||||
('CORRECTION_REASON', 'DATA_ERROR', '데이터오류', '원시 데이터 오류로 인한 정정', 10),
|
||||
('CORRECTION_REASON', 'POLICY_CHANGE', '정책변경', '정산 정책 변경으로 인한 소급 정정', 20),
|
||||
('CORRECTION_REASON', 'LATE_DATA', '지연수신', '보험사 데이터 지연 수신으로 인한 정정', 30),
|
||||
('CORRECTION_REASON', 'MANUAL_ADJ', '수동조정', '관리자 수동 조정', 40),
|
||||
('CORRECTION_REASON', 'OTHER', '기타', '기타 사유', 50),
|
||||
('CORRECTION_STATUS', 'DRAFT', '초안', '정정 신청 초안', 10),
|
||||
('CORRECTION_STATUS', 'APPROVED', '승인', '정정 승인 완료', 20),
|
||||
('CORRECTION_STATUS', 'APPLIED', '적용완료', '정정 차액 정산 반영 완료', 30),
|
||||
('CORRECTION_STATUS', 'CANCELLED', '취소', '정정 신청 취소', 40)
|
||||
ON CONFLICT (group_code, code) DO NOTHING;
|
||||
@@ -0,0 +1,54 @@
|
||||
-- V31: 수수료 이의신청 (commission_dispute)
|
||||
|
||||
-- ============================================================
|
||||
-- 1. commission_dispute — 이의신청 마스터
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE commission_dispute (
|
||||
dispute_id BIGSERIAL PRIMARY KEY,
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
settle_month CHAR(6) NOT NULL, -- 대상 정산년월 (YYYYMM)
|
||||
settle_id BIGINT REFERENCES settle_master(settle_id), -- 연관 정산 (선택)
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'OPEN', -- OPEN/IN_REVIEW/APPROVED/REJECTED
|
||||
disputed_amount NUMERIC(15,2), -- 이의 제기 금액 (NULL=전체)
|
||||
claim_amount NUMERIC(15,2), -- 설계사 주장 금액
|
||||
reason VARCHAR(2000) NOT NULL, -- 이의 신청 사유
|
||||
evidence_url VARCHAR(500), -- 증빙 자료 URL (첨부파일)
|
||||
reviewer_id BIGINT, -- 검토 담당자
|
||||
reviewed_at TIMESTAMP, -- 검토 시작 일시
|
||||
resolved_by BIGINT, -- 최종 처리자
|
||||
resolved_at TIMESTAMP, -- 최종 처리 일시
|
||||
resolution VARCHAR(2000), -- 처리 결과 상세
|
||||
adjustment_amount NUMERIC(15,2), -- 인정된 조정 금액 (APPROVED 시)
|
||||
correction_id BIGINT REFERENCES settle_correction(correction_id), -- 연계 정정건
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP
|
||||
);
|
||||
|
||||
COMMENT ON TABLE commission_dispute IS '수수료 이의신청 — 설계사가 정산 결과에 이의를 제기하는 프로세스';
|
||||
COMMENT ON COLUMN commission_dispute.agent_id IS '이의신청 설계사';
|
||||
COMMENT ON COLUMN commission_dispute.settle_month IS '이의 대상 정산년월 (YYYYMM)';
|
||||
COMMENT ON COLUMN commission_dispute.status IS 'OPEN/IN_REVIEW/APPROVED/REJECTED';
|
||||
COMMENT ON COLUMN commission_dispute.disputed_amount IS '이의 제기 금액 (NULL=전체 정산)';
|
||||
COMMENT ON COLUMN commission_dispute.claim_amount IS '설계사가 주장하는 정당 금액';
|
||||
COMMENT ON COLUMN commission_dispute.adjustment_amount IS 'APPROVED 시 실제 인정된 조정 금액';
|
||||
COMMENT ON COLUMN commission_dispute.correction_id IS '이의신청 결과로 생성된 정정건 참조';
|
||||
|
||||
CREATE INDEX idx_cd_agent ON commission_dispute(agent_id, settle_month);
|
||||
CREATE INDEX idx_cd_status ON commission_dispute(status, created_at DESC);
|
||||
CREATE INDEX idx_cd_settle ON commission_dispute(settle_id);
|
||||
|
||||
-- ============================================================
|
||||
-- 2. 공통코드 DISPUTE_STATUS
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO common_code_group (group_code, group_name, description, is_system, sort_order) VALUES
|
||||
('DISPUTE_STATUS', '이의신청상태', 'OPEN/IN_REVIEW/APPROVED/REJECTED', 'Y', 320)
|
||||
ON CONFLICT (group_code) DO NOTHING;
|
||||
|
||||
INSERT INTO common_code (group_code, code, code_name, code_desc, sort_order) VALUES
|
||||
('DISPUTE_STATUS', 'OPEN', '접수', '이의신청 접수 (검토 전)', 10),
|
||||
('DISPUTE_STATUS', 'IN_REVIEW', '검토중', '담당자 검토 진행 중', 20),
|
||||
('DISPUTE_STATUS', 'APPROVED', '인정', '이의신청 인정 — 정정 처리 진행', 30),
|
||||
('DISPUTE_STATUS', 'REJECTED', '기각', '이의신청 기각 — 원 정산 유지', 40)
|
||||
ON CONFLICT (group_code, code) DO NOTHING;
|
||||
@@ -0,0 +1,29 @@
|
||||
-- V32: settle_master 보류 사유 코드 컬럼 추가 + HOLD_REASON 공통코드
|
||||
|
||||
-- ============================================================
|
||||
-- 1. settle_master 에 hold_reason_code 컬럼 추가
|
||||
-- (기존 hold_reason VARCHAR(500) 자유텍스트 → 코드화 병행)
|
||||
-- ============================================================
|
||||
|
||||
ALTER TABLE settle_master
|
||||
ADD COLUMN hold_reason_code VARCHAR(30);
|
||||
|
||||
COMMENT ON COLUMN settle_master.hold_reason_code IS '보류 사유 코드 (HOLD_REASON 그룹). status=HOLD 일 때 필수';
|
||||
|
||||
-- ============================================================
|
||||
-- 2. 공통코드 HOLD_REASON
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO common_code_group (group_code, group_name, description, is_system, sort_order) VALUES
|
||||
('HOLD_REASON', '보류사유', 'NEED_DOC/UNDER_REVIEW/DISPUTE_OPEN/TAX_ISSUE/BANK_ERROR/COMPLIANCE/OTHER', 'Y', 330)
|
||||
ON CONFLICT (group_code) DO NOTHING;
|
||||
|
||||
INSERT INTO common_code (group_code, code, code_name, code_desc, sort_order) VALUES
|
||||
('HOLD_REASON', 'NEED_DOC', '서류미비', '필수 서류 미제출로 인한 보류', 10),
|
||||
('HOLD_REASON', 'UNDER_REVIEW', '검토중', '관리자 검토 진행 중 보류', 20),
|
||||
('HOLD_REASON', 'DISPUTE_OPEN', '이의신청', '이의신청(commission_dispute) 처리 중 보류', 30),
|
||||
('HOLD_REASON', 'TAX_ISSUE', '세무이슈', '세무 정보 미확인 또는 이슈', 40),
|
||||
('HOLD_REASON', 'BANK_ERROR', '계좌오류', '계좌 정보 오류 또는 이체 실패', 50),
|
||||
('HOLD_REASON', 'COMPLIANCE', '컴플라이언스', '법규/감독규정 검토 필요', 60),
|
||||
('HOLD_REASON', 'OTHER', '기타', '기타 보류 사유', 70)
|
||||
ON CONFLICT (group_code, code) DO NOTHING;
|
||||
@@ -0,0 +1,94 @@
|
||||
-- V33: 시책·인센티브 (incentive_program + incentive_payment)
|
||||
|
||||
-- ============================================================
|
||||
-- 1. incentive_program — 시책 프로그램 마스터
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE incentive_program (
|
||||
program_id BIGSERIAL PRIMARY KEY,
|
||||
program_name VARCHAR(200) NOT NULL, -- 시책명
|
||||
program_type VARCHAR(30) NOT NULL, -- 시책 유형 (INCENTIVE_TYPE)
|
||||
target_type VARCHAR(30) NOT NULL DEFAULT 'AGENT', -- 지급 대상 (AGENT/ORG/GRADE)
|
||||
target_grade_id BIGINT REFERENCES grade(grade_id), -- 대상 직급 (NULL=전체)
|
||||
target_org_id BIGINT REFERENCES organization(org_id), -- 대상 조직 (NULL=전체)
|
||||
product_category VARCHAR(30), -- 적용 상품 카테고리 (NULL=전체)
|
||||
start_month CHAR(6) NOT NULL, -- 시책 시작 정산월 (YYYYMM)
|
||||
end_month CHAR(6) NOT NULL, -- 시책 종료 정산월 (YYYYMM)
|
||||
condition_desc VARCHAR(2000), -- 지급 조건 상세 기술
|
||||
pay_rate NUMERIC(7,4), -- 지급률 (%) — rate 방식
|
||||
pay_amount_fixed NUMERIC(15,2), -- 고정 지급액 — amount 방식
|
||||
pay_type VARCHAR(20) NOT NULL DEFAULT 'RATE', -- RATE / FIXED_AMOUNT
|
||||
budget_amount NUMERIC(15,2), -- 시책 예산 (NULL=무제한)
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by BIGINT,
|
||||
updated_at TIMESTAMP,
|
||||
updated_by BIGINT,
|
||||
CHECK (end_month >= start_month),
|
||||
CHECK (pay_type IN ('RATE', 'FIXED_AMOUNT'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE incentive_program IS '시책 프로그램 마스터 — 기간/대상/조건/지급률 정의';
|
||||
COMMENT ON COLUMN incentive_program.program_type IS '시책 유형 코드 (INCENTIVE_TYPE 그룹)';
|
||||
COMMENT ON COLUMN incentive_program.target_type IS '지급 대상 구분 (AGENT=개인/ORG=조직/GRADE=직급)';
|
||||
COMMENT ON COLUMN incentive_program.start_month IS '시책 시작 정산월 (YYYYMM)';
|
||||
COMMENT ON COLUMN incentive_program.end_month IS '시책 종료 정산월 (YYYYMM, 포함)';
|
||||
COMMENT ON COLUMN incentive_program.pay_rate IS 'RATE 방식 시 지급률 (%)';
|
||||
COMMENT ON COLUMN incentive_program.pay_amount_fixed IS 'FIXED_AMOUNT 방식 시 고정 지급액';
|
||||
COMMENT ON COLUMN incentive_program.pay_type IS 'RATE=수수료 대비 비율 / FIXED_AMOUNT=건당 고정액';
|
||||
|
||||
CREATE INDEX idx_ip_prog_month ON incentive_program(start_month, end_month, is_active);
|
||||
CREATE INDEX idx_ip_prog_type ON incentive_program(program_type, is_active);
|
||||
|
||||
-- ============================================================
|
||||
-- 2. incentive_payment — 시책 지급 이력
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE incentive_payment (
|
||||
incentive_pay_id BIGSERIAL PRIMARY KEY,
|
||||
program_id BIGINT NOT NULL REFERENCES incentive_program(program_id),
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
settle_month CHAR(6) NOT NULL, -- 지급 정산월 (YYYYMM)
|
||||
base_amount NUMERIC(15,2), -- 기준 수수료 (RATE 방식)
|
||||
incentive_amount NUMERIC(15,2) NOT NULL, -- 시책 지급액
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'CALCULATED', -- CALCULATED/CONFIRMED/PAID/CANCELLED
|
||||
calc_date TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
confirmed_by BIGINT,
|
||||
confirmed_at TIMESTAMP,
|
||||
settle_id BIGINT REFERENCES settle_master(settle_id), -- 반영된 정산
|
||||
cancel_reason VARCHAR(500),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP,
|
||||
UNIQUE (program_id, agent_id, settle_month)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE incentive_payment IS '시책 지급 이력 — program_id + agent_id + settle_month 단위';
|
||||
COMMENT ON COLUMN incentive_payment.base_amount IS 'RATE 방식 시 계산 기준 수수료';
|
||||
COMMENT ON COLUMN incentive_payment.incentive_amount IS '최종 시책 지급액';
|
||||
COMMENT ON COLUMN incentive_payment.status IS 'CALCULATED/CONFIRMED/PAID/CANCELLED';
|
||||
COMMENT ON COLUMN incentive_payment.settle_id IS '시책 금액이 반영된 settle_master 참조';
|
||||
|
||||
CREATE INDEX idx_ipay_agent ON incentive_payment(agent_id, settle_month);
|
||||
CREATE INDEX idx_ipay_program ON incentive_payment(program_id, settle_month);
|
||||
CREATE INDEX idx_ipay_status ON incentive_payment(status, settle_month);
|
||||
|
||||
-- ============================================================
|
||||
-- 3. 공통코드 INCENTIVE_TYPE / INCENTIVE_PAY_STATUS
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO common_code_group (group_code, group_name, description, is_system, sort_order) VALUES
|
||||
('INCENTIVE_TYPE', '시책유형', 'RECRUIT_BONUS/MAINTAIN_BONUS/SPECIAL/CONTEST/OTHER', 'Y', 340),
|
||||
('INCENTIVE_PAY_STATUS', '시책지급상태', 'CALCULATED/CONFIRMED/PAID/CANCELLED', 'Y', 350)
|
||||
ON CONFLICT (group_code) DO NOTHING;
|
||||
|
||||
INSERT INTO common_code (group_code, code, code_name, code_desc, sort_order) VALUES
|
||||
('INCENTIVE_TYPE', 'RECRUIT_BONUS', '신계약시책', '신계약 실적 기반 시책', 10),
|
||||
('INCENTIVE_TYPE', 'MAINTAIN_BONUS', '유지시책', '유지율 기반 시책', 20),
|
||||
('INCENTIVE_TYPE', 'SPECIAL', '특별시책', '본사 특별 지정 시책', 30),
|
||||
('INCENTIVE_TYPE', 'CONTEST', '콘테스트', '경쟁 목표 달성 인센티브', 40),
|
||||
('INCENTIVE_TYPE', 'OTHER', '기타', '기타 시책', 50),
|
||||
('INCENTIVE_PAY_STATUS', 'CALCULATED', '산출', '시책 금액 산출 완료', 10),
|
||||
('INCENTIVE_PAY_STATUS', 'CONFIRMED', '확정', '지급 확정', 20),
|
||||
('INCENTIVE_PAY_STATUS', 'PAID', '지급완료', '정산 반영 완료', 30),
|
||||
('INCENTIVE_PAY_STATUS', 'CANCELLED', '취소', '시책 지급 취소', 40)
|
||||
ON CONFLICT (group_code, code) DO NOTHING;
|
||||
@@ -0,0 +1,69 @@
|
||||
-- V34: 해촉 정산 (termination_settlement) — 설계사 해촉 시 미지급분·환수 처리
|
||||
|
||||
-- ============================================================
|
||||
-- 1. termination_settlement — 해촉 정산 마스터
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE termination_settlement (
|
||||
term_settle_id BIGSERIAL PRIMARY KEY,
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
termination_date DATE NOT NULL, -- 해촉 일자
|
||||
org_history_id BIGINT REFERENCES agent_org_history(history_id), -- LEAVE 이력 참조
|
||||
calc_month CHAR(6) NOT NULL, -- 해촉 정산 처리 월 (YYYYMM)
|
||||
|
||||
-- 미지급 수수료 (해촉 시점 기준)
|
||||
unpaid_recruit_amount NUMERIC(15,2) NOT NULL DEFAULT 0, -- 미지급 신계약 수수료
|
||||
unpaid_installment_amount NUMERIC(15,2) NOT NULL DEFAULT 0, -- 미지급 분급 잔액
|
||||
unpaid_incentive_amount NUMERIC(15,2) NOT NULL DEFAULT 0, -- 미지급 시책
|
||||
|
||||
-- 환수 예정 금액
|
||||
chargeback_expected_amount NUMERIC(15,2) NOT NULL DEFAULT 0, -- 환수 예정 총액
|
||||
chargeback_waived_amount NUMERIC(15,2) NOT NULL DEFAULT 0, -- 면제 환수액
|
||||
|
||||
-- 공제 항목
|
||||
deduction_amount NUMERIC(15,2) NOT NULL DEFAULT 0, -- 공제 차감액
|
||||
|
||||
-- 최종 지급
|
||||
final_pay_amount NUMERIC(15,2) NOT NULL DEFAULT 0, -- 최종 지급액 (미지급 - 환수 - 공제)
|
||||
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'CALCULATING', -- CALCULATING/CONFIRMED/PAID/CANCELLED
|
||||
note VARCHAR(1000),
|
||||
confirmed_by BIGINT,
|
||||
confirmed_at TIMESTAMP,
|
||||
paid_at TIMESTAMP,
|
||||
payment_id BIGINT REFERENCES payment(payment_id), -- 최종 지급 참조
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by BIGINT,
|
||||
updated_at TIMESTAMP,
|
||||
updated_by BIGINT,
|
||||
UNIQUE (agent_id, termination_date) -- 해촉 1건당 정산 1건
|
||||
);
|
||||
|
||||
COMMENT ON TABLE termination_settlement IS '해촉 정산 — 설계사 해촉 시 미지급분/환수/최종지급 통합 처리';
|
||||
COMMENT ON COLUMN termination_settlement.termination_date IS '해촉 일자';
|
||||
COMMENT ON COLUMN termination_settlement.org_history_id IS 'agent_org_history의 LEAVE 이력 참조';
|
||||
COMMENT ON COLUMN termination_settlement.unpaid_recruit_amount IS '해촉 시점 미지급 신계약 수수료';
|
||||
COMMENT ON COLUMN termination_settlement.unpaid_installment_amount IS '해촉 시점 미지급 분급 잔액 (installment_plan.SCHEDULED 합계)';
|
||||
COMMENT ON COLUMN termination_settlement.unpaid_incentive_amount IS '해촉 시점 미지급 시책 금액';
|
||||
COMMENT ON COLUMN termination_settlement.chargeback_expected_amount IS '해촉 시점 발생 예정 환수 총액';
|
||||
COMMENT ON COLUMN termination_settlement.chargeback_waived_amount IS '합의·면제된 환수액';
|
||||
COMMENT ON COLUMN termination_settlement.final_pay_amount IS '최종 지급액 = (미지급합계) - (환수예정-면제) - 공제';
|
||||
COMMENT ON COLUMN termination_settlement.status IS 'CALCULATING/CONFIRMED/PAID/CANCELLED';
|
||||
|
||||
CREATE INDEX idx_ts_agent ON termination_settlement(agent_id, termination_date DESC);
|
||||
CREATE INDEX idx_ts_month ON termination_settlement(calc_month, status);
|
||||
|
||||
-- ============================================================
|
||||
-- 2. 공통코드 TERM_SETTLE_STATUS
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO common_code_group (group_code, group_name, description, is_system, sort_order) VALUES
|
||||
('TERM_SETTLE_STATUS', '해촉정산상태', 'CALCULATING/CONFIRMED/PAID/CANCELLED', 'Y', 360)
|
||||
ON CONFLICT (group_code) DO NOTHING;
|
||||
|
||||
INSERT INTO common_code (group_code, code, code_name, code_desc, sort_order) VALUES
|
||||
('TERM_SETTLE_STATUS', 'CALCULATING', '산출중', '해촉 정산 금액 산출 중', 10),
|
||||
('TERM_SETTLE_STATUS', 'CONFIRMED', '확정', '해촉 정산 금액 확정', 20),
|
||||
('TERM_SETTLE_STATUS', 'PAID', '지급완료', '최종 지급 완료', 30),
|
||||
('TERM_SETTLE_STATUS', 'CANCELLED', '취소', '해촉 정산 취소', 40)
|
||||
ON CONFLICT (group_code, code) DO NOTHING;
|
||||
@@ -0,0 +1,65 @@
|
||||
-- V35: 세금계산서 발행 이력 (tax_invoice)
|
||||
|
||||
-- ============================================================
|
||||
-- 1. tax_invoice — 세금계산서 발행 이력
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE tax_invoice (
|
||||
invoice_id BIGSERIAL PRIMARY KEY,
|
||||
invoice_no VARCHAR(50) NOT NULL UNIQUE, -- 발행 번호 (국세청 승인번호 등)
|
||||
invoice_type VARCHAR(20) NOT NULL, -- SUPPLY (매출) / PURCHASE (매입)
|
||||
issue_date DATE NOT NULL, -- 발행일
|
||||
supply_amount NUMERIC(15,2) NOT NULL, -- 공급가액
|
||||
tax_amount NUMERIC(15,2) NOT NULL, -- 세액 (공급가 × 10%)
|
||||
total_amount NUMERIC(15,2) NOT NULL, -- 합계액 (공급가 + 세액)
|
||||
|
||||
-- 거래 상대방
|
||||
counterpart_name VARCHAR(200) NOT NULL, -- 거래 상대방 상호
|
||||
counterpart_biz_no VARCHAR(20) NOT NULL, -- 거래 상대방 사업자번호
|
||||
counterpart_rep VARCHAR(100), -- 대표자명
|
||||
counterpart_addr VARCHAR(500), -- 주소
|
||||
|
||||
-- 내부 참조
|
||||
agent_id BIGINT REFERENCES agent(agent_id), -- 관련 설계사 (해당 시)
|
||||
settle_month CHAR(6), -- 관련 정산월 (YYYYMM, 해당 시)
|
||||
settle_id BIGINT REFERENCES settle_master(settle_id),
|
||||
|
||||
-- 발행 메타
|
||||
description VARCHAR(500), -- 품목/비고
|
||||
cancel_date DATE, -- 취소일 (NULL=유효)
|
||||
cancel_reason VARCHAR(500),
|
||||
issued_by BIGINT NOT NULL, -- 발행 처리자
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP,
|
||||
|
||||
CHECK (invoice_type IN ('SUPPLY', 'PURCHASE')),
|
||||
CHECK (total_amount = supply_amount + tax_amount)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE tax_invoice IS '세금계산서 발행 이력 (매출/매입)';
|
||||
COMMENT ON COLUMN tax_invoice.invoice_no IS '세금계산서 발행번호 (국세청 승인번호)';
|
||||
COMMENT ON COLUMN tax_invoice.invoice_type IS 'SUPPLY=매출계산서 / PURCHASE=매입계산서';
|
||||
COMMENT ON COLUMN tax_invoice.supply_amount IS '공급가액';
|
||||
COMMENT ON COLUMN tax_invoice.tax_amount IS '부가세액 (공급가 × 10%)';
|
||||
COMMENT ON COLUMN tax_invoice.total_amount IS '합계 금액 = 공급가 + 부가세';
|
||||
COMMENT ON COLUMN tax_invoice.counterpart_biz_no IS '거래 상대방 사업자등록번호';
|
||||
COMMENT ON COLUMN tax_invoice.cancel_date IS '세금계산서 취소일 (NULL이면 유효 상태)';
|
||||
COMMENT ON COLUMN tax_invoice.settle_month IS '연관 정산월 (YYYYMM)';
|
||||
|
||||
CREATE INDEX idx_ti_issue_date ON tax_invoice(issue_date DESC);
|
||||
CREATE INDEX idx_ti_type_month ON tax_invoice(invoice_type, settle_month);
|
||||
CREATE INDEX idx_ti_agent ON tax_invoice(agent_id, issue_date DESC);
|
||||
CREATE INDEX idx_ti_biz_no ON tax_invoice(counterpart_biz_no);
|
||||
|
||||
-- ============================================================
|
||||
-- 2. 공통코드 INVOICE_TYPE
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO common_code_group (group_code, group_name, description, is_system, sort_order) VALUES
|
||||
('INVOICE_TYPE', '세금계산서유형', 'SUPPLY/PURCHASE', 'Y', 370)
|
||||
ON CONFLICT (group_code) DO NOTHING;
|
||||
|
||||
INSERT INTO common_code (group_code, code, code_name, code_desc, sort_order) VALUES
|
||||
('INVOICE_TYPE', 'SUPPLY', '매출', '매출(공급) 세금계산서 — GA가 발행', 10),
|
||||
('INVOICE_TYPE', 'PURCHASE', '매입', '매입 세금계산서 — GA가 수취', 20)
|
||||
ON CONFLICT (group_code, code) DO NOTHING;
|
||||
@@ -0,0 +1,54 @@
|
||||
-- V36: 보험사 회신 인터페이스 (carrier_reconciliation_out) — 정산 결과 외부 전송 관리
|
||||
|
||||
-- ============================================================
|
||||
-- 1. carrier_reconciliation_out — 보험사 회신 (아웃바운드) 이력
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE carrier_reconciliation_out (
|
||||
recon_out_id BIGSERIAL PRIMARY KEY,
|
||||
carrier_id BIGINT NOT NULL REFERENCES insurance_company(company_id),
|
||||
settle_month CHAR(6) NOT NULL, -- 대상 정산월 (YYYYMM)
|
||||
file_path VARCHAR(1000), -- 전송 파일 경로 (SFTP/FTP 등)
|
||||
file_name VARCHAR(300), -- 파일명
|
||||
file_size BIGINT, -- 파일 크기 (bytes)
|
||||
record_count INT, -- 파일 내 레코드 수
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'READY', -- READY/SENT/ACK/FAIL
|
||||
sent_at TIMESTAMP, -- 전송 일시
|
||||
ack_at TIMESTAMP, -- 보험사 수신 확인 일시
|
||||
ack_message VARCHAR(1000), -- 보험사 회신 메시지
|
||||
fail_reason VARCHAR(1000), -- 실패 사유
|
||||
retry_count INT NOT NULL DEFAULT 0, -- 재시도 횟수
|
||||
last_retry_at TIMESTAMP, -- 마지막 재시도 일시
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by BIGINT,
|
||||
updated_at TIMESTAMP,
|
||||
UNIQUE (carrier_id, settle_month) -- 보험사 + 정산월 단위 단건
|
||||
);
|
||||
|
||||
COMMENT ON TABLE carrier_reconciliation_out IS '보험사 정산 회신 인터페이스 — 아웃바운드 전송 이력 관리';
|
||||
COMMENT ON COLUMN carrier_reconciliation_out.carrier_id IS '대상 보험사 (insurance_company.company_id)';
|
||||
COMMENT ON COLUMN carrier_reconciliation_out.settle_month IS '전송 대상 정산월 (YYYYMM)';
|
||||
COMMENT ON COLUMN carrier_reconciliation_out.file_path IS '전송 파일 저장 경로 (절대경로 또는 S3 URI)';
|
||||
COMMENT ON COLUMN carrier_reconciliation_out.status IS 'READY=전송 준비 / SENT=전송 완료 / ACK=수신 확인 / FAIL=전송 실패';
|
||||
COMMENT ON COLUMN carrier_reconciliation_out.sent_at IS '파일 전송 완료 일시';
|
||||
COMMENT ON COLUMN carrier_reconciliation_out.ack_at IS '보험사 수신 확인 일시';
|
||||
COMMENT ON COLUMN carrier_reconciliation_out.retry_count IS 'FAIL 후 재시도 횟수 (최대 재시도 횟수는 system_config 참조)';
|
||||
|
||||
CREATE INDEX idx_cro_carrier ON carrier_reconciliation_out(carrier_id, settle_month);
|
||||
CREATE INDEX idx_cro_status ON carrier_reconciliation_out(status, sent_at DESC);
|
||||
CREATE INDEX idx_cro_month ON carrier_reconciliation_out(settle_month, status);
|
||||
|
||||
-- ============================================================
|
||||
-- 2. 공통코드 RECON_OUT_STATUS
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO common_code_group (group_code, group_name, description, is_system, sort_order) VALUES
|
||||
('RECON_OUT_STATUS', '회신전송상태', 'READY/SENT/ACK/FAIL', 'Y', 380)
|
||||
ON CONFLICT (group_code) DO NOTHING;
|
||||
|
||||
INSERT INTO common_code (group_code, code, code_name, code_desc, sort_order) VALUES
|
||||
('RECON_OUT_STATUS', 'READY', '전송준비', '파일 생성 완료, 전송 대기 중', 10),
|
||||
('RECON_OUT_STATUS', 'SENT', '전송완료', '보험사로 파일 전송 완료 (확인 전)', 20),
|
||||
('RECON_OUT_STATUS', 'ACK', '수신확인', '보험사 수신 확인 완료', 30),
|
||||
('RECON_OUT_STATUS', 'FAIL', '전송실패', '파일 전송 실패 — 재시도 필요', 40)
|
||||
ON CONFLICT (group_code, code) DO NOTHING;
|
||||
@@ -0,0 +1,257 @@
|
||||
-- V37: KPI 대시보드 Materialized View 4종
|
||||
--
|
||||
-- REFRESH 전략:
|
||||
-- CONCURRENTLY 옵션으로 락 없이 갱신 (UNIQUE INDEX 필수).
|
||||
-- 야간 배치(ga-batch)에서 매일 00:30 순차 REFRESH.
|
||||
-- 명령: REFRESH MATERIALIZED VIEW CONCURRENTLY <mv_name>;
|
||||
--
|
||||
-- 주의: CONCURRENTLY 는 트랜잭션 안에서 실행 불가.
|
||||
-- 배치에서 Connection.setAutoCommit(true) 상태로 호출할 것.
|
||||
|
||||
-- ============================================================
|
||||
-- 1. mv_monthly_summary — 월별 정산 요약
|
||||
-- 단위: 정산월(yyyymm) 전체 합산
|
||||
-- ============================================================
|
||||
|
||||
CREATE MATERIALIZED VIEW mv_monthly_summary AS
|
||||
SELECT
|
||||
sm.settle_month AS yyyymm,
|
||||
COUNT(sm.settle_id) AS agent_count,
|
||||
COALESCE(SUM(sm.recruit_total), 0) AS total_recruit,
|
||||
COALESCE(SUM(sm.maintain_total), 0) AS total_maintain,
|
||||
COALESCE(SUM(sm.override_total), 0) AS total_override,
|
||||
COALESCE(SUM(sm.chargeback_total),0) AS total_chargeback,
|
||||
COALESCE(SUM(sm.gross_amount), 0) AS total_gross,
|
||||
COALESCE(SUM(sm.tax_amount), 0) AS total_tax,
|
||||
COALESCE(SUM(sm.net_amount), 0) AS total_net,
|
||||
-- 인센티브 합계 (해당 월 PAID 기준)
|
||||
COALESCE((
|
||||
SELECT SUM(ip.incentive_amount)
|
||||
FROM incentive_payment ip
|
||||
WHERE ip.settle_month = sm.settle_month
|
||||
AND ip.status = 'PAID'
|
||||
), 0) AS total_incentive,
|
||||
NOW() AS refreshed_at
|
||||
FROM settle_master sm
|
||||
WHERE sm.status IN ('CONFIRMED', 'PAID')
|
||||
GROUP BY sm.settle_month
|
||||
WITH DATA;
|
||||
|
||||
COMMENT ON MATERIALIZED VIEW mv_monthly_summary IS '월별 정산 요약 KPI — REFRESH CONCURRENTLY 야간 배치';
|
||||
COMMENT ON COLUMN mv_monthly_summary.yyyymm IS '정산년월 (YYYYMM)';
|
||||
COMMENT ON COLUMN mv_monthly_summary.agent_count IS '해당 월 확정/지급 완료 설계사 수';
|
||||
COMMENT ON COLUMN mv_monthly_summary.total_gross IS '총 수수료 (세전)';
|
||||
COMMENT ON COLUMN mv_monthly_summary.total_tax IS '총 원천세';
|
||||
COMMENT ON COLUMN mv_monthly_summary.total_net IS '총 순지급액 (세후)';
|
||||
COMMENT ON COLUMN mv_monthly_summary.total_incentive IS '해당 월 지급 완료 시책 합계';
|
||||
COMMENT ON COLUMN mv_monthly_summary.refreshed_at IS 'MATERIALIZED VIEW 마지막 갱신 시각';
|
||||
|
||||
-- CONCURRENTLY REFRESH 를 위한 UNIQUE INDEX (필수)
|
||||
CREATE UNIQUE INDEX idx_mv_monthly_summary_pk ON mv_monthly_summary(yyyymm);
|
||||
|
||||
-- ============================================================
|
||||
-- 2. mv_org_summary — 조직별 월별 요약
|
||||
-- 단위: org_id + yyyymm
|
||||
-- ============================================================
|
||||
|
||||
CREATE MATERIALIZED VIEW mv_org_summary AS
|
||||
SELECT
|
||||
a.org_id,
|
||||
o.org_name,
|
||||
o.org_type,
|
||||
sm.settle_month AS yyyymm,
|
||||
COUNT(DISTINCT sm.agent_id) AS agent_count,
|
||||
COALESCE(SUM(sm.recruit_total), 0) AS total_recruit,
|
||||
COALESCE(SUM(sm.maintain_total), 0) AS total_maintain,
|
||||
COALESCE(SUM(sm.override_total), 0) AS total_override,
|
||||
COALESCE(SUM(sm.chargeback_total),0) AS total_chargeback,
|
||||
COALESCE(SUM(sm.gross_amount), 0) AS total_gross,
|
||||
COALESCE(SUM(sm.net_amount), 0) AS total_net,
|
||||
NOW() AS refreshed_at
|
||||
FROM settle_master sm
|
||||
JOIN agent a ON a.agent_id = sm.agent_id
|
||||
JOIN organization o ON o.org_id = a.org_id
|
||||
WHERE sm.status IN ('CONFIRMED', 'PAID')
|
||||
GROUP BY a.org_id, o.org_name, o.org_type, sm.settle_month
|
||||
WITH DATA;
|
||||
|
||||
COMMENT ON MATERIALIZED VIEW mv_org_summary IS '조직별 월별 요약 KPI — REFRESH CONCURRENTLY 야간 배치';
|
||||
COMMENT ON COLUMN mv_org_summary.org_id IS '조직 ID';
|
||||
COMMENT ON COLUMN mv_org_summary.yyyymm IS '정산년월 (YYYYMM)';
|
||||
COMMENT ON COLUMN mv_org_summary.agent_count IS '해당 조직의 월 확정/지급 설계사 수';
|
||||
COMMENT ON COLUMN mv_org_summary.total_gross IS '조직 소속 설계사 총 수수료 합계 (세전)';
|
||||
COMMENT ON COLUMN mv_org_summary.total_net IS '조직 소속 설계사 총 순지급액 합계';
|
||||
|
||||
CREATE UNIQUE INDEX idx_mv_org_summary_pk ON mv_org_summary(org_id, yyyymm);
|
||||
CREATE INDEX idx_mv_org_summary_month ON mv_org_summary(yyyymm);
|
||||
|
||||
-- ============================================================
|
||||
-- 3. mv_retention — 계약 유지율 (13M / 25M)
|
||||
-- 단위: contract_month (계약 기준월) + carrier_id
|
||||
-- 유지율 = 기준월 이후 N개월 시점에 유효한 계약 비율
|
||||
-- ============================================================
|
||||
|
||||
CREATE MATERIALIZED VIEW mv_retention AS
|
||||
WITH base AS (
|
||||
-- 계약 기준월별 원수 계약 집계
|
||||
SELECT
|
||||
TO_CHAR(c.contract_date, 'YYYYMM') AS contract_month,
|
||||
p.company_id AS carrier_id,
|
||||
COUNT(c.contract_id) AS total_contracts
|
||||
FROM contract c
|
||||
JOIN product p ON p.product_id = c.product_id
|
||||
WHERE c.status != 'TERMINATE'
|
||||
GROUP BY TO_CHAR(c.contract_date, 'YYYYMM'), p.company_id
|
||||
),
|
||||
m13 AS (
|
||||
-- 13개월 시점 유지 계약 (lapse_month > 12 또는 아직 실효 없음)
|
||||
SELECT
|
||||
TO_CHAR(c.contract_date, 'YYYYMM') AS contract_month,
|
||||
p.company_id AS carrier_id,
|
||||
COUNT(c.contract_id) AS retained_13m
|
||||
FROM contract c
|
||||
JOIN product p ON p.product_id = c.product_id
|
||||
WHERE c.status != 'TERMINATE'
|
||||
AND (
|
||||
-- 실효 데이터 없거나 실효 경과월 > 12
|
||||
NOT EXISTS (
|
||||
SELECT 1 FROM chargeback cb
|
||||
WHERE cb.contract_id = c.contract_id
|
||||
AND cb.lapse_month IS NOT NULL
|
||||
AND cb.lapse_month <= 12
|
||||
)
|
||||
)
|
||||
GROUP BY TO_CHAR(c.contract_date, 'YYYYMM'), p.company_id
|
||||
),
|
||||
m25 AS (
|
||||
-- 25개월 시점 유지 계약 (lapse_month > 24 또는 실효 없음)
|
||||
SELECT
|
||||
TO_CHAR(c.contract_date, 'YYYYMM') AS contract_month,
|
||||
p.company_id AS carrier_id,
|
||||
COUNT(c.contract_id) AS retained_25m
|
||||
FROM contract c
|
||||
JOIN product p ON p.product_id = c.product_id
|
||||
WHERE c.status != 'TERMINATE'
|
||||
AND (
|
||||
NOT EXISTS (
|
||||
SELECT 1 FROM chargeback cb
|
||||
WHERE cb.contract_id = c.contract_id
|
||||
AND cb.lapse_month IS NOT NULL
|
||||
AND cb.lapse_month <= 24
|
||||
)
|
||||
)
|
||||
GROUP BY TO_CHAR(c.contract_date, 'YYYYMM'), p.company_id
|
||||
)
|
||||
SELECT
|
||||
b.contract_month,
|
||||
b.carrier_id,
|
||||
ic.company_name AS carrier_name,
|
||||
b.total_contracts,
|
||||
COALESCE(m13.retained_13m, 0) AS retained_13m,
|
||||
COALESCE(m25.retained_25m, 0) AS retained_25m,
|
||||
-- 13개월 유지율 %
|
||||
CASE WHEN b.total_contracts > 0
|
||||
THEN ROUND(COALESCE(m13.retained_13m, 0) * 100.0 / b.total_contracts, 2)
|
||||
ELSE 0
|
||||
END AS retention_rate_13m,
|
||||
-- 25개월 유지율 %
|
||||
CASE WHEN b.total_contracts > 0
|
||||
THEN ROUND(COALESCE(m25.retained_25m, 0) * 100.0 / b.total_contracts, 2)
|
||||
ELSE 0
|
||||
END AS retention_rate_25m,
|
||||
NOW() AS refreshed_at
|
||||
FROM base b
|
||||
JOIN insurance_company ic ON ic.company_id = b.carrier_id
|
||||
LEFT JOIN m13 ON m13.contract_month = b.contract_month AND m13.carrier_id = b.carrier_id
|
||||
LEFT JOIN m25 ON m25.contract_month = b.contract_month AND m25.carrier_id = b.carrier_id
|
||||
WITH DATA;
|
||||
|
||||
COMMENT ON MATERIALIZED VIEW mv_retention IS '계약 유지율 KPI (13M/25M) — REFRESH CONCURRENTLY 야간 배치';
|
||||
COMMENT ON COLUMN mv_retention.contract_month IS '계약 기준월 (YYYYMM)';
|
||||
COMMENT ON COLUMN mv_retention.carrier_id IS '보험사 ID';
|
||||
COMMENT ON COLUMN mv_retention.total_contracts IS '기준월 전체 유효 계약 수';
|
||||
COMMENT ON COLUMN mv_retention.retained_13m IS '13개월 시점 유지 계약 수';
|
||||
COMMENT ON COLUMN mv_retention.retained_25m IS '25개월 시점 유지 계약 수';
|
||||
COMMENT ON COLUMN mv_retention.retention_rate_13m IS '13개월 유지율 (%)';
|
||||
COMMENT ON COLUMN mv_retention.retention_rate_25m IS '25개월 유지율 (%)';
|
||||
|
||||
CREATE UNIQUE INDEX idx_mv_retention_pk ON mv_retention(contract_month, carrier_id);
|
||||
CREATE INDEX idx_mv_retention_month ON mv_retention(contract_month);
|
||||
|
||||
-- ============================================================
|
||||
-- 4. mv_cumulative — 설계사/조직별 누계
|
||||
-- 단위: agent_id 또는 org_id (두 레벨 모두 포함)
|
||||
-- ============================================================
|
||||
|
||||
CREATE MATERIALIZED VIEW mv_cumulative AS
|
||||
-- 설계사 레벨 누계
|
||||
SELECT
|
||||
'AGENT' AS level_type,
|
||||
a.agent_id AS entity_id,
|
||||
a.agent_name AS entity_name,
|
||||
a.org_id AS org_id,
|
||||
o.org_name AS org_name,
|
||||
MIN(sm.settle_month) AS first_settle_month,
|
||||
MAX(sm.settle_month) AS last_settle_month,
|
||||
COUNT(sm.settle_id) AS settle_month_count,
|
||||
COALESCE(SUM(sm.gross_amount), 0) AS cum_gross,
|
||||
COALESCE(SUM(sm.net_amount), 0) AS cum_net,
|
||||
COALESCE(SUM(sm.chargeback_total), 0) AS cum_chargeback,
|
||||
COALESCE(SUM(sm.override_total), 0) AS cum_override,
|
||||
-- 시책 누계
|
||||
COALESCE((
|
||||
SELECT SUM(ip.incentive_amount)
|
||||
FROM incentive_payment ip
|
||||
WHERE ip.agent_id = a.agent_id
|
||||
AND ip.status = 'PAID'
|
||||
), 0) AS cum_incentive,
|
||||
NOW() AS refreshed_at
|
||||
FROM settle_master sm
|
||||
JOIN agent a ON a.agent_id = sm.agent_id
|
||||
JOIN organization o ON o.org_id = a.org_id
|
||||
WHERE sm.status IN ('CONFIRMED', 'PAID')
|
||||
GROUP BY a.agent_id, a.agent_name, a.org_id, o.org_name
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- 조직 레벨 누계 (소속 설계사 합산)
|
||||
SELECT
|
||||
'ORG' AS level_type,
|
||||
o.org_id AS entity_id,
|
||||
o.org_name AS entity_name,
|
||||
o.org_id AS org_id,
|
||||
o.org_name AS org_name,
|
||||
MIN(sm.settle_month) AS first_settle_month,
|
||||
MAX(sm.settle_month) AS last_settle_month,
|
||||
COUNT(DISTINCT sm.settle_month) AS settle_month_count,
|
||||
COALESCE(SUM(sm.gross_amount), 0) AS cum_gross,
|
||||
COALESCE(SUM(sm.net_amount), 0) AS cum_net,
|
||||
COALESCE(SUM(sm.chargeback_total), 0) AS cum_chargeback,
|
||||
COALESCE(SUM(sm.override_total), 0) AS cum_override,
|
||||
COALESCE((
|
||||
SELECT SUM(ip.incentive_amount)
|
||||
FROM incentive_payment ip
|
||||
JOIN agent ia ON ia.agent_id = ip.agent_id
|
||||
WHERE ia.org_id = o.org_id
|
||||
AND ip.status = 'PAID'
|
||||
), 0) AS cum_incentive,
|
||||
NOW() AS refreshed_at
|
||||
FROM settle_master sm
|
||||
JOIN agent a ON a.agent_id = sm.agent_id
|
||||
JOIN organization o ON o.org_id = a.org_id
|
||||
WHERE sm.status IN ('CONFIRMED', 'PAID')
|
||||
GROUP BY o.org_id, o.org_name
|
||||
WITH DATA;
|
||||
|
||||
COMMENT ON MATERIALIZED VIEW mv_cumulative IS '설계사/조직 누계 수수료·환수 KPI — REFRESH CONCURRENTLY 야간 배치';
|
||||
COMMENT ON COLUMN mv_cumulative.level_type IS 'AGENT=설계사 레벨 / ORG=조직 레벨';
|
||||
COMMENT ON COLUMN mv_cumulative.entity_id IS 'level_type=AGENT이면 agent_id, ORG이면 org_id';
|
||||
COMMENT ON COLUMN mv_cumulative.cum_gross IS '누적 총 수수료 (세전)';
|
||||
COMMENT ON COLUMN mv_cumulative.cum_net IS '누적 순지급액 (세후)';
|
||||
COMMENT ON COLUMN mv_cumulative.cum_chargeback IS '누적 환수 합계';
|
||||
COMMENT ON COLUMN mv_cumulative.cum_incentive IS '누적 시책 지급액';
|
||||
COMMENT ON COLUMN mv_cumulative.refreshed_at IS 'MATERIALIZED VIEW 마지막 갱신 시각';
|
||||
|
||||
-- CONCURRENTLY 를 위한 UNIQUE INDEX: level_type + entity_id 조합
|
||||
CREATE UNIQUE INDEX idx_mv_cumulative_pk ON mv_cumulative(level_type, entity_id);
|
||||
CREATE INDEX idx_mv_cumulative_org ON mv_cumulative(org_id, level_type);
|
||||
@@ -0,0 +1,53 @@
|
||||
-- V38: 리포트 메뉴 하위 항목 추가
|
||||
-- GRP_REPORT / REPORT 그룹 모두 처리 (V12 = REPORT, V18 = GRP_REPORT)
|
||||
|
||||
-- 1. REPORT 그룹에 하위 PAGE 삽입 (menu_code=REPORT 기준)
|
||||
INSERT INTO menu (parent_menu_id, menu_code, menu_name, menu_type, menu_path, component_path, menu_level, sort_order)
|
||||
SELECT p.menu_id, x.code, x.name, 'PAGE', x.path, x.cmpt, 2, x.sort
|
||||
FROM menu p
|
||||
JOIN (VALUES
|
||||
('REPORT_PERFORMANCE', '실적 리포트', '/report/performance', 'report/PerformanceReport', 10),
|
||||
('REPORT_ORG', '조직별 리포트', '/report/org', 'report/OrgReport', 20),
|
||||
('REPORT_CHARGEBACK', '환수위험 리포트', '/report/chargeback-risk', 'report/ChargebackRiskReport', 30)
|
||||
) AS x(code, name, path, cmpt, sort)
|
||||
ON p.menu_code = 'REPORT'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM menu WHERE menu_code = x.code);
|
||||
|
||||
-- 2. GRP_REPORT 그룹에도 동일 PAGE 삽입 (V18 기준 경로; menu_code=GRP_REPORT)
|
||||
INSERT INTO menu (parent_menu_id, menu_code, menu_name, menu_type, menu_path, component_path, menu_level, sort_order)
|
||||
SELECT p.menu_id, x.code || '_GRP', x.name, 'PAGE', x.path, x.cmpt, 2, x.sort
|
||||
FROM menu p
|
||||
JOIN (VALUES
|
||||
('REPORT_PERFORMANCE', '실적 리포트', '/report/performance', 'report/PerformanceReport', 10),
|
||||
('REPORT_ORG', '조직별 리포트', '/report/org', 'report/OrgReport', 20),
|
||||
('REPORT_CHARGEBACK', '환수위험 리포트', '/report/chargeback-risk', 'report/ChargebackRiskReport', 30)
|
||||
) AS x(code, name, path, cmpt, sort)
|
||||
ON p.menu_code = 'GRP_REPORT'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM menu WHERE menu_code = x.code || '_GRP');
|
||||
|
||||
-- 3. 새 PAGE 메뉴에 권한 항목 추가
|
||||
INSERT INTO menu_permission (menu_id, perm_code, perm_name, sort_order)
|
||||
SELECT m.menu_id, p.code, p.name, p.sort
|
||||
FROM menu m
|
||||
CROSS JOIN (VALUES
|
||||
('READ', '조회', 10),
|
||||
('EXPORT', '엑셀', 60)
|
||||
) AS p(code, name, sort)
|
||||
WHERE m.menu_code IN (
|
||||
'REPORT_PERFORMANCE', 'REPORT_ORG', 'REPORT_CHARGEBACK',
|
||||
'REPORT_PERFORMANCE_GRP', 'REPORT_ORG_GRP', 'REPORT_CHARGEBACK_GRP'
|
||||
)
|
||||
ON CONFLICT (menu_id, perm_code) DO NOTHING;
|
||||
|
||||
-- 4. SUPER_ADMIN / ADMIN / MANAGER 에게 리포트 READ/EXPORT 권한 부여
|
||||
INSERT INTO role_menu_permission (role_id, menu_id, perm_code, is_granted)
|
||||
SELECT r.role_id, mp.menu_id, mp.perm_code, 'Y'
|
||||
FROM role r
|
||||
CROSS JOIN menu_permission mp
|
||||
JOIN menu m ON m.menu_id = mp.menu_id
|
||||
WHERE r.role_code IN ('SUPER_ADMIN', 'ADMIN', 'MANAGER')
|
||||
AND m.menu_code IN (
|
||||
'REPORT_PERFORMANCE', 'REPORT_ORG', 'REPORT_CHARGEBACK',
|
||||
'REPORT_PERFORMANCE_GRP', 'REPORT_ORG_GRP', 'REPORT_CHARGEBACK_GRP'
|
||||
)
|
||||
ON CONFLICT (role_id, menu_id, perm_code) DO NOTHING;
|
||||
@@ -0,0 +1,58 @@
|
||||
-- V39: KPI 대시보드 메뉴 4개 추가
|
||||
-- 부모 그룹: GRP_KPI (신규) — REPORT 그룹과 동일 레벨
|
||||
-- 화면: KPI_MONTHLY / KPI_ORG / KPI_RETENTION / KPI_CUMULATIVE
|
||||
|
||||
-- ============================================================
|
||||
-- 1. KPI 부모 그룹 메뉴 삽입
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO menu (parent_menu_id, menu_code, menu_name, menu_type, menu_path, component_path, menu_level, sort_order)
|
||||
VALUES (NULL, 'GRP_KPI', 'KPI 대시보드', 'GROUP', '/kpi', NULL, 1, 80)
|
||||
ON CONFLICT (menu_code) DO NOTHING;
|
||||
|
||||
-- ============================================================
|
||||
-- 2. KPI 하위 PAGE 메뉴 4개 삽입
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO menu (parent_menu_id, menu_code, menu_name, menu_type, menu_path, component_path, menu_level, sort_order)
|
||||
SELECT p.menu_id, x.code, x.name, 'PAGE', x.path, x.cmpt, 2, x.sort
|
||||
FROM menu p
|
||||
JOIN (VALUES
|
||||
('KPI_MONTHLY', '월별 정산 요약', '/kpi/monthly', 'kpi/KpiMonthlySummary', 10),
|
||||
('KPI_ORG', '조직별 요약', '/kpi/org', 'kpi/KpiOrgSummary', 20),
|
||||
('KPI_RETENTION', '유지율 현황', '/kpi/retention', 'kpi/KpiRetention', 30),
|
||||
('KPI_CUMULATIVE', '누계 현황', '/kpi/cumulative', 'kpi/KpiCumulative', 40)
|
||||
) AS x(code, name, path, cmpt, sort)
|
||||
ON p.menu_code = 'GRP_KPI'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM menu WHERE menu_code = x.code);
|
||||
|
||||
-- ============================================================
|
||||
-- 3. 권한 항목 (READ + EXPORT) 등록
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO menu_permission (menu_id, perm_code, perm_name, sort_order)
|
||||
SELECT m.menu_id, p.code, p.name, p.sort
|
||||
FROM menu m
|
||||
CROSS JOIN (VALUES
|
||||
('READ', '조회', 10),
|
||||
('EXPORT', '엑셀', 60)
|
||||
) AS p(code, name, sort)
|
||||
WHERE m.menu_code IN (
|
||||
'KPI_MONTHLY', 'KPI_ORG', 'KPI_RETENTION', 'KPI_CUMULATIVE'
|
||||
)
|
||||
ON CONFLICT (menu_id, perm_code) DO NOTHING;
|
||||
|
||||
-- ============================================================
|
||||
-- 4. SUPER_ADMIN / ADMIN / MANAGER 에게 READ + EXPORT 부여
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO role_menu_permission (role_id, menu_id, perm_code, is_granted)
|
||||
SELECT r.role_id, mp.menu_id, mp.perm_code, 'Y'
|
||||
FROM role r
|
||||
CROSS JOIN menu_permission mp
|
||||
JOIN menu m ON m.menu_id = mp.menu_id
|
||||
WHERE r.role_code IN ('SUPER_ADMIN', 'ADMIN', 'MANAGER')
|
||||
AND m.menu_code IN (
|
||||
'KPI_MONTHLY', 'KPI_ORG', 'KPI_RETENTION', 'KPI_CUMULATIVE'
|
||||
)
|
||||
ON CONFLICT (role_id, menu_id, perm_code) DO NOTHING;
|
||||
@@ -0,0 +1,59 @@
|
||||
-- V40: 수수료 종류 코드(COMMISSION_TYPE) + 통합 마스터(commission_master)
|
||||
|
||||
-- ============================================================
|
||||
-- 1. 공통코드 그룹 — COMMISSION_TYPE
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO common_code_group (group_code, group_name, description, is_system, sort_order) VALUES
|
||||
('COMMISSION_TYPE', '수수료종류', '모집/유지/수금/오버라이드/갱신/부활/유지보수수당/시책/위촉 9종', 'Y', 360)
|
||||
ON CONFLICT (group_code) DO NOTHING;
|
||||
|
||||
INSERT INTO common_code (group_code, code, code_name, code_desc, sort_order) VALUES
|
||||
('COMMISSION_TYPE', 'RECRUIT', '모집수수료', '신계약 체결 시 발생하는 기본 모집수수료', 10),
|
||||
('COMMISSION_TYPE', 'MAINTAIN', '유지수수료', '계약 유지 기간 중 발생하는 유지수수료', 20),
|
||||
('COMMISSION_TYPE', 'COLLECT', '수금수수료', '보험료 수납 단위로 발생하는 수금수수료', 30),
|
||||
('COMMISSION_TYPE', 'OVERRIDE', '오버라이드', '하위 설계사 수수료 기반 상위 직급 오버라이드', 40),
|
||||
('COMMISSION_TYPE', 'RENEWAL', '갱신수수료', '자동차/실비 등 갱신 계약 시 발생하는 수수료', 50),
|
||||
('COMMISSION_TYPE', 'REINSTATE', '부활수수료', '실효된 계약 부활 시 발생하는 수수료', 60),
|
||||
('COMMISSION_TYPE', 'PERSIST', '유지보수수당', '13/25/37/49개월 유지율 충족 시 지급하는 수당', 70),
|
||||
('COMMISSION_TYPE', 'INCENTIVE', '시책수수료', '본사 시책 프로그램에 따른 인센티브', 80),
|
||||
('COMMISSION_TYPE', 'ONBOARD', '위촉수수료', '보험사 위촉계약 체결 시 지급하는 위촉수수료', 90)
|
||||
ON CONFLICT (group_code, code) DO NOTHING;
|
||||
|
||||
-- ============================================================
|
||||
-- 2. commission_master — 전 수수료 종류 통합 마스터
|
||||
-- 모든 수수료 원장(recruit_ledger / maintain_ledger /
|
||||
-- collection_commission_ledger / override_ledger / 등)에서
|
||||
-- 산출된 결과를 단일 뷰로 집계하기 위한 허브 테이블.
|
||||
-- settle_master 조인 시 agent_id + settle_month 로 연결.
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE commission_master (
|
||||
master_id BIGSERIAL PRIMARY KEY,
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
commission_type VARCHAR(20) NOT NULL,
|
||||
settle_month CHAR(6) NOT NULL,
|
||||
source_table VARCHAR(50) NOT NULL, -- 원본 원장 테이블명 (recruit_ledger 등)
|
||||
source_id BIGINT NOT NULL, -- 원본 원장 PK
|
||||
gross_amount NUMERIC(15,2) NOT NULL DEFAULT 0, -- 세전 수수료
|
||||
tax_amount NUMERIC(15,2) NOT NULL DEFAULT 0, -- 원천세
|
||||
net_amount NUMERIC(15,2) NOT NULL DEFAULT 0, -- 세후 지급액
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'CALCULATED',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP,
|
||||
UNIQUE (agent_id, commission_type, settle_month, source_id),
|
||||
CHECK (commission_type IN ('RECRUIT','MAINTAIN','COLLECT','OVERRIDE','RENEWAL','REINSTATE','PERSIST','INCENTIVE','ONBOARD')),
|
||||
CHECK (status IN ('CALCULATED','CONFIRMED','PAID','CANCELLED'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE commission_master IS '수수료 통합 마스터 — 전 수수료 종류를 단일 허브에서 집계. settle_master 와 agent_id+settle_month 로 조인';
|
||||
COMMENT ON COLUMN commission_master.commission_type IS 'COMMISSION_TYPE 그룹 코드 (RECRUIT/MAINTAIN/COLLECT/OVERRIDE/RENEWAL/REINSTATE/PERSIST/INCENTIVE/ONBOARD)';
|
||||
COMMENT ON COLUMN commission_master.source_table IS '원본 원장 테이블명 (예: recruit_ledger)';
|
||||
COMMENT ON COLUMN commission_master.source_id IS '원본 원장 PK';
|
||||
COMMENT ON COLUMN commission_master.gross_amount IS '세전 수수료 금액';
|
||||
COMMENT ON COLUMN commission_master.net_amount IS '세후 실지급 금액';
|
||||
|
||||
CREATE INDEX idx_cm_agent_month ON commission_master(agent_id, settle_month);
|
||||
CREATE INDEX idx_cm_type_month ON commission_master(commission_type, settle_month);
|
||||
CREATE INDEX idx_cm_source ON commission_master(source_table, source_id);
|
||||
CREATE INDEX idx_cm_status ON commission_master(status, settle_month);
|
||||
@@ -0,0 +1,66 @@
|
||||
-- V41: 수금수수료 (collection_commission_rule + collection_commission_ledger)
|
||||
-- 보험료 수납 단위(매월)로 발생하는 수금수수료. 납입주기별 차등 적용.
|
||||
|
||||
-- ============================================================
|
||||
-- 1. collection_commission_rule — 납입주기별 수금수수료율 마스터
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE collection_commission_rule (
|
||||
rule_id BIGSERIAL PRIMARY KEY,
|
||||
product_id BIGINT NOT NULL REFERENCES product(product_id),
|
||||
payment_cycle VARCHAR(20) NOT NULL,
|
||||
commission_rate NUMERIC(7,4) NOT NULL,
|
||||
effective_from DATE NOT NULL,
|
||||
effective_to DATE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by BIGINT,
|
||||
updated_at TIMESTAMP,
|
||||
UNIQUE (product_id, payment_cycle, effective_from),
|
||||
CHECK (payment_cycle IN ('MONTHLY','QUARTERLY','SEMI','ANNUAL')),
|
||||
CHECK (commission_rate >= 0 AND commission_rate <= 1)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE collection_commission_rule IS '수금수수료율 마스터 — 상품/납입주기별 수금수수료율 정의';
|
||||
COMMENT ON COLUMN collection_commission_rule.product_id IS '적용 상품 FK';
|
||||
COMMENT ON COLUMN collection_commission_rule.payment_cycle IS '납입주기 (MONTHLY=월납/QUARTERLY=분기납/SEMI=반기납/ANNUAL=연납)';
|
||||
COMMENT ON COLUMN collection_commission_rule.commission_rate IS '수금수수료율 (소수, 예: 0.005 = 0.5%)';
|
||||
COMMENT ON COLUMN collection_commission_rule.effective_from IS '적용 시작일';
|
||||
COMMENT ON COLUMN collection_commission_rule.effective_to IS '적용 종료일 (NULL=현재 유효)';
|
||||
|
||||
CREATE INDEX idx_ccr_product ON collection_commission_rule(product_id, effective_from);
|
||||
|
||||
-- ============================================================
|
||||
-- 2. collection_commission_ledger — 수금수수료 원장
|
||||
-- 매월 수납 확인 후 발생. paid_at 기준으로 정산월 귀속.
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE collection_commission_ledger (
|
||||
ledger_id BIGSERIAL PRIMARY KEY,
|
||||
contract_id BIGINT NOT NULL REFERENCES contract(contract_id),
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
settle_month CHAR(6) NOT NULL,
|
||||
premium_amount NUMERIC(15,2) NOT NULL,
|
||||
commission_rate NUMERIC(7,4) NOT NULL,
|
||||
commission_amount NUMERIC(15,2) NOT NULL,
|
||||
payment_cycle VARCHAR(20) NOT NULL,
|
||||
paid_at DATE NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'CALCULATED',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP,
|
||||
CHECK (payment_cycle IN ('MONTHLY','QUARTERLY','SEMI','ANNUAL')),
|
||||
CHECK (status IN ('CALCULATED','CONFIRMED','PAID','CANCELLED'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE collection_commission_ledger IS '수금수수료 원장 — 매월 보험료 수납 단위로 발생';
|
||||
COMMENT ON COLUMN collection_commission_ledger.contract_id IS '대상 계약 FK';
|
||||
COMMENT ON COLUMN collection_commission_ledger.agent_id IS '수금 담당 설계사 FK';
|
||||
COMMENT ON COLUMN collection_commission_ledger.settle_month IS '정산 귀속월 (YYYYMM)';
|
||||
COMMENT ON COLUMN collection_commission_ledger.premium_amount IS '수납 보험료';
|
||||
COMMENT ON COLUMN collection_commission_ledger.commission_rate IS '적용 수금수수료율';
|
||||
COMMENT ON COLUMN collection_commission_ledger.commission_amount IS '수금수수료 = premium_amount * commission_rate';
|
||||
COMMENT ON COLUMN collection_commission_ledger.payment_cycle IS '납입주기';
|
||||
COMMENT ON COLUMN collection_commission_ledger.paid_at IS '실 보험료 납입일';
|
||||
|
||||
CREATE INDEX idx_ccl_agent_month ON collection_commission_ledger(agent_id, settle_month);
|
||||
CREATE INDEX idx_ccl_contract ON collection_commission_ledger(contract_id);
|
||||
CREATE INDEX idx_ccl_status ON collection_commission_ledger(status, settle_month);
|
||||
@@ -0,0 +1,122 @@
|
||||
-- V42: 갱신수수료 + 부활수수료 (rule + ledger 각 2쌍)
|
||||
-- 갱신: 자동차/실비/단기보험 갱신 계약 시 정률 또는 정액 수수료
|
||||
-- 부활: 실효 후 부활 시 수수료 + 기존 환수액 일부 환원
|
||||
|
||||
-- ============================================================
|
||||
-- 1. renewal_commission_rule — 갱신수수료율 마스터
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE renewal_commission_rule (
|
||||
rule_id BIGSERIAL PRIMARY KEY,
|
||||
product_id BIGINT NOT NULL REFERENCES product(product_id),
|
||||
pay_type VARCHAR(20) NOT NULL DEFAULT 'RATE',
|
||||
rate_value NUMERIC(7,4), -- RATE 방식: 갱신 보험료 대비 비율
|
||||
fixed_amount NUMERIC(15,2), -- FIXED 방식: 건당 고정 금액
|
||||
effective_from DATE NOT NULL,
|
||||
effective_to DATE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by BIGINT,
|
||||
updated_at TIMESTAMP,
|
||||
UNIQUE (product_id, effective_from),
|
||||
CHECK (pay_type IN ('RATE','FIXED')),
|
||||
CHECK (
|
||||
(pay_type = 'RATE' AND rate_value IS NOT NULL) OR
|
||||
(pay_type = 'FIXED' AND fixed_amount IS NOT NULL)
|
||||
)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE renewal_commission_rule IS '갱신수수료율 마스터 — 자동차/실비/단기보험 갱신 대상 상품별 룰';
|
||||
COMMENT ON COLUMN renewal_commission_rule.pay_type IS 'RATE=갱신보험료 대비 비율 / FIXED=건당 고정금액';
|
||||
COMMENT ON COLUMN renewal_commission_rule.rate_value IS 'RATE 방식 비율 (소수, 예: 0.02 = 2%)';
|
||||
COMMENT ON COLUMN renewal_commission_rule.fixed_amount IS 'FIXED 방식 건당 지급액';
|
||||
|
||||
CREATE INDEX idx_rcr_product ON renewal_commission_rule(product_id, effective_from);
|
||||
|
||||
-- ============================================================
|
||||
-- 2. renewal_commission_ledger — 갱신수수료 원장
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE renewal_commission_ledger (
|
||||
ledger_id BIGSERIAL PRIMARY KEY,
|
||||
contract_id BIGINT NOT NULL REFERENCES contract(contract_id),
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
rule_id BIGINT REFERENCES renewal_commission_rule(rule_id),
|
||||
settle_month CHAR(6) NOT NULL,
|
||||
renewal_date DATE NOT NULL,
|
||||
renewal_premium NUMERIC(15,2) NOT NULL,
|
||||
commission_amount NUMERIC(15,2) NOT NULL,
|
||||
pay_type VARCHAR(20) NOT NULL DEFAULT 'RATE',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'CALCULATED',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP,
|
||||
CHECK (pay_type IN ('RATE','FIXED')),
|
||||
CHECK (status IN ('CALCULATED','CONFIRMED','PAID','CANCELLED'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE renewal_commission_ledger IS '갱신수수료 원장 — 계약 갱신 1회당 발생';
|
||||
COMMENT ON COLUMN renewal_commission_ledger.renewal_date IS '계약 갱신일';
|
||||
COMMENT ON COLUMN renewal_commission_ledger.renewal_premium IS '갱신 보험료';
|
||||
COMMENT ON COLUMN renewal_commission_ledger.commission_amount IS '갱신수수료 (rate*premium 또는 fixed_amount)';
|
||||
|
||||
CREATE INDEX idx_rcl_agent_month ON renewal_commission_ledger(agent_id, settle_month);
|
||||
CREATE INDEX idx_rcl_contract ON renewal_commission_ledger(contract_id);
|
||||
|
||||
-- ============================================================
|
||||
-- 3. reinstatement_commission_rule — 부활수수료율 마스터
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE reinstatement_commission_rule (
|
||||
rule_id BIGSERIAL PRIMARY KEY,
|
||||
product_id BIGINT NOT NULL REFERENCES product(product_id),
|
||||
pay_type VARCHAR(20) NOT NULL DEFAULT 'RATE',
|
||||
rate_value NUMERIC(7,4), -- RATE: 부활 보험료 대비 비율
|
||||
fixed_amount NUMERIC(15,2), -- FIXED: 건당 고정 금액
|
||||
chargeback_reversal_rate NUMERIC(7,4) NOT NULL DEFAULT 0,
|
||||
-- 부활 시 기존 환수액 중 환원 비율 (예: 0.5 = 50% 환원)
|
||||
effective_from DATE NOT NULL,
|
||||
effective_to DATE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by BIGINT,
|
||||
updated_at TIMESTAMP,
|
||||
UNIQUE (product_id, effective_from),
|
||||
CHECK (pay_type IN ('RATE','FIXED')),
|
||||
CHECK (chargeback_reversal_rate >= 0 AND chargeback_reversal_rate <= 1)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE reinstatement_commission_rule IS '부활수수료율 마스터 — 실효 후 부활 시 적용 룰';
|
||||
COMMENT ON COLUMN reinstatement_commission_rule.chargeback_reversal_rate IS '기존 환수액 중 부활 시 환원 비율 (0~1)';
|
||||
|
||||
CREATE INDEX idx_rsr_product ON reinstatement_commission_rule(product_id, effective_from);
|
||||
|
||||
-- ============================================================
|
||||
-- 4. reinstatement_commission_ledger — 부활수수료 원장
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE reinstatement_commission_ledger (
|
||||
ledger_id BIGSERIAL PRIMARY KEY,
|
||||
contract_id BIGINT NOT NULL REFERENCES contract(contract_id),
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
rule_id BIGINT REFERENCES reinstatement_commission_rule(rule_id),
|
||||
settle_month CHAR(6) NOT NULL,
|
||||
reinstatement_date DATE NOT NULL,
|
||||
reinstatement_premium NUMERIC(15,2) NOT NULL,
|
||||
commission_amount NUMERIC(15,2) NOT NULL,
|
||||
chargeback_reversal NUMERIC(15,2) NOT NULL DEFAULT 0,
|
||||
-- 기존 환수액 중 환원금 (부활 인센티브)
|
||||
net_commission NUMERIC(15,2) NOT NULL,
|
||||
-- 최종 수수료 = commission_amount + chargeback_reversal
|
||||
pay_type VARCHAR(20) NOT NULL DEFAULT 'RATE',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'CALCULATED',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP,
|
||||
CHECK (pay_type IN ('RATE','FIXED')),
|
||||
CHECK (status IN ('CALCULATED','CONFIRMED','PAID','CANCELLED'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE reinstatement_commission_ledger IS '부활수수료 원장 — 실효 계약 부활 1건당 발생';
|
||||
COMMENT ON COLUMN reinstatement_commission_ledger.reinstatement_date IS '계약 부활일';
|
||||
COMMENT ON COLUMN reinstatement_commission_ledger.chargeback_reversal IS '부활로 인한 환수액 환원금';
|
||||
COMMENT ON COLUMN reinstatement_commission_ledger.net_commission IS '최종 수수료 = 부활수수료 + 환수환원금';
|
||||
|
||||
CREATE INDEX idx_rsl_agent_month ON reinstatement_commission_ledger(agent_id, settle_month);
|
||||
CREATE INDEX idx_rsl_contract ON reinstatement_commission_ledger(contract_id);
|
||||
@@ -0,0 +1,74 @@
|
||||
-- V43: 유지보수수당 (persistency_bonus_rule + persistency_bonus)
|
||||
-- 13/25/37/49개월 유지율 충족 시 1회 지급하는 유지보수수당.
|
||||
-- 등급별 정률(RATE) 또는 정액(FIXED) 지급.
|
||||
|
||||
-- ============================================================
|
||||
-- 1. persistency_bonus_rule — 유지보수수당 룰 마스터
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE persistency_bonus_rule (
|
||||
rule_id BIGSERIAL PRIMARY KEY,
|
||||
grade_id BIGINT REFERENCES grade(grade_id),
|
||||
-- NULL이면 전 직급 공통 적용
|
||||
retention_month INT NOT NULL,
|
||||
-- 유지 기준 개월수 (13/25/37/49)
|
||||
retention_rate_threshold NUMERIC(5,4) NOT NULL,
|
||||
-- 유지율 하한 기준 (예: 0.95 = 95% 이상)
|
||||
bonus_type VARCHAR(10) NOT NULL,
|
||||
bonus_value NUMERIC(15,4) NOT NULL,
|
||||
-- RATE: 모집수수료 대비 비율 / FIXED: 지급 고정액
|
||||
effective_from DATE NOT NULL,
|
||||
effective_to DATE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by BIGINT,
|
||||
updated_at TIMESTAMP,
|
||||
CHECK (retention_month IN (13, 25, 37, 49)),
|
||||
CHECK (bonus_type IN ('RATE','FIXED')),
|
||||
CHECK (retention_rate_threshold > 0 AND retention_rate_threshold <= 1)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE persistency_bonus_rule IS '유지보수수당 룰 마스터 — 직급/유지개월/유지율 임계치별 지급 기준';
|
||||
COMMENT ON COLUMN persistency_bonus_rule.grade_id IS '적용 직급 FK (NULL=전 직급 공통)';
|
||||
COMMENT ON COLUMN persistency_bonus_rule.retention_month IS '유지 기준 개월수 (13/25/37/49)';
|
||||
COMMENT ON COLUMN persistency_bonus_rule.retention_rate_threshold IS '유지율 최소 기준 (0초과~1이하, 예: 0.95)';
|
||||
COMMENT ON COLUMN persistency_bonus_rule.bonus_type IS 'RATE=모집수수료 대비 비율 / FIXED=건당 고정금액';
|
||||
COMMENT ON COLUMN persistency_bonus_rule.bonus_value IS 'RATE 방식: 비율값 / FIXED 방식: 지급 금액';
|
||||
|
||||
CREATE INDEX idx_pbr_grade_month ON persistency_bonus_rule(grade_id, retention_month, effective_from);
|
||||
|
||||
-- ============================================================
|
||||
-- 2. persistency_bonus — 유지보수수당 지급 이력
|
||||
-- UNIQUE(agent_id, base_month, retention_month) — 동일 기준월·개월수 중복 방지
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE persistency_bonus (
|
||||
bonus_id BIGSERIAL PRIMARY KEY,
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
rule_id BIGINT REFERENCES persistency_bonus_rule(rule_id),
|
||||
base_month CHAR(6) NOT NULL,
|
||||
-- 계약 체결 기준 정산월 (YYYYMM)
|
||||
retention_month INT NOT NULL,
|
||||
-- 평가 기준 개월수 (13/25/37/49)
|
||||
settle_month CHAR(6) NOT NULL,
|
||||
-- 실제 지급 정산월
|
||||
retention_rate NUMERIC(5,4) NOT NULL,
|
||||
-- 실제 유지율
|
||||
bonus_amount NUMERIC(15,2) NOT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'CALCULATED',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP,
|
||||
UNIQUE (agent_id, base_month, retention_month),
|
||||
CHECK (retention_month IN (13, 25, 37, 49)),
|
||||
CHECK (status IN ('CALCULATED','CONFIRMED','PAID','CANCELLED'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE persistency_bonus IS '유지보수수당 지급 이력 — 유지율 충족 확인 후 1회 지급';
|
||||
COMMENT ON COLUMN persistency_bonus.base_month IS '계약 체결 기준 정산월 (YYYYMM) — 유지율 계산 기산점';
|
||||
COMMENT ON COLUMN persistency_bonus.retention_month IS '평가 기준 개월수 (13/25/37/49)';
|
||||
COMMENT ON COLUMN persistency_bonus.settle_month IS '실제 지급 귀속 정산월 (YYYYMM)';
|
||||
COMMENT ON COLUMN persistency_bonus.retention_rate IS '평가 시점 실제 유지율';
|
||||
COMMENT ON COLUMN persistency_bonus.bonus_amount IS '지급 유지보수수당 금액';
|
||||
|
||||
CREATE INDEX idx_pb_agent_settle ON persistency_bonus(agent_id, settle_month);
|
||||
CREATE INDEX idx_pb_base_month ON persistency_bonus(base_month, retention_month);
|
||||
CREATE INDEX idx_pb_status ON persistency_bonus(status, settle_month);
|
||||
@@ -0,0 +1,77 @@
|
||||
-- V44: 오버라이드 원장 보강 (override_ledger + override_summary)
|
||||
-- 기존 V3의 override_rule + V6의 override_settle은 정산 결과 집계용.
|
||||
-- 이 파일은 calcOverride 결과를 수수료 종류 단위로 추적하는 원장과
|
||||
-- agent+settle_month 단위 합계 테이블을 추가한다.
|
||||
|
||||
-- ============================================================
|
||||
-- 1. override_ledger — 오버라이드 수수료 상세 원장
|
||||
-- source_commission_type 단위로 어떤 수수료가 오버라이드 원천인지 추적.
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE override_ledger (
|
||||
ledger_id BIGSERIAL PRIMARY KEY,
|
||||
from_agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
-- 원천 설계사 (수수료를 발생시킨 하위 설계사)
|
||||
to_agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
-- 오버라이드 수령 설계사 (상위 직급)
|
||||
org_id BIGINT REFERENCES organization(org_id),
|
||||
settle_month CHAR(6) NOT NULL,
|
||||
source_commission_type VARCHAR(20) NOT NULL,
|
||||
-- 원천 수수료 종류 (COMMISSION_TYPE 코드)
|
||||
source_ledger_table VARCHAR(50),
|
||||
-- 원천 원장 테이블명 (recruit_ledger 등)
|
||||
source_ledger_id BIGINT,
|
||||
-- 원천 원장 PK
|
||||
source_amount NUMERIC(15,2) NOT NULL,
|
||||
-- 오버라이드 계산 기준 수수료
|
||||
override_rate NUMERIC(7,4) NOT NULL,
|
||||
override_amount NUMERIC(15,2) NOT NULL,
|
||||
-- 최종 오버라이드 금액
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'CALCULATED',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP,
|
||||
CHECK (source_commission_type IN ('RECRUIT','MAINTAIN','COLLECT','RENEWAL','REINSTATE','PERSIST','INCENTIVE')),
|
||||
CHECK (status IN ('CALCULATED','CONFIRMED','PAID','CANCELLED'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE override_ledger IS '오버라이드 원장 — calcOverride 결과를 수수료 종류 단위로 상세 추적';
|
||||
COMMENT ON COLUMN override_ledger.from_agent_id IS '원천 설계사 (오버라이드 기준 수수료 발생 설계사)';
|
||||
COMMENT ON COLUMN override_ledger.to_agent_id IS '오버라이드 수령 설계사 (상위 직급 관리자)';
|
||||
COMMENT ON COLUMN override_ledger.source_commission_type IS '원천 수수료 종류 (COMMISSION_TYPE 코드)';
|
||||
COMMENT ON COLUMN override_ledger.source_ledger_table IS '원천 원장 테이블명';
|
||||
COMMENT ON COLUMN override_ledger.source_amount IS '오버라이드 계산 기준이 된 원천 수수료';
|
||||
COMMENT ON COLUMN override_ledger.override_rate IS '적용 오버라이드율';
|
||||
COMMENT ON COLUMN override_ledger.override_amount IS '최종 오버라이드 금액 = source_amount * override_rate';
|
||||
|
||||
CREATE INDEX idx_ol_to_agent_month ON override_ledger(to_agent_id, settle_month);
|
||||
CREATE INDEX idx_ol_from_agent ON override_ledger(from_agent_id, settle_month);
|
||||
CREATE INDEX idx_ol_org_month ON override_ledger(org_id, settle_month);
|
||||
CREATE INDEX idx_ol_status ON override_ledger(status, settle_month);
|
||||
|
||||
-- ============================================================
|
||||
-- 2. override_summary — agent+settle_month 단위 오버라이드 합계
|
||||
-- Materialized View 후보이나 갱신 제어를 위해 일반 테이블로.
|
||||
-- 배치 완료 후 UPSERT 방식으로 집계.
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE override_summary (
|
||||
summary_id BIGSERIAL PRIMARY KEY,
|
||||
to_agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
settle_month CHAR(6) NOT NULL,
|
||||
total_source_amount NUMERIC(15,2) NOT NULL DEFAULT 0,
|
||||
total_override_amount NUMERIC(15,2) NOT NULL DEFAULT 0,
|
||||
ledger_count INT NOT NULL DEFAULT 0,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'CALCULATED',
|
||||
calc_date TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP,
|
||||
UNIQUE (to_agent_id, settle_month),
|
||||
CHECK (status IN ('CALCULATED','CONFIRMED','PAID'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE override_summary IS '오버라이드 합계 — agent+settle_month 단위 배치 집계 결과';
|
||||
COMMENT ON COLUMN override_summary.to_agent_id IS '오버라이드 수령 설계사 (상위 직급)';
|
||||
COMMENT ON COLUMN override_summary.total_source_amount IS '오버라이드 계산 기준 원천 수수료 합계';
|
||||
COMMENT ON COLUMN override_summary.total_override_amount IS '최종 오버라이드 지급액 합계';
|
||||
COMMENT ON COLUMN override_summary.ledger_count IS '오버라이드 원장 건수';
|
||||
|
||||
CREATE INDEX idx_os_month ON override_summary(settle_month, status);
|
||||
@@ -0,0 +1,38 @@
|
||||
-- V45: 위촉계약 (agent_contract)
|
||||
-- 보험사-설계사 간 위촉계약서. 보험사별 활동 자격 + 위촉수수료 관리.
|
||||
|
||||
CREATE TABLE agent_contract (
|
||||
contract_id BIGSERIAL PRIMARY KEY,
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
carrier_id BIGINT NOT NULL REFERENCES insurance_company(company_id),
|
||||
contract_no VARCHAR(50) NOT NULL,
|
||||
signed_date DATE NOT NULL,
|
||||
effective_from DATE NOT NULL,
|
||||
effective_to DATE,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
onboarding_bonus_amount NUMERIC(15,2) NOT NULL DEFAULT 0,
|
||||
-- 위촉수수료 (입사 인센티브 성격)
|
||||
terminated_at TIMESTAMP,
|
||||
terminated_reason VARCHAR(500),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by BIGINT,
|
||||
updated_at TIMESTAMP,
|
||||
updated_by BIGINT,
|
||||
UNIQUE (agent_id, carrier_id, contract_no),
|
||||
CHECK (status IN ('ACTIVE','TERMINATED','SUSPENDED'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE agent_contract IS '위촉계약 — 보험사-설계사 위촉계약서 + 효력 기간 + 위촉수수료';
|
||||
COMMENT ON COLUMN agent_contract.agent_id IS '설계사 FK';
|
||||
COMMENT ON COLUMN agent_contract.carrier_id IS '보험사 FK (insurance_company)';
|
||||
COMMENT ON COLUMN agent_contract.contract_no IS '위촉계약 번호';
|
||||
COMMENT ON COLUMN agent_contract.signed_date IS '위촉계약 서명일';
|
||||
COMMENT ON COLUMN agent_contract.effective_from IS '위촉 효력 시작일';
|
||||
COMMENT ON COLUMN agent_contract.effective_to IS '위촉 효력 종료일 (NULL=현재 유효)';
|
||||
COMMENT ON COLUMN agent_contract.status IS 'ACTIVE=유효/TERMINATED=해촉/SUSPENDED=정지';
|
||||
COMMENT ON COLUMN agent_contract.onboarding_bonus_amount IS '위촉수수료 (위촉 시 지급하는 인센티브)';
|
||||
COMMENT ON COLUMN agent_contract.terminated_reason IS '해촉 사유';
|
||||
|
||||
CREATE INDEX idx_ac_agent ON agent_contract(agent_id, status);
|
||||
CREATE INDEX idx_ac_carrier ON agent_contract(carrier_id, status);
|
||||
CREATE INDEX idx_ac_effective ON agent_contract(effective_from, effective_to);
|
||||
@@ -0,0 +1,35 @@
|
||||
-- V46: 설계사 자격 관리 (agent_license)
|
||||
-- 생보/손보/변액 자격증 만료·갱신 이력. 만료 임박 알림용 인덱스 포함.
|
||||
|
||||
CREATE TABLE agent_license (
|
||||
license_id BIGSERIAL PRIMARY KEY,
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
license_type VARCHAR(20) NOT NULL,
|
||||
license_no VARCHAR(50) NOT NULL,
|
||||
issued_date DATE NOT NULL,
|
||||
expires_date DATE NOT NULL,
|
||||
renewed_from BIGINT REFERENCES agent_license(license_id),
|
||||
-- 갱신 전 자격증 참조
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by BIGINT,
|
||||
updated_at TIMESTAMP,
|
||||
UNIQUE (agent_id, license_type, license_no),
|
||||
CHECK (license_type IN ('LIFE','NONLIFE','VARIABLE')),
|
||||
CHECK (status IN ('ACTIVE','EXPIRED','SUSPENDED')),
|
||||
CHECK (expires_date > issued_date)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE agent_license IS '설계사 자격 관리 — 생보/손보/변액 자격증 만료·갱신 이력';
|
||||
COMMENT ON COLUMN agent_license.agent_id IS '설계사 FK';
|
||||
COMMENT ON COLUMN agent_license.license_type IS '자격 종류 (LIFE=생명보험/NONLIFE=손해보험/VARIABLE=변액보험)';
|
||||
COMMENT ON COLUMN agent_license.license_no IS '자격증 번호';
|
||||
COMMENT ON COLUMN agent_license.issued_date IS '자격증 발급일';
|
||||
COMMENT ON COLUMN agent_license.expires_date IS '자격증 만료일 (갱신 주기 5년 기준)';
|
||||
COMMENT ON COLUMN agent_license.renewed_from IS '갱신 전 자격증 ID (갱신 이력 추적용)';
|
||||
COMMENT ON COLUMN agent_license.status IS 'ACTIVE=유효/EXPIRED=만료/SUSPENDED=정지';
|
||||
|
||||
-- 만료 임박 알림용 인덱스 (expires_date 단독 + 복합)
|
||||
CREATE INDEX idx_al_agent ON agent_license(agent_id, status);
|
||||
CREATE INDEX idx_al_expires ON agent_license(expires_date, status);
|
||||
CREATE INDEX idx_al_type_expires ON agent_license(license_type, expires_date);
|
||||
@@ -0,0 +1,60 @@
|
||||
-- V47: 보수교육 (agent_training + training_requirement)
|
||||
-- 보험업법 시행령 제17조 기준 의무 교육 이수 시간 추적.
|
||||
-- 연간 12시간 의무 기준은 training_requirement에 외부화.
|
||||
|
||||
-- ============================================================
|
||||
-- 1. training_requirement — 연도별 의무 교육 시간 마스터
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE training_requirement (
|
||||
req_id SERIAL PRIMARY KEY,
|
||||
target_year INT NOT NULL UNIQUE,
|
||||
required_hours INT NOT NULL DEFAULT 12,
|
||||
-- 기본값 12시간/년 (보험업법 시행령 제17조)
|
||||
description VARCHAR(300),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by BIGINT,
|
||||
updated_at TIMESTAMP
|
||||
);
|
||||
|
||||
COMMENT ON TABLE training_requirement IS '보수교육 의무 시간 마스터 — 연도별 의무 교육 시간 기준';
|
||||
COMMENT ON COLUMN training_requirement.target_year IS '적용 연도';
|
||||
COMMENT ON COLUMN training_requirement.required_hours IS '연간 의무 교육 시간 (기본 12시간)';
|
||||
|
||||
-- 현재 연도 + 차기 연도 기본값 삽입
|
||||
INSERT INTO training_requirement (target_year, required_hours, description) VALUES
|
||||
(2025, 12, '보험업법 시행령 제17조 기준 연간 의무 보수교육'),
|
||||
(2026, 12, '보험업법 시행령 제17조 기준 연간 의무 보수교육')
|
||||
ON CONFLICT (target_year) DO NOTHING;
|
||||
|
||||
-- ============================================================
|
||||
-- 2. agent_training — 설계사 보수교육 이수 이력
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE agent_training (
|
||||
training_id BIGSERIAL PRIMARY KEY,
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
course_name VARCHAR(200) NOT NULL,
|
||||
course_type VARCHAR(20) NOT NULL,
|
||||
training_date DATE NOT NULL,
|
||||
hours NUMERIC(5,1) NOT NULL,
|
||||
certificate_no VARCHAR(100),
|
||||
instructor VARCHAR(100),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by BIGINT,
|
||||
updated_at TIMESTAMP,
|
||||
CHECK (course_type IN ('REGULAR','COMPLIANCE','PRODUCT')),
|
||||
CHECK (hours > 0)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE agent_training IS '보수교육 이수 이력 — 설계사 연간 의무 교육 이수 시간 추적';
|
||||
COMMENT ON COLUMN agent_training.agent_id IS '설계사 FK';
|
||||
COMMENT ON COLUMN agent_training.course_name IS '교육 과목명';
|
||||
COMMENT ON COLUMN agent_training.course_type IS '교육 유형 (REGULAR=정기보수/COMPLIANCE=컴플라이언스/PRODUCT=상품교육)';
|
||||
COMMENT ON COLUMN agent_training.training_date IS '교육 이수일';
|
||||
COMMENT ON COLUMN agent_training.hours IS '이수 시간';
|
||||
COMMENT ON COLUMN agent_training.certificate_no IS '이수증 번호';
|
||||
COMMENT ON COLUMN agent_training.instructor IS '강사명 또는 교육기관';
|
||||
|
||||
CREATE INDEX idx_at_agent_date ON agent_training(agent_id, training_date);
|
||||
CREATE INDEX idx_at_course_type ON agent_training(course_type, training_date);
|
||||
@@ -0,0 +1,40 @@
|
||||
-- V48: 계약 변경 (contract_endorsement)
|
||||
-- 보험료/수익자/피보험자/주소 변경 등 계약 변경 이력.
|
||||
-- requires_commission_recalc=true 이면 배치에서 수수료 재계산 트리거.
|
||||
|
||||
CREATE TABLE contract_endorsement (
|
||||
endorsement_id BIGSERIAL PRIMARY KEY,
|
||||
contract_id BIGINT NOT NULL REFERENCES contract(contract_id),
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
endorsement_type VARCHAR(30) NOT NULL,
|
||||
changed_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
old_value TEXT,
|
||||
-- 변경 전 값 (JSON 또는 텍스트)
|
||||
new_value TEXT,
|
||||
-- 변경 후 값 (JSON 또는 텍스트)
|
||||
reason VARCHAR(500),
|
||||
requires_commission_recalc BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
-- TRUE이면 배치 수수료 재계산 대상
|
||||
processed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
-- 재계산 처리 완료 여부
|
||||
processed_at TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by BIGINT,
|
||||
updated_at TIMESTAMP,
|
||||
CHECK (endorsement_type IN ('PREMIUM_CHANGE','BENEFICIARY','INSURED','ADDRESS','OTHER'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE contract_endorsement IS '계약 변경 이력 — 변경 유형별 old/new 값 보관 + 수수료 재계산 트리거';
|
||||
COMMENT ON COLUMN contract_endorsement.contract_id IS '대상 계약 FK';
|
||||
COMMENT ON COLUMN contract_endorsement.agent_id IS '담당 설계사 FK';
|
||||
COMMENT ON COLUMN contract_endorsement.endorsement_type IS '변경 유형 (PREMIUM_CHANGE=보험료변경/BENEFICIARY=수익자/INSURED=피보험자/ADDRESS=주소/OTHER=기타)';
|
||||
COMMENT ON COLUMN contract_endorsement.old_value IS '변경 전 값';
|
||||
COMMENT ON COLUMN contract_endorsement.new_value IS '변경 후 값';
|
||||
COMMENT ON COLUMN contract_endorsement.requires_commission_recalc IS '수수료 재계산 필요 여부 (TRUE이면 배치 재처리 대상)';
|
||||
COMMENT ON COLUMN contract_endorsement.processed IS '재계산 처리 완료 여부';
|
||||
|
||||
CREATE INDEX idx_ce_contract ON contract_endorsement(contract_id, changed_at);
|
||||
CREATE INDEX idx_ce_agent ON contract_endorsement(agent_id, changed_at);
|
||||
CREATE INDEX idx_ce_recalc ON contract_endorsement(requires_commission_recalc, processed)
|
||||
WHERE requires_commission_recalc = TRUE AND processed = FALSE;
|
||||
-- 재계산 미처리 건 빠른 조회용 부분 인덱스
|
||||
@@ -0,0 +1,49 @@
|
||||
-- V49: 민원 관리 (complaint)
|
||||
-- 고객 민원 접수 → 설계사 책임 추적 → 처리 상태 관리 → 환수 연동.
|
||||
-- 13M 이내 민원 = 환수 100% 트리거 가정 (chargeback_triggered).
|
||||
|
||||
CREATE TABLE complaint (
|
||||
complaint_id BIGSERIAL PRIMARY KEY,
|
||||
contract_id BIGINT REFERENCES contract(contract_id),
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
customer_name VARCHAR(100) NOT NULL,
|
||||
complaint_date DATE NOT NULL,
|
||||
channel VARCHAR(20) NOT NULL,
|
||||
complaint_type VARCHAR(30) NOT NULL,
|
||||
severity VARCHAR(10) NOT NULL DEFAULT 'MID',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'OPEN',
|
||||
resolution TEXT,
|
||||
-- 처리 결과 기술
|
||||
chargeback_triggered BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
-- TRUE이면 환수 자동 생성 대상
|
||||
settled_at TIMESTAMP,
|
||||
-- 민원 종결 시각
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by BIGINT,
|
||||
updated_at TIMESTAMP,
|
||||
updated_by BIGINT,
|
||||
CHECK (channel IN ('PHONE','EMAIL','VISIT','ONLINE','FAX')),
|
||||
CHECK (complaint_type IN ('MIS_SELLING','DELAY','UNFAIR','CANCELLATION','ETC')),
|
||||
CHECK (severity IN ('LOW','MID','HIGH')),
|
||||
CHECK (status IN ('OPEN','IN_PROGRESS','CLOSED','WITHDRAWN'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE complaint IS '민원 관리 — 고객 민원 접수·처리·환수 연동';
|
||||
COMMENT ON COLUMN complaint.contract_id IS '민원 대상 계약 FK (계약 특정 불가한 경우 NULL 허용)';
|
||||
COMMENT ON COLUMN complaint.agent_id IS '민원 책임 설계사 FK';
|
||||
COMMENT ON COLUMN complaint.customer_name IS '민원인 성명';
|
||||
COMMENT ON COLUMN complaint.complaint_date IS '민원 접수일';
|
||||
COMMENT ON COLUMN complaint.channel IS '접수 채널 (PHONE/EMAIL/VISIT/ONLINE/FAX)';
|
||||
COMMENT ON COLUMN complaint.complaint_type IS '민원 유형 (MIS_SELLING=불완전판매/DELAY=처리지연/UNFAIR=불공정/CANCELLATION=해지관련/ETC=기타)';
|
||||
COMMENT ON COLUMN complaint.severity IS '심각도 (LOW=낮음/MID=보통/HIGH=높음)';
|
||||
COMMENT ON COLUMN complaint.status IS '처리 상태 (OPEN=접수/IN_PROGRESS=처리중/CLOSED=완료/WITHDRAWN=취하)';
|
||||
COMMENT ON COLUMN complaint.resolution IS '처리 결과 상세 기술';
|
||||
COMMENT ON COLUMN complaint.chargeback_triggered IS 'TRUE=환수 트리거 발생 (13M 이내 민원 등)';
|
||||
COMMENT ON COLUMN complaint.settled_at IS '민원 종결 시각';
|
||||
|
||||
CREATE INDEX idx_comp_agent_date ON complaint(agent_id, complaint_date);
|
||||
CREATE INDEX idx_comp_status ON complaint(status, complaint_date);
|
||||
CREATE INDEX idx_comp_contract ON complaint(contract_id);
|
||||
CREATE INDEX idx_comp_chargeback ON complaint(chargeback_triggered, status)
|
||||
WHERE chargeback_triggered = TRUE;
|
||||
-- 환수 트리거 미처리 건 조회용 부분 인덱스
|
||||
@@ -0,0 +1,132 @@
|
||||
-- V50: 결재 워크플로우 (approval_line + approval_line_step + approval_request + approval_history)
|
||||
-- 정산/이의신청/시책/출금 결재선 마스터 + 다단 결재 요청·처리 이력.
|
||||
-- 최대 3단계 결재 (시스템 가정값, approval_line.max_step 으로 외부화).
|
||||
|
||||
-- ============================================================
|
||||
-- 1. approval_line — 결재선 마스터
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE approval_line (
|
||||
line_id BIGSERIAL PRIMARY KEY,
|
||||
line_code VARCHAR(50) NOT NULL UNIQUE,
|
||||
line_name VARCHAR(100) NOT NULL,
|
||||
max_step INT NOT NULL DEFAULT 3,
|
||||
target_type VARCHAR(20) NOT NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_by BIGINT,
|
||||
updated_at TIMESTAMP,
|
||||
CHECK (target_type IN ('SETTLE','DISPUTE','INCENTIVE','WITHDRAW','COMPLAINT')),
|
||||
CHECK (max_step BETWEEN 1 AND 5)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE approval_line IS '결재선 마스터 — 업무 유형별 결재 단계 정의';
|
||||
COMMENT ON COLUMN approval_line.line_code IS '결재선 코드 (예: SETTLE_DEFAULT)';
|
||||
COMMENT ON COLUMN approval_line.max_step IS '최대 결재 단계 수 (1~5, 기본 3)';
|
||||
COMMENT ON COLUMN approval_line.target_type IS '적용 업무 유형 (SETTLE=정산/DISPUTE=이의/INCENTIVE=시책/WITHDRAW=출금/COMPLAINT=민원)';
|
||||
|
||||
-- 기본 결재선 초기 데이터
|
||||
INSERT INTO approval_line (line_code, line_name, max_step, target_type, is_active) VALUES
|
||||
('SETTLE_DEFAULT', '정산 기본 결재선', 2, 'SETTLE', TRUE),
|
||||
('DISPUTE_DEFAULT', '이의신청 결재선', 2, 'DISPUTE', TRUE),
|
||||
('INCENTIVE_DEFAULT','시책 결재선', 2, 'INCENTIVE', TRUE),
|
||||
('WITHDRAW_DEFAULT', '출금신청 결재선', 3, 'WITHDRAW', TRUE),
|
||||
('COMPLAINT_DEFAULT','민원처리 결재선', 2, 'COMPLAINT', TRUE)
|
||||
ON CONFLICT (line_code) DO NOTHING;
|
||||
|
||||
-- ============================================================
|
||||
-- 2. approval_line_step — 결재선 단계별 역할 정의
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE approval_line_step (
|
||||
step_id BIGSERIAL PRIMARY KEY,
|
||||
line_id BIGINT NOT NULL REFERENCES approval_line(line_id),
|
||||
step_no INT NOT NULL,
|
||||
role_code VARCHAR(50) NOT NULL,
|
||||
-- 결재 역할 코드 (role 테이블 참조, 느슨한 참조)
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
UNIQUE (line_id, step_no),
|
||||
CHECK (step_no >= 1)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE approval_line_step IS '결재선 단계 — 결재선별 단계 순서와 결재 역할 매핑';
|
||||
COMMENT ON COLUMN approval_line_step.step_no IS '결재 단계 번호 (1부터 순서대로)';
|
||||
COMMENT ON COLUMN approval_line_step.role_code IS '해당 단계 결재 역할 코드';
|
||||
|
||||
-- 기본 결재선 단계 삽입
|
||||
INSERT INTO approval_line_step (line_id, step_no, role_code)
|
||||
SELECT l.line_id, s.step_no, s.role_code
|
||||
FROM approval_line l
|
||||
JOIN (VALUES
|
||||
('SETTLE_DEFAULT', 1, 'MANAGER'),
|
||||
('SETTLE_DEFAULT', 2, 'ADMIN'),
|
||||
('DISPUTE_DEFAULT', 1, 'MANAGER'),
|
||||
('DISPUTE_DEFAULT', 2, 'ADMIN'),
|
||||
('INCENTIVE_DEFAULT', 1, 'MANAGER'),
|
||||
('INCENTIVE_DEFAULT', 2, 'ADMIN'),
|
||||
('WITHDRAW_DEFAULT', 1, 'MANAGER'),
|
||||
('WITHDRAW_DEFAULT', 2, 'ADMIN'),
|
||||
('WITHDRAW_DEFAULT', 3, 'SUPER_ADMIN'),
|
||||
('COMPLAINT_DEFAULT', 1, 'MANAGER'),
|
||||
('COMPLAINT_DEFAULT', 2, 'ADMIN')
|
||||
) AS s(line_code, step_no, role_code) ON l.line_code = s.line_code
|
||||
ON CONFLICT (line_id, step_no) DO NOTHING;
|
||||
|
||||
-- ============================================================
|
||||
-- 3. approval_request — 결재 요청
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE approval_request (
|
||||
request_id BIGSERIAL PRIMARY KEY,
|
||||
target_type VARCHAR(20) NOT NULL,
|
||||
target_id BIGINT NOT NULL,
|
||||
-- 결재 대상 PK (settle_id / dispute_id 등)
|
||||
line_id BIGINT NOT NULL REFERENCES approval_line(line_id),
|
||||
requested_by BIGINT NOT NULL,
|
||||
-- 요청자 user_id (users 테이블 참조, 느슨한 참조)
|
||||
requested_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
current_step INT NOT NULL DEFAULT 1,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
|
||||
completed_at TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP,
|
||||
CHECK (target_type IN ('SETTLE','DISPUTE','INCENTIVE','WITHDRAW','COMPLAINT')),
|
||||
CHECK (status IN ('PENDING','APPROVED','REJECTED','CANCEL'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE approval_request IS '결재 요청 — 업무별 결재 요청 생성 및 진행 상태 관리';
|
||||
COMMENT ON COLUMN approval_request.target_type IS '결재 대상 업무 유형';
|
||||
COMMENT ON COLUMN approval_request.target_id IS '결재 대상 레코드 PK';
|
||||
COMMENT ON COLUMN approval_request.current_step IS '현재 결재 단계 번호';
|
||||
COMMENT ON COLUMN approval_request.status IS 'PENDING=진행중/APPROVED=최종승인/REJECTED=반려/CANCEL=취소';
|
||||
|
||||
CREATE INDEX idx_ar_target ON approval_request(target_type, target_id);
|
||||
CREATE INDEX idx_ar_status ON approval_request(status, requested_at);
|
||||
CREATE INDEX idx_ar_requester ON approval_request(requested_by, status);
|
||||
|
||||
-- ============================================================
|
||||
-- 4. approval_history — 결재 처리 이력
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE approval_history (
|
||||
history_id BIGSERIAL PRIMARY KEY,
|
||||
request_id BIGINT NOT NULL REFERENCES approval_request(request_id),
|
||||
step_no INT NOT NULL,
|
||||
approver_id BIGINT NOT NULL,
|
||||
-- 결재자 user_id (느슨한 참조)
|
||||
action VARCHAR(20) NOT NULL,
|
||||
comment VARCHAR(1000),
|
||||
processed_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
CHECK (action IN ('APPROVE','REJECT','RETURN'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE approval_history IS '결재 처리 이력 — 단계별 결재자 액션 및 코멘트 기록';
|
||||
COMMENT ON COLUMN approval_history.request_id IS '결재 요청 FK';
|
||||
COMMENT ON COLUMN approval_history.step_no IS '처리 단계 번호';
|
||||
COMMENT ON COLUMN approval_history.approver_id IS '결재자 user_id';
|
||||
COMMENT ON COLUMN approval_history.action IS 'APPROVE=승인/REJECT=반려/RETURN=반송';
|
||||
COMMENT ON COLUMN approval_history.comment IS '결재 코멘트';
|
||||
|
||||
CREATE INDEX idx_ah_request ON approval_history(request_id, step_no);
|
||||
CREATE INDEX idx_ah_approver ON approval_history(approver_id, processed_at);
|
||||
@@ -0,0 +1,63 @@
|
||||
-- V51: 공지사항 + 사용자 알림 (notice + user_notification)
|
||||
-- 시스템 공지 / 정책 공지 / 이벤트 공지 + 사용자별 개인 알림(읽음 여부).
|
||||
|
||||
-- ============================================================
|
||||
-- 1. notice — 공지사항
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE notice (
|
||||
notice_id BIGSERIAL PRIMARY KEY,
|
||||
title VARCHAR(300) NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
notice_type VARCHAR(20) NOT NULL DEFAULT 'SYSTEM',
|
||||
start_date DATE NOT NULL,
|
||||
end_date DATE,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_by BIGINT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP,
|
||||
updated_by BIGINT,
|
||||
CHECK (notice_type IN ('SYSTEM','POLICY','EVENT')),
|
||||
CHECK (end_date IS NULL OR end_date >= start_date)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE notice IS '공지사항 — 시스템/정책/이벤트 공지 게시판';
|
||||
COMMENT ON COLUMN notice.notice_type IS 'SYSTEM=시스템공지/POLICY=정책공지/EVENT=이벤트';
|
||||
COMMENT ON COLUMN notice.start_date IS '공지 게시 시작일';
|
||||
COMMENT ON COLUMN notice.end_date IS '공지 게시 종료일 (NULL=무기한)';
|
||||
COMMENT ON COLUMN notice.is_active IS '공지 활성 여부';
|
||||
|
||||
CREATE INDEX idx_notice_date_type ON notice(start_date, end_date, notice_type, is_active);
|
||||
|
||||
-- ============================================================
|
||||
-- 2. user_notification — 사용자 개인 알림
|
||||
-- 정산/이의신청/결재 등 이벤트 발생 시 개인 알림 생성.
|
||||
-- ============================================================
|
||||
|
||||
CREATE TABLE user_notification (
|
||||
notification_id BIGSERIAL PRIMARY KEY,
|
||||
user_id BIGINT NOT NULL,
|
||||
-- users 테이블 참조 (느슨한 참조 — 공통모듈 의존 최소화)
|
||||
title VARCHAR(300) NOT NULL,
|
||||
content TEXT,
|
||||
ref_type VARCHAR(30),
|
||||
-- 참조 업무 유형 (SETTLE/DISPUTE/APPROVAL/COMPLAINT 등)
|
||||
ref_id BIGINT,
|
||||
-- 참조 레코드 PK
|
||||
is_read BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
read_at TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
CHECK (ref_type IS NULL OR ref_type IN ('SETTLE','DISPUTE','APPROVAL','COMPLAINT','INCENTIVE','WITHDRAW','NOTICE'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE user_notification IS '사용자 개인 알림 — 이벤트 발생 시 user_id 단위로 생성';
|
||||
COMMENT ON COLUMN user_notification.user_id IS '알림 수신 사용자 ID';
|
||||
COMMENT ON COLUMN user_notification.ref_type IS '참조 업무 유형 (SETTLE/DISPUTE/APPROVAL/COMPLAINT/INCENTIVE/WITHDRAW/NOTICE)';
|
||||
COMMENT ON COLUMN user_notification.ref_id IS '참조 레코드 PK';
|
||||
COMMENT ON COLUMN user_notification.is_read IS '읽음 여부';
|
||||
COMMENT ON COLUMN user_notification.read_at IS '읽은 시각';
|
||||
|
||||
-- user_id+is_read 복합 인덱스 — 읽지 않은 알림 빠른 조회
|
||||
CREATE INDEX idx_un_user_read ON user_notification(user_id, is_read);
|
||||
CREATE INDEX idx_un_created ON user_notification(created_at DESC);
|
||||
CREATE INDEX idx_un_ref ON user_notification(ref_type, ref_id);
|
||||
@@ -0,0 +1,36 @@
|
||||
-- V52: 첨부파일 (attachment)
|
||||
-- 도메인 무관 공통 첨부. ref_type + ref_id 조합으로 어느 도메인 레코드에도 첨부 가능.
|
||||
-- 파일 실체는 스토리지(로컬/S3). file_path에 경로 저장.
|
||||
|
||||
CREATE TABLE attachment (
|
||||
attachment_id BIGSERIAL PRIMARY KEY,
|
||||
ref_type VARCHAR(50) NOT NULL,
|
||||
ref_id BIGINT NOT NULL,
|
||||
file_name VARCHAR(300) NOT NULL,
|
||||
file_path VARCHAR(1000) NOT NULL,
|
||||
file_size BIGINT NOT NULL,
|
||||
-- bytes 단위
|
||||
mime_type VARCHAR(100),
|
||||
uploaded_by BIGINT NOT NULL,
|
||||
-- 업로더 user_id (느슨한 참조)
|
||||
uploaded_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
CHECK (ref_type IN (
|
||||
'AGENT_CONTRACT','COMPLAINT','APPROVAL_REQUEST',
|
||||
'WITHDRAW_REQUEST','NOTICE','DISPUTE','INCENTIVE',
|
||||
'AGENT_LICENSE','AGENT_TRAINING'
|
||||
)),
|
||||
CHECK (file_size > 0)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE attachment IS '공통 첨부파일 — ref_type+ref_id 조합으로 모든 도메인에 첨부 연결';
|
||||
COMMENT ON COLUMN attachment.ref_type IS '첨부 대상 도메인 유형 (AGENT_CONTRACT/COMPLAINT/APPROVAL_REQUEST 등)';
|
||||
COMMENT ON COLUMN attachment.ref_id IS '첨부 대상 레코드 PK';
|
||||
COMMENT ON COLUMN attachment.file_name IS '원본 파일명';
|
||||
COMMENT ON COLUMN attachment.file_path IS '저장 경로 (로컬 절대경로 또는 S3 키)';
|
||||
COMMENT ON COLUMN attachment.file_size IS '파일 크기 (bytes)';
|
||||
COMMENT ON COLUMN attachment.mime_type IS 'MIME 타입 (예: application/pdf)';
|
||||
COMMENT ON COLUMN attachment.uploaded_by IS '업로더 user_id';
|
||||
|
||||
-- ref_type + ref_id 복합 인덱스 — 도메인별 첨부 목록 조회
|
||||
CREATE INDEX idx_att_ref ON attachment(ref_type, ref_id);
|
||||
CREATE INDEX idx_att_uploader ON attachment(uploaded_by, uploaded_at);
|
||||
@@ -0,0 +1,45 @@
|
||||
-- V53: 출금 신청 (withdraw_request)
|
||||
-- 정산 확정 후 설계사 수수료 출금 신청 → 결재 → 펌뱅킹 송신 → 결과 반영.
|
||||
-- account_no는 AES 암호화 대상 (애플리케이션 EncryptTypeHandler 처리).
|
||||
|
||||
CREATE TABLE withdraw_request (
|
||||
request_id BIGSERIAL PRIMARY KEY,
|
||||
settle_master_id BIGINT NOT NULL REFERENCES settle_master(settle_id),
|
||||
agent_id BIGINT NOT NULL REFERENCES agent(agent_id),
|
||||
amount NUMERIC(15,2) NOT NULL,
|
||||
requested_by BIGINT NOT NULL,
|
||||
-- 신청자 user_id (느슨한 참조)
|
||||
requested_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
approval_request_id BIGINT REFERENCES approval_request(request_id),
|
||||
bank_code VARCHAR(10) NOT NULL,
|
||||
account_no VARCHAR(200) NOT NULL,
|
||||
-- AES 암호화 대상 (EncryptTypeHandler)
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'REQUESTED',
|
||||
sent_at TIMESTAMP,
|
||||
-- 펌뱅킹 송신 시각
|
||||
completed_at TIMESTAMP,
|
||||
-- 입금 완료 시각
|
||||
fail_reason VARCHAR(500),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP,
|
||||
CHECK (amount > 0),
|
||||
CHECK (status IN ('REQUESTED','APPROVED','SENT','COMPLETED','FAILED','CANCELLED'))
|
||||
);
|
||||
|
||||
COMMENT ON TABLE withdraw_request IS '출금 신청 — 정산 확정 후 수수료 출금 결재→펌뱅킹→완료 워크플로우';
|
||||
COMMENT ON COLUMN withdraw_request.settle_master_id IS '출금 기준 정산 FK (settle_master)';
|
||||
COMMENT ON COLUMN withdraw_request.agent_id IS '출금 대상 설계사 FK';
|
||||
COMMENT ON COLUMN withdraw_request.amount IS '출금 신청 금액';
|
||||
COMMENT ON COLUMN withdraw_request.requested_by IS '신청자 user_id';
|
||||
COMMENT ON COLUMN withdraw_request.approval_request_id IS '결재 요청 FK (approval_request)';
|
||||
COMMENT ON COLUMN withdraw_request.bank_code IS '출금 은행 코드';
|
||||
COMMENT ON COLUMN withdraw_request.account_no IS '출금 계좌번호 (AES 암호화, EncryptTypeHandler 처리)';
|
||||
COMMENT ON COLUMN withdraw_request.status IS 'REQUESTED=신청/APPROVED=결재완료/SENT=펌뱅킹송신/COMPLETED=입금완료/FAILED=실패/CANCELLED=취소';
|
||||
COMMENT ON COLUMN withdraw_request.sent_at IS '펌뱅킹 송신 시각';
|
||||
COMMENT ON COLUMN withdraw_request.completed_at IS '입금 완료 확인 시각';
|
||||
COMMENT ON COLUMN withdraw_request.fail_reason IS '실패 사유 (FAILED 상태 시)';
|
||||
|
||||
CREATE INDEX idx_wr_agent_status ON withdraw_request(agent_id, status);
|
||||
CREATE INDEX idx_wr_settle ON withdraw_request(settle_master_id);
|
||||
CREATE INDEX idx_wr_status_date ON withdraw_request(status, requested_at);
|
||||
CREATE INDEX idx_wr_approval ON withdraw_request(approval_request_id);
|
||||
@@ -0,0 +1,198 @@
|
||||
-- V54: P4 도메인 메뉴 일괄 등록 (V40~V53 대응)
|
||||
--
|
||||
-- 신규 부모 그룹: GRP_COMMISSION "수수료 마스터" (P4-A 5개 자식)
|
||||
-- 기존 GRP_ORG 아래: 위촉계약/자격관리/보수교육
|
||||
-- 기존 GRP_PRD 아래: 계약변경/민원관리 (GRP_CONTRACT_OP 대신 GRP_PRD 활용)
|
||||
-- 기존 GRP_SYSTEM 아래: 결재/공지/첨부/출금
|
||||
|
||||
-- ============================================================
|
||||
-- 1. GRP_COMMISSION 부모 그룹 메뉴 신설
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO menu (parent_menu_id, menu_code, menu_name, menu_type, menu_path, menu_icon, menu_level, sort_order, is_visible, is_active, description)
|
||||
VALUES (NULL, 'GRP_COMMISSION', '수수료 마스터', 'DIRECTORY', NULL, 'dollar', 1, 45, 'Y', 'Y', '수수료 종류별 원장 · 룰 관리')
|
||||
ON CONFLICT (menu_code) DO NOTHING;
|
||||
|
||||
-- ============================================================
|
||||
-- 2. GRP_COMMISSION 하위 PAGE 5개 (P4-A)
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO menu (parent_menu_id, menu_code, menu_name, menu_type, menu_path, component_path, menu_level, sort_order)
|
||||
SELECT p.menu_id, x.code, x.name, 'PAGE', x.path, x.cmpt, 2, x.sort
|
||||
FROM menu p
|
||||
JOIN (VALUES
|
||||
('COMM_TYPE', '수수료 종류 코드', '/commission/type', 'commission/CommType', 10),
|
||||
('COMM_MASTER', '수수료 통합 원장', '/commission/master', 'commission/CommMaster', 20),
|
||||
('COLLECT_COMM', '수금수수료', '/commission/collection', 'commission/CollectComm', 30),
|
||||
('RENEWAL_COMM', '갱신수수료', '/commission/renewal', 'commission/RenewalComm', 40),
|
||||
('REINSTATE_COMM', '부활수수료', '/commission/reinstate', 'commission/ReinstateComm', 50),
|
||||
('PERSIST_BONUS', '유지보수수당', '/commission/persist', 'commission/PersistBonus', 60),
|
||||
('OVERRIDE_LEDGER', '오버라이드 원장', '/commission/override', 'commission/OverrideLedger', 70)
|
||||
) AS x(code, name, path, cmpt, sort)
|
||||
ON p.menu_code = 'GRP_COMMISSION'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM menu WHERE menu_code = x.code);
|
||||
|
||||
-- ============================================================
|
||||
-- 3. GRP_ORG 하위 PAGE 3개 (P4-B 설계사 라이프사이클)
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO menu (parent_menu_id, menu_code, menu_name, menu_type, menu_path, component_path, menu_level, sort_order)
|
||||
SELECT p.menu_id, x.code, x.name, 'PAGE', x.path, x.cmpt, 2, x.sort
|
||||
FROM menu p
|
||||
JOIN (VALUES
|
||||
('AGENT_CONTRACT', '위촉계약', '/org/agent-contract', 'org/AgentContract', 30),
|
||||
('AGENT_LICENSE', '자격 관리', '/org/agent-license', 'org/AgentLicense', 40),
|
||||
('AGENT_TRAINING', '보수교육', '/org/agent-training', 'org/AgentTraining', 50)
|
||||
) AS x(code, name, path, cmpt, sort)
|
||||
ON p.menu_code = 'GRP_ORG'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM menu WHERE menu_code = x.code);
|
||||
|
||||
-- ============================================================
|
||||
-- 4. GRP_PRD 하위 PAGE 2개 (계약변경 / 민원관리)
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO menu (parent_menu_id, menu_code, menu_name, menu_type, menu_path, component_path, menu_level, sort_order)
|
||||
SELECT p.menu_id, x.code, x.name, 'PAGE', x.path, x.cmpt, 2, x.sort
|
||||
FROM menu p
|
||||
JOIN (VALUES
|
||||
('ENDORSE', '계약 변경', '/contract/endorsement', 'contract/Endorsement', 40),
|
||||
('COMPLAINT', '민원 관리', '/contract/complaint', 'contract/Complaint', 50)
|
||||
) AS x(code, name, path, cmpt, sort)
|
||||
ON p.menu_code = 'GRP_PRD'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM menu WHERE menu_code = x.code);
|
||||
|
||||
-- ============================================================
|
||||
-- 5. GRP_SYSTEM 하위 PAGE 4개 (결재/공지/첨부/출금)
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO menu (parent_menu_id, menu_code, menu_name, menu_type, menu_path, component_path, menu_level, sort_order)
|
||||
SELECT p.menu_id, x.code, x.name, 'PAGE', x.path, x.cmpt, 2, x.sort
|
||||
FROM menu p
|
||||
JOIN (VALUES
|
||||
('APPROVAL', '결재 관리', '/system/approval', 'system/Approval', 70),
|
||||
('NOTICE', '공지사항', '/system/notice', 'system/Notice', 80),
|
||||
('ATTACHMENT', '첨부파일', '/system/attachment', 'system/Attachment', 90),
|
||||
('WITHDRAW', '출금 신청', '/system/withdraw', 'system/Withdraw', 95)
|
||||
) AS x(code, name, path, cmpt, sort)
|
||||
ON p.menu_code = 'GRP_SYSTEM'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM menu WHERE menu_code = x.code);
|
||||
|
||||
-- ============================================================
|
||||
-- 6. GRP_COMMISSION 에 READ 권한 등록 (대메뉴 expand 용)
|
||||
-- ============================================================
|
||||
|
||||
INSERT INTO menu_permission (menu_id, perm_code, perm_name, sort_order)
|
||||
SELECT menu_id, 'READ', '조회', 1 FROM menu WHERE menu_code = 'GRP_COMMISSION'
|
||||
ON CONFLICT (menu_id, perm_code) DO NOTHING;
|
||||
|
||||
INSERT INTO role_menu_permission (role_id, menu_id, perm_code, is_granted)
|
||||
SELECT r.role_id, m.menu_id, 'READ', 'Y'
|
||||
FROM role r CROSS JOIN menu m
|
||||
WHERE r.role_code IN ('SUPER_ADMIN','ADMIN','MANAGER','AGENT')
|
||||
AND m.menu_code = 'GRP_COMMISSION'
|
||||
ON CONFLICT (role_id, menu_id, perm_code) DO NOTHING;
|
||||
|
||||
-- ============================================================
|
||||
-- 7. 전체 신규 PAGE 메뉴에 권한 항목 등록
|
||||
-- 수수료 도메인: READ/CREATE/UPDATE/DELETE/EXPORT
|
||||
-- 관리 도메인(결재/공지/출금): READ/CREATE/UPDATE/APPROVE
|
||||
-- 조회성(첨부): READ/CREATE/DELETE
|
||||
-- ============================================================
|
||||
|
||||
-- 수수료 + 설계사 라이프사이클 + 계약변경/민원: READ/CREATE/UPDATE/DELETE/EXPORT
|
||||
INSERT INTO menu_permission (menu_id, perm_code, perm_name, sort_order)
|
||||
SELECT m.menu_id, p.code, p.name, p.sort
|
||||
FROM menu m
|
||||
CROSS JOIN (VALUES
|
||||
('READ', '조회', 10),
|
||||
('CREATE', '등록', 20),
|
||||
('UPDATE', '수정', 30),
|
||||
('DELETE', '삭제', 40),
|
||||
('EXPORT', '엑셀', 60)
|
||||
) AS p(code, name, sort)
|
||||
WHERE m.menu_code IN (
|
||||
'COMM_TYPE','COMM_MASTER','COLLECT_COMM','RENEWAL_COMM',
|
||||
'REINSTATE_COMM','PERSIST_BONUS','OVERRIDE_LEDGER',
|
||||
'AGENT_CONTRACT','AGENT_LICENSE','AGENT_TRAINING',
|
||||
'ENDORSE','COMPLAINT'
|
||||
)
|
||||
ON CONFLICT (menu_id, perm_code) DO NOTHING;
|
||||
|
||||
-- 결재/공지/출금: READ/CREATE/UPDATE/APPROVE
|
||||
INSERT INTO menu_permission (menu_id, perm_code, perm_name, sort_order)
|
||||
SELECT m.menu_id, p.code, p.name, p.sort
|
||||
FROM menu m
|
||||
CROSS JOIN (VALUES
|
||||
('READ', '조회', 10),
|
||||
('CREATE', '등록', 20),
|
||||
('UPDATE', '수정', 30),
|
||||
('APPROVE', '결재', 50)
|
||||
) AS p(code, name, sort)
|
||||
WHERE m.menu_code IN ('APPROVAL','NOTICE','WITHDRAW')
|
||||
ON CONFLICT (menu_id, perm_code) DO NOTHING;
|
||||
|
||||
-- 첨부파일: READ/CREATE/DELETE
|
||||
INSERT INTO menu_permission (menu_id, perm_code, perm_name, sort_order)
|
||||
SELECT m.menu_id, p.code, p.name, p.sort
|
||||
FROM menu m
|
||||
CROSS JOIN (VALUES
|
||||
('READ', '조회', 10),
|
||||
('CREATE', '등록', 20),
|
||||
('DELETE', '삭제', 40)
|
||||
) AS p(code, name, sort)
|
||||
WHERE m.menu_code = 'ATTACHMENT'
|
||||
ON CONFLICT (menu_id, perm_code) DO NOTHING;
|
||||
|
||||
-- ============================================================
|
||||
-- 8. 역할별 권한 부여
|
||||
-- SUPER_ADMIN / ADMIN: 전체 부여
|
||||
-- MANAGER: READ + CREATE + UPDATE + APPROVE (DELETE 제외)
|
||||
-- AGENT: 본인 관련 READ 만 (COMM_MASTER/AGENT_CONTRACT/AGENT_LICENSE/AGENT_TRAINING/NOTICE/WITHDRAW)
|
||||
-- ============================================================
|
||||
|
||||
-- SUPER_ADMIN / ADMIN — 모든 신규 메뉴 전체 권한
|
||||
INSERT INTO role_menu_permission (role_id, menu_id, perm_code, is_granted)
|
||||
SELECT r.role_id, mp.menu_id, mp.perm_code, 'Y'
|
||||
FROM role r
|
||||
CROSS JOIN menu_permission mp
|
||||
JOIN menu m ON m.menu_id = mp.menu_id
|
||||
WHERE r.role_code IN ('SUPER_ADMIN','ADMIN')
|
||||
AND m.menu_code IN (
|
||||
'COMM_TYPE','COMM_MASTER','COLLECT_COMM','RENEWAL_COMM',
|
||||
'REINSTATE_COMM','PERSIST_BONUS','OVERRIDE_LEDGER',
|
||||
'AGENT_CONTRACT','AGENT_LICENSE','AGENT_TRAINING',
|
||||
'ENDORSE','COMPLAINT',
|
||||
'APPROVAL','NOTICE','ATTACHMENT','WITHDRAW'
|
||||
)
|
||||
ON CONFLICT (role_id, menu_id, perm_code) DO NOTHING;
|
||||
|
||||
-- MANAGER — READ/CREATE/UPDATE/APPROVE (DELETE 제외)
|
||||
INSERT INTO role_menu_permission (role_id, menu_id, perm_code, is_granted)
|
||||
SELECT r.role_id, mp.menu_id, mp.perm_code, 'Y'
|
||||
FROM role r
|
||||
CROSS JOIN menu_permission mp
|
||||
JOIN menu m ON m.menu_id = mp.menu_id
|
||||
WHERE r.role_code = 'MANAGER'
|
||||
AND mp.perm_code IN ('READ','CREATE','UPDATE','APPROVE','EXPORT')
|
||||
AND m.menu_code IN (
|
||||
'COMM_TYPE','COMM_MASTER','COLLECT_COMM','RENEWAL_COMM',
|
||||
'REINSTATE_COMM','PERSIST_BONUS','OVERRIDE_LEDGER',
|
||||
'AGENT_CONTRACT','AGENT_LICENSE','AGENT_TRAINING',
|
||||
'ENDORSE','COMPLAINT',
|
||||
'APPROVAL','NOTICE','ATTACHMENT','WITHDRAW'
|
||||
)
|
||||
ON CONFLICT (role_id, menu_id, perm_code) DO NOTHING;
|
||||
|
||||
-- AGENT — 본인 관련 메뉴 READ 만
|
||||
INSERT INTO role_menu_permission (role_id, menu_id, perm_code, is_granted)
|
||||
SELECT r.role_id, mp.menu_id, mp.perm_code, 'Y'
|
||||
FROM role r
|
||||
CROSS JOIN menu_permission mp
|
||||
JOIN menu m ON m.menu_id = mp.menu_id
|
||||
WHERE r.role_code = 'AGENT'
|
||||
AND mp.perm_code = 'READ'
|
||||
AND m.menu_code IN (
|
||||
'COMM_MASTER','AGENT_CONTRACT','AGENT_LICENSE','AGENT_TRAINING',
|
||||
'NOTICE','WITHDRAW'
|
||||
)
|
||||
ON CONFLICT (role_id, menu_id, perm_code) DO NOTHING;
|
||||
@@ -0,0 +1,128 @@
|
||||
-- V55: P4 도메인에서 사용하는 공통코드 그룹/상세 일괄 INSERT
|
||||
-- core-architect 가 사용한 코드 그룹 누락분 보강.
|
||||
|
||||
-- group_code 길이 한도 상향 (기존 VARCHAR(20) → 30) — NOTIFICATION_REF_TYPE / AGENT_CONTRACT_STATUS 등 21자 이상 수용
|
||||
ALTER TABLE common_code_group ALTER COLUMN group_code TYPE VARCHAR(30);
|
||||
ALTER TABLE common_code ALTER COLUMN group_code TYPE VARCHAR(30);
|
||||
|
||||
-- ===== 그룹 =====
|
||||
INSERT INTO common_code_group (group_code, group_name, description, is_system, sort_order) VALUES
|
||||
('PAYMENT_CYCLE', '수금주기', 'MONTHLY/QUARTERLY/SEMI/ANNUAL', 'Y', 200),
|
||||
('BONUS_TYPE', '수당지급유형', 'RATE/FIXED', 'Y', 210),
|
||||
('RETENTION_MONTH', '유지기준개월', 'M13/M25/M37/M49', 'Y', 220),
|
||||
('AGENT_CONTRACT_STATUS','위촉계약상태', 'ACTIVE/TERMINATED', 'Y', 230),
|
||||
('LICENSE_TYPE', '자격증유형', 'LIFE/NONLIFE/VARIABLE', 'Y', 240),
|
||||
('LICENSE_STATUS', '자격증상태', 'ACTIVE/EXPIRED/SUSPENDED', 'Y', 250),
|
||||
('COURSE_TYPE', '교육유형', 'REGULAR/COMPLIANCE/PRODUCT', 'Y', 260),
|
||||
('ENDORSEMENT_TYPE', '계약변경유형', 'PREMIUM/BENEFICIARY/INSURED/ADDRESS', 'Y', 270),
|
||||
('COMPLAINT_CHANNEL', '민원접수채널', 'PHONE/EMAIL/VISIT/ONLINE', 'Y', 280),
|
||||
('COMPLAINT_TYPE', '민원유형', 'MIS_SELLING/DELAY/COVERAGE/REFUND/ETC', 'Y', 290),
|
||||
('COMPLAINT_SEVERITY', '민원심각도', 'LOW/MID/HIGH', 'Y', 300),
|
||||
('COMPLAINT_STATUS', '민원처리상태', 'OPEN/IN_PROGRESS/CLOSED', 'Y', 310),
|
||||
('APPROVAL_STATUS', '결재상태', 'PENDING/APPROVED/REJECTED/CANCEL', 'Y', 320),
|
||||
('APPROVAL_ACTION', '결재처리', 'APPROVE/REJECT', 'Y', 330),
|
||||
('NOTICE_TYPE', '공지유형', 'SYSTEM/POLICY/EVENT', 'Y', 340),
|
||||
('NOTIFICATION_REF_TYPE','알림참조유형', 'SETTLE/DISPUTE/INCENTIVE/WITHDRAW/...', 'Y', 350),
|
||||
('ATTACHMENT_REF_TYPE', '첨부참조유형', 'AGENT_CONTRACT/COMPLAINT/...', 'Y', 360),
|
||||
('WITHDRAW_STATUS', '출금신청상태', 'REQUESTED/APPROVED/SENT/COMPLETED/FAILED','Y', 370),
|
||||
('HOLD_REASON', '보류사유', 'NEED_DOC/UNDER_REVIEW/DISPUTE_OPEN/...','Y', 380)
|
||||
ON CONFLICT (group_code) DO NOTHING;
|
||||
|
||||
-- ===== 상세 =====
|
||||
INSERT INTO common_code (group_code, code, code_name, sort_order) VALUES
|
||||
-- PAYMENT_CYCLE
|
||||
('PAYMENT_CYCLE','MONTHLY','월납',10),
|
||||
('PAYMENT_CYCLE','QUARTERLY','분기납',20),
|
||||
('PAYMENT_CYCLE','SEMI','반기납',30),
|
||||
('PAYMENT_CYCLE','ANNUAL','연납',40),
|
||||
-- BONUS_TYPE
|
||||
('BONUS_TYPE','RATE','정률',10),
|
||||
('BONUS_TYPE','FIXED','정액',20),
|
||||
-- RETENTION_MONTH
|
||||
('RETENTION_MONTH','M13','13개월',10),
|
||||
('RETENTION_MONTH','M25','25개월',20),
|
||||
('RETENTION_MONTH','M37','37개월',30),
|
||||
('RETENTION_MONTH','M49','49개월',40),
|
||||
-- AGENT_CONTRACT_STATUS
|
||||
('AGENT_CONTRACT_STATUS','ACTIVE','유효',10),
|
||||
('AGENT_CONTRACT_STATUS','TERMINATED','해촉',20),
|
||||
-- LICENSE_TYPE
|
||||
('LICENSE_TYPE','LIFE','생명보험',10),
|
||||
('LICENSE_TYPE','NONLIFE','손해보험',20),
|
||||
('LICENSE_TYPE','VARIABLE','변액보험',30),
|
||||
-- LICENSE_STATUS
|
||||
('LICENSE_STATUS','ACTIVE','유효',10),
|
||||
('LICENSE_STATUS','EXPIRED','만료',20),
|
||||
('LICENSE_STATUS','SUSPENDED','정지',30),
|
||||
-- COURSE_TYPE
|
||||
('COURSE_TYPE','REGULAR','보수교육',10),
|
||||
('COURSE_TYPE','COMPLIANCE','준법교육',20),
|
||||
('COURSE_TYPE','PRODUCT','상품교육',30),
|
||||
-- ENDORSEMENT_TYPE
|
||||
('ENDORSEMENT_TYPE','PREMIUM_CHANGE','보험료변경',10),
|
||||
('ENDORSEMENT_TYPE','BENEFICIARY','수익자변경',20),
|
||||
('ENDORSEMENT_TYPE','INSURED','피보험자변경',30),
|
||||
('ENDORSEMENT_TYPE','ADDRESS','주소변경',40),
|
||||
-- COMPLAINT_CHANNEL
|
||||
('COMPLAINT_CHANNEL','PHONE','전화',10),
|
||||
('COMPLAINT_CHANNEL','EMAIL','이메일',20),
|
||||
('COMPLAINT_CHANNEL','VISIT','방문',30),
|
||||
('COMPLAINT_CHANNEL','ONLINE','온라인',40),
|
||||
-- COMPLAINT_TYPE
|
||||
('COMPLAINT_TYPE','MIS_SELLING','불완전판매',10),
|
||||
('COMPLAINT_TYPE','DELAY','업무지연',20),
|
||||
('COMPLAINT_TYPE','COVERAGE','보장설명미흡',30),
|
||||
('COMPLAINT_TYPE','REFUND','환급요청',40),
|
||||
('COMPLAINT_TYPE','ETC','기타',90),
|
||||
-- COMPLAINT_SEVERITY
|
||||
('COMPLAINT_SEVERITY','LOW','경미',10),
|
||||
('COMPLAINT_SEVERITY','MID','보통',20),
|
||||
('COMPLAINT_SEVERITY','HIGH','중대',30),
|
||||
-- COMPLAINT_STATUS
|
||||
('COMPLAINT_STATUS','OPEN','접수',10),
|
||||
('COMPLAINT_STATUS','IN_PROGRESS','처리중',20),
|
||||
('COMPLAINT_STATUS','CLOSED','처리완료',30),
|
||||
-- APPROVAL_STATUS
|
||||
('APPROVAL_STATUS','PENDING','결재대기',10),
|
||||
('APPROVAL_STATUS','APPROVED','승인',20),
|
||||
('APPROVAL_STATUS','REJECTED','반려',30),
|
||||
('APPROVAL_STATUS','CANCEL','취소',40),
|
||||
-- APPROVAL_ACTION
|
||||
('APPROVAL_ACTION','APPROVE','승인',10),
|
||||
('APPROVAL_ACTION','REJECT','반려',20),
|
||||
-- NOTICE_TYPE
|
||||
('NOTICE_TYPE','SYSTEM','시스템',10),
|
||||
('NOTICE_TYPE','POLICY','정책',20),
|
||||
('NOTICE_TYPE','EVENT','이벤트',30),
|
||||
-- NOTIFICATION_REF_TYPE
|
||||
('NOTIFICATION_REF_TYPE','SETTLE','정산',10),
|
||||
('NOTIFICATION_REF_TYPE','DISPUTE','이의신청',20),
|
||||
('NOTIFICATION_REF_TYPE','INCENTIVE','시책',30),
|
||||
('NOTIFICATION_REF_TYPE','WITHDRAW','출금',40),
|
||||
('NOTIFICATION_REF_TYPE','COMPLAINT','민원',50),
|
||||
('NOTIFICATION_REF_TYPE','APPROVAL','결재',60),
|
||||
('NOTIFICATION_REF_TYPE','SYSTEM','시스템',70),
|
||||
-- ATTACHMENT_REF_TYPE
|
||||
('ATTACHMENT_REF_TYPE','AGENT_CONTRACT','위촉계약서',10),
|
||||
('ATTACHMENT_REF_TYPE','COMPLAINT','민원',20),
|
||||
('ATTACHMENT_REF_TYPE','DISPUTE','이의신청',30),
|
||||
('ATTACHMENT_REF_TYPE','SETTLE','정산',40),
|
||||
('ATTACHMENT_REF_TYPE','TRAINING','교육',50),
|
||||
('ATTACHMENT_REF_TYPE','LICENSE','자격증',60),
|
||||
('ATTACHMENT_REF_TYPE','ENDORSEMENT','계약변경',70),
|
||||
('ATTACHMENT_REF_TYPE','NOTICE','공지',80),
|
||||
('ATTACHMENT_REF_TYPE','ETC','기타',90),
|
||||
-- WITHDRAW_STATUS
|
||||
('WITHDRAW_STATUS','REQUESTED','신청',10),
|
||||
('WITHDRAW_STATUS','APPROVED','승인',20),
|
||||
('WITHDRAW_STATUS','SENT','전송완료',30),
|
||||
('WITHDRAW_STATUS','COMPLETED','이체완료',40),
|
||||
('WITHDRAW_STATUS','FAILED','실패',90),
|
||||
-- HOLD_REASON
|
||||
('HOLD_REASON','NEED_DOC','서류미비',10),
|
||||
('HOLD_REASON','UNDER_REVIEW','검토중',20),
|
||||
('HOLD_REASON','DISPUTE_OPEN','이의신청중',30),
|
||||
('HOLD_REASON','LICENSE_EXPIRED','자격증만료',40),
|
||||
('HOLD_REASON','TRAINING_INSUFFICIENT','교육시간미달',50),
|
||||
('HOLD_REASON','ETC','기타',90)
|
||||
ON CONFLICT (group_code, code) DO NOTHING;
|
||||
@@ -0,0 +1,27 @@
|
||||
-- V56: agent 테이블 세무 컬럼 누락 보강
|
||||
-- 운영 DB 의 V23 SQL 과 현재 V23 SQL 의 체크섬 미스매치로 인해
|
||||
-- agent.tax_type / business_no / vat_type 가 적용되지 않은 상태.
|
||||
-- AgentMapper.xml 이 위 3개 컬럼을 참조하므로 /api/agents 가 500 에러.
|
||||
-- IF NOT EXISTS 로 idempotent 추가.
|
||||
|
||||
ALTER TABLE agent ADD COLUMN IF NOT EXISTS tax_type VARCHAR(20);
|
||||
ALTER TABLE agent ADD COLUMN IF NOT EXISTS business_no VARCHAR(20);
|
||||
ALTER TABLE agent ADD COLUMN IF NOT EXISTS vat_type VARCHAR(20);
|
||||
|
||||
COMMENT ON COLUMN agent.tax_type IS '세무유형 (사업소득/기타소득 등 TAX_TYPE 코드)';
|
||||
COMMENT ON COLUMN agent.business_no IS '사업자등록번호 (사업소득자)';
|
||||
COMMENT ON COLUMN agent.vat_type IS '부가세유형 (VAT_TYPE 코드)';
|
||||
|
||||
-- TAX_TYPE / VAT_TYPE common_code 그룹이 없으면 추가
|
||||
INSERT INTO common_code_group (group_code, group_name, description, is_system, sort_order) VALUES
|
||||
('TAX_TYPE', '세무유형', 'BUSINESS/OTHER 등', 'Y', 400),
|
||||
('VAT_TYPE', '부가세유형', 'GENERAL/SIMPLE/EXEMPT', 'Y', 410)
|
||||
ON CONFLICT (group_code) DO NOTHING;
|
||||
|
||||
INSERT INTO common_code (group_code, code, code_name, sort_order) VALUES
|
||||
('TAX_TYPE','BUSINESS','사업소득',10),
|
||||
('TAX_TYPE','OTHER','기타소득',20),
|
||||
('VAT_TYPE','GENERAL','일반과세',10),
|
||||
('VAT_TYPE','SIMPLE','간이과세',20),
|
||||
('VAT_TYPE','EXEMPT','면세',30)
|
||||
ON CONFLICT (group_code, code) DO NOTHING;
|
||||
Reference in New Issue
Block a user