Wave J: 카드보안·자금·규제 고도화 (패리티 70%→80%)
패리티 분석의 최우선 갭(카드보안·자금연동·운영·규제)을 데이터모델+시드+ 런타임서비스+화면으로 체계적 보강. 전부 실측·런타임 검증. ■ J-1 카드보안 (승인 60→82) - card_vault(6,680): PCI 토큰볼트 — PAN 원문 미저장, 마스킹+SHA256 해시. - au_3ds(1,235): 3DS/SCA — ECI·CAVV·책임전환(ISSUER 1,143). - au_verify(8,191): AVS/CVV + 리스크판정(APPROVE/REVIEW/DECLINE). - 서비스 TOKENIZE/AUTH_3DS/AUTH_VERIFY (au). ■ J-2 자금이동 (정산 75→85) - st_funding_instr(355k): 펌뱅킹 펀딩지시/반환(CONFIRMED/RETURNED). - ac_dcc(426): DCC 다통화 승인시 환율고정(USD/JPY/EUR/CNY + 마크업 3%). - 서비스 ST_FUNDINSTR/AC_DCC. ■ J-3 수수료·분쟁 (수수료 80→88, 분쟁 70→82) - st_cb_fee(175): 채그백 건당수수료(단계별 차등). - ac_retrieval(127) + 분쟁 SLA타이머·fraud_flag. 서비스 ACQ_RETRIEVAL. ■ J-4 리포팅·규제 (리포팅 70→85) - rp_merchant_stmt(12.8k): 가맹점 월명세서. - rp_regulatory(134): 여신전문금융업법 정산주기 준수·거래량 보고. ■ J-5 화면·검증 - 포털 "카드보안·규제"(SY0004, #sec): 토큰볼트·3DS·AVS/CVV·DCC·펀딩·규제. - 통합빌드 error 0, 5,907 서비스 AVAIL, 6본 신규서비스 실호출 검증(미결2PC 0). - PARITY_ANALYSIS 재채점: 가중 ≈80/100. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
782b802156
commit
d292772b1f
21 changed files with 1337 additions and 7 deletions
157
db/schema.d/72-security.sql
Normal file
157
db/schema.d/72-security.sql
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
-- ===========================================================================
|
||||
-- 72-security.sql : 패리티 고도화 (Wave J) — 카드보안·자금연동·수수료·분쟁·리포팅
|
||||
-- 실제 매입사 대비 갭이던 PCI/3DS/AVS·CVV, 은행 rails 펀딩, DCC, 채그백수수료,
|
||||
-- retrieval, 규제보고를 데이터 모델로 추가. 기존 구조 불변(추가만).
|
||||
-- ===========================================================================
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- J-1. 카드보안
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 토큰볼트: PAN 을 토큰으로 치환, 원문은 저장하지 않음(마스킹만 보관). PCI 스코프 축소.
|
||||
CREATE SEQUENCE IF NOT EXISTS card_token_seq START 4000000;
|
||||
CREATE TABLE IF NOT EXISTS card_vault (
|
||||
token TEXT PRIMARY KEY, -- 표면 토큰(비민감). 예: TKN-xxxxxxxx
|
||||
pan_masked TEXT NOT NULL, -- 4111-****-****-1111 (마스킹)
|
||||
pan_hash TEXT NOT NULL, -- SHA-256(PAN) — 중복탐지/조회용(원문 불가역)
|
||||
bin TEXT NOT NULL, -- 앞 6자리(라우팅)
|
||||
last4 TEXT NOT NULL,
|
||||
card_type TEXT NOT NULL DEFAULT 'CREDIT',
|
||||
issuer TEXT NOT NULL DEFAULT 'BC',
|
||||
exp_ym TEXT, -- YYYYMM (만료)
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS ix_vault_hash ON card_vault(pan_hash);
|
||||
CREATE INDEX IF NOT EXISTS ix_vault_bin ON card_vault(bin);
|
||||
|
||||
-- 3DS/SCA 인증 결과 (비대면 거래 인증·책임전환)
|
||||
CREATE SEQUENCE IF NOT EXISTS au_3ds_seq START 500000;
|
||||
CREATE TABLE IF NOT EXISTS au_3ds (
|
||||
tds_id BIGINT PRIMARY KEY,
|
||||
purchase_id BIGINT,
|
||||
token TEXT,
|
||||
version TEXT NOT NULL DEFAULT '2.2.0', -- 3DS 버전
|
||||
eci TEXT NOT NULL, -- 05=완전인증 06=시도 07=미인증
|
||||
cavv TEXT, -- 인증검증값(Base64)
|
||||
ds_trans_id TEXT, -- Directory Server txn id
|
||||
auth_status TEXT NOT NULL, -- Y=인증 A=시도 N=실패 U=불가 R=거부
|
||||
liability TEXT NOT NULL DEFAULT 'ISSUER', -- 책임주체: ISSUER(전환됨)/MERCHANT
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS ix_3ds_pid ON au_3ds(purchase_id);
|
||||
|
||||
-- AVS/CVV 검증 응답
|
||||
CREATE SEQUENCE IF NOT EXISTS au_verify_seq START 550000;
|
||||
CREATE TABLE IF NOT EXISTS au_verify (
|
||||
vrf_id BIGINT PRIMARY KEY,
|
||||
purchase_id BIGINT,
|
||||
token TEXT,
|
||||
avs_code TEXT NOT NULL DEFAULT 'U', -- Y/A/Z/N/U (주소·우편일치)
|
||||
cvv_code TEXT NOT NULL DEFAULT 'U', -- M=일치 N=불일치 P=미처리 U=불가
|
||||
risk_score INTEGER NOT NULL DEFAULT 0, -- 0~999
|
||||
decision TEXT NOT NULL DEFAULT 'APPROVE', -- APPROVE/DECLINE/REVIEW
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS ix_verify_pid ON au_verify(purchase_id);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- J-2. 자금이동 실연동
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 펀딩 지시/반환 (펌뱅킹/ACH 등가). 순액정산 결과를 은행 rails 로 지급 지시.
|
||||
CREATE SEQUENCE IF NOT EXISTS st_fundinstr_seq START 850000;
|
||||
CREATE TABLE IF NOT EXISTS st_funding_instr (
|
||||
instr_id BIGINT PRIMARY KEY,
|
||||
merchant_id TEXT NOT NULL,
|
||||
biz_date DATE NOT NULL,
|
||||
bank_code TEXT NOT NULL DEFAULT 'KB', -- 입금은행
|
||||
account_no TEXT NOT NULL,
|
||||
amount BIGINT NOT NULL, -- 지급액(펀딩 deposit)
|
||||
rail TEXT NOT NULL DEFAULT 'FIRMBANK', -- FIRMBANK/ACH/RTGS
|
||||
status TEXT NOT NULL DEFAULT 'SENT', -- SENT/CONFIRMED/RETURNED
|
||||
return_code TEXT, -- 반환사유(계좌오류 등)
|
||||
sent_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
confirmed_at TIMESTAMPTZ
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS ix_fundinstr_merch ON st_funding_instr(merchant_id, biz_date);
|
||||
|
||||
-- DCC (해외카드 원화가맹점 결제시 통화선택) — 승인시점 환율고정.
|
||||
CREATE SEQUENCE IF NOT EXISTS ac_dcc_seq START 450000;
|
||||
CREATE TABLE IF NOT EXISTS ac_dcc (
|
||||
dcc_id BIGINT PRIMARY KEY,
|
||||
purchase_id BIGINT NOT NULL,
|
||||
base_ccy TEXT NOT NULL DEFAULT 'KRW', -- 가맹점 통화
|
||||
txn_ccy TEXT NOT NULL, -- 카드소지자 통화(USD/JPY/EUR...)
|
||||
base_amount BIGINT NOT NULL, -- 원화 금액
|
||||
txn_amount NUMERIC(18,2) NOT NULL, -- 외화 금액
|
||||
fx_rate NUMERIC(14,6) NOT NULL, -- 고정환율
|
||||
markup_bps INTEGER NOT NULL DEFAULT 300,-- DCC 마크업(3%)
|
||||
opted_in BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS ix_dcc_pid ON ac_dcc(purchase_id);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- J-3. 수수료·분쟁 운영
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 채그백 수수료 (분쟁 발생시 가맹점 부과 건당 수수료)
|
||||
CREATE SEQUENCE IF NOT EXISTS st_cbfee_seq START 950000;
|
||||
CREATE TABLE IF NOT EXISTS st_cb_fee (
|
||||
cbfee_id BIGINT PRIMARY KEY,
|
||||
dispute_id BIGINT NOT NULL,
|
||||
merchant_id TEXT NOT NULL,
|
||||
fee_amount BIGINT NOT NULL DEFAULT 15000, -- 건당 채그백 수수료(원)
|
||||
stage TEXT NOT NULL, -- 어느 단계에서 부과
|
||||
billed BOOLEAN NOT NULL DEFAULT false,
|
||||
biz_date DATE NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
-- retrieval request (매출전표 조회요청 — 채그백 전 단계)
|
||||
CREATE SEQUENCE IF NOT EXISTS ac_retrieval_seq START 620000;
|
||||
CREATE TABLE IF NOT EXISTS ac_retrieval (
|
||||
retr_id BIGINT PRIMARY KEY,
|
||||
purchase_id BIGINT NOT NULL,
|
||||
merchant_id TEXT NOT NULL,
|
||||
reason TEXT NOT NULL, -- 조회사유
|
||||
status TEXT NOT NULL DEFAULT 'OPEN', -- OPEN/FULFILLED/EXPIRED
|
||||
sla_due DATE NOT NULL, -- SLA 마감일
|
||||
fulfilled_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
-- 분쟁 SLA 타이머 컬럼 추가 (기존 ac_dispute 확장)
|
||||
ALTER TABLE ac_dispute ADD COLUMN IF NOT EXISTS sla_due DATE;
|
||||
ALTER TABLE ac_dispute ADD COLUMN IF NOT EXISTS fraud_flag BOOLEAN NOT NULL DEFAULT false;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- J-4. 리포팅·규제
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 가맹점 월 명세서
|
||||
CREATE SEQUENCE IF NOT EXISTS rp_stmt_seq START 700000;
|
||||
CREATE TABLE IF NOT EXISTS rp_merchant_stmt (
|
||||
stmt_id BIGINT PRIMARY KEY,
|
||||
merchant_id TEXT NOT NULL,
|
||||
stmt_month TEXT NOT NULL, -- YYYYMM
|
||||
gross_sales BIGINT NOT NULL DEFAULT 0,
|
||||
txn_count BIGINT NOT NULL DEFAULT 0,
|
||||
total_fees BIGINT NOT NULL DEFAULT 0,
|
||||
interchange BIGINT NOT NULL DEFAULT 0,
|
||||
scheme_fee BIGINT NOT NULL DEFAULT 0,
|
||||
markup BIGINT NOT NULL DEFAULT 0,
|
||||
cb_fees BIGINT NOT NULL DEFAULT 0,
|
||||
net_deposit BIGINT NOT NULL DEFAULT 0,
|
||||
issued_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
UNIQUE (merchant_id, stmt_month)
|
||||
);
|
||||
|
||||
-- 규제보고 (여신전문금융업법 정산주기 준수 등)
|
||||
CREATE SEQUENCE IF NOT EXISTS rp_reg_seq START 710000;
|
||||
CREATE TABLE IF NOT EXISTS rp_regulatory (
|
||||
reg_id BIGINT PRIMARY KEY,
|
||||
report_type TEXT NOT NULL, -- SETTLE_CYCLE/FEE_DISCLOSURE/TXN_VOLUME
|
||||
period TEXT NOT NULL, -- YYYYMM
|
||||
metric TEXT NOT NULL,
|
||||
value NUMERIC(18,2) NOT NULL,
|
||||
compliant BOOLEAN NOT NULL DEFAULT true,
|
||||
note TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
145
db/schema.d/97c-security-seed.sql
Normal file
145
db/schema.d/97c-security-seed.sql
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
-- ===========================================================================
|
||||
-- 97c-security-seed.sql : Wave J 시드 (72-security DDL 이후).
|
||||
-- 토큰볼트·3DS·AVS/CVV·펀딩지시·DCC·채그백수수료·명세서·규제보고 소급 적재.
|
||||
-- idempotent 가드. 대량 매입 성능 고려하여 최근 구간 위주 + 요약은 전량.
|
||||
-- ===========================================================================
|
||||
SELECT setseed(0.51);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 1. 토큰볼트: 기존 card_limit 의 카드번호를 토큰화 (PAN 원문 미저장).
|
||||
-- ---------------------------------------------------------------------------
|
||||
INSERT INTO card_vault (token, pan_masked, pan_hash, bin, last4, card_type, issuer, exp_ym)
|
||||
SELECT 'TKN-' || substr(md5(cl.card_no), 1, 12),
|
||||
substr(cl.card_no,1,4) || '-****-****-' || right(cl.card_no,4),
|
||||
encode(sha256(cl.card_no::bytea), 'hex'),
|
||||
substr(cl.card_no,1,6), right(cl.card_no,4),
|
||||
CASE WHEN (('x'||substr(md5(cl.card_no),1,4))::bit(16)::int) % 3 = 0 THEN 'CHECK' ELSE 'CREDIT' END,
|
||||
(ARRAY['BC','KB','SHINHAN','HYUNDAI','SAMSUNG','LOTTE','NH','HANA'])[1 + (('x'||substr(md5(cl.card_no),5,4))::bit(16)::int) % 8],
|
||||
to_char(current_date + ((('x'||substr(md5(cl.card_no),9,3))::bit(12)::int % 48)) * interval '1 month','YYYYMM')
|
||||
FROM card_limit cl
|
||||
ON CONFLICT (token) DO NOTHING;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 2. 3DS/SCA: 비대면(EDI/FOREIGN) 매입에 3DS 인증결과 부여 (최근 3개월 구간).
|
||||
-- ---------------------------------------------------------------------------
|
||||
INSERT INTO au_3ds (tds_id, purchase_id, version, eci, cavv, ds_trans_id, auth_status, liability)
|
||||
SELECT nextval('au_3ds_seq'), p.purchase_id, '2.2.0',
|
||||
CASE WHEN r < 0.85 THEN '05' WHEN r < 0.95 THEN '06' ELSE '07' END,
|
||||
substr(md5(p.purchase_id::text),1,28),
|
||||
'DS-' || substr(md5(p.purchase_id::text||'ds'),1,16),
|
||||
CASE WHEN r < 0.85 THEN 'Y' WHEN r < 0.93 THEN 'A' WHEN r < 0.97 THEN 'N' ELSE 'U' END,
|
||||
CASE WHEN r < 0.93 THEN 'ISSUER' ELSE 'MERCHANT' END
|
||||
FROM (SELECT purchase_id, random() r FROM purchase
|
||||
WHERE channel IN ('EDI','FOREIGN') AND purchase_id < 10000000) p
|
||||
WHERE NOT EXISTS (SELECT 1 FROM au_3ds t WHERE t.purchase_id = p.purchase_id);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 3. AVS/CVV 검증 (전 채널, 최근 3개월).
|
||||
-- ---------------------------------------------------------------------------
|
||||
INSERT INTO au_verify (vrf_id, purchase_id, avs_code, cvv_code, risk_score, decision)
|
||||
SELECT nextval('au_verify_seq'), p.purchase_id,
|
||||
(ARRAY['Y','Y','Y','A','Z','N','U'])[1 + (p.purchase_id % 7)],
|
||||
(ARRAY['M','M','M','M','N','P','U'])[1 + (p.purchase_id % 7)],
|
||||
(p.purchase_id * 7919) % 1000,
|
||||
CASE WHEN (p.purchase_id * 7919) % 1000 > 900 THEN 'DECLINE'
|
||||
WHEN (p.purchase_id * 7919) % 1000 > 750 THEN 'REVIEW' ELSE 'APPROVE' END
|
||||
FROM purchase p WHERE p.purchase_id < 10000000
|
||||
AND NOT EXISTS (SELECT 1 FROM au_verify v WHERE v.purchase_id = p.purchase_id);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 4. 펀딩 지시 (순액정산→가맹점 지급, 은행 rails). 펀딩건에 1:1.
|
||||
-- ---------------------------------------------------------------------------
|
||||
INSERT INTO st_funding_instr (instr_id, merchant_id, biz_date, bank_code, account_no, amount, rail, status, confirmed_at)
|
||||
SELECT nextval('st_fundinstr_seq'), f.merchant_id, f.biz_date,
|
||||
(ARRAY['KB','SHINHAN','HANA','NH','WOORI'])[1 + (('x'||substr(md5(f.merchant_id),1,4))::bit(16)::int) % 5],
|
||||
lpad(((('x'||substr(md5(f.merchant_id),5,6))::bit(24)::int))::text,12,'0'),
|
||||
f.deposit, 'FIRMBANK',
|
||||
CASE WHEN f.deposit <= 0 THEN 'RETURNED' WHEN random() < 0.995 THEN 'CONFIRMED' ELSE 'SENT' END,
|
||||
CASE WHEN random() < 0.995 THEN f.biz_date::timestamptz + interval '1 day 14 hours' ELSE NULL END
|
||||
FROM st_merchant_funding f
|
||||
WHERE NOT EXISTS (SELECT 1 FROM st_funding_instr i WHERE i.merchant_id=f.merchant_id AND i.biz_date=f.biz_date);
|
||||
|
||||
-- return_code 부여(반환건)
|
||||
UPDATE st_funding_instr SET return_code='R01-계좌불일치'
|
||||
WHERE status='RETURNED' AND return_code IS NULL;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 5. DCC (해외카드 매입 = channel FOREIGN 일부). 승인시 환율고정.
|
||||
-- ---------------------------------------------------------------------------
|
||||
INSERT INTO ac_dcc (dcc_id, purchase_id, base_ccy, txn_ccy, base_amount, txn_amount, fx_rate, markup_bps, opted_in)
|
||||
SELECT nextval('ac_dcc_seq'), p.purchase_id, 'KRW',
|
||||
(ARRAY['USD','JPY','EUR','CNY'])[1 + (p.purchase_id % 4)],
|
||||
p.amount,
|
||||
round(p.amount / fx.rate, 2),
|
||||
fx.rate, 300, true
|
||||
FROM purchase p
|
||||
CROSS JOIN LATERAL (SELECT (ARRAY[1330.0, 8.9, 1440.0, 185.0])[1 + (p.purchase_id % 4)] AS rate) fx
|
||||
WHERE p.channel='FOREIGN' AND p.purchase_id < 10000000
|
||||
AND NOT EXISTS (SELECT 1 FROM ac_dcc d WHERE d.purchase_id = p.purchase_id);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 6. 채그백 수수료 (기존 분쟁건에 건당 부과) + 분쟁 SLA/fraud 채움.
|
||||
-- ---------------------------------------------------------------------------
|
||||
UPDATE ac_dispute SET sla_due = opened_at::date + 45,
|
||||
fraud_flag = (reason_code IN ('10.4','4853'))
|
||||
WHERE sla_due IS NULL;
|
||||
|
||||
INSERT INTO st_cb_fee (cbfee_id, dispute_id, merchant_id, fee_amount, stage, billed, biz_date)
|
||||
SELECT nextval('st_cbfee_seq'), d.dispute_id, d.merchant_id,
|
||||
CASE d.stage WHEN 'ARBITRATION' THEN 50000 WHEN 'PRE_ARB' THEN 30000 ELSE 15000 END,
|
||||
d.stage, (d.status IN ('LOST','ACCEPTED')), d.opened_at::date
|
||||
FROM ac_dispute d
|
||||
WHERE NOT EXISTS (SELECT 1 FROM st_cb_fee f WHERE f.dispute_id = d.dispute_id);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 7. retrieval request (분쟁 전 단계 조회요청) — 분쟁건의 일부 + 별도 케이스.
|
||||
-- ---------------------------------------------------------------------------
|
||||
INSERT INTO ac_retrieval (retr_id, purchase_id, merchant_id, reason, status, sla_due, fulfilled_at)
|
||||
SELECT nextval('ac_retrieval_seq'), d.purchase_id, d.merchant_id,
|
||||
(ARRAY['거래내역요청','매출전표사본','서명확인','상품수령증빙'])[1 + (d.dispute_id % 4)],
|
||||
(ARRAY['FULFILLED','FULFILLED','OPEN','EXPIRED'])[1 + (d.dispute_id % 4)],
|
||||
d.opened_at::date + 20,
|
||||
CASE WHEN d.dispute_id % 4 < 2 THEN d.opened_at::timestamptz + interval '5 days' ELSE NULL END
|
||||
FROM ac_dispute d
|
||||
WHERE d.stage IN ('REPRESENT','PRE_ARB','ARBITRATION')
|
||||
AND NOT EXISTS (SELECT 1 FROM ac_retrieval r WHERE r.purchase_id = d.purchase_id);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 8. 가맹점 월 명세서 (전 기간 월별 집계).
|
||||
-- ---------------------------------------------------------------------------
|
||||
INSERT INTO rp_merchant_stmt (stmt_id, merchant_id, stmt_month, gross_sales, txn_count,
|
||||
total_fees, interchange, scheme_fee, markup, cb_fees, net_deposit)
|
||||
SELECT nextval('rp_stmt_seq'), s.merchant_id, s.mth,
|
||||
s.gross, s.cnt, s.fees, s.ic, s.sf, s.mk,
|
||||
coalesce(cf.cbf,0),
|
||||
s.gross - s.fees - coalesce(cf.cbf,0)
|
||||
FROM (
|
||||
SELECT p.merchant_id, to_char(p.biz_date,'YYYYMM') mth,
|
||||
sum(CASE WHEN p.status='S' THEN p.amount ELSE 0 END) gross, count(*) cnt,
|
||||
coalesce(sum(fc.mdr_total),0) fees, coalesce(sum(fc.interchange),0) ic,
|
||||
coalesce(sum(fc.scheme_fee),0) sf, coalesce(sum(fc.markup),0) mk
|
||||
FROM purchase p LEFT JOIN st_fee_component fc ON fc.purchase_id=p.purchase_id
|
||||
GROUP BY p.merchant_id, to_char(p.biz_date,'YYYYMM')
|
||||
) s
|
||||
LEFT JOIN (
|
||||
SELECT merchant_id, to_char(biz_date,'YYYYMM') mth, sum(fee_amount) cbf
|
||||
FROM st_cb_fee GROUP BY merchant_id, to_char(biz_date,'YYYYMM')
|
||||
) cf ON cf.merchant_id=s.merchant_id AND cf.mth=s.mth
|
||||
WHERE s.gross > 0
|
||||
ON CONFLICT (merchant_id, stmt_month) DO NOTHING;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 9. 규제보고 (여신전문금융업법: 정산주기 준수·수수료 공시·거래량).
|
||||
-- ---------------------------------------------------------------------------
|
||||
INSERT INTO rp_regulatory (reg_id, report_type, period, metric, value, compliant, note)
|
||||
SELECT nextval('rp_reg_seq'), 'SETTLE_CYCLE', to_char(biz_date,'YYYYMM'),
|
||||
'평균정산일수(D+n)', round(avg((settled_at::date - biz_date)),2),
|
||||
(avg((settled_at::date - biz_date)) <= 3), '여전법 정산주기 준수(≤3영업일)'
|
||||
FROM settlement GROUP BY to_char(biz_date,'YYYYMM')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO rp_regulatory (reg_id, report_type, period, metric, value, compliant, note)
|
||||
SELECT nextval('rp_reg_seq'), 'TXN_VOLUME', to_char(biz_date,'YYYYMM'),
|
||||
'월 매입건수', count(*), true, '거래량 보고'
|
||||
FROM purchase GROUP BY to_char(biz_date,'YYYYMM')
|
||||
ON CONFLICT DO NOTHING;
|
||||
Loading…
Add table
Add a link
Reference in a new issue