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
177
legacy-oracle/proc/ACQUIRE.pc
Normal file
177
legacy-oracle/proc/ACQUIRE.pc
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/*==========================================================================*/
|
||||
/* ACQUIRE.pc - 매입 접수 온라인 서비스 (As-Is 원본, Oracle Pro*C) */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* 대상 : BC 매입시스템 / Tuxedo ATMI 서비스 ACQUIRE */
|
||||
/* DBMS : Oracle 19c 전처리 : Pro*C/C++ (proc) */
|
||||
/* ※ 이 파일은 **As-Is 역사 원본**이다. 현행 오픈스택 이식본은 */
|
||||
/* app/src/ac/svc/ACQUIRE.pgc (ECPG/PostgreSQL). 대조는 */
|
||||
/* docs/ORACLE_PROVENANCE.md 참조. 컴파일 대상 아님(빌드 제외). */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* 변경이력 */
|
||||
/* 1998.11.02 KIM K.H 최초작성 (신용승인 연계 매입) */
|
||||
/* 2004.06.18 PARK J.S 체크카드 매입구분 추가, DECODE 요율분기 */
|
||||
/* 2011.03.30 LEE S.W 원천징수(3.3%) 반영, 세금계산서 연계 */
|
||||
/* 2019.09.01 CHOI H.W Oracle 11g -> 19c, CHAR->VARCHAR2 정비 */
|
||||
/*==========================================================================*/
|
||||
#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);
|
||||
|
||||
/* 전역 FML 필드 ID (FLD.h 에서 생성) */
|
||||
#include "acqfld.h"
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
VARCHAR h_merch[16];
|
||||
VARCHAR h_name[64];
|
||||
VARCHAR h_status[2];
|
||||
VARCHAR h_bizdate[9]; /* YYYYMMDD */
|
||||
VARCHAR h_cardtype[2]; /* C=신용 K=체크 */
|
||||
long h_amount;
|
||||
long h_limit;
|
||||
long h_daysum;
|
||||
long h_daycnt;
|
||||
long h_mdr_bps;
|
||||
long h_fee;
|
||||
long h_net;
|
||||
long h_wht; /* 원천징수액 */
|
||||
long h_pid;
|
||||
long h_grade;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* ACQUIRE - Tuxedo 서비스 엔트리 */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void ACQUIRE(TPSVCINFO *rqst)
|
||||
{
|
||||
FBFR32 *fb = (FBFR32 *)rqst->data;
|
||||
char merch[16], bizdate[9];
|
||||
long amount;
|
||||
|
||||
userlog("ACQUIRE 진입: 매입 접수 요청");
|
||||
|
||||
/* Pro*C 오류는 즉시 라벨분기 (전형적 레거시 패턴) */
|
||||
EXEC SQL WHENEVER SQLERROR GOTO sql_error;
|
||||
|
||||
/* ---- 1) 요청 FML 파싱 -------------------------------------------- */
|
||||
Fget(fb, ACQ_MERCHANT, 0, merch, (FLDLEN32 *)NULL);
|
||||
Fget(fb, ACQ_BIZDATE, 0, bizdate, (FLDLEN32 *)NULL);
|
||||
amount = Fvall(fb, ACQ_AMOUNT, 0);
|
||||
|
||||
strcpy((char *)h_merch.arr, merch); h_merch.len = strlen(merch);
|
||||
strcpy((char *)h_bizdate.arr, bizdate); h_bizdate.len = strlen(bizdate);
|
||||
h_amount = amount;
|
||||
|
||||
if (h_amount <= 0) {
|
||||
Fchg(fb, ACQ_RC, 0, (char *)"E101", 0L);
|
||||
tpreturn(TPFAIL, 0, (char *)fb, 0L, 0L);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 영업일 미지정시 시스템일자 (Oracle SYSDATE) */
|
||||
if (h_bizdate.len == 0) {
|
||||
EXEC SQL SELECT TO_CHAR(SYSDATE,'YYYYMMDD') INTO :h_bizdate FROM DUAL;
|
||||
}
|
||||
|
||||
/* ---- 2) 가맹점 마스터 조회 (NVL 로 널가드) ----------------------- */
|
||||
EXEC SQL
|
||||
SELECT m.name,
|
||||
NVL(m.status,'N'),
|
||||
NVL(m.daily_limit, 0),
|
||||
NVL(m.mdr_bps, 25),
|
||||
DECODE(m.risk_grade, 'A',1, 'B',2, 'C',3, 9)
|
||||
INTO :h_name, :h_status, :h_limit, :h_mdr_bps, :h_grade
|
||||
FROM merchant m
|
||||
WHERE m.merchant_id = :h_merch;
|
||||
|
||||
if (strncmp((char *)h_status.arr, "A", 1) != 0) {
|
||||
userlog("ACQUIRE: 비활성 가맹점 %s status=%.1s", merch, h_status.arr);
|
||||
Fchg(fb, ACQ_RC, 0, (char *)"E203", 0L);
|
||||
tpreturn(TPFAIL, 0, (char *)fb, 0L, 0L);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ---- 3) 당일 누적 매입 조회 (한도 점검용) ------------------------ */
|
||||
EXEC SQL
|
||||
SELECT COUNT(*), NVL(SUM(amount), 0)
|
||||
INTO :h_daycnt, :h_daysum
|
||||
FROM purchase
|
||||
WHERE merchant_id = :h_merch
|
||||
AND biz_date = TO_DATE(:h_bizdate,'YYYYMMDD')
|
||||
AND status <> 'C';
|
||||
|
||||
if (h_daysum + h_amount > h_limit) {
|
||||
userlog("ACQUIRE: 일한도 초과 merch=%s sum=%ld+%ld > %ld",
|
||||
merch, h_daysum, h_amount, h_limit);
|
||||
Fchg(fb, ACQ_RC, 0, (char *)"E210", 0L);
|
||||
tpreturn(TPFAIL, 0, (char *)fb, 0L, 0L);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ---- 4) 수수료/원천/정산액 산출 (DECODE 카드구분 요율) ----------- */
|
||||
/* 카드종류는 승인원장 조인으로 (외부조인 (+) — 무승인 매입 허용) */
|
||||
EXEC SQL
|
||||
SELECT NVL(a.card_type, 'C')
|
||||
INTO :h_cardtype
|
||||
FROM au_authorization a
|
||||
WHERE a.auth_id (+) = :h_pid;
|
||||
|
||||
h_fee = h_amount * h_mdr_bps / 10000;
|
||||
/* 병의원/약국(원천징수 대상 업종)만 3.3% 원천 (DECODE 업종분기) */
|
||||
EXEC SQL
|
||||
SELECT DECODE(mcc.risk_level, 1, ROUND(:h_amount * 33 / 1000), 0)
|
||||
INTO :h_wht
|
||||
FROM mm_merch_mcc mm, mm_mcc mcc
|
||||
WHERE mm.merchant_id = :h_merch
|
||||
AND mcc.mcc = mm.mcc
|
||||
AND ROWNUM = 1;
|
||||
|
||||
h_net = h_amount - h_fee - h_wht;
|
||||
|
||||
/* ---- 5) 매입원장 채번 및 적재 (시퀀스 .NEXTVAL) ------------------ */
|
||||
EXEC SQL SELECT purchase_seq.NEXTVAL INTO :h_pid FROM DUAL;
|
||||
|
||||
EXEC SQL
|
||||
INSERT INTO purchase
|
||||
(purchase_id, merchant_id, amount, fee, net, wht,
|
||||
status, biz_date, created_at)
|
||||
VALUES (:h_pid, :h_merch, :h_amount, :h_fee, :h_net, :h_wht,
|
||||
'A', TO_DATE(:h_bizdate,'YYYYMMDD'), SYSDATE);
|
||||
|
||||
EXEC SQL
|
||||
INSERT INTO approval (approval_id, purchase_id, approved, approved_at)
|
||||
VALUES (approval_seq.NEXTVAL, :h_pid, 'Y', SYSDATE);
|
||||
|
||||
/* ---- 6) 정산 PL/SQL 패키지 호출 (묶음 정산 연계) ----------------- */
|
||||
EXEC SQL EXECUTE
|
||||
BEGIN
|
||||
pkg_settle.acquire_post(:h_pid, :h_merch, :h_amount, :h_fee, :h_net);
|
||||
END;
|
||||
END-EXEC;
|
||||
|
||||
/* ---- 7) 커밋 및 응답 -------------------------------------------- */
|
||||
EXEC SQL COMMIT WORK;
|
||||
|
||||
Fchg(fb, ACQ_PURCHASE_ID, 0, (char *)&h_pid, 0L);
|
||||
Fchg(fb, ACQ_FEE, 0, (char *)&h_fee, 0L);
|
||||
Fchg(fb, ACQ_NET, 0, (char *)&h_net, 0L);
|
||||
Fchg(fb, ACQ_STATUS, 0, (char *)"S", 0L);
|
||||
|
||||
userlog("ACQUIRE 완료: pid=%ld fee=%ld wht=%ld net=%ld", h_pid, h_fee, h_wht, h_net);
|
||||
tpreturn(TPSUCCESS, 0, (char *)fb, 0L, 0L);
|
||||
return;
|
||||
|
||||
sql_error:
|
||||
userlog("ACQUIRE SQL 오류: %.70s (sqlcode=%ld)",
|
||||
sqlca.sqlerrm.sqlerrmc, sqlca.sqlcode);
|
||||
EXEC SQL WHENEVER SQLERROR CONTINUE;
|
||||
EXEC SQL ROLLBACK WORK;
|
||||
Fchg(fb, ACQ_RC, 0, (char *)"E900", 0L);
|
||||
tpreturn(TPFAIL, 0, (char *)fb, 0L, 0L);
|
||||
return;
|
||||
}
|
||||
234
legacy-oracle/proc/AUTH_APPROVE.pc
Normal file
234
legacy-oracle/proc/AUTH_APPROVE.pc
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
/*==========================================================================*/
|
||||
/* AUTH_APPROVE.pc - 승인확정 온라인 서비스 (As-Is 원본, Oracle Pro*C) */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* 대상 : BC 매입시스템 / Tuxedo ATMI 서비스 AUTH_APPROVE */
|
||||
/* DBMS : Oracle 19c 전처리 : Pro*C/C++ (proc) */
|
||||
/* 기능 : 승인 확정(pending->approved) — 원장 상태전이 + 카드 한도차감 */
|
||||
/* ※ 이 파일은 **As-Is 역사 원본**이다. 현행 오픈스택 이식본은 */
|
||||
/* app/src/au/svc/AUTH_APPROVE.pgc (ECPG/PostgreSQL). 컴파일 제외. */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* 변경이력 */
|
||||
/* 1999.05.12 KIM K.H 최초작성 (승인원장 확정전이) */
|
||||
/* 2003.10.07 YOON D.H 블랙리스트/velocity 룰 추가, DECODE 등급분기 */
|
||||
/* 2010.08.24 LEE S.W 당일 상태분포 재집계, au_summary 연계 */
|
||||
/* 2016.02.19 JANG M.K 이상거래 점수(au_fraud_log) 반영 */
|
||||
/* 2019.09.01 CHOI H.W Oracle 11g -> 19c, CHAR->VARCHAR2 정비 */
|
||||
/*==========================================================================*/
|
||||
#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 "aufld.h"
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
VARCHAR h_card[24];
|
||||
VARCHAR h_merch[64];
|
||||
VARCHAR h_bizdate[9]; /* YYYYMMDD */
|
||||
VARCHAR h_status[2];
|
||||
VARCHAR h_cstat[16];
|
||||
long h_auth;
|
||||
long h_amount;
|
||||
long h_delta;
|
||||
long h_cnt;
|
||||
long h_sum;
|
||||
long h_appr;
|
||||
long h_black;
|
||||
long h_vel;
|
||||
long h_risk;
|
||||
long h_grade;
|
||||
long h_mdr_bps;
|
||||
long h_fee;
|
||||
long h_vat;
|
||||
long h_dlim;
|
||||
long h_avail;
|
||||
long h_led;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* AUTH_APPROVE - Tuxedo 서비스 엔트리 */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void AUTH_APPROVE(TPSVCINFO *rqst)
|
||||
{
|
||||
FBFR32 *fb = (FBFR32 *)rqst->data;
|
||||
char card[24], merch[64];
|
||||
long rc = 0;
|
||||
TPINIT *tpi = (TPINIT *)NULL;
|
||||
|
||||
userlog("AUTH_APPROVE 진입: 승인 확정(pending->approved)");
|
||||
EXEC SQL WHENEVER SQLERROR GOTO sql_error;
|
||||
|
||||
/* ---- 1) 요청 FML 파싱 -------------------------------------------- */
|
||||
h_auth = Fvall(fb, AU_AUTH_ID, 0);
|
||||
if (h_auth <= 0) {
|
||||
userlog("AUTH_APPROVE: 식별자 범위오류 auth_id=%ld", h_auth);
|
||||
Fchg(fb, AU_RC, 0, (char *)"E801", 0L);
|
||||
tpreturn(TPFAIL, 0, (char *)fb, 0L, 0L);
|
||||
return;
|
||||
}
|
||||
h_delta = Fvall(fb, AU_DELTA, 0);
|
||||
if (h_delta < 0) h_delta = -h_delta;
|
||||
|
||||
/* ---- 2) 대상 승인건 조회 (현재상태/금액/카드/영업일) -------------- */
|
||||
/* 무마스터 승인 허용: 카드마스터는 외부조인 (+) 으로 등급만 취득 */
|
||||
EXEC SQL
|
||||
SELECT a.status,
|
||||
NVL(a.amount, 0),
|
||||
NVL(a.card_no, ' '),
|
||||
TO_CHAR(NVL(a.biz_date, SYSDATE),'YYYYMMDD'),
|
||||
DECODE(NVL(c.risk_grade,'B'), 'A',1, 'B',2, 'C',3, 9)
|
||||
INTO :h_status, :h_amount, :h_card, :h_bizdate, :h_grade
|
||||
FROM au_authorization a, card_master c
|
||||
WHERE a.auth_id = :h_auth
|
||||
AND c.card_no (+) = a.card_no;
|
||||
|
||||
if (sqlca.sqlcode == 1403) {
|
||||
userlog("AUTH_APPROVE: 대상 승인건 없음 auth_id=%ld", h_auth);
|
||||
Fchg(fb, AU_RC, 0, (char *)"E831", 0L);
|
||||
tpreturn(TPFAIL, 0, (char *)fb, 0L, 0L);
|
||||
return;
|
||||
}
|
||||
strcpy(card, (char *)h_card.arr);
|
||||
|
||||
/* ---- 3) 전이 가능여부 분기 (허용 상태에서만 A 로 전이) ------------ */
|
||||
if (strncmp((char *)h_status.arr, "A", 1) != 0 &&
|
||||
strncmp((char *)h_status.arr, "P", 1) != 0) {
|
||||
userlog("AUTH_APPROVE: 상태전이 불가 cur=%.1s auth_id=%ld",
|
||||
h_status.arr, h_auth);
|
||||
Fchg(fb, AU_RC, 0, (char *)"E833", 0L);
|
||||
tpreturn(TPFAIL, 0, (char *)fb, 0L, 0L);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ---- 4) 본처리: 원장 상태전이 (+금액조정 델타) ------------------- */
|
||||
EXEC SQL
|
||||
UPDATE au_authorization
|
||||
SET status = 'A', updated_at = SYSDATE
|
||||
WHERE auth_id = :h_auth
|
||||
AND status IN ('A','P');
|
||||
if (sqlca.sqlerrd[2] == 0) {
|
||||
userlog("AUTH_APPROVE: 반영건수 0 (경합/이미전이) auth_id=%ld", h_auth);
|
||||
Fchg(fb, AU_RC, 0, (char *)"E835", 0L);
|
||||
EXEC SQL ROLLBACK WORK;
|
||||
tpreturn(TPFAIL, 0, (char *)fb, 0L, 0L);
|
||||
return;
|
||||
}
|
||||
if (h_delta > 0) {
|
||||
EXEC SQL
|
||||
UPDATE au_authorization
|
||||
SET amount = amount + :h_delta, updated_at = SYSDATE
|
||||
WHERE auth_id = :h_auth;
|
||||
h_amount += h_delta;
|
||||
}
|
||||
|
||||
/* ---- 5) 카드 당일 상태분포 재집계 (한도판정 기초) --------------- */
|
||||
EXEC SQL
|
||||
SELECT COUNT(*), NVL(SUM(amount),0),
|
||||
NVL(SUM(DECODE(status,'A',1,0)),0)
|
||||
INTO :h_cnt, :h_sum, :h_appr
|
||||
FROM au_authorization
|
||||
WHERE card_no = :h_card
|
||||
AND biz_date = TO_DATE(:h_bizdate,'YYYYMMDD');
|
||||
|
||||
/* ---- 6) 업무규칙: 블랙리스트/카드상태/velocity/부정점수 --------- */
|
||||
EXEC SQL
|
||||
SELECT COUNT(*) INTO :h_black
|
||||
FROM au_blacklist
|
||||
WHERE card_no = :h_card;
|
||||
if (h_black > 0) { rc = 91; userlog("AUTH_APPROVE: 블랙리스트 적중 card=%s", card); }
|
||||
|
||||
EXEC SQL
|
||||
SELECT NVL(MAX(status),'NONE'), NVL(MAX(avail_limit),0)
|
||||
INTO :h_cstat, :h_avail
|
||||
FROM card_limit
|
||||
WHERE card_no = :h_card;
|
||||
if (strncmp((char *)h_cstat.arr, "ACTIVE", 6) != 0 &&
|
||||
strncmp((char *)h_cstat.arr, "NONE", 4) != 0) {
|
||||
if (rc == 0) rc = 92;
|
||||
userlog("AUTH_APPROVE: 카드상태 비정상 card=%s status=%.8s", card, h_cstat.arr);
|
||||
}
|
||||
|
||||
EXEC SQL
|
||||
SELECT COUNT(*) INTO :h_vel
|
||||
FROM au_authorization
|
||||
WHERE card_no = :h_card
|
||||
AND created_at > SYSDATE - 1/24;
|
||||
if (h_vel >= 10) { if (rc == 0) rc = 93;
|
||||
userlog("AUTH_APPROVE: velocity 경보 card=%s 1시간 %ld건", card, h_vel); }
|
||||
|
||||
EXEC SQL
|
||||
SELECT NVL(MAX(score),0) INTO :h_risk
|
||||
FROM au_fraud_log
|
||||
WHERE card_no = :h_card
|
||||
AND ROWNUM <= 100;
|
||||
if (h_risk >= 90) userlog("AUTH_APPROVE: 고위험 카드 card=%s 최고점=%ld", card, h_risk);
|
||||
|
||||
/* ---- 7) 상태전이 이력 적재 (감사원장, 시퀀스 .NEXTVAL 채번) ----- */
|
||||
EXEC SQL SELECT au_audit_seq.NEXTVAL INTO :h_led FROM DUAL;
|
||||
EXEC SQL
|
||||
INSERT INTO au_audit
|
||||
(audit_id, auth_id, card_no, from_status, to_status,
|
||||
amount, audit_rc, created_at)
|
||||
VALUES (:h_led, :h_auth, :h_card, :h_status, 'A',
|
||||
:h_amount, :rc, SYSDATE);
|
||||
|
||||
/* ---- 8) 가맹점 당일 승인 집계 (au_summary upsert, PL/SQL) ------ */
|
||||
Fget(fb, AU_MERCHANT, 0, merch, (FLDLEN32 *)NULL);
|
||||
strcpy((char *)h_merch.arr, merch); h_merch.len = strlen(merch);
|
||||
if (h_merch.len > 0) {
|
||||
EXEC SQL
|
||||
SELECT COUNT(*),
|
||||
NVL(SUM(DECODE(status,'A',1,0)),0),
|
||||
NVL(SUM(amount),0)
|
||||
INTO :h_cnt, :h_appr, :h_sum
|
||||
FROM au_authorization
|
||||
WHERE merchant_id = :h_merch
|
||||
AND biz_date = TO_DATE(:h_bizdate,'YYYYMMDD');
|
||||
EXEC SQL EXECUTE
|
||||
BEGIN
|
||||
pkg_settle.upsert_auth_summary(:h_merch, :h_bizdate,
|
||||
:h_cnt, :h_appr, :h_sum);
|
||||
END;
|
||||
END-EXEC;
|
||||
}
|
||||
|
||||
/* ---- 9) 정산 참고치: MDR 수수료/부가세 (DECODE 요율) ------------ */
|
||||
EXEC SQL
|
||||
SELECT NVL(m.mdr_bps, 25) INTO :h_mdr_bps
|
||||
FROM merchant m
|
||||
WHERE m.merchant_id = :h_merch;
|
||||
h_fee = ROUND(h_amount * h_mdr_bps / 10000);
|
||||
h_vat = ROUND(h_fee / 10);
|
||||
|
||||
/* ---- 10) 업무체인: 승인확정 한도차감 (LIMIT_DEC PL/SQL 패키지) -- */
|
||||
EXEC SQL EXECUTE
|
||||
BEGIN
|
||||
pkg_settle.limit_dec(:h_card, :h_amount, :h_avail);
|
||||
END;
|
||||
END-EXEC;
|
||||
|
||||
EXEC SQL COMMIT WORK;
|
||||
|
||||
Fchg(fb, AU_STATUS, 0, (char *)"A", 0L);
|
||||
Fchg(fb, AU_FEE, 0, (char *)&h_fee, 0L);
|
||||
Fchg(fb, AU_AVAIL, 0, (char *)&h_avail, 0L);
|
||||
Fchg(fb, AU_RC, 0, (char *)&rc, 0L);
|
||||
userlog("AUTH_APPROVE 완료: auth_id=%ld amt=%ld fee=%ld rc=%ld",
|
||||
h_auth, h_amount, h_fee, rc);
|
||||
tpreturn(TPSUCCESS, 0, (char *)fb, 0L, 0L);
|
||||
return;
|
||||
|
||||
sql_error:
|
||||
userlog("AUTH_APPROVE SQL 오류: %.70s (sqlcode=%ld)",
|
||||
sqlca.sqlerrm.sqlerrmc, sqlca.sqlcode);
|
||||
EXEC SQL WHENEVER SQLERROR CONTINUE;
|
||||
EXEC SQL ROLLBACK WORK;
|
||||
Fchg(fb, AU_RC, 0, (char *)"E900", 0L);
|
||||
tpreturn(TPFAIL, 0, (char *)fb, 0L, 0L);
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
247
legacy-oracle/proc/PAY_FILEGEN.pc
Normal file
247
legacy-oracle/proc/PAY_FILEGEN.pc
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
/*==========================================================================*/
|
||||
/* PAY_FILEGEN.pc - 지급파일 생성 배치 (As-Is 원본, Oracle Pro*C) */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* 대상 : BC 매입시스템 / 지급(펌뱅킹) 파일 생성 배치 PAYFGEN */
|
||||
/* DBMS : Oracle 19c 전처리 : Pro*C/C++ (proc) */
|
||||
/* 실행 : payfgen <YYYYMMDD> (인자 생략시 SYSDATE) */
|
||||
/* 기능 : 당일 승인(A) 지급건을 커서로 스윕하여 py_file 헤더 채번 + */
|
||||
/* 평문 지급레코드를 UTL_FILE 로 디스크 파일에 기록(펌뱅킹 규격). */
|
||||
/* ※ 이 파일은 **As-Is 역사 원본**이다. 현행 오픈스택 이식본은 */
|
||||
/* app/src/py/svc/PAY_FILEGEN.pgc (ECPG/PostgreSQL, Tuxedo 서비스화; */
|
||||
/* 디스크 I/O 는 별도 xfer 로 분리됨). 컴파일 대상 아님(빌드 제외). */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* 변경이력 */
|
||||
/* 2000.07.03 KIM K.H 최초작성 (전은행 공통 지급파일 EBCDIC->ASCII) */
|
||||
/* 2006.12.20 PARK J.S 정책 파라미터(cm_param) 기반 최대건수 분할 */
|
||||
/* 2013.04.09 LEE S.W UTL_FILE 로 헤더/명세/트레일러 3레코드 규격화 */
|
||||
/* 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_fname[64];
|
||||
VARCHAR h_dir[32];
|
||||
VARCHAR h_bankcd[4];
|
||||
VARCHAR h_acctno[20];
|
||||
VARCHAR h_merch[16];
|
||||
VARCHAR h_line[256];
|
||||
VARCHAR h_pval[16];
|
||||
long h_fileid;
|
||||
long h_payid;
|
||||
long h_amount;
|
||||
long h_fee;
|
||||
long h_net;
|
||||
long h_reccnt;
|
||||
long h_totamt;
|
||||
long h_thr;
|
||||
long h_seq;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
/* 당일 승인(A) 지급 대상 커서 — 계좌 마스터 외부조인으로 은행/계좌 획득 */
|
||||
EXEC SQL DECLARE cur_pay CURSOR FOR
|
||||
SELECT p.payout_id,
|
||||
p.merchant_id,
|
||||
NVL(a.bank_code, '000'),
|
||||
NVL(a.account_no, 'X'),
|
||||
NVL(p.amount, 0),
|
||||
NVL(p.fee, 0),
|
||||
NVL(p.net, 0)
|
||||
FROM py_payout p, py_account a
|
||||
WHERE a.merchant_id (+) = p.merchant_id
|
||||
AND p.biz_date = TO_DATE(:h_bizdate,'YYYYMMDD')
|
||||
AND p.status = 'A'
|
||||
ORDER BY p.merchant_id, p.payout_id;
|
||||
|
||||
static void sql_error(const char *stage);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int done = 0;
|
||||
|
||||
strcpy((char *)h_user.arr, "pybatch"); h_user.len = strlen((char *)h_user.arr);
|
||||
strcpy((char *)h_pass.arr, "pybatch"); 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) 영업일 결정 -------------------------------------------- */
|
||||
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,'YYYYMMDD') INTO :h_bizdate FROM DUAL;
|
||||
}
|
||||
printf("[PAY_FILEGEN] 지급파일 생성 개시 bizdate=%.8s\n", h_bizdate.arr);
|
||||
|
||||
/* ---- 2) 편성 대상 사전집계 (건수/총액) ------------------------- */
|
||||
EXEC SQL
|
||||
SELECT COUNT(*), NVL(SUM(net), 0)
|
||||
INTO :h_reccnt, :h_totamt
|
||||
FROM py_payout
|
||||
WHERE biz_date = TO_DATE(:h_bizdate,'YYYYMMDD')
|
||||
AND status = 'A';
|
||||
if (h_reccnt == 0) {
|
||||
printf("[PAY_FILEGEN] 편성 대상 승인건 없음 - 파일생성 생략\n");
|
||||
EXEC SQL ROLLBACK WORK RELEASE;
|
||||
return 0;
|
||||
}
|
||||
if (h_totamt <= 0) {
|
||||
fprintf(stderr, "[PAY_FILEGEN] 편성 총액 비정상 amt=%ld\n", h_totamt);
|
||||
EXEC SQL ROLLBACK WORK RELEASE;
|
||||
return 4;
|
||||
}
|
||||
|
||||
/* ---- 3) 정책 파라미터 조회 (최대 레코드수) — NVL 널가드 --------- */
|
||||
EXEC SQL
|
||||
SELECT NVL(MAX(param_val), '100000')
|
||||
INTO :h_pval
|
||||
FROM cm_param
|
||||
WHERE param_key = 'pay_filegen_max_rec';
|
||||
h_thr = atol((char *)h_pval.arr);
|
||||
if (h_thr <= 0) h_thr = 100000;
|
||||
if (h_reccnt > h_thr) {
|
||||
fprintf(stderr, "[PAY_FILEGEN] 최대 레코드수 초과 %ld > %ld - 분할 필요\n",
|
||||
h_reccnt, h_thr);
|
||||
EXEC SQL ROLLBACK WORK RELEASE;
|
||||
return 5;
|
||||
}
|
||||
|
||||
/* ---- 4) 파일 채번 및 헤더행 적재 (시퀀스 .NEXTVAL) ------------- */
|
||||
EXEC SQL SELECT py_file_seq.NEXTVAL INTO :h_fileid FROM DUAL;
|
||||
sprintf((char *)h_fname.arr, "PAYOUT_%.8s_%ld.dat",
|
||||
h_bizdate.arr, h_fileid);
|
||||
h_fname.len = strlen((char *)h_fname.arr);
|
||||
strcpy((char *)h_dir.arr, "PAYOUT_OUT"); /* DIRECTORY 객체명 */
|
||||
h_dir.len = strlen((char *)h_dir.arr);
|
||||
|
||||
EXEC SQL
|
||||
INSERT INTO py_file
|
||||
(file_id, biz_date, file_name, record_count, total_amount, status, created_at)
|
||||
VALUES (:h_fileid, TO_DATE(:h_bizdate,'YYYYMMDD'), :h_fname,
|
||||
:h_reccnt, :h_totamt, 'G', SYSDATE);
|
||||
|
||||
/* UTL_FILE 로 파일 오픈 후 헤더레코드('H') 기록 (PL/SQL 익명블록) */
|
||||
EXEC SQL EXECUTE
|
||||
BEGIN
|
||||
pkg_payfile.open_file(:h_dir, :h_fname);
|
||||
pkg_payfile.put_header(:h_bizdate, :h_reccnt, :h_totamt);
|
||||
END;
|
||||
END-EXEC;
|
||||
|
||||
/* ---- 5) 본처리: 지급건 커서 루프 + 명세레코드('D') 기록 -------- */
|
||||
h_seq = 0;
|
||||
EXEC SQL OPEN cur_pay;
|
||||
for (;;) {
|
||||
EXEC SQL WHENEVER NOTFOUND DO done = 1;
|
||||
EXEC SQL FETCH cur_pay
|
||||
INTO :h_payid, :h_merch, :h_bankcd, :h_acctno,
|
||||
:h_amount, :h_fee, :h_net;
|
||||
if (done) break;
|
||||
|
||||
h_seq += 1;
|
||||
|
||||
/* 무계좌(외부조인 미스) 건은 파일에서 제외하고 보류 전이 */
|
||||
if (strncmp((char *)h_bankcd.arr, "000", 3) == 0) {
|
||||
printf("[PAY_FILEGEN] 계좌미등록 payout=%ld merch=%.*s - 보류전이\n",
|
||||
h_payid, h_merch.len, h_merch.arr);
|
||||
EXEC SQL
|
||||
UPDATE py_payout
|
||||
SET status = 'H', updated_at = SYSDATE
|
||||
WHERE payout_id = :h_payid;
|
||||
h_seq -= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 펌뱅킹 명세레코드 조립 (고정폭: 구분1 은행3 계좌20 금액13) */
|
||||
sprintf((char *)h_line.arr, "D%3.3s%-20.20s%013ld",
|
||||
h_bankcd.arr, h_acctno.arr, h_net);
|
||||
h_line.len = strlen((char *)h_line.arr);
|
||||
|
||||
EXEC SQL EXECUTE
|
||||
BEGIN
|
||||
pkg_payfile.put_line(:h_line);
|
||||
END;
|
||||
END-EXEC;
|
||||
|
||||
/* 지급건을 이 파일로 편성 ('A'->'F') */
|
||||
EXEC SQL
|
||||
UPDATE py_payout
|
||||
SET file_id = :h_fileid,
|
||||
status = DECODE(status, 'A', 'F', status),
|
||||
updated_at = SYSDATE
|
||||
WHERE payout_id = :h_payid;
|
||||
|
||||
if (h_seq % 1000 == 0) {
|
||||
printf("[PAY_FILEGEN] 진행 %ld건 편성 - 중간커밋\n", h_seq);
|
||||
EXEC SQL COMMIT WORK;
|
||||
}
|
||||
}
|
||||
EXEC SQL CLOSE cur_pay;
|
||||
|
||||
/* ---- 6) 트레일러('T') 기록 및 파일 클로즈 --------------------- */
|
||||
EXEC SQL EXECUTE
|
||||
BEGIN
|
||||
pkg_payfile.put_trailer(:h_seq, :h_totamt);
|
||||
pkg_payfile.close_file;
|
||||
END;
|
||||
END-EXEC;
|
||||
|
||||
/* ---- 7) 파일헤더 확정 (실제 기록건수 반영, 'G'->'C') ----------- */
|
||||
EXEC SQL
|
||||
UPDATE py_file
|
||||
SET record_count = :h_seq,
|
||||
status = 'C',
|
||||
closed_at = SYSDATE
|
||||
WHERE file_id = :h_fileid;
|
||||
|
||||
EXEC SQL
|
||||
INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date)
|
||||
VALUES (cm_log_seq.NEXTVAL, 'PAY_FILEGEN', 'I',
|
||||
'PAY_FILEGEN file='||:h_fileid||' name='||:h_fname
|
||||
||' rec='||:h_seq||' amt='||:h_totamt,
|
||||
TO_DATE(:h_bizdate,'YYYYMMDD'));
|
||||
|
||||
/* ---- 8) 최종 커밋 --------------------------------------------- */
|
||||
EXEC SQL COMMIT WORK;
|
||||
|
||||
printf("[PAY_FILEGEN] 완료 file=%ld name=%.*s rec=%ld amt=%ld\n",
|
||||
h_fileid, h_fname.len, h_fname.arr, h_seq, h_totamt);
|
||||
EXEC SQL COMMIT WORK RELEASE;
|
||||
return 0;
|
||||
|
||||
connect_err:
|
||||
fprintf(stderr, "[PAY_FILEGEN] DB 접속 실패: %.70s\n", sqlca.sqlerrm.sqlerrmc);
|
||||
return 8;
|
||||
|
||||
sqlfail:
|
||||
sql_error("지급파일 생성");
|
||||
/* UTL_FILE 핸들 정리 (best-effort) */
|
||||
EXEC SQL WHENEVER SQLERROR CONTINUE;
|
||||
EXEC SQL EXECUTE BEGIN pkg_payfile.close_file; END; END-EXEC;
|
||||
EXEC SQL ROLLBACK WORK RELEASE;
|
||||
return 12;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* sql_error - 오류 로깅 (sqlca/oraca) */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static void sql_error(const char *stage)
|
||||
{
|
||||
fprintf(stderr, "[PAY_FILEGEN] SQL 오류 (%s): %.70s\n",
|
||||
stage, sqlca.sqlerrm.sqlerrmc);
|
||||
fprintf(stderr, " sqlcode=%ld rows=%ld\n",
|
||||
sqlca.sqlcode, sqlca.sqlerrd[2]);
|
||||
}
|
||||
224
legacy-oracle/proc/RECONCILE.pc
Normal file
224
legacy-oracle/proc/RECONCILE.pc
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/*==========================================================================*/
|
||||
/* RECONCILE.pc - 대사(對査) 온라인 서비스 (As-Is 원본, Oracle Pro*C) */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* 대상 : BC 매입시스템 / Tuxedo ATMI 서비스 RECONCILE */
|
||||
/* DBMS : Oracle 19c 전처리 : Pro*C/C++ (proc) */
|
||||
/* 기능 : 당일 매입 vs 원장 대사 — 커서순회 매칭분류 + 예외적재 + 정산연계. */
|
||||
/* ※ 이 파일은 **As-Is 역사 원본**이다. 현행 오픈스택 이식본은 */
|
||||
/* app/src/rc/svc/RECONCILE.pgc (ECPG/PostgreSQL). 컴파일 제외. */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* 변경이력 */
|
||||
/* 2001.07.16 SEO K.T 최초작성 (일 매입-원장 대사) */
|
||||
/* 2005.12.02 HAN Y.J 허용오차(tolerance) 매칭 도입, DECODE 등급 */
|
||||
/* 2009.04.27 LEE S.W 조직/코드 트리 CONNECT BY 집계 추가 */
|
||||
/* 2015.10.13 JANG M.K 예외원장(rc_exception) 분리, 감사로그 표준화 */
|
||||
/* 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 "rcfld.h"
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
VARCHAR h_bizdate[9]; /* YYYYMMDD */
|
||||
VARCHAR h_merch[64];
|
||||
VARCHAR h_status[16];
|
||||
VARCHAR h_pstat[2];
|
||||
VARCHAR h_orgcode[16]; /* 조직/코드 트리 루트 */
|
||||
VARCHAR h_orgname[64];
|
||||
long h_pid;
|
||||
long h_amt;
|
||||
long h_fee;
|
||||
long h_net;
|
||||
long h_act;
|
||||
long h_exp;
|
||||
long h_gross;
|
||||
long h_cnt;
|
||||
long h_mcnt;
|
||||
long h_ecnt;
|
||||
long h_mdr_bps;
|
||||
long h_limit;
|
||||
long h_led;
|
||||
long h_lvl; /* 코드트리 계층레벨 */
|
||||
long h_orgsum;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* RECONCILE - Tuxedo 서비스 엔트리 */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void RECONCILE(TPSVCINFO *rqst)
|
||||
{
|
||||
FBFR32 *fb = (FBFR32 *)rqst->data;
|
||||
char bizdate[9], merch[64];
|
||||
long tol = 0, rc_code = 0, adiff = 0;
|
||||
long scan_rows = 0, matched = 0, unmatched = 0, unmatched_amt = 0;
|
||||
|
||||
userlog("RECONCILE 진입: 당일 매입-원장 대사");
|
||||
EXEC SQL WHENEVER SQLERROR GOTO sql_error;
|
||||
|
||||
/* ---- 1) 입력 검증 ------------------------------------------------ */
|
||||
Fget(fb, RC_BIZDATE, 0, bizdate, (FLDLEN32 *)NULL);
|
||||
if (strlen(bizdate) < 8) {
|
||||
EXEC SQL SELECT TO_CHAR(SYSDATE,'YYYYMMDD') INTO :h_bizdate FROM DUAL;
|
||||
strcpy(bizdate, (char *)h_bizdate.arr);
|
||||
}
|
||||
strcpy((char *)h_bizdate.arr, bizdate); h_bizdate.len = strlen(bizdate);
|
||||
h_pid = Fvall(fb, RC_PURCHASE_ID, 0);
|
||||
h_net = Fvall(fb, RC_NET, 0);
|
||||
|
||||
/* ---- 2) 마스터/정책 조회 (미커밋 매입은 전문값, 외부조인 (+)) ---- */
|
||||
EXEC SQL
|
||||
SELECT NVL(p.amount,0), NVL(p.fee,0), NVL(p.net,:h_net),
|
||||
NVL(p.status,'A'), NVL(m.merchant_id, ' '),
|
||||
NVL(m.mdr_bps, 25), NVL(m.daily_limit, 100000000)
|
||||
INTO :h_amt, :h_fee, :h_net, :h_pstat, :h_merch, :h_mdr_bps, :h_limit
|
||||
FROM purchase p, merchant m
|
||||
WHERE p.purchase_id = :h_pid
|
||||
AND m.merchant_id (+) = p.merchant_id;
|
||||
if (sqlca.sqlcode == 1403) {
|
||||
h_amt = Fvall(fb, RC_AMOUNT, 0);
|
||||
h_fee = Fvall(fb, RC_FEE, 0);
|
||||
h_net = Fvall(fb, RC_NET, 0);
|
||||
Fget(fb, RC_MERCHANT, 0, merch, (FLDLEN32 *)NULL);
|
||||
strcpy((char *)h_merch.arr, merch); h_merch.len = strlen(merch);
|
||||
h_mdr_bps = 25; h_limit = 100000000;
|
||||
userlog("RECONCILE: 체인 신규매입(미커밋) pid=%ld — 전문값 대사", h_pid);
|
||||
}
|
||||
|
||||
/* ---- 3) 당일 매입/대사로그/예외 집계 (NVL 널가드) --------------- */
|
||||
EXEC SQL
|
||||
SELECT COUNT(*), NVL(SUM(amount),0)
|
||||
INTO :h_cnt, :h_gross
|
||||
FROM purchase
|
||||
WHERE biz_date = TO_DATE(:h_bizdate,'YYYYMMDD');
|
||||
EXEC SQL
|
||||
SELECT COUNT(*) INTO :h_mcnt
|
||||
FROM rc_match_log
|
||||
WHERE biz_date = TO_DATE(:h_bizdate,'YYYYMMDD')
|
||||
AND status = 'MATCHED';
|
||||
EXEC SQL
|
||||
SELECT COUNT(*) INTO :h_ecnt
|
||||
FROM rc_exception
|
||||
WHERE biz_date = TO_DATE(:h_bizdate,'YYYYMMDD')
|
||||
AND resolved = 'N';
|
||||
|
||||
/* ---- 4) 거래집합 커서순회 + 허용오차 매칭분류 ------------------- */
|
||||
EXEC SQL DECLARE cur_reconcile CURSOR FOR
|
||||
SELECT p.purchase_id, NVL(p.net,0)
|
||||
FROM purchase p
|
||||
WHERE p.biz_date = TO_DATE(:h_bizdate,'YYYYMMDD')
|
||||
ORDER BY p.purchase_id;
|
||||
EXEC SQL OPEN cur_reconcile;
|
||||
for (;;) {
|
||||
EXEC SQL WHENEVER NOTFOUND DO break;
|
||||
EXEC SQL FETCH cur_reconcile INTO :h_pid, :h_exp;
|
||||
EXEC SQL
|
||||
SELECT NVL(SUM(amount),0) INTO :h_act
|
||||
FROM ledger
|
||||
WHERE purchase_id = :h_pid
|
||||
AND entry_type IN ('RECON','SETTLE');
|
||||
adiff = h_exp - h_act;
|
||||
if (adiff < 0) adiff = -adiff;
|
||||
scan_rows++;
|
||||
if (adiff <= (tol > 0 ? tol : 0)) matched++;
|
||||
else { unmatched++; unmatched_amt += adiff; }
|
||||
}
|
||||
EXEC SQL WHENEVER NOTFOUND CONTINUE;
|
||||
EXEC SQL CLOSE cur_reconcile;
|
||||
userlog("RECONCILE 대사스캔: scan=%ld match=%ld unmatch=%ld",
|
||||
scan_rows, matched, unmatched);
|
||||
|
||||
/* ---- 5) 조직/코드 트리 집계 (계층질의 CONNECT BY PRIOR) --------- */
|
||||
/* 가맹점이 속한 정산조직 코드트리를 루트→하위로 전개하여 소속 조직의 */
|
||||
/* 당일 정산 순액 합계를 취득한다(대사 대상 조직 범위 확정용). */
|
||||
EXEC SQL
|
||||
SELECT NVL(org_code,'ROOT'), NVL(org_name,'-')
|
||||
INTO :h_orgcode, :h_orgname
|
||||
FROM rc_org_map
|
||||
WHERE merchant_id = :h_merch
|
||||
AND ROWNUM = 1;
|
||||
if (sqlca.sqlcode == 1403) { strcpy((char *)h_orgcode.arr, "ROOT");
|
||||
h_orgcode.len = 4; }
|
||||
EXEC SQL
|
||||
SELECT NVL(SUM(s.net),0), NVL(MAX(LEVEL),1)
|
||||
INTO :h_orgsum, :h_lvl
|
||||
FROM settlement s, rc_org o
|
||||
WHERE s.biz_date = TO_DATE(:h_bizdate,'YYYYMMDD')
|
||||
AND s.org_code = o.org_code
|
||||
AND o.org_code IN (
|
||||
SELECT org_code
|
||||
FROM rc_org
|
||||
START WITH org_code = :h_orgcode
|
||||
CONNECT BY PRIOR org_code = parent_code);
|
||||
userlog("RECONCILE 코드트리: org=%.8s depth=%ld 정산합=%ld",
|
||||
h_orgcode.arr, h_lvl, h_orgsum);
|
||||
|
||||
/* ---- 6) 업무규칙 분기 (매칭율 기반 상태판정, DECODE) ------------- */
|
||||
if (h_gross <= 0 && scan_rows == 0) {
|
||||
rc_code = 0; strcpy((char *)h_status.arr, "NODATA");
|
||||
} else if (unmatched == 0) {
|
||||
rc_code = 0; strcpy((char *)h_status.arr, "MATCHED");
|
||||
} else if (unmatched * 100 <= (scan_rows > 0 ? scan_rows : 1) * 5) {
|
||||
rc_code = 1; strcpy((char *)h_status.arr, "TOLERATED");
|
||||
} else {
|
||||
rc_code = 2; strcpy((char *)h_status.arr, "EXCEPTION");
|
||||
}
|
||||
h_status.len = strlen((char *)h_status.arr);
|
||||
/* 감사 심각도 라벨 (DECODE 코드분기) */
|
||||
EXEC SQL
|
||||
SELECT DECODE(:rc_code, 0,'I', 1,'W', 2,'E', 'X')
|
||||
INTO :h_pstat
|
||||
FROM DUAL;
|
||||
|
||||
/* ---- 7) 본처리: RECON 원장 적재 (.NEXTVAL 채번) ---------------- */
|
||||
EXEC SQL SELECT ledger_seq.NEXTVAL INTO :h_led FROM DUAL;
|
||||
EXEC SQL
|
||||
INSERT INTO ledger
|
||||
(ledger_id, purchase_id, entry_type, amount, biz_date, posted_at)
|
||||
VALUES (:h_led, :h_pid, 'RECON', :h_net,
|
||||
TO_DATE(:h_bizdate,'YYYYMMDD'), SYSDATE);
|
||||
|
||||
/* ---- 8) 불일치 예외 적재 + 감사로그 (PL/SQL 대사 패키지) -------- */
|
||||
if (rc_code >= 2) {
|
||||
EXEC SQL
|
||||
INSERT INTO rc_exception
|
||||
(exc_id, biz_date, merchant_id, unmatch_cnt, unmatch_amt,
|
||||
resolved, created_at)
|
||||
VALUES (rc_exception_seq.NEXTVAL, TO_DATE(:h_bizdate,'YYYYMMDD'),
|
||||
:h_merch, :unmatched, :unmatched_amt, 'N', SYSDATE);
|
||||
}
|
||||
EXEC SQL EXECUTE
|
||||
BEGIN
|
||||
pkg_settle.recon_audit(:h_bizdate, :h_merch, :scan_rows,
|
||||
:matched, :unmatched, :rc_code);
|
||||
END;
|
||||
END-EXEC;
|
||||
|
||||
EXEC SQL COMMIT WORK;
|
||||
|
||||
/* ---- 9) 응답부 ------------------------------------------------- */
|
||||
Fchg(fb, RC_STATUS, 0, (char *)h_status.arr, 0L);
|
||||
Fchg(fb, RC_MATCHED, 0, (char *)&matched, 0L);
|
||||
Fchg(fb, RC_UNMATCHED, 0, (char *)&unmatched, 0L);
|
||||
Fchg(fb, RC_RC, 0, (char *)&rc_code, 0L);
|
||||
userlog("RECONCILE 완료: biz=%.8s status=%.10s rc=%ld orgsum=%ld",
|
||||
h_bizdate.arr, h_status.arr, rc_code, h_orgsum);
|
||||
tpreturn(TPSUCCESS, 0, (char *)fb, 0L, 0L);
|
||||
return;
|
||||
|
||||
sql_error:
|
||||
userlog("RECONCILE SQL 오류: %.70s (sqlcode=%ld)",
|
||||
sqlca.sqlerrm.sqlerrmc, sqlca.sqlcode);
|
||||
EXEC SQL WHENEVER SQLERROR CONTINUE;
|
||||
EXEC SQL ROLLBACK WORK;
|
||||
Fchg(fb, RC_RC, 0, (char *)"E900", 0L);
|
||||
tpreturn(TPFAIL, 0, (char *)fb, 0L, 0L);
|
||||
return;
|
||||
}
|
||||
162
legacy-oracle/proc/SETTLE.pc
Normal file
162
legacy-oracle/proc/SETTLE.pc
Normal 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;
|
||||
}
|
||||
157
legacy-oracle/proc/ST_MDR.pc
Normal file
157
legacy-oracle/proc/ST_MDR.pc
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
/*==========================================================================*/
|
||||
/* ST_MDR.pc - MDR 수수료 원장기표 온라인 서비스 (As-Is 원본, Oracle Pro*C)*/
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* 대상 : BC 매입시스템 / Tuxedo ATMI 서비스 ST_MDR */
|
||||
/* DBMS : Oracle 19c 전처리 : Pro*C/C++ (proc) */
|
||||
/* 기능 : 매입건 MDR 수수료를 계산·검증하여 원장(ledger)에 기표한다. */
|
||||
/* ※ 이 파일은 **As-Is 역사 원본**이다. 현행 오픈스택 이식본은 */
|
||||
/* app/src/st/svc/ST_MDR.pgc (ECPG/PostgreSQL). 컴파일 제외. */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* 변경이력 */
|
||||
/* 2000.03.21 PARK J.S 최초작성 (MDR 원장기표) */
|
||||
/* 2007.11.05 HAN Y.J 가맹점 요율(mdr_bps) 마스터 연동, DECODE 분기 */
|
||||
/* 2013.06.30 LEE S.W 부가세 분리기표, 복식부기 차대변 연계 */
|
||||
/* 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_pstat[2];
|
||||
long h_pid;
|
||||
long h_sid;
|
||||
long h_amount;
|
||||
long h_fee;
|
||||
long h_vat;
|
||||
long h_net;
|
||||
long h_mdr_bps;
|
||||
long h_led;
|
||||
long h_dup;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* ST_MDR - Tuxedo 서비스 엔트리 */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void ST_MDR(TPSVCINFO *rqst)
|
||||
{
|
||||
FBFR32 *fb = (FBFR32 *)rqst->data;
|
||||
char merch[64], bizdate[9];
|
||||
|
||||
userlog("ST_MDR 진입: MDR 수수료 원장기표");
|
||||
EXEC SQL WHENEVER SQLERROR GOTO sql_error;
|
||||
|
||||
/* ---- 1) 요청 FML 파싱 -------------------------------------------- */
|
||||
h_pid = Fvall(fb, ST_PURCHASE_ID, 0);
|
||||
h_sid = Fvall(fb, ST_SETTLE_ID, 0);
|
||||
h_fee = Fvall(fb, ST_FEE, 0);
|
||||
Fget(fb, ST_BIZDATE, 0, bizdate, (FLDLEN32 *)NULL);
|
||||
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("ST_MDR: 매입 ID 필수 pid=%ld", h_pid);
|
||||
Fchg(fb, ST_RC, 0, (char *)"E802", 0L);
|
||||
tpreturn(TPFAIL, 0, (char *)fb, 0L, 0L);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ---- 2) 매입원장 조회 (금액/가맹점/상태 확보, NVL 널가드) --------- */
|
||||
EXEC SQL
|
||||
SELECT NVL(p.amount, 0),
|
||||
NVL(p.merchant_id, ' '),
|
||||
NVL(p.status, 'A')
|
||||
INTO :h_amount, :h_merch, :h_pstat
|
||||
FROM purchase p
|
||||
WHERE p.purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode == 1403) {
|
||||
/* 체인 내 신규매입(미커밋)은 전문값을 사용 */
|
||||
h_amount = Fvall(fb, ST_AMOUNT, 0);
|
||||
Fget(fb, ST_MERCHANT, 0, merch, (FLDLEN32 *)NULL);
|
||||
strcpy((char *)h_merch.arr, merch); h_merch.len = strlen(merch);
|
||||
userlog("ST_MDR: 미커밋 매입 pid=%ld — 전문값 사용", h_pid);
|
||||
}
|
||||
|
||||
/* ---- 3) 요율조회 및 수수료 산출 (요청 fee 우선, 없으면 재계산) --- */
|
||||
EXEC SQL
|
||||
SELECT NVL(m.mdr_bps, 25),
|
||||
DECODE(NVL(m.status,'N'), 'A', 0, 1)
|
||||
INTO :h_mdr_bps, :h_dup
|
||||
FROM merchant m
|
||||
WHERE m.merchant_id = :h_merch;
|
||||
if (h_fee <= 0) h_fee = ROUND(h_amount * h_mdr_bps / 10000);
|
||||
h_vat = ROUND(h_fee / 10); /* 수수료 부가세 10% 분리기표 */
|
||||
h_net = h_amount - h_fee - h_vat;
|
||||
|
||||
/* ---- 4) 중복기표 방지: 동일 매입 MDR 기존 원장 존재여부 --------- */
|
||||
EXEC SQL
|
||||
SELECT COUNT(*) INTO :h_dup
|
||||
FROM ledger
|
||||
WHERE purchase_id = :h_pid
|
||||
AND entry_type = 'MDR';
|
||||
if (h_dup > 0) {
|
||||
userlog("ST_MDR: MDR 기표 이미 존재 pid=%ld — 스킵", h_pid);
|
||||
Fchg(fb, ST_STATUS, 0, (char *)"D", 0L);
|
||||
EXEC SQL COMMIT WORK;
|
||||
tpreturn(TPSUCCESS, 0, (char *)fb, 0L, 0L);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ---- 5) 원장 기표: 시퀀스 채번 (.NEXTVAL) 후 MDR/VAT 2건 적재 --- */
|
||||
EXEC SQL SELECT ledger_seq.NEXTVAL INTO :h_led FROM DUAL;
|
||||
EXEC SQL
|
||||
INSERT INTO ledger
|
||||
(ledger_id, purchase_id, entry_type, amount, biz_date, posted_at)
|
||||
VALUES (:h_led, :h_pid, 'MDR', :h_fee,
|
||||
TO_DATE(:h_bizdate,'YYYYMMDD'), SYSDATE);
|
||||
EXEC SQL
|
||||
INSERT INTO ledger
|
||||
(ledger_id, purchase_id, entry_type, amount, biz_date, posted_at)
|
||||
VALUES (ledger_seq.NEXTVAL, :h_pid, 'VAT', :h_vat,
|
||||
TO_DATE(:h_bizdate,'YYYYMMDD'), SYSDATE);
|
||||
|
||||
/* ---- 6) 복식부기 전표 반영 (PL/SQL 원장 패키지) ----------------- */
|
||||
EXEC SQL EXECUTE
|
||||
BEGIN
|
||||
pkg_ledger.post_voucher(:h_pid, 'MDR', :h_fee, :h_vat, :h_bizdate);
|
||||
END;
|
||||
END-EXEC;
|
||||
|
||||
/* ---- 7) 정산연계: 수수료-원장반영 (LG_SETTLEPOST PL/SQL) -------- */
|
||||
EXEC SQL EXECUTE
|
||||
BEGIN
|
||||
pkg_settle.settle_post(:h_pid, :h_sid, :h_fee, :h_net);
|
||||
END;
|
||||
END-EXEC;
|
||||
|
||||
EXEC SQL COMMIT WORK;
|
||||
|
||||
Fchg(fb, ST_LEDGER_ID, 0, (char *)&h_led, 0L);
|
||||
Fchg(fb, ST_FEE, 0, (char *)&h_fee, 0L);
|
||||
Fchg(fb, ST_NET, 0, (char *)&h_net, 0L);
|
||||
Fchg(fb, ST_STATUS, 0, (char *)"S", 0L);
|
||||
userlog("ST_MDR 완료: pid=%ld ledger=%ld fee=%ld vat=%ld net=%ld",
|
||||
h_pid, h_led, h_fee, h_vat, h_net);
|
||||
tpreturn(TPSUCCESS, 0, (char *)fb, 0L, 0L);
|
||||
return;
|
||||
|
||||
sql_error:
|
||||
userlog("ST_MDR 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue