Phase 2b: 11개 모듈 전량 실동작 (333 서비스, 전서버 부팅)
- 10개 모듈 추가/확장(au py rc st lg cl mm vl mg cm), 각 30 서비스 = 330 + tmsrv - build.sh 자동발견으로 11 모듈서버 + dbio 라이브러리 23 + 배치 22 빌드 - schema.d 11파일 → 75 테이블, 모듈별 disjoint - 부팅 리소스 규명: fs.mqueue.queues_max=8192(330큐>256), NDRX_MSGSIZEMAX 16000· MSGMAX 50(큐당 5.6MB→0.8MB), msgqueue ulimit 2GB → 전 12서버 runok - 검증: xadmin psc 333 AVAIL, 매입체인 XA 커밋, prepared_xacts=0 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8219b85f14
commit
bec83c721e
73 changed files with 10705 additions and 35 deletions
660
app/src/au/au_svr.pgc
Normal file
660
app/src/au/au_svr.pgc
Normal file
|
|
@ -0,0 +1,660 @@
|
|||
/*
|
||||
* au_svr.pgc - au (승인/한도) MODULE SERVER.
|
||||
*
|
||||
* ONE binary that tpadvertise()s ALL ~30 online au services (the real Tuxedo
|
||||
* "one module server, many services" pattern). Every service is a distinct
|
||||
* 승인/한도 operation with genuine EXEC SQL (directly, or via the linked
|
||||
* libaudbio.a dbio layer) and common math from libacqcommon.a.
|
||||
*
|
||||
* XA: the connection is opened once by tpopen() (ECPG XA switch); there is NO
|
||||
* EXEC SQL CONNECT. Owner-writes discipline: services in this server never
|
||||
* tpcall each other; each owns its tables on this process's XA branch.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include <ubf.h>
|
||||
#include <userlog.h>
|
||||
#include <ndebug.h>
|
||||
#include "acq.fd.h"
|
||||
#include "au_dbio.h"
|
||||
#include "acq_common.h"
|
||||
|
||||
/* ----- small UBF helpers ------------------------------------------------- */
|
||||
static long getl(UBFH *b, BFLDID f) { long v = 0; Bget(b, f, 0, (char *)&v, 0L); return v; }
|
||||
static void gets_(UBFH *b, BFLDID f, char *out, int cap)
|
||||
{ BFLDLEN l = cap; out[0] = 0; Bget(b, f, 0, out, &l); }
|
||||
static void setl(UBFH *b, BFLDID f, long v) { Bchg(b, f, 0, (char *)&v, 0L); }
|
||||
|
||||
#define FAIL(b) do { tpreturn(TPFAIL, 0, (char *)(b), 0L, 0L); return; } while (0)
|
||||
#define OK(b) do { tpreturn(TPSUCCESS, 0, (char *)(b), 0L, 0L); return; } while (0)
|
||||
|
||||
/* ----- service prototypes ------------------------------------------------ */
|
||||
void AUTH(TPSVCINFO *p); void AUTH_CANCEL(TPSVCINFO *p);
|
||||
void AUTH_PARTCXL(TPSVCINFO *p); void LIMIT_CHK(TPSVCINFO *p);
|
||||
void LIMIT_DEC(TPSVCINFO *p); void LIMIT_RST(TPSVCINFO *p);
|
||||
void LIMIT_INQ(TPSVCINFO *p); void STANDIN(TPSVCINFO *p);
|
||||
void FRAUD_DETECT(TPSVCINFO *p); void AUTH_RETRY(TPSVCINFO *p);
|
||||
void INSTALL_AUTH(TPSVCINFO *p); void AUTH_STATUS(TPSVCINFO *p);
|
||||
void AUTH_REVERSE(TPSVCINFO *p); void AUTH_APPROVE(TPSVCINFO *p);
|
||||
void AUTH_DECLINE(TPSVCINFO *p); void CARD_VALIDATE(TPSVCINFO *p);
|
||||
void VELOCITY_CHK(TPSVCINFO *p); void BLACKLIST_CHK(TPSVCINFO *p);
|
||||
void AUTH_HOLD(TPSVCINFO *p); void AUTH_RELEASE(TPSVCINFO *p);
|
||||
void AUTH_HISTORY(TPSVCINFO *p); void LIMIT_SET(TPSVCINFO *p);
|
||||
void LIMIT_TEMP(TPSVCINFO *p); void AUTH_SUMMARY(TPSVCINFO *p);
|
||||
void AUTH_ROUTE(TPSVCINFO *p); void DCC_QUOTE(TPSVCINFO *p);
|
||||
void AUTH_CAPTURE(TPSVCINFO *p); void PREAUTH(TPSVCINFO *p);
|
||||
void PREAUTH_COMPLETE(TPSVCINFO *p); void AUTH_VOID(TPSVCINFO *p);
|
||||
|
||||
/* ----- advertise table (this is what "scales to 30" cleanly) ------------- */
|
||||
static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
|
||||
{"AUTH", AUTH}, {"AUTH_CANCEL", AUTH_CANCEL},
|
||||
{"AUTH_PARTCXL", AUTH_PARTCXL}, {"LIMIT_CHK", LIMIT_CHK},
|
||||
{"LIMIT_DEC", LIMIT_DEC}, {"LIMIT_RST", LIMIT_RST},
|
||||
{"LIMIT_INQ", LIMIT_INQ}, {"STANDIN", STANDIN},
|
||||
{"FRAUD_DETECT", FRAUD_DETECT}, {"AUTH_RETRY", AUTH_RETRY},
|
||||
{"INSTALL_AUTH", INSTALL_AUTH}, {"AUTH_STATUS", AUTH_STATUS},
|
||||
{"AUTH_REVERSE", AUTH_REVERSE}, {"AUTH_APPROVE", AUTH_APPROVE},
|
||||
{"AUTH_DECLINE", AUTH_DECLINE}, {"CARD_VALIDATE", CARD_VALIDATE},
|
||||
{"VELOCITY_CHK", VELOCITY_CHK}, {"BLACKLIST_CHK", BLACKLIST_CHK},
|
||||
{"AUTH_HOLD", AUTH_HOLD}, {"AUTH_RELEASE", AUTH_RELEASE},
|
||||
{"AUTH_HISTORY", AUTH_HISTORY}, {"LIMIT_SET", LIMIT_SET},
|
||||
{"LIMIT_TEMP", LIMIT_TEMP}, {"AUTH_SUMMARY", AUTH_SUMMARY},
|
||||
{"AUTH_ROUTE", AUTH_ROUTE}, {"DCC_QUOTE", DCC_QUOTE},
|
||||
{"AUTH_CAPTURE", AUTH_CAPTURE}, {"PREAUTH", PREAUTH},
|
||||
{"PREAUTH_COMPLETE", PREAUTH_COMPLETE}, {"AUTH_VOID", AUTH_VOID},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
int tpsvrinit(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
if (tpopen() < 0) {
|
||||
userlog("au_svr: tpopen FAIL: %s", tpstrerror(tperrno));
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; SVCS[i].name != NULL; i++) {
|
||||
if (tpadvertise((char *)SVCS[i].name, SVCS[i].fn) < 0) {
|
||||
userlog("au_svr: tpadvertise(%s) FAIL: %s", SVCS[i].name, tpstrerror(tperrno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
userlog("au_svr: %d au(승인/한도) 서비스 광고 완료, RM 오픈", i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tpsvrdone(void)
|
||||
{
|
||||
tpclose();
|
||||
userlog("au_svr: tpsvrdone");
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
/* 1. AUTH - 승인 접수: 한도 점검 후 authorization 원장 기록 + 한도 차감. */
|
||||
/* ========================================================================= */
|
||||
void AUTH(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], merch[64], bizdate[16], appr[12];
|
||||
long amount, auth_id, lim = 0, used = 0;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (card[0] == 0) { userlog("AUTH: T_KEY1(카드번호) 누락"); FAIL(b); }
|
||||
gets_(b, T_MERCHANT, merch, sizeof(merch));
|
||||
amount = getl(b, T_AMOUNT);
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
|
||||
/* 한도 점검: 초과면 거절(D) 상태로 기록 */
|
||||
if (audb_limit_get(card, &lim, &used) < 0) FAIL(b);
|
||||
if (used + amount > lim) {
|
||||
userlog("AUTH 한도초과 card=%s used=%ld amt=%ld lim=%ld -> 거절", card, used, amount, lim);
|
||||
auth_id = audb_next_auth_id();
|
||||
if (auth_id < 0) FAIL(b);
|
||||
if (audb_insert_auth(auth_id, card, merch, amount, "000000", "AUTH", "D", bizdate) < 0) FAIL(b);
|
||||
setl(b, T_ID1, auth_id);
|
||||
setl(b, T_RC, 1);
|
||||
Bchg(b, T_STATUS, 0, "D", 0L);
|
||||
OK(b);
|
||||
}
|
||||
auth_id = audb_next_auth_id();
|
||||
if (auth_id < 0) FAIL(b);
|
||||
sprintf(appr, "%06ld", auth_id % 1000000);
|
||||
if (audb_insert_auth(auth_id, card, merch, amount, appr, "AUTH", "A", bizdate) < 0) FAIL(b);
|
||||
if (audb_limit_dec(card, amount) < 0) FAIL(b);
|
||||
|
||||
setl(b, T_ID1, auth_id);
|
||||
setl(b, T_RC, 0);
|
||||
Bchg(b, T_STR2, 0, appr, 0L);
|
||||
Bchg(b, T_STATUS, 0, "A", 0L);
|
||||
userlog("AUTH 승인 auth_id=%ld card=%s merch=%s amt=%ld appr=%s", auth_id, card, merch, amount, appr);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 2. AUTH_CANCEL - 승인 전체 취소 + 한도 원복. */
|
||||
void AUTH_CANCEL(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], bizdate[16], reason[128];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id, h_auth, h_amt;
|
||||
char h_card[24], h_bizdate[16], h_reason[128];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_auth = getl(b, T_ID1);
|
||||
h_amt = getl(b, T_AMOUNT);
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
gets_(b, T_REASON, reason, sizeof(reason)); if (reason[0] == 0) strcpy(reason, "CUSTOMER");
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
strncpy(h_reason, reason, sizeof(h_reason)-1); h_reason[sizeof(h_reason)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT nextval('au_cancel_seq') INTO :h_id;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL INSERT INTO au_cancel (cancel_id, auth_id, cancel_type, amount, reason, biz_date)
|
||||
VALUES (:h_id, :h_auth, 'FULL', :h_amt, :h_reason, :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (audb_update_auth_status(h_auth, "C") < 0) FAIL(b);
|
||||
if (card[0] && audb_limit_dec(card, -h_amt) < 0) FAIL(b);
|
||||
setl(b, T_CANCEL_ID, h_id);
|
||||
Bchg(b, T_STATUS, 0, "C", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 3. AUTH_PARTCXL - 부분 취소: 승인 금액 감액 + 한도 부분 원복. */
|
||||
void AUTH_PARTCXL(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id, h_auth, h_amt, h_new;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_auth = getl(b, T_ID1);
|
||||
h_amt = getl(b, T_AMOUNT); /* 취소 금액 */
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT amount INTO :h_new FROM au_authorization WHERE auth_id = :h_auth;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
h_new = h_new - h_amt;
|
||||
EXEC SQL SELECT nextval('au_cancel_seq') INTO :h_id;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL INSERT INTO au_cancel (cancel_id, auth_id, cancel_type, amount, reason, biz_date)
|
||||
VALUES (:h_id, :h_auth, 'PARTIAL', :h_amt, 'PARTIAL', :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (audb_update_auth_amount(h_auth, h_new) < 0) FAIL(b);
|
||||
if (card[0] && audb_limit_dec(card, -h_amt) < 0) FAIL(b);
|
||||
setl(b, T_CANCEL_ID, h_id);
|
||||
setl(b, T_AMOUNT, h_new);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 4. LIMIT_CHK - 카드 한도 점검 (사용가능 여부만 리턴). */
|
||||
void LIMIT_CHK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
long amount, lim = 0, used = 0;
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
amount = getl(b, T_AMOUNT);
|
||||
if (audb_limit_get(card, &lim, &used) < 0) FAIL(b);
|
||||
setl(b, T_AMT1, lim);
|
||||
setl(b, T_AMT2, used);
|
||||
setl(b, T_RC, (used + amount > lim) ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 5. LIMIT_DEC - 한도 차감(사용금액 증가). */
|
||||
void LIMIT_DEC(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
long amount = getl(b, T_AMOUNT);
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (audb_limit_dec(card, amount) < 0) FAIL(b);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 6. LIMIT_RST - 한도 사용금액 초기화(일마감 원복). */
|
||||
void LIMIT_RST(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (audb_limit_reset(card) < 0) FAIL(b);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 7. LIMIT_INQ - 한도 조회 (가용한도 계산). */
|
||||
void LIMIT_INQ(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
long lim = 0, used = 0;
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (audb_limit_get(card, &lim, &used) < 0) FAIL(b);
|
||||
setl(b, T_AMT1, lim);
|
||||
setl(b, T_AMT2, used);
|
||||
setl(b, T_AMT3, lim - used); /* 가용한도 */
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 8. STANDIN - 발급사 무응답 시 대리승인(STANDIN, 소액 한도 내). */
|
||||
void STANDIN(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], merch[64], bizdate[16];
|
||||
long amount, auth_id, stand_lim = 50000;
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
gets_(b, T_MERCHANT, merch, sizeof(merch));
|
||||
amount = getl(b, T_AMOUNT);
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
if (amount > stand_lim) { setl(b, T_RC, 1); Bchg(b, T_STATUS, 0, "D", 0L); OK(b); }
|
||||
auth_id = audb_next_auth_id();
|
||||
if (auth_id < 0) FAIL(b);
|
||||
if (audb_insert_auth(auth_id, card, merch, amount, "STDIN0", "STANDIN", "A", bizdate) < 0) FAIL(b);
|
||||
setl(b, T_ID1, auth_id);
|
||||
setl(b, T_RC, 0);
|
||||
Bchg(b, T_STATUS, 0, "A", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 9. FRAUD_DETECT - 부정거래 스코어링 + 위험시 fraud_log 기록. */
|
||||
void FRAUD_DETECT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], bizdate[16], reason[128];
|
||||
long auth_id, amount, score = 0, fraud_id;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
auth_id = getl(b, T_ID1);
|
||||
amount = getl(b, T_AMOUNT);
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
/* 룰: 고액 + 당일 승인건수 과다 = 스코어 상승 */
|
||||
if (amount > 1000000) score += 50;
|
||||
EXEC SQL SELECT count(*) INTO :h_cnt FROM au_authorization WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_cnt > 5) score += 40;
|
||||
score += (h_cnt * 2);
|
||||
|
||||
strcpy(reason, score >= 50 ? "HIGH_RISK" : "OK");
|
||||
setl(b, T_ARG1, score);
|
||||
if (score >= 50) {
|
||||
fraud_id = audb_insert_fraud(auth_id, card, score, reason, bizdate);
|
||||
if (fraud_id < 0) FAIL(b);
|
||||
setl(b, T_ID2, fraud_id);
|
||||
setl(b, T_RC, 1);
|
||||
} else {
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 10. AUTH_RETRY - 거절 승인 재시도 (상태 D->A 재승인). */
|
||||
void AUTH_RETRY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
long auth_id = getl(b, T_ID1), amount = getl(b, T_AMOUNT), lim = 0, used = 0;
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (audb_limit_get(card, &lim, &used) < 0) FAIL(b);
|
||||
if (used + amount > lim) { setl(b, T_RC, 1); FAIL(b); }
|
||||
if (audb_update_auth_status(auth_id, "A") < 0) FAIL(b);
|
||||
if (audb_limit_dec(card, amount) < 0) FAIL(b);
|
||||
setl(b, T_RC, 0);
|
||||
Bchg(b, T_STATUS, 0, "A", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 11. INSTALL_AUTH - 할부 승인: 개월 수만큼 분할 승인 레코드. */
|
||||
void INSTALL_AUTH(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], merch[64], bizdate[16];
|
||||
long months, amount, i, auth_id;
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
gets_(b, T_MERCHANT, merch, sizeof(merch));
|
||||
amount = getl(b, T_AMOUNT);
|
||||
months = getl(b, T_INSTALL_N); if (months < 1) months = 3;
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
for (i = 1; i <= months; i++) {
|
||||
auth_id = audb_next_auth_id();
|
||||
if (auth_id < 0) FAIL(b);
|
||||
if (audb_insert_auth(auth_id, card, merch, amount / months, "INST00", "INSTALL", "A", bizdate) < 0) FAIL(b);
|
||||
}
|
||||
if (audb_limit_dec(card, amount) < 0) FAIL(b);
|
||||
setl(b, T_COUNT, months);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 12. AUTH_STATUS - 승인 상태 조회 (dbio). */
|
||||
void AUTH_STATUS(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long auth_id = getl(b, T_ID1);
|
||||
char st[4];
|
||||
if (audb_get_auth_status(auth_id, st) < 0) FAIL(b);
|
||||
Bchg(b, T_STATUS, 0, st, 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 13. AUTH_REVERSE - 승인 역전(reversal) + 한도 원복. */
|
||||
void AUTH_REVERSE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
long auth_id = getl(b, T_ID1), amount = getl(b, T_AMOUNT);
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (audb_update_auth_status(auth_id, "R") < 0) FAIL(b);
|
||||
if (card[0] && audb_limit_dec(card, -amount) < 0) FAIL(b);
|
||||
Bchg(b, T_STATUS, 0, "R", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 14. AUTH_APPROVE - 승인 확정(pending->approved). */
|
||||
void AUTH_APPROVE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long auth_id = getl(b, T_ID1);
|
||||
if (audb_update_auth_status(auth_id, "A") < 0) FAIL(b);
|
||||
Bchg(b, T_STATUS, 0, "A", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 15. AUTH_DECLINE - 승인 거절 처리. */
|
||||
void AUTH_DECLINE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char reason[128];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_auth;
|
||||
char h_reason[128];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_auth = getl(b, T_ID1);
|
||||
gets_(b, T_REASON, reason, sizeof(reason)); if (reason[0] == 0) strcpy(reason, "DECLINE");
|
||||
strncpy(h_reason, reason, sizeof(h_reason)-1); h_reason[sizeof(h_reason)-1] = 0;
|
||||
EXEC SQL UPDATE au_authorization SET status = 'D', decline_reason = :h_reason, updated_at = now()
|
||||
WHERE auth_id = :h_auth;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
Bchg(b, T_STATUS, 0, "D", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 16. CARD_VALIDATE - 카드번호 Luhn 검증 (common lib). */
|
||||
void CARD_VALIDATE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
setl(b, T_RC, acq_luhn_ok(card) ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 17. VELOCITY_CHK - 속도(velocity) 점검: 당일 카드 승인건수/합계. */
|
||||
void VELOCITY_CHK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt, h_sum;
|
||||
char h_card[24], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0) INTO :h_cnt, :h_sum
|
||||
FROM au_authorization WHERE card_no = :h_card AND biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_sum);
|
||||
setl(b, T_RC, (h_cnt > 10) ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 18. BLACKLIST_CHK - 블랙리스트 카드 조회. */
|
||||
void BLACKLIST_CHK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
EXEC SQL SELECT count(*) INTO :h_cnt FROM au_blacklist WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_RC, (h_cnt > 0) ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 19. AUTH_HOLD - 승인 보류. */
|
||||
void AUTH_HOLD(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long auth_id = getl(b, T_ID1);
|
||||
if (audb_update_auth_status(auth_id, "H") < 0) FAIL(b);
|
||||
Bchg(b, T_STATUS, 0, "H", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 20. AUTH_RELEASE - 보류 해제. */
|
||||
void AUTH_RELEASE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long auth_id = getl(b, T_ID1);
|
||||
if (audb_update_auth_status(auth_id, "A") < 0) FAIL(b);
|
||||
Bchg(b, T_STATUS, 0, "A", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 21. AUTH_HISTORY - 카드 승인 이력 건수 조회. */
|
||||
void AUTH_HISTORY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
EXEC SQL SELECT count(*) INTO :h_cnt FROM au_authorization WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 22. LIMIT_SET - 카드 한도 설정/등록 (dbio upsert). */
|
||||
void LIMIT_SET(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
long lim = getl(b, T_AMT1);
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (lim <= 0) lim = 1000000;
|
||||
if (audb_limit_set(card, lim) < 0) FAIL(b);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 23. LIMIT_TEMP - 임시 한도 상향 (temp_limit 저장 + 당일 상향). */
|
||||
void LIMIT_TEMP(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_temp;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
h_temp = getl(b, T_AMT1); if (h_temp <= 0) h_temp = 2000000;
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
EXEC SQL UPDATE card_limit
|
||||
SET temp_limit = :h_temp, daily_limit = daily_limit + :h_temp, updated_at = now()
|
||||
WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 24. AUTH_SUMMARY - 가맹점 당일 승인 집계 upsert (dbio). */
|
||||
void AUTH_SUMMARY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char merch[64], bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt, h_appr, h_dec, h_amt;
|
||||
char h_merch[64], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_MERCHANT, merch, sizeof(merch));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
EXEC SQL SELECT count(*),
|
||||
count(*) FILTER (WHERE status = 'A'),
|
||||
count(*) FILTER (WHERE status = 'D'),
|
||||
coalesce(sum(amount),0)
|
||||
INTO :h_cnt, :h_appr, :h_dec, :h_amt
|
||||
FROM au_authorization WHERE merchant_id = :h_merch AND biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (audb_upsert_auth_summary(merch, bizdate, h_cnt, h_appr, h_dec, h_amt) < 0) FAIL(b);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_amt);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 25. AUTH_ROUTE - 승인 라우팅(발급사 BIN 기준 라우팅 코드 산출). */
|
||||
void AUTH_ROUTE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], route[8];
|
||||
long bin;
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
bin = atol(card) / 1000000000L; /* 앞 6자리 근사 BIN */
|
||||
if (card[0] == '4') strcpy(route, "VISA");
|
||||
else if (card[0] == '5') strcpy(route, "MC");
|
||||
else if (card[0] == '3') strcpy(route, "AMEX");
|
||||
else strcpy(route, "LOCAL");
|
||||
Bchg(b, T_STR1, 0, route, 0L);
|
||||
setl(b, T_ARG1, bin);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 26. DCC_QUOTE - 해외승인 DCC 환산 견적(통화 -> 원화). */
|
||||
void DCC_QUOTE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char ccy[8];
|
||||
long fx, rate = 1350, krw;
|
||||
fx = getl(b, T_FX_AMT);
|
||||
gets_(b, T_CCY, ccy, sizeof(ccy)); if (ccy[0] == 0) strcpy(ccy, "USD");
|
||||
krw = fx * rate / 100;
|
||||
setl(b, T_AMOUNT, krw);
|
||||
setl(b, T_ARG1, rate);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 27. AUTH_CAPTURE - 승인 매입확정(capture): 상태 A->M(매입대상). */
|
||||
void AUTH_CAPTURE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_auth;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_auth = getl(b, T_ID1);
|
||||
EXEC SQL UPDATE au_authorization SET status = 'M', captured_at = now(), updated_at = now()
|
||||
WHERE auth_id = :h_auth AND status = 'A';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); FAIL(b); }
|
||||
setl(b, T_RC, 0);
|
||||
Bchg(b, T_STATUS, 0, "M", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 28. PREAUTH - 예비승인(pre-authorization) 기록. */
|
||||
void PREAUTH(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], merch[64], bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id, h_amt;
|
||||
char h_card[24], h_merch[64], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
gets_(b, T_MERCHANT, merch, sizeof(merch));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
h_amt = getl(b, T_AMOUNT);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
EXEC SQL SELECT nextval('au_preauth_seq') INTO :h_id;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL INSERT INTO au_preauth (preauth_id, card_no, merchant_id, amount, status, biz_date)
|
||||
VALUES (:h_id, :h_card, :h_merch, :h_amt, 'P', :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_ID2, h_id);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 29. PREAUTH_COMPLETE - 예비승인 확정: preauth 소진 + 본승인 생성. */
|
||||
void PREAUTH_COMPLETE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16];
|
||||
long auth_id;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pre, h_amt;
|
||||
char h_card[24], h_merch[64], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_pre = getl(b, T_ID2);
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT card_no, merchant_id, amount INTO :h_card, :h_merch, :h_amt
|
||||
FROM au_preauth WHERE preauth_id = :h_pre;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
EXEC SQL UPDATE au_preauth SET status = 'C' WHERE preauth_id = :h_pre;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
auth_id = audb_next_auth_id();
|
||||
if (auth_id < 0) FAIL(b);
|
||||
if (audb_insert_auth(auth_id, h_card, h_merch, h_amt, "PRECMP", "PREAUTH", "A", bizdate) < 0) FAIL(b);
|
||||
setl(b, T_ID1, auth_id);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 30. AUTH_VOID - 당일 승인 무효화(void) + 한도 원복. */
|
||||
void AUTH_VOID(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id, h_auth, h_amt;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_auth = getl(b, T_ID1); h_amt = getl(b, T_AMOUNT);
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
EXEC SQL SELECT nextval('au_cancel_seq') INTO :h_id;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL INSERT INTO au_cancel (cancel_id, auth_id, cancel_type, amount, reason, biz_date)
|
||||
VALUES (:h_id, :h_auth, 'VOID', :h_amt, 'VOID', :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (audb_update_auth_status(h_auth, "V") < 0) FAIL(b);
|
||||
if (card[0] && audb_limit_dec(card, -h_amt) < 0) FAIL(b);
|
||||
setl(b, T_CANCEL_ID, h_id);
|
||||
Bchg(b, T_STATUS, 0, "V", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
58
app/src/au/batch/au_fraud_scan_batch.pgc
Normal file
58
app/src/au/batch/au_fraud_scan_batch.pgc
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* au_fraud_scan_batch.pgc - au 부정거래 스캔 배치 (GROUP BY HAVING + XA).
|
||||
*
|
||||
* Groups the day's authorizations by card and, for cards whose승인건수/합계 that
|
||||
* exceed velocity thresholds (HAVING), inserts a fraud_log row via the dbio
|
||||
* layer - all under ONE global XA transaction. Usage: au_fraud_scan_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "au_dbio.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
long rows = 0;
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
char h_card[24];
|
||||
long h_cnt, h_sum, h_score;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE fsc CURSOR FOR
|
||||
SELECT card_no, count(*), coalesce(sum(amount),0)
|
||||
FROM au_authorization
|
||||
WHERE biz_date = :h_bizdate
|
||||
GROUP BY card_no
|
||||
HAVING count(*) > 5 OR coalesce(sum(amount),0) > 5000000
|
||||
ORDER BY card_no;
|
||||
EXEC SQL OPEN fsc;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
for (;;) {
|
||||
EXEC SQL FETCH fsc INTO :h_card, :h_cnt, :h_sum;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE fsc; tpabort(0); return 1; }
|
||||
h_score = h_cnt * 10 + (h_sum > 5000000 ? 40 : 0);
|
||||
if (audb_insert_fraud(0, h_card, h_score, "VELOCITY_BATCH", bizdate) < 0) {
|
||||
EXEC SQL CLOSE fsc; tpabort(0); return 1;
|
||||
}
|
||||
rows++;
|
||||
}
|
||||
EXEC SQL CLOSE fsc;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> au_fraud_scan_batch COMMIT: bizdate=%s flagged_cards=%ld\n", bizdate, rows);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
54
app/src/au/batch/au_settle_reflect_batch.pgc
Normal file
54
app/src/au/batch/au_settle_reflect_batch.pgc
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* au_settle_reflect_batch.pgc - au 승인 정산반영 배치 (커서 M->S + XA).
|
||||
*
|
||||
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
|
||||
* transaction, an EXEC SQL cursor scans captured authorizations (status='M')
|
||||
* for a biz_date and flips each to settled (status='S') via the dbio layer,
|
||||
* then tpcommit drives XA 2PC. Usage: au_settle_reflect_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "au_dbio.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
long rows = 0;
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_auth, h_amt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE arc CURSOR FOR
|
||||
SELECT auth_id, amount FROM au_authorization
|
||||
WHERE biz_date = :h_bizdate AND status = 'M'
|
||||
ORDER BY auth_id;
|
||||
EXEC SQL OPEN arc;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
for (;;) {
|
||||
EXEC SQL FETCH arc INTO :h_auth, :h_amt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE arc; tpabort(0); return 1; }
|
||||
if (audb_update_auth_status(h_auth, "S") < 0) {
|
||||
EXEC SQL CLOSE arc; tpabort(0); return 1;
|
||||
}
|
||||
rows++;
|
||||
}
|
||||
EXEC SQL CLOSE arc;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> au_settle_reflect_batch COMMIT: bizdate=%s reflected(M->S)=%ld\n", bizdate, rows);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
121
app/src/au/dbio/au_auth_dbio.pgc
Normal file
121
app/src/au/dbio/au_auth_dbio.pgc
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* au_auth_dbio.pgc - 승인(authorization)/부정거래 DB 접근 (libaudbio.a).
|
||||
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <userlog.h>
|
||||
#include "au_dbio.h"
|
||||
|
||||
long audb_next_auth_id(void)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
EXEC SQL SELECT nextval('au_auth_seq') INTO :h_id;
|
||||
if (sqlca.sqlcode < 0) {
|
||||
userlog("audb_next_auth_id FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
return h_id;
|
||||
}
|
||||
|
||||
int audb_insert_auth(long auth_id, const char *card, const char *merch, long amount,
|
||||
const char *appr_code, const char *auth_type, const char *status,
|
||||
const char *bizdate)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id = auth_id, h_amount = amount;
|
||||
char h_card[24], h_merch[64], h_appr[12], h_type[12], h_status[8], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_card, card, sizeof(h_card) - 1); h_card[sizeof(h_card)-1] = 0;
|
||||
strncpy(h_merch, merch, sizeof(h_merch) - 1); h_merch[sizeof(h_merch)-1] = 0;
|
||||
strncpy(h_appr, appr_code, sizeof(h_appr) - 1); h_appr[sizeof(h_appr)-1] = 0;
|
||||
strncpy(h_type, auth_type, sizeof(h_type) - 1); h_type[sizeof(h_type)-1] = 0;
|
||||
strncpy(h_status, status, sizeof(h_status) - 1); h_status[sizeof(h_status)-1] = 0;
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate) - 1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
EXEC SQL INSERT INTO au_authorization
|
||||
(auth_id, card_no, merchant_id, amount, approval_code, auth_type, status, biz_date)
|
||||
VALUES (:h_id, :h_card, :h_merch, :h_amount, :h_appr, :h_type, :h_status, :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) {
|
||||
userlog("audb_insert_auth FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int audb_update_auth_status(long auth_id, const char *status)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id = auth_id;
|
||||
char h_status[8];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_status, status, sizeof(h_status) - 1); h_status[sizeof(h_status)-1] = 0;
|
||||
|
||||
EXEC SQL UPDATE au_authorization SET status = :h_status, updated_at = now()
|
||||
WHERE auth_id = :h_id;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) {
|
||||
userlog("audb_update_auth_status FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int audb_get_auth_status(long auth_id, char *out)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id = auth_id;
|
||||
char h_status[8];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
EXEC SQL SELECT status INTO :h_status FROM au_authorization WHERE auth_id = :h_id;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) {
|
||||
userlog("audb_get_auth_status FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
out[0] = h_status[0];
|
||||
out[1] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int audb_update_auth_amount(long auth_id, long amount)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id = auth_id, h_amount = amount;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
EXEC SQL UPDATE au_authorization SET amount = :h_amount, updated_at = now()
|
||||
WHERE auth_id = :h_id;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) {
|
||||
userlog("audb_update_auth_amount FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
long audb_insert_fraud(long auth_id, const char *card, long score, const char *reason,
|
||||
const char *bizdate)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id, h_auth = auth_id, h_score = score;
|
||||
char h_card[24], h_reason[128], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_card, card, sizeof(h_card) - 1); h_card[sizeof(h_card)-1] = 0;
|
||||
strncpy(h_reason, reason, sizeof(h_reason) - 1); h_reason[sizeof(h_reason)-1] = 0;
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate) - 1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT nextval('au_fraud_seq') INTO :h_id;
|
||||
if (sqlca.sqlcode < 0) return -1;
|
||||
|
||||
EXEC SQL INSERT INTO au_fraud_log (fraud_id, auth_id, card_no, score, reason, biz_date)
|
||||
VALUES (:h_id, :h_auth, :h_card, :h_score, :h_reason, :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) {
|
||||
userlog("audb_insert_fraud FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
return h_id;
|
||||
}
|
||||
32
app/src/au/dbio/au_dbio.h
Normal file
32
app/src/au/dbio/au_dbio.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* au_dbio.h - au 모듈 (승인/한도) DB 접근 계층 (libaudbio.a).
|
||||
* ECPG (EXEC SQL) functions compiled into a static library and linked into
|
||||
* au_svr and the au batches. They run on the caller's XA branch/connection
|
||||
* (no EXEC SQL CONNECT); sqlca is the shared per-thread ECPG SQLCA.
|
||||
* Return convention: 0 = ok, -1 = SQL error (caller may also inspect sqlca).
|
||||
*/
|
||||
#ifndef AU_DBIO_H
|
||||
#define AU_DBIO_H
|
||||
|
||||
/* authorization */
|
||||
long audb_next_auth_id(void);
|
||||
int audb_insert_auth(long auth_id, const char *card, const char *merch, long amount,
|
||||
const char *appr_code, const char *auth_type, const char *status,
|
||||
const char *bizdate);
|
||||
int audb_update_auth_status(long auth_id, const char *status);
|
||||
int audb_get_auth_status(long auth_id, char *out /* >= 2 bytes */);
|
||||
int audb_update_auth_amount(long auth_id, long amount);
|
||||
|
||||
/* fraud */
|
||||
long audb_insert_fraud(long auth_id, const char *card, long score, const char *reason,
|
||||
const char *bizdate);
|
||||
|
||||
/* card limit */
|
||||
int audb_limit_get(const char *card, long *limit_out, long *used_out);
|
||||
int audb_limit_dec(const char *card, long amount);
|
||||
int audb_limit_reset(const char *card);
|
||||
int audb_limit_set(const char *card, long limit);
|
||||
int audb_upsert_auth_summary(const char *merch, const char *bizdate, long cnt,
|
||||
long approved, long declined, long amount);
|
||||
|
||||
#endif /* AU_DBIO_H */
|
||||
108
app/src/au/dbio/au_limit_dbio.pgc
Normal file
108
app/src/au/dbio/au_limit_dbio.pgc
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* au_limit_dbio.pgc - 카드 한도(card_limit) + 승인 일집계 DB 접근 (libaudbio.a).
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <userlog.h>
|
||||
#include "au_dbio.h"
|
||||
|
||||
int audb_limit_get(const char *card, long *limit_out, long *used_out)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_limit, h_used;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_card, card, sizeof(h_card) - 1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT daily_limit, used_amount INTO :h_limit, :h_used
|
||||
FROM card_limit WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) {
|
||||
userlog("audb_limit_get FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
*limit_out = h_limit;
|
||||
*used_out = h_used;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int audb_limit_dec(const char *card, long amount)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_amount = amount;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_card, card, sizeof(h_card) - 1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL UPDATE card_limit SET used_amount = used_amount + :h_amount, updated_at = now()
|
||||
WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) {
|
||||
userlog("audb_limit_dec FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int audb_limit_reset(const char *card)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_card, card, sizeof(h_card) - 1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL UPDATE card_limit SET used_amount = 0, updated_at = now()
|
||||
WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) {
|
||||
userlog("audb_limit_reset FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int audb_limit_set(const char *card, long limit)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_limit = limit;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_card, card, sizeof(h_card) - 1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL INSERT INTO card_limit (card_no, daily_limit, used_amount)
|
||||
VALUES (:h_card, :h_limit, 0)
|
||||
ON CONFLICT (card_no) DO UPDATE
|
||||
SET daily_limit = EXCLUDED.daily_limit, updated_at = now();
|
||||
if (sqlca.sqlcode < 0) {
|
||||
userlog("audb_limit_set FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int audb_upsert_auth_summary(const char *merch, const char *bizdate, long cnt,
|
||||
long approved, long declined, long amount)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt = cnt, h_appr = approved, h_dec = declined, h_amt = amount;
|
||||
char h_merch[64], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_merch, merch, sizeof(h_merch) - 1); h_merch[sizeof(h_merch)-1] = 0;
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate) - 1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
EXEC SQL INSERT INTO au_summary
|
||||
(merchant_id, biz_date, auth_count, approve_count, decline_count, auth_amount)
|
||||
VALUES (:h_merch, :h_bizdate, :h_cnt, :h_appr, :h_dec, :h_amt)
|
||||
ON CONFLICT (merchant_id, biz_date) DO UPDATE
|
||||
SET auth_count = au_summary.auth_count + EXCLUDED.auth_count,
|
||||
approve_count = au_summary.approve_count + EXCLUDED.approve_count,
|
||||
decline_count = au_summary.decline_count + EXCLUDED.decline_count,
|
||||
auth_amount = au_summary.auth_amount + EXCLUDED.auth_amount,
|
||||
updated_at = now();
|
||||
if (sqlca.sqlcode < 0) {
|
||||
userlog("audb_upsert_auth_summary FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue