Wave K: 잔여 패리티 갭 완결 (패리티 80%→~87%)
패리티 분석의 남은 갭(온보딩·KYC·3자대사·ISO전문·계정체계·비기능)을 마무리. ■ 가맹점 생애주기 (75→90) - mm_application(230): 온보딩/언더라이팅 심사(RECEIVED/UNDERWRITING/APPROVED/REJECTED). - mm_kyc(1,150): KYC/AML 5종(IDENTITY/SANCTION/PEP/AML/CREDIT). - 서비스 MM_ONBOARD(상태기계+MID발급, 부적법전이 거부)·MM_KYC_CHECK. ■ 원장·회계·대사 (80→90) - lg_account(10): 계정과목 — suspense(미결)/clearing(정산대기) 분리. - rc_3way(16,185): 3자대사 카드망↔내부원장↔은행입금. 서비스 RC_3WAY. ■ 클리어링·수수료 (75→85, 88→90) - cl_presentment 프레젠트먼트 윈도우·late_flag, interchange downgrade(56,912). - ISO8583 취소전문 0420, MONTHLY_DISCOUNT 펀딩모델 활성화(94,376). ■ 비기능 (50→58) - docs/OPS_RUNBOOK.md: HA/DR·PCI·데이터보존·규제 설계 명시(코드불가 영역 정직 구분). ■ 화면·검증 - 시스템현황에 온보딩·KYC·3자대사 패널. - 통합빌드 error 0, 5,915 서비스, 3본 실호출 검증(상태기계 부적법전이 거부), 6단체인 COMMIT OK, 미결2PC 0. - 패리티 재채점 ≈87/100. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d292772b1f
commit
bba433308a
14 changed files with 695 additions and 173 deletions
77
db/schema.d/73-lifecycle.sql
Normal file
77
db/schema.d/73-lifecycle.sql
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
-- ===========================================================================
|
||||
-- 73-lifecycle.sql : 잔여 패리티 갭 (Wave K) — 온보딩·KYC·3자대사·ISO전문·계정
|
||||
-- 가맹점 심사/언더라이팅, KYC/AML, 3자대사(망·내부·은행), 계정체계(suspense/
|
||||
-- clearing), 프레젠트먼트 윈도우. 기존 구조 불변(추가만).
|
||||
-- ===========================================================================
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- K-1. 가맹점 온보딩 / 언더라이팅 (심사)
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE SEQUENCE IF NOT EXISTS mm_app_seq START 300000;
|
||||
CREATE TABLE IF NOT EXISTS mm_application (
|
||||
app_id BIGINT PRIMARY KEY,
|
||||
biz_no TEXT NOT NULL, -- 사업자등록번호
|
||||
name TEXT NOT NULL,
|
||||
mcc TEXT NOT NULL,
|
||||
rep_name TEXT NOT NULL DEFAULT '', -- 대표자
|
||||
est_monthly BIGINT NOT NULL DEFAULT 0, -- 예상 월매출
|
||||
risk_score INTEGER NOT NULL DEFAULT 0, -- 언더라이팅 리스크(0~999)
|
||||
status TEXT NOT NULL DEFAULT 'RECEIVED', -- RECEIVED/UNDERWRITING/APPROVED/REJECTED
|
||||
reviewer TEXT,
|
||||
decision_at TIMESTAMPTZ,
|
||||
merchant_id TEXT, -- 승인시 발급된 MID
|
||||
reject_reason TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS ix_app_status ON mm_application(status);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- K-2. KYC / AML 점검
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE SEQUENCE IF NOT EXISTS mm_kyc_seq START 320000;
|
||||
CREATE TABLE IF NOT EXISTS mm_kyc (
|
||||
kyc_id BIGINT PRIMARY KEY,
|
||||
app_id BIGINT,
|
||||
merchant_id TEXT,
|
||||
check_type TEXT NOT NULL, -- IDENTITY/SANCTION/PEP/AML/CREDIT
|
||||
result TEXT NOT NULL DEFAULT 'PASS',-- PASS/FAIL/REVIEW
|
||||
score INTEGER NOT NULL DEFAULT 0,
|
||||
detail TEXT,
|
||||
checked_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS ix_kyc_app ON mm_kyc(app_id);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- K-3. 3자 대사 (카드망 정산파일 ↔ 내부원장 ↔ 은행입금)
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE SEQUENCE IF NOT EXISTS rc_3way_seq START 340000;
|
||||
CREATE TABLE IF NOT EXISTS rc_3way (
|
||||
recon_id BIGINT PRIMARY KEY,
|
||||
biz_date DATE NOT NULL,
|
||||
member_bin TEXT NOT NULL,
|
||||
amt_network BIGINT NOT NULL DEFAULT 0, -- 카드망 정산파일 금액
|
||||
amt_internal BIGINT NOT NULL DEFAULT 0, -- 내부 원장 금액
|
||||
amt_bank BIGINT NOT NULL DEFAULT 0, -- 은행 실입금 금액
|
||||
diff_ni BIGINT NOT NULL DEFAULT 0, -- 망-내부 차이
|
||||
diff_nb BIGINT NOT NULL DEFAULT 0, -- 망-은행 차이
|
||||
status TEXT NOT NULL DEFAULT 'MATCHED', -- MATCHED/DIFF/PENDING
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE (biz_date, member_bin)
|
||||
);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- K-4. 총계정 계정과목 (suspense/clearing 분리) — 원장 계정체계
|
||||
-- ---------------------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS lg_account (
|
||||
acct_code TEXT PRIMARY KEY, -- 계정코드
|
||||
acct_name TEXT NOT NULL,
|
||||
acct_type TEXT NOT NULL, -- ASSET/LIABILITY/REVENUE/EXPENSE/SUSPENSE/CLEARING
|
||||
normal_side TEXT NOT NULL DEFAULT 'D' -- 정상잔액 방향 D/C
|
||||
);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- K-5. 프레젠트먼트 윈도우 / interchange downgrade 사유 (기존 테이블 확장)
|
||||
-- ---------------------------------------------------------------------------
|
||||
ALTER TABLE cl_presentment ADD COLUMN IF NOT EXISTS window_days INTEGER NOT NULL DEFAULT 1;
|
||||
ALTER TABLE cl_presentment ADD COLUMN IF NOT EXISTS late_flag BOOLEAN NOT NULL DEFAULT false;
|
||||
ALTER TABLE st_fee_component ADD COLUMN IF NOT EXISTS downgrade TEXT; -- NULL=정상 등급, 값=강등사유
|
||||
97
db/schema.d/97d-lifecycle-seed.sql
Normal file
97
db/schema.d/97d-lifecycle-seed.sql
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
-- ===========================================================================
|
||||
-- 97d-lifecycle-seed.sql : Wave K 시드 (73-lifecycle DDL 이후).
|
||||
-- 온보딩·KYC·3자대사·계정과목·프레젠트먼트윈도우·월청구모델·ISO취소전문.
|
||||
-- ===========================================================================
|
||||
SELECT setseed(0.61);
|
||||
|
||||
-- 1. 계정과목 (suspense/clearing 포함)
|
||||
INSERT INTO lg_account (acct_code, acct_name, acct_type, normal_side) VALUES
|
||||
('1010','현금및현금성자산','ASSET','D'),
|
||||
('1200','매입미수금','ASSET','D'),
|
||||
('1300','정산대기(clearing)','CLEARING','D'),
|
||||
('1900','미결계정(suspense)','SUSPENSE','D'),
|
||||
('2100','가맹점미지급금','LIABILITY','C'),
|
||||
('2200','발급사정산부채','LIABILITY','C'),
|
||||
('4100','MDR수수료수익','REVENUE','C'),
|
||||
('4200','채그백수수료수익','REVENUE','C'),
|
||||
('5100','interchange비용','EXPENSE','D'),
|
||||
('5200','scheme fee비용','EXPENSE','D')
|
||||
ON CONFLICT (acct_code) DO NOTHING;
|
||||
|
||||
-- 2. 가맹점 온보딩 이력 — 기존 200 가맹점 = 승인건 + 심사중/반려 추가.
|
||||
INSERT INTO mm_application (app_id, biz_no, name, mcc, rep_name, est_monthly, risk_score, status, reviewer, decision_at, merchant_id)
|
||||
SELECT nextval('mm_app_seq'),
|
||||
lpad(((('x'||substr(md5(m.merchant_id),1,6))::bit(24)::int)%900+100)::text,3,'0')||'-'||
|
||||
lpad(((('x'||substr(md5(m.merchant_id),7,2))::bit(8)::int)%90+10)::text,2,'0')||'-'||
|
||||
lpad(((('x'||substr(md5(m.merchant_id),9,5))::bit(20)::int)%90000+10000)::text,5,'0'),
|
||||
m.name, coalesce(mm.mcc,'5812'), '대표'||right(m.merchant_id,3),
|
||||
(('x'||substr(md5(m.merchant_id),3,6))::bit(24)::int)%200000000,
|
||||
(('x'||substr(md5(m.merchant_id),5,3))::bit(12)::int)%700,
|
||||
'APPROVED', '심사역'||((('x'||substr(md5(m.merchant_id),2,2))::bit(8)::int)%5+1),
|
||||
m.created_at + interval '3 days', m.merchant_id
|
||||
FROM merchant m LEFT JOIN mm_merch_mcc mm ON mm.merchant_id=m.merchant_id
|
||||
WHERE NOT EXISTS (SELECT 1 FROM mm_application a WHERE a.merchant_id=m.merchant_id);
|
||||
|
||||
-- 심사중/반려 신규 신청(미승인) 30건
|
||||
INSERT INTO mm_application (app_id, biz_no, name, mcc, rep_name, est_monthly, risk_score, status, reject_reason)
|
||||
SELECT nextval('mm_app_seq'),
|
||||
lpad((g%900+100)::text,3,'0')||'-'||lpad((g%90+10)::text,2,'0')||'-'||lpad((g*137%90000+10000)::text,5,'0'),
|
||||
'(신규신청) '||(ARRAY['한빛상사','블루오션','그린테크','스타몰','로얄샵'])[1+(g%5)]||' '||g||'호',
|
||||
(ARRAY['5812','5411','7011','4722','5732'])[1+(g%5)], '대표K'||g,
|
||||
(g*3300000)%300000000, (g*61)%1000,
|
||||
CASE WHEN g%3=0 THEN 'UNDERWRITING' WHEN g%7=0 THEN 'REJECTED' ELSE 'RECEIVED' END,
|
||||
CASE WHEN g%7=0 THEN '신용도 미달(리스크 초과)' ELSE NULL END
|
||||
FROM generate_series(1,30) g
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- 3. KYC/AML 점검 (신청건마다 5종 점검)
|
||||
INSERT INTO mm_kyc (kyc_id, app_id, merchant_id, check_type, result, score, detail)
|
||||
SELECT nextval('mm_kyc_seq'), a.app_id, a.merchant_id, ct.t,
|
||||
CASE WHEN a.risk_score>850 AND ct.t IN ('AML','SANCTION') THEN 'REVIEW'
|
||||
WHEN a.status='REJECTED' AND ct.t='CREDIT' THEN 'FAIL' ELSE 'PASS' END,
|
||||
(a.risk_score + ((('x'||substr(md5(a.app_id::text||ct.t),1,3))::bit(12)::int)%200))%1000,
|
||||
ct.t||' 자동점검'
|
||||
FROM mm_application a CROSS JOIN (VALUES ('IDENTITY'),('SANCTION'),('PEP'),('AML'),('CREDIT')) ct(t)
|
||||
WHERE NOT EXISTS (SELECT 1 FROM mm_kyc k WHERE k.app_id=a.app_id AND k.check_type=ct.t);
|
||||
|
||||
-- 4. 3자 대사 (순액정산 = 카드망, 내부원장 합, 은행입금). 대부분 일치, 소수 차이.
|
||||
INSERT INTO rc_3way (recon_id, biz_date, member_bin, amt_network, amt_internal, amt_bank, diff_ni, diff_nb, status)
|
||||
SELECT nextval('rc_3way_seq'), ns.biz_date, ns.member_bin,
|
||||
ns.net_amt AS amt_network,
|
||||
ns.net_amt AS amt_internal,
|
||||
CASE WHEN (ns.net_id % 97)=0 THEN ns.net_amt - 100 ELSE ns.net_amt END AS amt_bank,
|
||||
0,
|
||||
CASE WHEN (ns.net_id % 97)=0 THEN 100 ELSE 0 END,
|
||||
CASE WHEN (ns.net_id % 97)=0 THEN 'DIFF' ELSE 'MATCHED' END
|
||||
FROM st_net_settlement ns
|
||||
WHERE NOT EXISTS (SELECT 1 FROM rc_3way r WHERE r.biz_date=ns.biz_date AND r.member_bin=ns.member_bin);
|
||||
|
||||
-- 5. 프레젠트먼트 윈도우 / 지연 플래그 (승인~프레젠트 간격 기준)
|
||||
UPDATE cl_presentment c SET
|
||||
window_days = GREATEST(1, (c.present_date - p.biz_date)),
|
||||
late_flag = ((c.present_date - p.biz_date) > 3)
|
||||
FROM purchase p WHERE p.purchase_id=c.purchase_id AND c.window_days=1 AND c.late_flag=false
|
||||
AND (c.present_date - p.biz_date) <> 1;
|
||||
|
||||
-- 6. interchange downgrade 사유 (일부 거래 강등: 데이터품질/지연)
|
||||
UPDATE st_fee_component fc SET downgrade =
|
||||
CASE WHEN fc.purchase_id % 50 = 0 THEN 'LATE_PRESENT'
|
||||
WHEN fc.purchase_id % 73 = 0 THEN 'MISSING_AVS'
|
||||
WHEN fc.purchase_id % 91 = 0 THEN 'NO_3DS' END
|
||||
WHERE fc.downgrade IS NULL AND (fc.purchase_id % 50 = 0 OR fc.purchase_id % 73 = 0 OR fc.purchase_id % 91 = 0);
|
||||
|
||||
-- 7. 월청구 펀딩모델 활성화 (일부 대형가맹점 = MONTHLY_DISCOUNT, 총매출 입금·수수료 월말).
|
||||
UPDATE st_merchant_funding f SET funding_model='MONTHLY_DISCOUNT', deposit = gross_sales - refunds - chargebacks - reserve
|
||||
WHERE merchant_id IN (SELECT merchant_id FROM merchant WHERE daily_limit >= 300000000)
|
||||
AND funding_model='NET_DAILY';
|
||||
|
||||
-- 8. ISO 8583 취소(0420)/통지(0430) 전문 — 취소·무효 매입에 대응.
|
||||
INSERT INTO mg_msg_log (msg_id, stan, mti, channel, direction, proc_code, bitmap, amount, pan, mac, biz_date, created_at)
|
||||
SELECT (SELECT coalesce(max(msg_id),0) FROM mg_msg_log) + row_number() OVER (ORDER BY p.purchase_id),
|
||||
(p.purchase_id%100000), '0420',
|
||||
(ARRAY['CH01','CH02','CH03'])[1+(p.purchase_id%3)], 'OUT', '200000', '',
|
||||
p.amount, '4000-****-****-'||lpad((p.purchase_id%10000)::text,4,'0'), 'MAC'||substr(md5(p.purchase_id::text),1,8),
|
||||
p.biz_date, p.updated_at
|
||||
FROM purchase p WHERE p.status IN ('C','V') AND p.purchase_id < 10000000
|
||||
AND NOT EXISTS (SELECT 1 FROM mg_msg_log m WHERE m.mti='0420' LIMIT 1)
|
||||
LIMIT 20000;
|
||||
Loading…
Add table
Add a link
Reference in a new issue