Wave H: Oracle 계보(As-Is) 심기 + 시스템 조망 재편(운영 콘솔)

■ Oracle 계보 — "원본은 Oracle 19c + Pro*C 였다"
현행 코드(ECPG/PostgreSQL)가 Oracle 시스템의 1차 이관본임을 콘크리트하게 보존.
- legacy-oracle/proc/*.pc (7본): ACQUIRE/AUTH_APPROVE/ST_MDR/SETTLE/RECONCILE/
  CL_DAILY/PAY_FILEGEN. 순수 Oracle Pro*C 방언 — sqlca/oraca, VARCHAR,
  WHENEVER SQLERROR GOTO, NVL/DECODE/SYSDATE/DUAL/ROWNUM/(+)/CONNECT BY/
  .NEXTVAL/TO_DATE, PL/SQL 패키지 호출, COMMIT WORK. 컴파일 대상 아님(As-Is 원본).
- legacy-oracle/plsql/*.sql (2본): PKG_SETTLE(정산), PKG_LEDGER(복식부기 기표).
  VARCHAR2/%TYPE/%ROWTYPE/CURSOR/EXCEPTION/RAISE_APPLICATION_ERROR.
- docs/ORACLE_PROVENANCE.md: As-Is(Oracle)→현행(ECPG)→To-Be(Spring Boot) 3단 계보
  + Oracle→PostgreSQL 방언 이관 매핑 15종 + "왜 DB는 PostgreSQL인가".
- gen_metrics.py: legacy-oracle 실측(원본 9파일 1,827LOC, 방언 12종 히트) →
  마이그레이션 난이도 화면에 "④ Oracle 계보" 패널 추가.

■ 시스템 조망 재편 — 실제 매입시스템 운영 콘솔
"마이그레이션 난이도"(Forge 관점 메타)를 시스템 조망에서 분리하고, 시스템 자체의
상태·아키텍처를 보여주는 운영 화면 신설.
- 신규 "시스템 현황"(#sys): 헬스 KPI(서버11/서비스1466/미결2PC/당일매입/채널UP/
  큐적체/오류) + 아키텍처 토폴로지(채널·카드망→전문GW→승인·매입→정산·지급→
  원장·마감·대사·검증→마스터·공통 계층도) + 채널상태 + 큐적체 + 처리량·오류율
  + 정산사이클(마감·순액정산·클리어링·프레젠트먼트). 전부 실측 조회.
- nav 재편: [시스템 조망]=시스템현황·아키텍처토폴로지·정산경제,
  [전환 분석(Forge)]=마이그레이션난이도.
- 토폴로지 모듈박스 렌더 버그(return ASI) 수정.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
hyeongwoo 2026-07-23 12:10:37 +09:00
parent 2ac4c3c920
commit e1729d6edc
14 changed files with 2054 additions and 7 deletions

View file

@ -0,0 +1,162 @@
/*==========================================================================*/
/* SETTLE.pc - 정산확정 온라인 서비스 (As-Is 원본, Oracle Pro*C) */
/*--------------------------------------------------------------------------*/
/* 대상 : BC 매입시스템 / Tuxedo ATMI 서비스 SETTLE */
/* DBMS : Oracle 19c 전처리 : Pro*C/C++ (proc) */
/* 기능 : 매입건 정산 확정 — 정산원장(settlement) 채번·적재 + 원장 기표. */
/* ※ 이 파일은 **As-Is 역사 원본**이다. 현행 오픈스택 이식본은 */
/* app/src/st/svc/SETTLE.pgc (ECPG/PostgreSQL). 컴파일 제외. */
/*--------------------------------------------------------------------------*/
/* 변경이력 */
/* 2000.03.21 PARK J.S 최초작성 (정산확정 원장적재) */
/* 2006.09.14 HAN Y.J 가맹점 지급주기(D+n) DECODE 반영 */
/* 2012.05.08 LEE S.W 정산 중복확정 방지, ROWNUM 최근건 조회 */
/* 2019.09.01 CHOI H.W Oracle 11g -> 19c, 시퀀스/커밋 표준화 */
/*==========================================================================*/
#include <stdio.h>
#include <string.h>
#include <atmi.h>
#include <fml32.h>
#include <userlog.h>
EXEC SQL INCLUDE sqlca;
EXEC SQL INCLUDE oraca;
EXEC ORACLE OPTION (ORACA=YES);
#include "stfld.h"
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR h_merch[64];
VARCHAR h_bizdate[9]; /* YYYYMMDD */
VARCHAR h_pdate[9];
VARCHAR h_pstat[2];
VARCHAR h_paycyc[4]; /* 지급주기 코드 */
long h_pid;
long h_sid;
long h_amount;
long h_fee;
long h_net;
long h_dcnt;
long h_dup;
long h_addday;
EXEC SQL END DECLARE SECTION;
/*--------------------------------------------------------------------------*/
/* SETTLE - Tuxedo 서비스 엔트리 */
/*--------------------------------------------------------------------------*/
void SETTLE(TPSVCINFO *rqst)
{
FBFR32 *fb = (FBFR32 *)rqst->data;
char merch[64], bizdate[9];
userlog("SETTLE 진입: 정산 확정");
EXEC SQL WHENEVER SQLERROR GOTO sql_error;
/* ---- 1) 요청 FML 파싱 -------------------------------------------- */
h_pid = Fvall(fb, ST_PURCHASE_ID, 0);
h_net = Fvall(fb, ST_NET, 0);
Fget(fb, ST_MERCHANT, 0, merch, (FLDLEN32 *)NULL);
Fget(fb, ST_BIZDATE, 0, bizdate, (FLDLEN32 *)NULL);
strcpy((char *)h_merch.arr, merch); h_merch.len = strlen(merch);
strcpy((char *)h_bizdate.arr, bizdate); h_bizdate.len = strlen(bizdate);
if (h_bizdate.len == 0) {
EXEC SQL SELECT TO_CHAR(SYSDATE,'YYYYMMDD') INTO :h_bizdate FROM DUAL;
}
if (h_pid <= 0) {
userlog("SETTLE: 매입 ID 필수 pid=%ld", h_pid);
Fchg(fb, ST_RC, 0, (char *)"E802", 0L);
tpreturn(TPFAIL, 0, (char *)fb, 0L, 0L);
return;
}
/* ---- 2) 매입 상태/금액 확인 + 정산액 보정 (NVL/DECODE) ----------- */
EXEC SQL
SELECT NVL(p.amount,0), NVL(p.fee,0), NVL(p.net,:h_net),
NVL(p.status,'A')
INTO :h_amount, :h_fee, :h_net, :h_pstat
FROM purchase p
WHERE p.purchase_id = :h_pid;
if (sqlca.sqlcode == 1403) {
h_amount = Fvall(fb, ST_AMOUNT, 0);
userlog("SETTLE: 미커밋 매입 pid=%ld — 전문 net=%ld 사용", h_pid, h_net);
}
/* ---- 3) 중복확정 방지: 동일 매입 확정 정산 존재여부 (ROWNUM) ---- */
EXEC SQL
SELECT NVL(MAX(settlement_id),0)
INTO :h_dup
FROM settlement
WHERE purchase_id = :h_pid
AND status = 'SETTLED'
AND ROWNUM = 1;
if (h_dup > 0) {
userlog("SETTLE: 이미 확정된 정산 pid=%ld sid=%ld — 스킵", h_pid, h_dup);
Fchg(fb, ST_SETTLE_ID, 0, (char *)&h_dup, 0L);
Fchg(fb, ST_STATUS, 0, (char *)"D", 0L);
EXEC SQL COMMIT WORK;
tpreturn(TPSUCCESS, 0, (char *)fb, 0L, 0L);
return;
}
/* ---- 4) 가맹점 지급주기 조회 → 지급예정일 산정 (DECODE D+n) ----- */
EXEC SQL
SELECT NVL(paycycle,'D1'),
DECODE(NVL(paycycle,'D1'), 'D0',0, 'D1',1, 'D2',2, 'W1',7, 1)
INTO :h_paycyc, :h_addday
FROM merchant
WHERE merchant_id = :h_merch;
EXEC SQL
SELECT TO_CHAR(TO_DATE(:h_bizdate,'YYYYMMDD') + :h_addday,'YYYYMMDD')
INTO :h_pdate
FROM DUAL;
/* ---- 5) 본처리: 정산원장 채번(.NEXTVAL) 및 적재 ----------------- */
EXEC SQL SELECT settlement_seq.NEXTVAL INTO :h_sid FROM DUAL;
EXEC SQL
INSERT INTO settlement
(settlement_id, purchase_id, merchant_id, net,
biz_date, pay_date, status, created_at)
VALUES (:h_sid, :h_pid, :h_merch, :h_net,
TO_DATE(:h_bizdate,'YYYYMMDD'),
TO_DATE(:h_pdate,'YYYYMMDD'), 'SETTLED', SYSDATE);
/* ---- 6) 정산원장 기표 (ledger SETTLE 엔트리) ------------------- */
EXEC SQL
INSERT INTO ledger
(ledger_id, purchase_id, entry_type, amount, biz_date, posted_at)
VALUES (ledger_seq.NEXTVAL, :h_pid, 'SETTLE', :h_net,
TO_DATE(:h_bizdate,'YYYYMMDD'), SYSDATE);
/* ---- 7) 매입 상태 정산완료 전이 ------------------------------- */
EXEC SQL
UPDATE purchase
SET status = 'S', settled_at = SYSDATE
WHERE purchase_id = :h_pid
AND status <> 'C';
/* ---- 8) 정산확정-수수료산출 연계 (PL/SQL 정산 패키지) ---------- */
EXEC SQL EXECUTE
BEGIN
pkg_settle.settle_confirm(:h_sid, :h_pid, :h_merch, :h_net);
END;
END-EXEC;
EXEC SQL COMMIT WORK;
Fchg(fb, ST_SETTLE_ID, 0, (char *)&h_sid, 0L);
Fchg(fb, ST_NET, 0, (char *)&h_net, 0L);
Fchg(fb, ST_STATUS, 0, (char *)"S", 0L);
userlog("SETTLE 완료: pid=%ld sid=%ld net=%ld paydate=%.8s",
h_pid, h_sid, h_net, h_pdate.arr);
tpreturn(TPSUCCESS, 0, (char *)fb, 0L, 0L);
return;
sql_error:
userlog("SETTLE SQL 오류: %.70s (sqlcode=%ld)",
sqlca.sqlerrm.sqlerrmc, sqlca.sqlcode);
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK;
Fchg(fb, ST_RC, 0, (char *)"E900", 0L);
tpreturn(TPFAIL, 0, (char *)fb, 0L, 0L);
return;
}