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:
parent
2ac4c3c920
commit
e1729d6edc
14 changed files with 2054 additions and 7 deletions
230
legacy-oracle/proc/CL_DAILY.pc
Normal file
230
legacy-oracle/proc/CL_DAILY.pc
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
/*==========================================================================*/
|
||||
/* CL_DAILY.pc - 일마감 배치 (As-Is 원본, Oracle Pro*C) */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* 대상 : BC 매입시스템 / 일일 마감 배치 CLDAILY (야간 JOB) */
|
||||
/* DBMS : Oracle 19c 전처리 : Pro*C/C++ (proc) */
|
||||
/* 실행 : cldaily <YYYYMMDD> (인자 생략시 전영업일 = SYSDATE-1) */
|
||||
/* ※ 이 파일은 **As-Is 역사 원본**이다. 현행 오픈스택 이식본은 */
|
||||
/* app/src/cl/svc/CL_DAILY.pgc (ECPG/PostgreSQL, Tuxedo 서비스화). */
|
||||
/* 원본은 순수 배치(main+커서루프) 였다. 컴파일 대상 아님(빌드 제외). */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* 변경이력 */
|
||||
/* 1999.02.15 KIM K.H 최초작성 (가맹점별 당일 매입 집계/마감이력) */
|
||||
/* 2003.10.07 PARK J.S 기간잠금(cl_period_lock) 선점검 추가 */
|
||||
/* 2009.05.22 LEE S.W 보류(H)/미매칭 잔존시 경고후 마감강행 정책 반영 */
|
||||
/* 2015.08.11 JUNG M.K 마감 규모별 심각도(sev) 분류, cm_log 요약적재 */
|
||||
/* 2019.09.01 CHOI H.W Oracle 11g -> 19c, CHAR->VARCHAR2 정비 */
|
||||
/*==========================================================================*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
EXEC SQL INCLUDE sqlca;
|
||||
EXEC SQL INCLUDE oraca;
|
||||
EXEC ORACLE OPTION (ORACA=YES);
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
VARCHAR h_user[32];
|
||||
VARCHAR h_pass[32];
|
||||
VARCHAR h_dbstr[32];
|
||||
VARCHAR h_bizdate[9]; /* YYYYMMDD */
|
||||
VARCHAR h_merch[16];
|
||||
VARCHAR h_mname[64];
|
||||
VARCHAR h_status[2];
|
||||
VARCHAR h_zmsg[64];
|
||||
long h_locked;
|
||||
long h_pend;
|
||||
long h_unmatch;
|
||||
long h_prevcnt;
|
||||
long h_cid;
|
||||
long h_txncnt;
|
||||
long h_gross;
|
||||
long h_fee;
|
||||
long h_net;
|
||||
long h_totcnt;
|
||||
long h_totamt;
|
||||
long h_nmerch;
|
||||
long h_zsev;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
/* 가맹점별 당일 확정매입 커서 (취소 C 제외) — 마감 대상 스윕 */
|
||||
EXEC SQL DECLARE cur_merch CURSOR FOR
|
||||
SELECT m.merchant_id,
|
||||
NVL(m.name,'(무명)'),
|
||||
NVL(m.status,'N'),
|
||||
COUNT(p.purchase_id),
|
||||
NVL(SUM(p.amount), 0),
|
||||
NVL(SUM(p.fee), 0),
|
||||
NVL(SUM(p.net), 0)
|
||||
FROM merchant m, purchase p
|
||||
WHERE p.merchant_id (+) = m.merchant_id
|
||||
AND p.biz_date = TO_DATE(:h_bizdate,'YYYYMMDD')
|
||||
AND NVL(p.status,'A') <> 'C'
|
||||
GROUP BY m.merchant_id, m.name, m.status
|
||||
HAVING COUNT(p.purchase_id) > 0
|
||||
ORDER BY m.merchant_id;
|
||||
|
||||
static void sql_error(const char *stage);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int done = 0;
|
||||
|
||||
/* ---- 0) 접속 (배치는 자기 세션으로 CONNECT) ---------------------- */
|
||||
strcpy((char *)h_user.arr, "clbatch"); h_user.len = strlen((char *)h_user.arr);
|
||||
strcpy((char *)h_pass.arr, "clbatch"); h_pass.len = strlen((char *)h_pass.arr);
|
||||
strcpy((char *)h_dbstr.arr, "ACQPRD"); h_dbstr.len = strlen((char *)h_dbstr.arr);
|
||||
|
||||
EXEC SQL WHENEVER SQLERROR GOTO connect_err;
|
||||
EXEC SQL CONNECT :h_user IDENTIFIED BY :h_pass USING :h_dbstr;
|
||||
|
||||
/* 이후 오류는 표준 라벨분기 */
|
||||
EXEC SQL WHENEVER SQLERROR GOTO sqlfail;
|
||||
|
||||
/* ---- 1) 영업일 결정 (인자 없으면 전영업일 SYSDATE-1) ------------- */
|
||||
if (argc >= 2) {
|
||||
strncpy((char *)h_bizdate.arr, argv[1], 8);
|
||||
h_bizdate.arr[8] = '\0';
|
||||
h_bizdate.len = strlen((char *)h_bizdate.arr);
|
||||
} else {
|
||||
EXEC SQL SELECT TO_CHAR(SYSDATE-1,'YYYYMMDD') INTO :h_bizdate FROM DUAL;
|
||||
}
|
||||
printf("[CL_DAILY] 일마감 개시 bizdate=%.8s\n", h_bizdate.arr);
|
||||
|
||||
/* ---- 2) 기간 잠금 선점검 (잠기면 즉시 중단) --------------------- */
|
||||
EXEC SQL SELECT COUNT(*) INTO :h_locked
|
||||
FROM cl_period_lock
|
||||
WHERE period_key = :h_bizdate
|
||||
AND locked = 'Y';
|
||||
if (h_locked > 0) {
|
||||
fprintf(stderr, "[CL_DAILY] 기간잠금 상태 - 일마감 불가 bizdate=%.8s\n",
|
||||
h_bizdate.arr);
|
||||
EXEC SQL ROLLBACK WORK RELEASE;
|
||||
return 4;
|
||||
}
|
||||
|
||||
/* ---- 3) 사전상태 점검 (보류/미매칭/기마감) — 경고후 강행 -------- */
|
||||
EXEC SQL SELECT COUNT(*) INTO :h_pend
|
||||
FROM purchase
|
||||
WHERE biz_date = TO_DATE(:h_bizdate,'YYYYMMDD')
|
||||
AND status = 'H';
|
||||
EXEC SQL SELECT NVL(COUNT(*),0) INTO :h_unmatch
|
||||
FROM ac_unmatch
|
||||
WHERE biz_date = TO_DATE(:h_bizdate,'YYYYMMDD');
|
||||
EXEC SQL SELECT COUNT(*) INTO :h_prevcnt
|
||||
FROM cl_close_log
|
||||
WHERE close_type = 'DAILY'
|
||||
AND period_key = :h_bizdate
|
||||
AND status <> 'X';
|
||||
if (h_pend > 0)
|
||||
printf("[CL_DAILY] 경고: 보류(H) %ld건 잔존 - 마감 진행\n", h_pend);
|
||||
if (h_unmatch > 0)
|
||||
printf("[CL_DAILY] 경고: 미매칭 %ld건 잔존 - 마감 진행\n", h_unmatch);
|
||||
if (h_prevcnt > 0)
|
||||
printf("[CL_DAILY] 기마감 %ld건 존재 - 신규 마감이력 추가생성\n", h_prevcnt);
|
||||
|
||||
/* ---- 4) 마감헤더 채번 (시퀀스 .NEXTVAL) ------------------------ */
|
||||
EXEC SQL SELECT cl_close_seq.NEXTVAL INTO :h_cid FROM DUAL;
|
||||
EXEC SQL
|
||||
INSERT INTO cl_close_log
|
||||
(close_id, close_type, period_key, status,
|
||||
txn_count, total_amount, opened_at)
|
||||
VALUES (:h_cid, 'DAILY', :h_bizdate, 'O',
|
||||
0, 0, SYSDATE);
|
||||
|
||||
/* ---- 5) 본처리: 가맹점별 집계 커서 루프 ------------------------ */
|
||||
h_totcnt = 0; h_totamt = 0; h_nmerch = 0;
|
||||
EXEC SQL OPEN cur_merch;
|
||||
for (;;) {
|
||||
EXEC SQL WHENEVER NOTFOUND DO done = 1;
|
||||
EXEC SQL FETCH cur_merch
|
||||
INTO :h_merch, :h_mname, :h_status,
|
||||
:h_txncnt, :h_gross, :h_fee, :h_net;
|
||||
if (done) break;
|
||||
|
||||
/* 비활성 가맹점은 집계만 하고 정산연계는 보류(로그) */
|
||||
if (strncmp((char *)h_status.arr, "A", 1) != 0)
|
||||
printf("[CL_DAILY] 주의: 비활성(%.1s) 가맹점 %.*s 마감집계 포함\n",
|
||||
h_status.arr, h_merch.len, h_merch.arr);
|
||||
|
||||
EXEC SQL
|
||||
INSERT INTO cl_close_detail
|
||||
(close_id, merchant_id, txn_count,
|
||||
gross_amount, fee_amount, net_amount, created_at)
|
||||
VALUES (:h_cid, :h_merch, :h_txncnt,
|
||||
:h_gross, :h_fee, :h_net, SYSDATE);
|
||||
|
||||
/* 마감된 매입행을 'S'(마감완료)로 상태전이 */
|
||||
EXEC SQL
|
||||
UPDATE purchase
|
||||
SET status = DECODE(status, 'A', 'S', status),
|
||||
closed_at = SYSDATE,
|
||||
close_id = :h_cid
|
||||
WHERE merchant_id = :h_merch
|
||||
AND biz_date = TO_DATE(:h_bizdate,'YYYYMMDD')
|
||||
AND status = 'A';
|
||||
|
||||
h_totcnt += h_txncnt;
|
||||
h_totamt += h_gross;
|
||||
h_nmerch += 1;
|
||||
if (h_nmerch % 500 == 0) {
|
||||
printf("[CL_DAILY] 진행 %ld개 가맹점 누적 %ld건 %ld원 - 중간커밋\n",
|
||||
h_nmerch, h_totcnt, h_totamt);
|
||||
EXEC SQL COMMIT WORK;
|
||||
}
|
||||
}
|
||||
EXEC SQL CLOSE cur_merch;
|
||||
|
||||
/* ---- 6) 마감헤더 확정 (집계 반영, 상태 O->C) ------------------- */
|
||||
EXEC SQL
|
||||
UPDATE cl_close_log
|
||||
SET txn_count = :h_totcnt,
|
||||
total_amount = :h_totamt,
|
||||
status = 'C',
|
||||
closed_at = SYSDATE
|
||||
WHERE close_id = :h_cid;
|
||||
|
||||
/* ---- 7) 마감 규모별 심각도 분류 (DECODE 대체 if-ladder) -------- */
|
||||
if (h_totcnt == 0) { h_zsev = 0; strcpy((char *)h_zmsg.arr, "마감대상 없음"); }
|
||||
else if (h_totamt >= 500000000L){ h_zsev = 3; strcpy((char *)h_zmsg.arr, "고액 마감구간"); }
|
||||
else if (h_totamt >= 50000000L) { h_zsev = 2; strcpy((char *)h_zmsg.arr, "중액 마감구간"); }
|
||||
else { h_zsev = 1; strcpy((char *)h_zmsg.arr, "소액 마감구간"); }
|
||||
h_zmsg.len = strlen((char *)h_zmsg.arr);
|
||||
|
||||
EXEC SQL
|
||||
INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date)
|
||||
VALUES (cm_log_seq.NEXTVAL, 'CL_DAILY',
|
||||
DECODE(SIGN(:h_zsev - 2), 1, 'W', 'I'),
|
||||
'CL_DAILY 일마감 sev='||:h_zsev||' '||:h_zmsg
|
||||
||' cnt='||:h_totcnt||' amt='||:h_totamt,
|
||||
TO_DATE(:h_bizdate,'YYYYMMDD'));
|
||||
|
||||
/* ---- 8) 최종 커밋 --------------------------------------------- */
|
||||
EXEC SQL COMMIT WORK;
|
||||
|
||||
printf("[CL_DAILY] 일마감 완료 cid=%ld 가맹점=%ld 건수=%ld 금액=%ld sev=%ld(%s)\n",
|
||||
h_cid, h_nmerch, h_totcnt, h_totamt, h_zsev, h_zmsg.arr);
|
||||
EXEC SQL COMMIT WORK RELEASE;
|
||||
return 0;
|
||||
|
||||
connect_err:
|
||||
fprintf(stderr, "[CL_DAILY] DB 접속 실패: %.70s\n", sqlca.sqlerrm.sqlerrmc);
|
||||
return 8;
|
||||
|
||||
sqlfail:
|
||||
sql_error("일마감 본처리");
|
||||
EXEC SQL WHENEVER SQLERROR CONTINUE;
|
||||
EXEC SQL ROLLBACK WORK RELEASE;
|
||||
return 12;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* sql_error - 오류 로깅 (sqlca/oraca) */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static void sql_error(const char *stage)
|
||||
{
|
||||
fprintf(stderr, "[CL_DAILY] SQL 오류 (%s): %.70s\n",
|
||||
stage, sqlca.sqlerrm.sqlerrmc);
|
||||
fprintf(stderr, " sqlcode=%ld rows=%ld stmt=%.60s\n",
|
||||
sqlca.sqlcode, sqlca.sqlerrd[2], oraca.orastxt.orastxtc);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue