-- Card-acquiring schema (카드 매입/승인/정산/원장 + ac 모듈 상세 테이블) -- Loaded into PostgreSQL on first boot (docker-entrypoint-initdb.d). -- --------------------------------------------------------------------------- -- 가맹점 (merchant) -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS merchant ( merchant_id TEXT PRIMARY KEY, name TEXT NOT NULL, mdr_bps INTEGER NOT NULL DEFAULT 25, -- Merchant Discount Rate, basis points (0.25%) daily_limit BIGINT NOT NULL DEFAULT 100000000, status TEXT NOT NULL DEFAULT 'ACTIVE', created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- --------------------------------------------------------------------------- -- 매입 (purchase) - the acquiring transaction -- --------------------------------------------------------------------------- CREATE SEQUENCE IF NOT EXISTS purchase_seq; CREATE TABLE IF NOT EXISTS purchase ( purchase_id BIGINT PRIMARY KEY, merchant_id TEXT NOT NULL, amount BIGINT NOT NULL, -- minor units (원, 정수) fee BIGINT NOT NULL, -- MDR fee net BIGINT NOT NULL, -- amount - fee status TEXT NOT NULL, -- A=접수, M=대사완료, S=정산완료, C=취소, H=보류, V=void biz_date DATE NOT NULL, channel TEXT NOT NULL DEFAULT 'POS', -- POS/EDC/EDI/FOREIGN issuer TEXT NOT NULL DEFAULT 'UNKNOWN', category TEXT NOT NULL DEFAULT 'GEN', created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- --------------------------------------------------------------------------- -- 승인 (approval) -- --------------------------------------------------------------------------- CREATE SEQUENCE IF NOT EXISTS approval_seq; CREATE TABLE IF NOT EXISTS approval ( approval_id BIGINT PRIMARY KEY, purchase_id BIGINT NOT NULL, approved BOOLEAN NOT NULL DEFAULT true, approved_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- --------------------------------------------------------------------------- -- 원장 (ledger) - recon/settle entries -- --------------------------------------------------------------------------- CREATE SEQUENCE IF NOT EXISTS ledger_seq; CREATE TABLE IF NOT EXISTS ledger ( ledger_id BIGINT PRIMARY KEY, purchase_id BIGINT NOT NULL, entry_type TEXT NOT NULL, -- RECON / SETTLE / XFER / SETTLELINK amount BIGINT NOT NULL, biz_date DATE NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- --------------------------------------------------------------------------- -- 정산 (settlement) - netting written during 정산 -- --------------------------------------------------------------------------- CREATE SEQUENCE IF NOT EXISTS settlement_seq; CREATE TABLE IF NOT EXISTS settlement ( settlement_id BIGINT PRIMARY KEY, purchase_id BIGINT NOT NULL, merchant_id TEXT NOT NULL, net BIGINT NOT NULL, biz_date DATE NOT NULL, status TEXT NOT NULL DEFAULT 'SETTLED', settled_at TIMESTAMPTZ NOT NULL DEFAULT now() ); -- --------------------------------------------------------------------------- -- ac 모듈 상세 테이블 (취소/할부/수수료조정/원천/세금계산서/해외/EDI/미매입/집계) -- --------------------------------------------------------------------------- CREATE SEQUENCE IF NOT EXISTS ac_cancel_seq; CREATE TABLE IF NOT EXISTS ac_cancel ( cancel_id BIGINT PRIMARY KEY, purchase_id BIGINT NOT NULL, cancel_type TEXT NOT NULL, -- FULL / PARTIAL / REFUND / VOID amount BIGINT NOT NULL, reason TEXT NOT NULL DEFAULT '', biz_date DATE NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE SEQUENCE IF NOT EXISTS ac_install_seq; CREATE TABLE IF NOT EXISTS ac_install ( install_id BIGINT PRIMARY KEY, purchase_id BIGINT NOT NULL, seq_no INTEGER NOT NULL, months INTEGER NOT NULL, month_amount BIGINT NOT NULL, biz_date DATE NOT NULL ); CREATE SEQUENCE IF NOT EXISTS ac_feeadj_seq; CREATE TABLE IF NOT EXISTS ac_fee_adj ( adj_id BIGINT PRIMARY KEY, purchase_id BIGINT NOT NULL, delta BIGINT NOT NULL, reason TEXT NOT NULL DEFAULT '', biz_date DATE NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE SEQUENCE IF NOT EXISTS ac_wht_seq; CREATE TABLE IF NOT EXISTS ac_wht ( wht_id BIGINT PRIMARY KEY, purchase_id BIGINT NOT NULL, tax_amount BIGINT NOT NULL, biz_date DATE NOT NULL ); CREATE SEQUENCE IF NOT EXISTS ac_taxinv_seq; CREATE TABLE IF NOT EXISTS ac_tax_invoice ( inv_id BIGINT PRIMARY KEY, purchase_id BIGINT NOT NULL, merchant_id TEXT NOT NULL, supply BIGINT NOT NULL, vat BIGINT NOT NULL, biz_date DATE NOT NULL ); CREATE SEQUENCE IF NOT EXISTS ac_fx_seq; CREATE TABLE IF NOT EXISTS ac_fx ( fx_id BIGINT PRIMARY KEY, purchase_id BIGINT NOT NULL, ccy TEXT NOT NULL, fx_amount BIGINT NOT NULL, krw_amount BIGINT NOT NULL, rate_bps BIGINT NOT NULL, biz_date DATE NOT NULL ); CREATE SEQUENCE IF NOT EXISTS ac_edi_seq; CREATE TABLE IF NOT EXISTS ac_edi ( edi_id BIGINT PRIMARY KEY, merchant_id TEXT NOT NULL, doc_no TEXT NOT NULL, amount BIGINT NOT NULL, biz_date DATE NOT NULL ); CREATE SEQUENCE IF NOT EXISTS ac_unmatch_seq; CREATE TABLE IF NOT EXISTS ac_unmatch ( unmatch_id BIGINT PRIMARY KEY, purchase_id BIGINT NOT NULL, reason TEXT NOT NULL, biz_date DATE NOT NULL ); -- 가맹점 일별 집계 (배치가 채움) CREATE TABLE IF NOT EXISTS merchant_summary ( merchant_id TEXT NOT NULL, biz_date DATE NOT NULL, txn_count BIGINT NOT NULL DEFAULT 0, gross_amount BIGINT NOT NULL DEFAULT 0, fee_amount BIGINT NOT NULL DEFAULT 0, net_amount BIGINT NOT NULL DEFAULT 0, updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), PRIMARY KEY (merchant_id, biz_date) ); -- Seed merchants so ACQUIRE has a valid counterparty. INSERT INTO merchant (merchant_id, name, mdr_bps, daily_limit) VALUES ('M0001', '클라로 커피', 25, 100000000), ('M0002', '포지 마트', 25, 100000000), ('M0003', '클라로 면세점', 30, 500000000) ON CONFLICT (merchant_id) DO NOTHING;