/*==========================================================================*/ /* 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 #include #include #include #include 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; }