Phase 2c: 전 11모듈 per-service 레거시 구조 분해·확장 (실동작 유지)
- 10개 모듈(au py rc st lg cl mm vl mg cm)을 ac 템플릿대로 분해: svc/ 30 서비스 .pgc + 카피북 .h, 얇은 <mod>_svr 디스패처 dbio/ ~25 .pgc(+.h), batch/ ~17 .pgc, run/ ~17 .sh (모듈마다) - 파일: svc 330 + dbio 276 + batch 187 + run 187, 총 소스 1602본 - 서비스별 고유 실로직(정규화 md5), build.sh 자동발견(inline/split 양립) - 통합 검증: build DONE modules=11 servers=11 batches=187, 12서버 runok, 333 서비스 AVAIL, 매입체인 XA 커밋(status=S), prepared_xacts=0 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c3b99a8b75
commit
fd8b418c6e
1404 changed files with 30322 additions and 5994 deletions
|
|
@ -1,53 +1,56 @@
|
|||
/*
|
||||
* au_svr.pgc - au (승인/한도) MODULE SERVER.
|
||||
* au_svr.pgc - au (승인/한도) MODULE SERVER (thin dispatcher).
|
||||
*
|
||||
* 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.
|
||||
* The legacy "one module server, many services" pattern: this binary owns NO
|
||||
* business logic. Each of au's ~30 online services now lives in its own file
|
||||
* (app/src/au/svc/<SVCNAME>.pgc) with its own copybook header
|
||||
* (app/src/au/svc/<SVCNAME>.h); those objects are archived into libausvc.a and
|
||||
* linked into this server. Here we only:
|
||||
* - include every service copybook (for the extern prototypes),
|
||||
* - tpopen() the ECPG XA RM,
|
||||
* - tpadvertise() all services from a {name, fn} table,
|
||||
* - tpclose() at shutdown.
|
||||
*
|
||||
* 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.
|
||||
* XA: the connection is opened once by tpopen() (ECPG XA switch libndrxxaecpg.so);
|
||||
* there is NO EXEC SQL CONNECT. Each tpcall runs 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); }
|
||||
/* every au service's copybook header (declares its record struct + prototype) */
|
||||
#include "AUTH.h"
|
||||
#include "AUTH_CANCEL.h"
|
||||
#include "AUTH_PARTCXL.h"
|
||||
#include "LIMIT_CHK.h"
|
||||
#include "LIMIT_DEC.h"
|
||||
#include "LIMIT_RST.h"
|
||||
#include "LIMIT_INQ.h"
|
||||
#include "STANDIN.h"
|
||||
#include "FRAUD_DETECT.h"
|
||||
#include "AUTH_RETRY.h"
|
||||
#include "INSTALL_AUTH.h"
|
||||
#include "AUTH_STATUS.h"
|
||||
#include "AUTH_REVERSE.h"
|
||||
#include "AUTH_APPROVE.h"
|
||||
#include "AUTH_DECLINE.h"
|
||||
#include "CARD_VALIDATE.h"
|
||||
#include "VELOCITY_CHK.h"
|
||||
#include "BLACKLIST_CHK.h"
|
||||
#include "AUTH_HOLD.h"
|
||||
#include "AUTH_RELEASE.h"
|
||||
#include "AUTH_HISTORY.h"
|
||||
#include "LIMIT_SET.h"
|
||||
#include "LIMIT_TEMP.h"
|
||||
#include "AUTH_SUMMARY.h"
|
||||
#include "AUTH_ROUTE.h"
|
||||
#include "DCC_QUOTE.h"
|
||||
#include "AUTH_CAPTURE.h"
|
||||
#include "PREAUTH.h"
|
||||
#include "PREAUTH_COMPLETE.h"
|
||||
#include "AUTH_VOID.h"
|
||||
|
||||
#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) ------------- */
|
||||
/* ----- advertise table: {service name, function} (fn is extern from its file) */
|
||||
static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
|
||||
{"AUTH", AUTH}, {"AUTH_CANCEL", AUTH_CANCEL},
|
||||
{"AUTH_PARTCXL", AUTH_PARTCXL}, {"LIMIT_CHK", LIMIT_CHK},
|
||||
|
|
@ -90,571 +93,4 @@ void tpsvrdone(void)
|
|||
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: */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue