규모확장 Wave B: 전 11모듈 svc 75→133·batch 35→46 (BAIS 온라인 1:1)
- svc 825→1,463 (모듈당 133), batch 385→506 (모듈당 46) — 전부 새 고유 실업무 로직 + 카피북 헤더, 디스패처 133 advertise, 한글 기능설명(매니페스트 추출) - BAIS As-Is 대비: 온라인 1,463 vs 1,466(99.8%), 배치 506 vs 503(초과) - 화면 매니페스트 1,463 재생성 - 검증: build DONE modules=11 batches=506, 12서버 runok, xadmin psc 1,466 AVAIL, 매입체인 XA 커밋, 신규서비스 실데이터 스모크, 전 코퍼스 .pgc 클론 0 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ea90bef264
commit
c62d91b7a7
1526 changed files with 59213 additions and 12 deletions
|
|
@ -94,6 +94,65 @@
|
|||
#include "RISK_SCORE_INQ.h"
|
||||
#include "APPROVAL_RATE.h"
|
||||
#include "AUTH_DUP_CHK.h"
|
||||
/* --- scale-out services (승인/한도 심화) --- */
|
||||
#include "LIMIT_MONTH_CHK.h"
|
||||
#include "LIMIT_MONTH_INQ.h"
|
||||
#include "LIMIT_PERTX_CHK.h"
|
||||
#include "LIMIT_CUMUL_INQ.h"
|
||||
#include "LIMIT_DAILY_INQ.h"
|
||||
#include "LIMIT_ADJUST.h"
|
||||
#include "LIMIT_FREEZE.h"
|
||||
#include "LIMIT_UNFREEZE.h"
|
||||
#include "LIMIT_TIER_INQ.h"
|
||||
#include "LIMIT_OVER_ALERT.h"
|
||||
#include "CARD_LOST_REG.h"
|
||||
#include "CARD_STOLEN_REG.h"
|
||||
#include "CARD_REACTIVATE.h"
|
||||
#include "CARD_STATE_HIST.h"
|
||||
#include "CARD_EXPIRE_CHK.h"
|
||||
#include "CARD_ACTIVATE.h"
|
||||
#include "CHANNEL_POLICY.h"
|
||||
#include "BRAND_POLICY.h"
|
||||
#include "MCC_POLICY.h"
|
||||
#include "CHANNEL_STAT.h"
|
||||
#include "BRAND_AUTH_STAT.h"
|
||||
#include "MCC_AUTH_STAT.h"
|
||||
#include "AUTH_PARTAPPR.h"
|
||||
#include "PREAUTH_PARTUSE.h"
|
||||
#include "CANCEL_AMT_INQ.h"
|
||||
#include "CANCEL_FULL.h"
|
||||
#include "CANCEL_HISTORY.h"
|
||||
#include "CANCEL_SUMMARY.h"
|
||||
#include "VELOCITY_DAY.h"
|
||||
#include "VELOCITY_AMT.h"
|
||||
#include "VELOCITY_MCC.h"
|
||||
#include "VELOCITY_CHAN.h"
|
||||
#include "VELOCITY_RESET.h"
|
||||
#include "FRAUD_RULE_NIGHT.h"
|
||||
#include "FRAUD_RULE_INTL.h"
|
||||
#include "FRAUD_RULE_MCC.h"
|
||||
#include "FRAUD_SCORE_SUM.h"
|
||||
#include "FRAUD_CASE_CLOSE.h"
|
||||
#include "FRAUD_CASE_LIST.h"
|
||||
#include "WHITELIST_ADD.h"
|
||||
#include "WHITELIST_DEL.h"
|
||||
#include "WHITELIST_CHK.h"
|
||||
#include "BLACKLIST_COUNT.h"
|
||||
#include "BLACKLIST_PROMO.h"
|
||||
#include "TOKEN_ISSUE.h"
|
||||
#include "TOKEN_REVOKE.h"
|
||||
#include "TOKEN_INQ.h"
|
||||
#include "KEY_ROTATE_LOG.h"
|
||||
#include "STANDIN_STAT.h"
|
||||
#include "STANDIN_RECON.h"
|
||||
#include "STANDIN_LIMIT.h"
|
||||
#include "STAT_DECLINE.h"
|
||||
#include "STAT_DAILY_SUM.h"
|
||||
#include "STAT_AMT_BAND.h"
|
||||
#include "STAT_APPROVE_TR.h"
|
||||
#include "AUTH_REPROC_REQ.h"
|
||||
#include "AUTH_REPROC_STAT.h"
|
||||
#include "LIMIT_EXHAUST_LST.h"
|
||||
|
||||
/* ----- advertise table: {service name, function} (fn is extern from its file) */
|
||||
static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
|
||||
|
|
@ -135,6 +194,36 @@ static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
|
|||
{"MERCH_AUTH_RANK", MERCH_AUTH_RANK}, {"CARD_DAILY_RPT", CARD_DAILY_RPT},
|
||||
{"RISK_SCORE_INQ", RISK_SCORE_INQ}, {"APPROVAL_RATE", APPROVAL_RATE},
|
||||
{"AUTH_DUP_CHK", AUTH_DUP_CHK},
|
||||
/* --- scale-out services (승인/한도 심화) --- */
|
||||
{"LIMIT_MONTH_CHK", LIMIT_MONTH_CHK}, {"LIMIT_MONTH_INQ", LIMIT_MONTH_INQ},
|
||||
{"LIMIT_PERTX_CHK", LIMIT_PERTX_CHK}, {"LIMIT_CUMUL_INQ", LIMIT_CUMUL_INQ},
|
||||
{"LIMIT_DAILY_INQ", LIMIT_DAILY_INQ}, {"LIMIT_ADJUST", LIMIT_ADJUST},
|
||||
{"LIMIT_FREEZE", LIMIT_FREEZE}, {"LIMIT_UNFREEZE", LIMIT_UNFREEZE},
|
||||
{"LIMIT_TIER_INQ", LIMIT_TIER_INQ}, {"LIMIT_OVER_ALERT", LIMIT_OVER_ALERT},
|
||||
{"CARD_LOST_REG", CARD_LOST_REG}, {"CARD_STOLEN_REG", CARD_STOLEN_REG},
|
||||
{"CARD_REACTIVATE", CARD_REACTIVATE}, {"CARD_STATE_HIST", CARD_STATE_HIST},
|
||||
{"CARD_EXPIRE_CHK", CARD_EXPIRE_CHK}, {"CARD_ACTIVATE", CARD_ACTIVATE},
|
||||
{"CHANNEL_POLICY", CHANNEL_POLICY}, {"BRAND_POLICY", BRAND_POLICY},
|
||||
{"MCC_POLICY", MCC_POLICY}, {"CHANNEL_STAT", CHANNEL_STAT},
|
||||
{"BRAND_AUTH_STAT", BRAND_AUTH_STAT}, {"MCC_AUTH_STAT", MCC_AUTH_STAT},
|
||||
{"AUTH_PARTAPPR", AUTH_PARTAPPR}, {"PREAUTH_PARTUSE", PREAUTH_PARTUSE},
|
||||
{"CANCEL_AMT_INQ", CANCEL_AMT_INQ}, {"CANCEL_FULL", CANCEL_FULL},
|
||||
{"CANCEL_HISTORY", CANCEL_HISTORY}, {"CANCEL_SUMMARY", CANCEL_SUMMARY},
|
||||
{"VELOCITY_DAY", VELOCITY_DAY}, {"VELOCITY_AMT", VELOCITY_AMT},
|
||||
{"VELOCITY_MCC", VELOCITY_MCC}, {"VELOCITY_CHAN", VELOCITY_CHAN},
|
||||
{"VELOCITY_RESET", VELOCITY_RESET}, {"FRAUD_RULE_NIGHT", FRAUD_RULE_NIGHT},
|
||||
{"FRAUD_RULE_INTL", FRAUD_RULE_INTL}, {"FRAUD_RULE_MCC", FRAUD_RULE_MCC},
|
||||
{"FRAUD_SCORE_SUM", FRAUD_SCORE_SUM}, {"FRAUD_CASE_CLOSE", FRAUD_CASE_CLOSE},
|
||||
{"FRAUD_CASE_LIST", FRAUD_CASE_LIST}, {"WHITELIST_ADD", WHITELIST_ADD},
|
||||
{"WHITELIST_DEL", WHITELIST_DEL}, {"WHITELIST_CHK", WHITELIST_CHK},
|
||||
{"BLACKLIST_COUNT", BLACKLIST_COUNT}, {"BLACKLIST_PROMO", BLACKLIST_PROMO},
|
||||
{"TOKEN_ISSUE", TOKEN_ISSUE}, {"TOKEN_REVOKE", TOKEN_REVOKE},
|
||||
{"TOKEN_INQ", TOKEN_INQ}, {"KEY_ROTATE_LOG", KEY_ROTATE_LOG},
|
||||
{"STANDIN_STAT", STANDIN_STAT}, {"STANDIN_RECON", STANDIN_RECON},
|
||||
{"STANDIN_LIMIT", STANDIN_LIMIT}, {"STAT_DECLINE", STAT_DECLINE},
|
||||
{"STAT_DAILY_SUM", STAT_DAILY_SUM}, {"STAT_AMT_BAND", STAT_AMT_BAND},
|
||||
{"STAT_APPROVE_TR", STAT_APPROVE_TR}, {"AUTH_REPROC_REQ", AUTH_REPROC_REQ},
|
||||
{"AUTH_REPROC_STAT", AUTH_REPROC_STAT}, {"LIMIT_EXHAUST_LST", LIMIT_EXHAUST_LST},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
|||
16
app/src/au/batch/au_brand_mix_batch.h
Normal file
16
app/src/au/batch/au_brand_mix_batch.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* au_brand_mix_batch.h - au 배치 au_brand_mix_batch 카피북 (batch copybook / record layout).
|
||||
* 배치가 EXEC SQL INCLUDE 로 인라인하는 레코드 구조 정의. 런타임 인클루드는
|
||||
* 배치 본문(.pgc)이 직접 가진다. dbio(libaudbio.a) 경유, XA 브랜치 실행.
|
||||
*/
|
||||
#ifndef AU_BRAND_MIX_BATCH_H
|
||||
#define AU_BRAND_MIX_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
char biz_date[16];
|
||||
long amount;
|
||||
long rows;
|
||||
} au_au_brand_mix_batch_rec_t;
|
||||
|
||||
#endif /* AU_BRAND_MIX_BATCH_H */
|
||||
54
app/src/au/batch/au_brand_mix_batch.pgc
Normal file
54
app/src/au/batch/au_brand_mix_batch.pgc
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* au_brand_mix_batch.pgc - au 브랜드별 승인 믹스 집계 배치 (substr GROUP BY 커서 + XA).
|
||||
*
|
||||
* Groups the day's authorizations by card brand (leading digit) reporting count
|
||||
* and amount, and accumulates the top brand by amount, under one global XA
|
||||
* transaction. Read-only report. Usage: au_brand_mix_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "au_dbio.h"
|
||||
EXEC SQL INCLUDE au_brand_mix_batch;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
long total = 0, top_amt = 0;
|
||||
char top_lead[4] = "";
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_lead[4];
|
||||
long h_cnt, 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 bmx CURSOR FOR
|
||||
SELECT substr(card_no, 1, 1), count(*), coalesce(sum(amount),0)
|
||||
FROM au_authorization
|
||||
WHERE biz_date = :h_bizdate AND status IN ('A','M','S')
|
||||
GROUP BY substr(card_no, 1, 1) ORDER BY coalesce(sum(amount),0) DESC;
|
||||
EXEC SQL OPEN bmx;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH bmx INTO :h_lead, :h_cnt, :h_amt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d]\n", sqlca.sqlcode); EXEC SQL CLOSE bmx; tpabort(0); return 1; }
|
||||
total += h_cnt;
|
||||
if (h_amt > top_amt) { top_amt = h_amt; strncpy(top_lead, h_lead, sizeof(top_lead)-1); }
|
||||
printf(" brand_lead=%s cnt=%ld amt=%ld\n", h_lead, h_cnt, h_amt);
|
||||
}
|
||||
EXEC SQL CLOSE bmx;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> au_brand_mix_batch COMMIT: bizdate=%s total=%ld top_lead=%s top_amt=%ld\n",
|
||||
bizdate, total, top_lead, top_amt);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
16
app/src/au/batch/au_card_dormant_batch.h
Normal file
16
app/src/au/batch/au_card_dormant_batch.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* au_card_dormant_batch.h - au 배치 au_card_dormant_batch 카피북 (batch copybook / record layout).
|
||||
* 배치가 EXEC SQL INCLUDE 로 인라인하는 레코드 구조 정의. 런타임 인클루드는
|
||||
* 배치 본문(.pgc)이 직접 가진다. dbio(libaudbio.a) 경유, XA 브랜치 실행.
|
||||
*/
|
||||
#ifndef AU_CARD_DORMANT_BATCH_H
|
||||
#define AU_CARD_DORMANT_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
char biz_date[16];
|
||||
long amount;
|
||||
long rows;
|
||||
} au_au_card_dormant_batch_rec_t;
|
||||
|
||||
#endif /* AU_CARD_DORMANT_BATCH_H */
|
||||
43
app/src/au/batch/au_card_dormant_batch.pgc
Normal file
43
app/src/au/batch/au_card_dormant_batch.pgc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* au_card_dormant_batch.pgc - au 휴면 카드 일괄 표시 배치 (집합 UPDATE + XA).
|
||||
*
|
||||
* Counts, then set-updates every ACTIVE card with no authorization in the last
|
||||
* 90 days to status DORMANT in a single UPDATE, under one global XA transaction.
|
||||
* No cursor, no dbio. Usage: au_card_dormant_batch
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "au_dbio.h"
|
||||
EXEC SQL INCLUDE au_card_dormant_batch;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cand = 0;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
(void)argc; (void)argv;
|
||||
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 SELECT count(*) INTO :h_cand FROM card_limit
|
||||
WHERE status = 'ACTIVE'
|
||||
AND card_no NOT IN (SELECT DISTINCT card_no FROM au_authorization
|
||||
WHERE created_at >= now() - interval '90 days');
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "SELECT FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
|
||||
EXEC SQL UPDATE card_limit SET status = 'DORMANT', updated_at = now()
|
||||
WHERE status = 'ACTIVE'
|
||||
AND card_no NOT IN (SELECT DISTINCT card_no FROM au_authorization
|
||||
WHERE created_at >= now() - interval '90 days');
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "UPDATE FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> au_card_dormant_batch COMMIT: dormant_marked=%ld\n", h_cand);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
16
app/src/au/batch/au_channel_stat_batch.h
Normal file
16
app/src/au/batch/au_channel_stat_batch.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* au_channel_stat_batch.h - au 배치 au_channel_stat_batch 카피북 (batch copybook / record layout).
|
||||
* 배치가 EXEC SQL INCLUDE 로 인라인하는 레코드 구조 정의. 런타임 인클루드는
|
||||
* 배치 본문(.pgc)이 직접 가진다. dbio(libaudbio.a) 경유, XA 브랜치 실행.
|
||||
*/
|
||||
#ifndef AU_CHANNEL_STAT_BATCH_H
|
||||
#define AU_CHANNEL_STAT_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
char biz_date[16];
|
||||
long amount;
|
||||
long rows;
|
||||
} au_au_channel_stat_batch_rec_t;
|
||||
|
||||
#endif /* AU_CHANNEL_STAT_BATCH_H */
|
||||
52
app/src/au/batch/au_channel_stat_batch.pgc
Normal file
52
app/src/au/batch/au_channel_stat_batch.pgc
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* au_channel_stat_batch.pgc - au 채널별 매입 집계 배치 (GROUP BY 커서 + XA).
|
||||
*
|
||||
* Reports per-channel count / sum / average purchase amount for a business day,
|
||||
* scanning a GROUP BY cursor under one global XA transaction. Read-only report.
|
||||
* Usage: au_channel_stat_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "au_dbio.h"
|
||||
EXEC SQL INCLUDE au_channel_stat_batch;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
long chans = 0, total = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_chan[16];
|
||||
long h_cnt, h_sum, h_avg;
|
||||
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 cstb CURSOR FOR
|
||||
SELECT channel, count(*), coalesce(sum(amount),0),
|
||||
CAST(coalesce(avg(amount),0) AS bigint)
|
||||
FROM purchase WHERE biz_date = :h_bizdate
|
||||
GROUP BY channel ORDER BY count(*) DESC;
|
||||
EXEC SQL OPEN cstb;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH cstb INTO :h_chan, :h_cnt, :h_sum, :h_avg;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d]\n", sqlca.sqlcode); EXEC SQL CLOSE cstb; tpabort(0); return 1; }
|
||||
chans++;
|
||||
total += h_cnt;
|
||||
printf(" channel=%s cnt=%ld sum=%ld avg=%ld\n", h_chan, h_cnt, h_sum, h_avg);
|
||||
}
|
||||
EXEC SQL CLOSE cstb;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> au_channel_stat_batch COMMIT: bizdate=%s channels=%ld total=%ld\n", bizdate, chans, total);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
16
app/src/au/batch/au_exhaust_alert_batch.h
Normal file
16
app/src/au/batch/au_exhaust_alert_batch.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* au_exhaust_alert_batch.h - au 배치 au_exhaust_alert_batch 카피북 (batch copybook / record layout).
|
||||
* 배치가 EXEC SQL INCLUDE 로 인라인하는 레코드 구조 정의. 런타임 인클루드는
|
||||
* 배치 본문(.pgc)이 직접 가진다. dbio(libaudbio.a) 경유, XA 브랜치 실행.
|
||||
*/
|
||||
#ifndef AU_EXHAUST_ALERT_BATCH_H
|
||||
#define AU_EXHAUST_ALERT_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
char biz_date[16];
|
||||
long amount;
|
||||
long rows;
|
||||
} au_au_exhaust_alert_batch_rec_t;
|
||||
|
||||
#endif /* AU_EXHAUST_ALERT_BATCH_H */
|
||||
50
app/src/au/batch/au_exhaust_alert_batch.pgc
Normal file
50
app/src/au/batch/au_exhaust_alert_batch.pgc
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* au_exhaust_alert_batch.pgc - au 한도 소진 경보 로그 배치 (커서 + userlog + XA).
|
||||
*
|
||||
* Cursor-scans cards that have burned >= 90% of their daily limit and emits a
|
||||
* userlog alert for each, counting alerts, under one global XA transaction.
|
||||
* No dbio writes. Usage: au_exhaust_alert_batch
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "au_dbio.h"
|
||||
EXEC SQL INCLUDE au_exhaust_alert_batch;
|
||||
#include <userlog.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
long alerts = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_card[24];
|
||||
long h_bps;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
(void)argc; (void)argv;
|
||||
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 exa CURSOR FOR
|
||||
SELECT card_no, used_amount * 10000 / daily_limit
|
||||
FROM card_limit
|
||||
WHERE daily_limit > 0 AND used_amount * 10 >= daily_limit * 9
|
||||
ORDER BY used_amount * 10000 / daily_limit DESC;
|
||||
EXEC SQL OPEN exa;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH exa INTO :h_card, :h_bps;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d]\n", sqlca.sqlcode); EXEC SQL CLOSE exa; tpabort(0); return 1; }
|
||||
userlog("au_exhaust_alert 소진임박 card=%s %ldbps", h_card, h_bps);
|
||||
alerts++;
|
||||
}
|
||||
EXEC SQL CLOSE exa;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> au_exhaust_alert_batch COMMIT: alerts=%ld\n", alerts);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
16
app/src/au/batch/au_mcc_risk_batch.h
Normal file
16
app/src/au/batch/au_mcc_risk_batch.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* au_mcc_risk_batch.h - au 배치 au_mcc_risk_batch 카피북 (batch copybook / record layout).
|
||||
* 배치가 EXEC SQL INCLUDE 로 인라인하는 레코드 구조 정의. 런타임 인클루드는
|
||||
* 배치 본문(.pgc)이 직접 가진다. dbio(libaudbio.a) 경유, XA 브랜치 실행.
|
||||
*/
|
||||
#ifndef AU_MCC_RISK_BATCH_H
|
||||
#define AU_MCC_RISK_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
char biz_date[16];
|
||||
long amount;
|
||||
long rows;
|
||||
} au_au_mcc_risk_batch_rec_t;
|
||||
|
||||
#endif /* AU_MCC_RISK_BATCH_H */
|
||||
52
app/src/au/batch/au_mcc_risk_batch.pgc
Normal file
52
app/src/au/batch/au_mcc_risk_batch.pgc
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* au_mcc_risk_batch.pgc - au 고위험 업종 매입 집계 배치 (GROUP BY HAVING 커서 + XA).
|
||||
*
|
||||
* Reports categories whose day's purchase volume exceeds 3,000,000 (HAVING),
|
||||
* scanning count/sum/max per category under one global XA transaction. Read-only
|
||||
* report. Usage: au_mcc_risk_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "au_dbio.h"
|
||||
EXEC SQL INCLUDE au_mcc_risk_batch;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
long groups = 0, grand = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_cat[32];
|
||||
long h_cnt, h_sum, h_max;
|
||||
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 mrk CURSOR FOR
|
||||
SELECT category, count(*), coalesce(sum(amount),0), coalesce(max(amount),0)
|
||||
FROM purchase WHERE biz_date = :h_bizdate
|
||||
GROUP BY category HAVING coalesce(sum(amount),0) > 3000000
|
||||
ORDER BY coalesce(sum(amount),0) DESC;
|
||||
EXEC SQL OPEN mrk;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH mrk INTO :h_cat, :h_cnt, :h_sum, :h_max;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d]\n", sqlca.sqlcode); EXEC SQL CLOSE mrk; tpabort(0); return 1; }
|
||||
groups++;
|
||||
grand += h_sum;
|
||||
printf(" risk category=%s cnt=%ld sum=%ld max=%ld\n", h_cat, h_cnt, h_sum, h_max);
|
||||
}
|
||||
EXEC SQL CLOSE mrk;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> au_mcc_risk_batch COMMIT: bizdate=%s risk_groups=%ld grand=%ld\n", bizdate, groups, grand);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
16
app/src/au/batch/au_month_limit_batch.h
Normal file
16
app/src/au/batch/au_month_limit_batch.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* au_month_limit_batch.h - au 배치 au_month_limit_batch 카피북 (batch copybook / record layout).
|
||||
* 배치가 EXEC SQL INCLUDE 로 인라인하는 레코드 구조 정의. 런타임 인클루드는
|
||||
* 배치 본문(.pgc)이 직접 가진다. dbio(libaudbio.a) 경유, XA 브랜치 실행.
|
||||
*/
|
||||
#ifndef AU_MONTH_LIMIT_BATCH_H
|
||||
#define AU_MONTH_LIMIT_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
char biz_date[16];
|
||||
long amount;
|
||||
long rows;
|
||||
} au_au_month_limit_batch_rec_t;
|
||||
|
||||
#endif /* AU_MONTH_LIMIT_BATCH_H */
|
||||
37
app/src/au/batch/au_month_limit_batch.pgc
Normal file
37
app/src/au/batch/au_month_limit_batch.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* au_month_limit_batch.pgc - au 월 한도 소진 카드 집계 배치 (단일 집계 + XA).
|
||||
*
|
||||
* Aggregates in ONE query how many active cards have burned >= 80% of their
|
||||
* daily limit and their total used amount, under one global XA transaction.
|
||||
* No cursor. Usage: au_month_limit_batch
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "au_dbio.h"
|
||||
EXEC SQL INCLUDE au_month_limit_batch;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cards = 0, h_used = 0;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
(void)argc; (void)argv;
|
||||
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 SELECT count(*), coalesce(sum(used_amount),0)
|
||||
INTO :h_cards, :h_used
|
||||
FROM card_limit
|
||||
WHERE daily_limit > 0 AND used_amount * 100 >= daily_limit * 80;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "SELECT FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> au_month_limit_batch COMMIT: cards_over80=%ld used_total=%ld\n", h_cards, h_used);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
16
app/src/au/batch/au_pertx_audit_batch.h
Normal file
16
app/src/au/batch/au_pertx_audit_batch.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* au_pertx_audit_batch.h - au 배치 au_pertx_audit_batch 카피북 (batch copybook / record layout).
|
||||
* 배치가 EXEC SQL INCLUDE 로 인라인하는 레코드 구조 정의. 런타임 인클루드는
|
||||
* 배치 본문(.pgc)이 직접 가진다. dbio(libaudbio.a) 경유, XA 브랜치 실행.
|
||||
*/
|
||||
#ifndef AU_PERTX_AUDIT_BATCH_H
|
||||
#define AU_PERTX_AUDIT_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
char biz_date[16];
|
||||
long amount;
|
||||
long rows;
|
||||
} au_au_pertx_audit_batch_rec_t;
|
||||
|
||||
#endif /* AU_PERTX_AUDIT_BATCH_H */
|
||||
51
app/src/au/batch/au_pertx_audit_batch.pgc
Normal file
51
app/src/au/batch/au_pertx_audit_batch.pgc
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* au_pertx_audit_batch.pgc - au 건별 한도 초과 승인 감사 배치 (JOIN 커서 + XA).
|
||||
*
|
||||
* Joins the day's authorizations to card_limit and, for single transactions
|
||||
* exceeding 20% of the daily limit (per-tx cap), logs a fraud row via dbio,
|
||||
* all under ONE global XA transaction. Usage: au_pertx_audit_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "au_dbio.h"
|
||||
EXEC SQL INCLUDE au_pertx_audit_batch;
|
||||
|
||||
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], h_card[24];
|
||||
long 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 pxa CURSOR FOR
|
||||
SELECT a.card_no, a.amount
|
||||
FROM au_authorization a JOIN card_limit l ON l.card_no = a.card_no
|
||||
WHERE a.biz_date = :h_bizdate AND a.amount > l.daily_limit / 5
|
||||
ORDER BY a.amount DESC;
|
||||
EXEC SQL OPEN pxa;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH pxa INTO :h_card, :h_amt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d]\n", sqlca.sqlcode); EXEC SQL CLOSE pxa; tpabort(0); return 1; }
|
||||
if (audb_insert_fraud(0, h_card, 500, "PERTX_OVER", bizdate) < 0) { EXEC SQL CLOSE pxa; tpabort(0); return 1; }
|
||||
rows++;
|
||||
}
|
||||
EXEC SQL CLOSE pxa;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> au_pertx_audit_batch COMMIT: bizdate=%s flagged=%ld\n", bizdate, rows);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
16
app/src/au/batch/au_reproc_queue_batch.h
Normal file
16
app/src/au/batch/au_reproc_queue_batch.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* au_reproc_queue_batch.h - au 배치 au_reproc_queue_batch 카피북 (batch copybook / record layout).
|
||||
* 배치가 EXEC SQL INCLUDE 로 인라인하는 레코드 구조 정의. 런타임 인클루드는
|
||||
* 배치 본문(.pgc)이 직접 가진다. dbio(libaudbio.a) 경유, XA 브랜치 실행.
|
||||
*/
|
||||
#ifndef AU_REPROC_QUEUE_BATCH_H
|
||||
#define AU_REPROC_QUEUE_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
char biz_date[16];
|
||||
long amount;
|
||||
long rows;
|
||||
} au_au_reproc_queue_batch_rec_t;
|
||||
|
||||
#endif /* AU_REPROC_QUEUE_BATCH_H */
|
||||
49
app/src/au/batch/au_reproc_queue_batch.pgc
Normal file
49
app/src/au/batch/au_reproc_queue_batch.pgc
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* au_reproc_queue_batch.pgc - au 보류 승인 재처리 큐 배치 (커서 + dbio + XA).
|
||||
*
|
||||
* Cursor-scans the day's HELD (H) authorizations and re-approves each by driving
|
||||
* the dbio status transition to A, under one global XA transaction.
|
||||
* Usage: au_reproc_queue_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "au_dbio.h"
|
||||
EXEC SQL INCLUDE au_reproc_queue_batch;
|
||||
|
||||
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;
|
||||
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 rpq CURSOR FOR
|
||||
SELECT auth_id FROM au_authorization
|
||||
WHERE biz_date = :h_bizdate AND status = 'H' ORDER BY auth_id;
|
||||
EXEC SQL OPEN rpq;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH rpq INTO :h_auth;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d]\n", sqlca.sqlcode); EXEC SQL CLOSE rpq; tpabort(0); return 1; }
|
||||
if (audb_update_auth_status(h_auth, "A") < 0) { EXEC SQL CLOSE rpq; tpabort(0); return 1; }
|
||||
rows++;
|
||||
}
|
||||
EXEC SQL CLOSE rpq;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> au_reproc_queue_batch COMMIT: bizdate=%s reprocessed=%ld\n", bizdate, rows);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
16
app/src/au/batch/au_stolen_sweep_batch.h
Normal file
16
app/src/au/batch/au_stolen_sweep_batch.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* au_stolen_sweep_batch.h - au 배치 au_stolen_sweep_batch 카피북 (batch copybook / record layout).
|
||||
* 배치가 EXEC SQL INCLUDE 로 인라인하는 레코드 구조 정의. 런타임 인클루드는
|
||||
* 배치 본문(.pgc)이 직접 가진다. dbio(libaudbio.a) 경유, XA 브랜치 실행.
|
||||
*/
|
||||
#ifndef AU_STOLEN_SWEEP_BATCH_H
|
||||
#define AU_STOLEN_SWEEP_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
char biz_date[16];
|
||||
long amount;
|
||||
long rows;
|
||||
} au_au_stolen_sweep_batch_rec_t;
|
||||
|
||||
#endif /* AU_STOLEN_SWEEP_BATCH_H */
|
||||
48
app/src/au/batch/au_stolen_sweep_batch.pgc
Normal file
48
app/src/au/batch/au_stolen_sweep_batch.pgc
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* au_stolen_sweep_batch.pgc - au 도난/분실 카드 잔여승인 정리 배치 (커서 + XA).
|
||||
*
|
||||
* Cursor-scans blacklist entries flagged STOLEN/LOST and cancels each card's
|
||||
* still-open (A/H) authorizations with an inner UPDATE, under one global XA
|
||||
* transaction. Usage: au_stolen_sweep_batch
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "au_dbio.h"
|
||||
EXEC SQL INCLUDE au_stolen_sweep_batch;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
long cards = 0, cancelled = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
(void)argc; (void)argv;
|
||||
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 ssw CURSOR FOR
|
||||
SELECT card_no FROM au_blacklist WHERE reason IN ('STOLEN','LOST') ORDER BY card_no;
|
||||
EXEC SQL OPEN ssw;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH ssw INTO :h_card;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d]\n", sqlca.sqlcode); EXEC SQL CLOSE ssw; tpabort(0); return 1; }
|
||||
EXEC SQL UPDATE au_authorization SET status = 'C', updated_at = now()
|
||||
WHERE card_no = :h_card AND status IN ('A','H');
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE ssw; tpabort(0); return 1; }
|
||||
if (sqlca.sqlcode != 100) cancelled++;
|
||||
cards++;
|
||||
}
|
||||
EXEC SQL CLOSE ssw;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> au_stolen_sweep_batch COMMIT: cards=%ld cancelled_batches=%ld\n", cards, cancelled);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
16
app/src/au/batch/au_token_revoke_batch.h
Normal file
16
app/src/au/batch/au_token_revoke_batch.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* au_token_revoke_batch.h - au 배치 au_token_revoke_batch 카피북 (batch copybook / record layout).
|
||||
* 배치가 EXEC SQL INCLUDE 로 인라인하는 레코드 구조 정의. 런타임 인클루드는
|
||||
* 배치 본문(.pgc)이 직접 가진다. dbio(libaudbio.a) 경유, XA 브랜치 실행.
|
||||
*/
|
||||
#ifndef AU_TOKEN_REVOKE_BATCH_H
|
||||
#define AU_TOKEN_REVOKE_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
char biz_date[16];
|
||||
long amount;
|
||||
long rows;
|
||||
} au_au_token_revoke_batch_rec_t;
|
||||
|
||||
#endif /* AU_TOKEN_REVOKE_BATCH_H */
|
||||
49
app/src/au/batch/au_token_revoke_batch.pgc
Normal file
49
app/src/au/batch/au_token_revoke_batch.pgc
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* au_token_revoke_batch.pgc - au 폐기 토큰 카드 원장 표시 배치 (커서 + XA).
|
||||
*
|
||||
* Cursor-scans TOKEN_REVOKED blacklist rows (card + reason) and marks each
|
||||
* card_limit row REVOKED with an inner UPDATE, under one global XA transaction.
|
||||
* Usage: au_token_revoke_batch
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "au_dbio.h"
|
||||
EXEC SQL INCLUDE au_token_revoke_batch;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
long seen = 0, marked = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_card[24], h_reason[64];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
(void)argc; (void)argv;
|
||||
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 trv CURSOR FOR
|
||||
SELECT card_no, reason FROM au_blacklist
|
||||
WHERE reason = 'TOKEN_REVOKED' ORDER BY created_at;
|
||||
EXEC SQL OPEN trv;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH trv INTO :h_card, :h_reason;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d]\n", sqlca.sqlcode); EXEC SQL CLOSE trv; tpabort(0); return 1; }
|
||||
EXEC SQL UPDATE card_limit SET status = 'REVOKED', updated_at = now()
|
||||
WHERE card_no = :h_card AND status <> 'REVOKED';
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE trv; tpabort(0); return 1; }
|
||||
if (sqlca.sqlcode != 100) marked++;
|
||||
seen++;
|
||||
}
|
||||
EXEC SQL CLOSE trv;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> au_token_revoke_batch COMMIT: revoked_tokens=%ld cards_marked=%ld\n", seen, marked);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
16
app/src/au/batch/au_whitelist_clean_batch.h
Normal file
16
app/src/au/batch/au_whitelist_clean_batch.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* au_whitelist_clean_batch.h - au 배치 au_whitelist_clean_batch 카피북 (batch copybook / record layout).
|
||||
* 배치가 EXEC SQL INCLUDE 로 인라인하는 레코드 구조 정의. 런타임 인클루드는
|
||||
* 배치 본문(.pgc)이 직접 가진다. dbio(libaudbio.a) 경유, XA 브랜치 실행.
|
||||
*/
|
||||
#ifndef AU_WHITELIST_CLEAN_BATCH_H
|
||||
#define AU_WHITELIST_CLEAN_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
char biz_date[16];
|
||||
long amount;
|
||||
long rows;
|
||||
} au_au_whitelist_clean_batch_rec_t;
|
||||
|
||||
#endif /* AU_WHITELIST_CLEAN_BATCH_H */
|
||||
39
app/src/au/batch/au_whitelist_clean_batch.pgc
Normal file
39
app/src/au/batch/au_whitelist_clean_batch.pgc
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* au_whitelist_clean_batch.pgc - au 만료 폐기토큰 블랙 정리 배치 (집합 DELETE + XA).
|
||||
*
|
||||
* Counts, then set-deletes TOKEN_REVOKED blacklist rows older than 30 days in a
|
||||
* single DELETE (auto-whitelisting expired revocations), under one global XA
|
||||
* transaction. No cursor. Usage: au_whitelist_clean_batch
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "au_dbio.h"
|
||||
EXEC SQL INCLUDE au_whitelist_clean_batch;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_stale = 0;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
(void)argc; (void)argv;
|
||||
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 SELECT count(*) INTO :h_stale FROM au_blacklist
|
||||
WHERE reason = 'TOKEN_REVOKED' AND created_at < now() - interval '30 days';
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "SELECT FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
|
||||
EXEC SQL DELETE FROM au_blacklist
|
||||
WHERE reason = 'TOKEN_REVOKED' AND created_at < now() - interval '30 days';
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "DELETE FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> au_whitelist_clean_batch COMMIT: expired_revocations_cleared=%ld\n", h_stale);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
20
app/src/au/svc/AUTH_PARTAPPR.h
Normal file
20
app/src/au/svc/AUTH_PARTAPPR.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* AUTH_PARTAPPR.h - au 서비스 AUTH_PARTAPPR 카피북 (copybook / record header).
|
||||
* 요청: 카드/금액. 응답: 승인금액/부분승인여부
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef AUTH_PARTAPPR_H
|
||||
#define AUTH_PARTAPPR_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_auth_partappr_rec_t;
|
||||
|
||||
void AUTH_PARTAPPR(TPSVCINFO *p);
|
||||
|
||||
#endif /* AUTH_PARTAPPR_H */
|
||||
44
app/src/au/svc/AUTH_PARTAPPR.pgc
Normal file
44
app/src/au/svc/AUTH_PARTAPPR.pgc
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* AUTH_PARTAPPR.pgc - au 모듈 서비스 AUTH_PARTAPPR (one service = one file).
|
||||
* 부분 승인: 가용한도(일한도-사용액)가 요청액보다 작으면 가용한도만큼만
|
||||
* 승인해 원장에 기록하고 한도를 차감한다. 전액 RC=0, 부분 RC=1, 불가 RC=2.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "AUTH_PARTAPPR.h"
|
||||
|
||||
void AUTH_PARTAPPR(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], merch[64], bizdate[16];
|
||||
long amount, avail, appr, aid, rc;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_daily = 0, h_used = 0;
|
||||
char h_card[24];
|
||||
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));
|
||||
amount = getl(b, T_AMOUNT);
|
||||
if (card[0] == 0 || amount <= 0 || bizdate[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT daily_limit, used_amount INTO :h_daily, :h_used
|
||||
FROM card_limit WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
|
||||
avail = h_daily - h_used;
|
||||
if (avail <= 0) { setl(b, T_AMT1, 0); setl(b, T_RC, 2); OK(b); }
|
||||
|
||||
appr = (amount <= avail) ? amount : avail;
|
||||
rc = (appr == amount) ? 0 : 1;
|
||||
aid = audb_next_auth_id();
|
||||
if (aid < 0) FAIL(b);
|
||||
if (audb_insert_auth(aid, card, merch, appr, "PART", "AUTH", "A", bizdate) < 0) FAIL(b);
|
||||
if (audb_limit_dec(card, appr) < 0) FAIL(b);
|
||||
|
||||
setl(b, T_ID2, aid);
|
||||
setl(b, T_AMT1, appr);
|
||||
setl(b, T_RC, rc);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/AUTH_REPROC_REQ.h
Normal file
20
app/src/au/svc/AUTH_REPROC_REQ.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* AUTH_REPROC_REQ.h - au 서비스 AUTH_REPROC_REQ 카피북 (copybook / record header).
|
||||
* 요청: 승인ID. 응답: 재처리 결과
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef AUTH_REPROC_REQ_H
|
||||
#define AUTH_REPROC_REQ_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_auth_reproc_req_rec_t;
|
||||
|
||||
void AUTH_REPROC_REQ(TPSVCINFO *p);
|
||||
|
||||
#endif /* AUTH_REPROC_REQ_H */
|
||||
34
app/src/au/svc/AUTH_REPROC_REQ.pgc
Normal file
34
app/src/au/svc/AUTH_REPROC_REQ.pgc
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* AUTH_REPROC_REQ.pgc - au 모듈 서비스 AUTH_REPROC_REQ (one service = one file).
|
||||
* 승인 재처리 요청: 거절(D)/보류(H) 상태의 승인을 재처리 대상으로 다시
|
||||
* 승인(A)으로 되돌린다(재시도 워크플로 진입). 대상 아님이면 RC=1.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "AUTH_REPROC_REQ.h"
|
||||
|
||||
void AUTH_REPROC_REQ(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_auth;
|
||||
char h_old[4];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_auth = getl(b, T_ID2);
|
||||
if (h_auth <= 0) FAIL(b);
|
||||
memset(h_old, 0, sizeof(h_old));
|
||||
|
||||
EXEC SQL SELECT status INTO :h_old FROM au_authorization
|
||||
WHERE auth_id = :h_auth AND status IN ('D','H');
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
|
||||
|
||||
EXEC SQL UPDATE au_authorization SET status = 'A', updated_at = now()
|
||||
WHERE auth_id = :h_auth;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
userlog("AUTH_REPROC_REQ auth=%ld %s->A", h_auth, h_old);
|
||||
Bchg(b, T_STATUS, 0, h_old, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/AUTH_REPROC_STAT.h
Normal file
20
app/src/au/svc/AUTH_REPROC_STAT.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* AUTH_REPROC_STAT.h - au 서비스 AUTH_REPROC_STAT 카피북 (copybook / record header).
|
||||
* 요청: 영업일. 응답: 보류건수/재처리건수
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef AUTH_REPROC_STAT_H
|
||||
#define AUTH_REPROC_STAT_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_auth_reproc_stat_rec_t;
|
||||
|
||||
void AUTH_REPROC_STAT(TPSVCINFO *p);
|
||||
|
||||
#endif /* AUTH_REPROC_STAT_H */
|
||||
32
app/src/au/svc/AUTH_REPROC_STAT.pgc
Normal file
32
app/src/au/svc/AUTH_REPROC_STAT.pgc
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* AUTH_REPROC_STAT.pgc - au 모듈 서비스 AUTH_REPROC_STAT (one service = one file).
|
||||
* 재처리 현황: 영업일 승인 원장에서 보류(H) 대기 건수와, 갱신시각이 생성시각
|
||||
* 이후로 밀린(재처리·상태변경된) 건수를 집계해 재처리 큐 상태를 응답한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "AUTH_REPROC_STAT.h"
|
||||
|
||||
void AUTH_REPROC_STAT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_hold = 0, h_reproc = 0;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
if (bizdate[0] == 0) FAIL(b);
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT count(*) FILTER (WHERE status = 'H'),
|
||||
count(*) FILTER (WHERE updated_at > created_at)
|
||||
INTO :h_hold, :h_reproc
|
||||
FROM au_authorization WHERE biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
setl(b, T_ARG1, h_hold);
|
||||
setl(b, T_ARG2, h_reproc);
|
||||
setl(b, T_RC, (h_hold > 0) ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/BLACKLIST_COUNT.h
Normal file
20
app/src/au/svc/BLACKLIST_COUNT.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* BLACKLIST_COUNT.h - au 서비스 BLACKLIST_COUNT 카피북 (copybook / record header).
|
||||
* 요청: 없음. 응답: 총건수/도난건수/당일등재
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef BLACKLIST_COUNT_H
|
||||
#define BLACKLIST_COUNT_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_blacklist_count_rec_t;
|
||||
|
||||
void BLACKLIST_COUNT(TPSVCINFO *p);
|
||||
|
||||
#endif /* BLACKLIST_COUNT_H */
|
||||
27
app/src/au/svc/BLACKLIST_COUNT.pgc
Normal file
27
app/src/au/svc/BLACKLIST_COUNT.pgc
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* BLACKLIST_COUNT.pgc - au 모듈 서비스 BLACKLIST_COUNT (one service = one file).
|
||||
* 블랙리스트 통계: 전체 등재 수, 도난(REPORTED_STOLEN/STOLEN) 등재 수,
|
||||
* 당일 신규 등재 수를 한 번의 집계로 뽑아 대시보드용으로 응답한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "BLACKLIST_COUNT.h"
|
||||
|
||||
void BLACKLIST_COUNT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_total = 0, h_stolen = 0, h_today = 0;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
EXEC SQL SELECT count(*),
|
||||
count(*) FILTER (WHERE reason IN ('REPORTED_STOLEN','STOLEN')),
|
||||
count(*) FILTER (WHERE created_at >= current_date)
|
||||
INTO :h_total, :h_stolen, :h_today
|
||||
FROM au_blacklist;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
setl(b, T_COUNT, h_total);
|
||||
setl(b, T_ARG1, h_stolen);
|
||||
setl(b, T_ARG2, h_today);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/BLACKLIST_PROMO.h
Normal file
20
app/src/au/svc/BLACKLIST_PROMO.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* BLACKLIST_PROMO.h - au 서비스 BLACKLIST_PROMO 카피북 (copybook / record header).
|
||||
* 요청: 영업일. 응답: 승격후보 문자열/후보수
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef BLACKLIST_PROMO_H
|
||||
#define BLACKLIST_PROMO_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_blacklist_promo_rec_t;
|
||||
|
||||
void BLACKLIST_PROMO(TPSVCINFO *p);
|
||||
|
||||
#endif /* BLACKLIST_PROMO_H */
|
||||
44
app/src/au/svc/BLACKLIST_PROMO.pgc
Normal file
44
app/src/au/svc/BLACKLIST_PROMO.pgc
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* BLACKLIST_PROMO.pgc - au 모듈 서비스 BLACKLIST_PROMO (one service = one file).
|
||||
* 블랙 승격 후보 조회: 영업일 부정 적발 점수 합이 1500 이상이면서 아직
|
||||
* 블랙리스트에 없는 카드를 커서로 골라 "카드:점수합;" 후보 목록을 만든다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "BLACKLIST_PROMO.h"
|
||||
|
||||
void BLACKLIST_PROMO(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16], cand[256] = "", item[40];
|
||||
long n = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_sum;
|
||||
char h_bizdate[16], h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
if (bizdate[0] == 0) FAIL(b);
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
EXEC SQL DECLARE cur_blpromo CURSOR FOR
|
||||
SELECT f.card_no, sum(f.score) FROM au_fraud_log f
|
||||
WHERE f.biz_date = :h_bizdate
|
||||
AND f.card_no NOT IN (SELECT card_no FROM au_blacklist)
|
||||
GROUP BY f.card_no HAVING sum(f.score) >= 1500
|
||||
ORDER BY sum(f.score) DESC;
|
||||
EXEC SQL OPEN cur_blpromo;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH cur_blpromo INTO :h_card, :h_sum;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cur_blpromo; FAIL(b); }
|
||||
n++;
|
||||
snprintf(item, sizeof(item), "%s:%ld;", h_card, h_sum);
|
||||
if (strlen(cand) + strlen(item) < sizeof(cand) - 1) strcat(cand, item);
|
||||
}
|
||||
EXEC SQL CLOSE cur_blpromo;
|
||||
|
||||
Bchg(b, T_STR1, 0, cand, 0L);
|
||||
setl(b, T_COUNT, n);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/BRAND_AUTH_STAT.h
Normal file
20
app/src/au/svc/BRAND_AUTH_STAT.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* BRAND_AUTH_STAT.h - au 서비스 BRAND_AUTH_STAT 카피북 (copybook / record header).
|
||||
* 요청: 영업일. 응답: 브랜드별 접수/승인 분포/총건수
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef BRAND_AUTH_STAT_H
|
||||
#define BRAND_AUTH_STAT_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_brand_auth_stat_rec_t;
|
||||
|
||||
void BRAND_AUTH_STAT(TPSVCINFO *p);
|
||||
|
||||
#endif /* BRAND_AUTH_STAT_H */
|
||||
45
app/src/au/svc/BRAND_AUTH_STAT.pgc
Normal file
45
app/src/au/svc/BRAND_AUTH_STAT.pgc
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* BRAND_AUTH_STAT.pgc - au 모듈 서비스 BRAND_AUTH_STAT (one service = one file).
|
||||
* 브랜드별 승인 통계: 영업일 승인 원장을 카드 선두자리(브랜드)로 그룹핑해
|
||||
* 접수/승인 건수를 함께 뽑는 커서를 돌며 "선두=접수/승인;" 문자열을 만든다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "BRAND_AUTH_STAT.h"
|
||||
|
||||
void BRAND_AUTH_STAT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16], mix[256] = "", item[48];
|
||||
long total = 0, appr = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_all, h_ok;
|
||||
char h_bizdate[16], h_lead[4];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
if (bizdate[0] == 0) FAIL(b);
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
EXEC SQL DECLARE cur_brstat CURSOR FOR
|
||||
SELECT substr(card_no, 1, 1), count(*),
|
||||
count(*) FILTER (WHERE status IN ('A','M','S'))
|
||||
FROM au_authorization WHERE biz_date = :h_bizdate
|
||||
GROUP BY substr(card_no, 1, 1) ORDER BY 1;
|
||||
EXEC SQL OPEN cur_brstat;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH cur_brstat INTO :h_lead, :h_all, :h_ok;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cur_brstat; FAIL(b); }
|
||||
total += h_all;
|
||||
appr += h_ok;
|
||||
snprintf(item, sizeof(item), "%s=%ld/%ld;", h_lead, h_all, h_ok);
|
||||
if (strlen(mix) + strlen(item) < sizeof(mix) - 1) strcat(mix, item);
|
||||
}
|
||||
EXEC SQL CLOSE cur_brstat;
|
||||
|
||||
Bchg(b, T_STR1, 0, mix, 0L);
|
||||
setl(b, T_COUNT, total);
|
||||
setl(b, T_ARG1, appr);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/BRAND_POLICY.h
Normal file
20
app/src/au/svc/BRAND_POLICY.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* BRAND_POLICY.h - au 서비스 BRAND_POLICY 카피북 (copybook / record header).
|
||||
* 요청: 카드. 응답: 브랜드/당일건수/정책판정
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef BRAND_POLICY_H
|
||||
#define BRAND_POLICY_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_brand_policy_rec_t;
|
||||
|
||||
void BRAND_POLICY(TPSVCINFO *p);
|
||||
|
||||
#endif /* BRAND_POLICY_H */
|
||||
41
app/src/au/svc/BRAND_POLICY.pgc
Normal file
41
app/src/au/svc/BRAND_POLICY.pgc
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* BRAND_POLICY.pgc - au 모듈 서비스 BRAND_POLICY (one service = one file).
|
||||
* 브랜드별 승인 정책: 카드 선두자리로 브랜드(VISA/MC/AMEX/LOCAL)를 판별하고
|
||||
* 당일 동일 브랜드 승인건수를 세어 AMEX 는 3건, 그 외는 8건 초과 시 제한한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "BRAND_POLICY.h"
|
||||
|
||||
void BRAND_POLICY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
const char *brand;
|
||||
long cap;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt = 0;
|
||||
char h_card[24], h_lead[4];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (card[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
h_lead[0] = card[0]; h_lead[1] = 0;
|
||||
|
||||
switch (card[0]) {
|
||||
case '4': brand = "VISA"; cap = 8; break;
|
||||
case '5': brand = "MC"; cap = 8; break;
|
||||
case '3': brand = "AMEX"; cap = 3; break;
|
||||
default: brand = "LOCAL"; cap = 8; break;
|
||||
}
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :h_cnt FROM au_authorization
|
||||
WHERE substr(card_no, 1, 1) = :h_lead
|
||||
AND biz_date = current_date AND status = 'A';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
Bchg(b, T_ISSUER, 0, (char *)brand, 0L);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_RC, (h_cnt > cap) ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/CANCEL_AMT_INQ.h
Normal file
20
app/src/au/svc/CANCEL_AMT_INQ.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* CANCEL_AMT_INQ.h - au 서비스 CANCEL_AMT_INQ 카피북 (copybook / record header).
|
||||
* 요청: 승인ID. 응답: 원승인액/기취소액/취소가능액
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef CANCEL_AMT_INQ_H
|
||||
#define CANCEL_AMT_INQ_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_cancel_amt_inq_rec_t;
|
||||
|
||||
void CANCEL_AMT_INQ(TPSVCINFO *p);
|
||||
|
||||
#endif /* CANCEL_AMT_INQ_H */
|
||||
36
app/src/au/svc/CANCEL_AMT_INQ.pgc
Normal file
36
app/src/au/svc/CANCEL_AMT_INQ.pgc
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* CANCEL_AMT_INQ.pgc - au 모듈 서비스 CANCEL_AMT_INQ (one service = one file).
|
||||
* 취소가능액 조회: 원승인 금액에서 이미 취소된 누계를 빼 취소가능 잔액을
|
||||
* 계산한다. 승인상태가 취소불가(취소완료/무효)면 RC=1 로 알린다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "CANCEL_AMT_INQ.h"
|
||||
|
||||
void CANCEL_AMT_INQ(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long cancelable;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id, h_amt = 0, h_cxl = 0;
|
||||
char h_status[4];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_id = getl(b, T_ID2);
|
||||
if (h_id <= 0) FAIL(b);
|
||||
memset(h_status, 0, sizeof(h_status));
|
||||
|
||||
EXEC SQL SELECT amount, status INTO :h_amt, :h_status
|
||||
FROM au_authorization WHERE auth_id = :h_id;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
|
||||
EXEC SQL SELECT coalesce(sum(amount),0) INTO :h_cxl
|
||||
FROM au_cancel WHERE auth_id = :h_id;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
cancelable = h_amt - h_cxl;
|
||||
setl(b, T_AMT1, h_amt);
|
||||
setl(b, T_AMT2, h_cxl);
|
||||
setl(b, T_AMT3, cancelable);
|
||||
setl(b, T_RC, (h_status[0] == 'C' || h_status[0] == 'V') ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/CANCEL_FULL.h
Normal file
20
app/src/au/svc/CANCEL_FULL.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* CANCEL_FULL.h - au 서비스 CANCEL_FULL 카피북 (copybook / record header).
|
||||
* 요청: 승인ID/사유. 응답: 취소ID/취소액
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef CANCEL_FULL_H
|
||||
#define CANCEL_FULL_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_cancel_full_rec_t;
|
||||
|
||||
void CANCEL_FULL(TPSVCINFO *p);
|
||||
|
||||
#endif /* CANCEL_FULL_H */
|
||||
42
app/src/au/svc/CANCEL_FULL.pgc
Normal file
42
app/src/au/svc/CANCEL_FULL.pgc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* CANCEL_FULL.pgc - au 모듈 서비스 CANCEL_FULL (one service = one file).
|
||||
* 전액 취소: 승인(A)/매입확정(M) 상태의 원승인을 전액 취소 처리한다. 취소
|
||||
* 원장(au_cancel FULL)을 채번·삽입하고 원승인 상태를 C 로 바꾼다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "CANCEL_FULL.h"
|
||||
|
||||
void CANCEL_FULL(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char reason[128];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_auth, h_cid, h_amt = 0;
|
||||
char h_bizdate[16], h_reason[128];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_auth = getl(b, T_ID2);
|
||||
gets_(b, T_REASON, reason, sizeof(reason));
|
||||
if (h_auth <= 0) FAIL(b);
|
||||
strncpy(h_reason, reason, sizeof(h_reason)-1); h_reason[sizeof(h_reason)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT amount, to_char(biz_date, 'YYYY-MM-DD')
|
||||
INTO :h_amt, :h_bizdate
|
||||
FROM au_authorization WHERE auth_id = :h_auth AND status IN ('A','M');
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
|
||||
|
||||
EXEC SQL SELECT nextval('au_cancel_seq') INTO :h_cid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL INSERT INTO au_cancel (cancel_id, auth_id, cancel_type, amount, reason, biz_date)
|
||||
VALUES (:h_cid, :h_auth, 'FULL', :h_amt, :h_reason, :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL UPDATE au_authorization SET status = 'C', updated_at = now()
|
||||
WHERE auth_id = :h_auth;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
setl(b, T_ID1, h_cid);
|
||||
setl(b, T_AMT1, h_amt);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/CANCEL_HISTORY.h
Normal file
20
app/src/au/svc/CANCEL_HISTORY.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* CANCEL_HISTORY.h - au 서비스 CANCEL_HISTORY 카피북 (copybook / record header).
|
||||
* 요청: 승인ID. 응답: 취소내역 문자열/건수/합계
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef CANCEL_HISTORY_H
|
||||
#define CANCEL_HISTORY_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_cancel_history_rec_t;
|
||||
|
||||
void CANCEL_HISTORY(TPSVCINFO *p);
|
||||
|
||||
#endif /* CANCEL_HISTORY_H */
|
||||
42
app/src/au/svc/CANCEL_HISTORY.pgc
Normal file
42
app/src/au/svc/CANCEL_HISTORY.pgc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* CANCEL_HISTORY.pgc - au 모듈 서비스 CANCEL_HISTORY (one service = one file).
|
||||
* 승인건 취소 이력: 특정 원승인에 걸린 취소들을 시간순 커서로 순회하며
|
||||
* "유형:금액;" 이력 문자열과 취소 건수/취소 합계를 조립해 응답한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "CANCEL_HISTORY.h"
|
||||
|
||||
void CANCEL_HISTORY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char hist[256] = "", item[48];
|
||||
long cnt = 0, sum = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_auth, h_amt;
|
||||
char h_type[12];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_auth = getl(b, T_ID2);
|
||||
if (h_auth <= 0) FAIL(b);
|
||||
|
||||
EXEC SQL DECLARE cur_cxhist CURSOR FOR
|
||||
SELECT cancel_type, amount FROM au_cancel
|
||||
WHERE auth_id = :h_auth ORDER BY created_at;
|
||||
EXEC SQL OPEN cur_cxhist;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH cur_cxhist INTO :h_type, :h_amt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cur_cxhist; FAIL(b); }
|
||||
cnt++;
|
||||
sum += h_amt;
|
||||
snprintf(item, sizeof(item), "%s:%ld;", h_type, h_amt);
|
||||
if (strlen(hist) + strlen(item) < sizeof(hist) - 1) strcat(hist, item);
|
||||
}
|
||||
EXEC SQL CLOSE cur_cxhist;
|
||||
|
||||
Bchg(b, T_STR1, 0, hist, 0L);
|
||||
setl(b, T_COUNT, cnt);
|
||||
setl(b, T_AMT1, sum);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/CANCEL_SUMMARY.h
Normal file
20
app/src/au/svc/CANCEL_SUMMARY.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* CANCEL_SUMMARY.h - au 서비스 CANCEL_SUMMARY 카피북 (copybook / record header).
|
||||
* 요청: 영업일. 응답: 취소건수/합계/전액/부분
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef CANCEL_SUMMARY_H
|
||||
#define CANCEL_SUMMARY_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_cancel_summary_rec_t;
|
||||
|
||||
void CANCEL_SUMMARY(TPSVCINFO *p);
|
||||
|
||||
#endif /* CANCEL_SUMMARY_H */
|
||||
34
app/src/au/svc/CANCEL_SUMMARY.pgc
Normal file
34
app/src/au/svc/CANCEL_SUMMARY.pgc
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* CANCEL_SUMMARY.pgc - au 모듈 서비스 CANCEL_SUMMARY (one service = one file).
|
||||
* 일별 취소 집계: 영업일 취소 원장을 전체/전액(FULL)/부분(PARTIAL)로 나눠
|
||||
* 건수와 취소 합계를 한 번의 집계 쿼리로 뽑아 응답한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "CANCEL_SUMMARY.h"
|
||||
|
||||
void CANCEL_SUMMARY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt = 0, h_sum = 0, h_full = 0, h_part = 0;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
if (bizdate[0] == 0) FAIL(b);
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0),
|
||||
count(*) FILTER (WHERE cancel_type = 'FULL'),
|
||||
count(*) FILTER (WHERE cancel_type = 'PARTIAL')
|
||||
INTO :h_cnt, :h_sum, :h_full, :h_part
|
||||
FROM au_cancel WHERE biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_AMT1, h_sum);
|
||||
setl(b, T_ARG1, h_full);
|
||||
setl(b, T_ARG2, h_part);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/CARD_ACTIVATE.h
Normal file
20
app/src/au/svc/CARD_ACTIVATE.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* CARD_ACTIVATE.h - au 서비스 CARD_ACTIVATE 카피북 (copybook / record header).
|
||||
* 요청: 카드/한도. 응답: 신규활성화 결과
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef CARD_ACTIVATE_H
|
||||
#define CARD_ACTIVATE_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_card_activate_rec_t;
|
||||
|
||||
void CARD_ACTIVATE(TPSVCINFO *p);
|
||||
|
||||
#endif /* CARD_ACTIVATE_H */
|
||||
33
app/src/au/svc/CARD_ACTIVATE.pgc
Normal file
33
app/src/au/svc/CARD_ACTIVATE.pgc
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* CARD_ACTIVATE.pgc - au 모듈 서비스 CARD_ACTIVATE (one service = one file).
|
||||
* 카드 신규 활성화: 원장이 없으면 요청 한도(기본 100만원)로 생성하고, 이미
|
||||
* 있으면 상태만 ACTIVE 로 되살리는 upsert 를 수행한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "CARD_ACTIVATE.h"
|
||||
|
||||
void CARD_ACTIVATE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_daily;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
h_daily = getl(b, T_AMT1);
|
||||
if (card[0] == 0) FAIL(b);
|
||||
if (h_daily <= 0) h_daily = 1000000;
|
||||
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, status)
|
||||
VALUES (:h_card, :h_daily, 'ACTIVE')
|
||||
ON CONFLICT (card_no) DO UPDATE SET status = 'ACTIVE', updated_at = now();
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
userlog("CARD_ACTIVATE card=%s limit=%ld", card, h_daily);
|
||||
setl(b, T_AMT1, h_daily);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/CARD_EXPIRE_CHK.h
Normal file
20
app/src/au/svc/CARD_EXPIRE_CHK.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* CARD_EXPIRE_CHK.h - au 서비스 CARD_EXPIRE_CHK 카피북 (copybook / record header).
|
||||
* 요청: 카드. 응답: 활동건수/경과일/휴면여부
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef CARD_EXPIRE_CHK_H
|
||||
#define CARD_EXPIRE_CHK_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_card_expire_chk_rec_t;
|
||||
|
||||
void CARD_EXPIRE_CHK(TPSVCINFO *p);
|
||||
|
||||
#endif /* CARD_EXPIRE_CHK_H */
|
||||
37
app/src/au/svc/CARD_EXPIRE_CHK.pgc
Normal file
37
app/src/au/svc/CARD_EXPIRE_CHK.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* CARD_EXPIRE_CHK.pgc - au 모듈 서비스 CARD_EXPIRE_CHK (one service = one file).
|
||||
* 카드 휴면(만료 근사) 점검: 마지막 승인 이후 경과일을 EPOCH 로 환산해
|
||||
* 90일 넘게 활동이 없으면 휴면(RC=1)으로 판정한다. 활동건수도 함께 응답.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "CARD_EXPIRE_CHK.h"
|
||||
|
||||
void CARD_EXPIRE_CHK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt = 0, h_days = 0;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (card[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT count(*),
|
||||
CAST(coalesce(EXTRACT(EPOCH FROM now() - max(created_at)) / 86400, 9999) AS bigint)
|
||||
INTO :h_cnt, :h_days
|
||||
FROM au_authorization WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_ARG1, h_days);
|
||||
if (h_days > 90) {
|
||||
userlog("CARD_EXPIRE_CHK 휴면 card=%s %ld일", card, h_days);
|
||||
setl(b, T_RC, 1);
|
||||
} else {
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/CARD_LOST_REG.h
Normal file
20
app/src/au/svc/CARD_LOST_REG.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* CARD_LOST_REG.h - au 서비스 CARD_LOST_REG 카피북 (copybook / record header).
|
||||
* 요청: 카드/사유. 응답: 분실등록 결과
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef CARD_LOST_REG_H
|
||||
#define CARD_LOST_REG_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_card_lost_reg_rec_t;
|
||||
|
||||
void CARD_LOST_REG(TPSVCINFO *p);
|
||||
|
||||
#endif /* CARD_LOST_REG_H */
|
||||
33
app/src/au/svc/CARD_LOST_REG.pgc
Normal file
33
app/src/au/svc/CARD_LOST_REG.pgc
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* CARD_LOST_REG.pgc - au 모듈 서비스 CARD_LOST_REG (one service = one file).
|
||||
* 분실 등록: 카드 원장 상태를 LOST 로 바꾸고 블랙리스트에 LOST 사유로
|
||||
* 등재(중복 시 무시)해 이후 승인 시도를 원천 차단한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "CARD_LOST_REG.h"
|
||||
|
||||
void CARD_LOST_REG(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], reason[128];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
gets_(b, T_REASON, reason, sizeof(reason));
|
||||
if (card[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL UPDATE card_limit SET status = 'LOST', updated_at = now()
|
||||
WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
EXEC SQL INSERT INTO au_blacklist (card_no, reason)
|
||||
VALUES (:h_card, 'LOST') ON CONFLICT (card_no) DO NOTHING;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
userlog("CARD_LOST_REG 분실등록 card=%s reason=%s", card, reason);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/CARD_REACTIVATE.h
Normal file
20
app/src/au/svc/CARD_REACTIVATE.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* CARD_REACTIVATE.h - au 서비스 CARD_REACTIVATE 카피북 (copybook / record header).
|
||||
* 요청: 카드. 응답: 재활성화 결과
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef CARD_REACTIVATE_H
|
||||
#define CARD_REACTIVATE_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_card_reactivate_rec_t;
|
||||
|
||||
void CARD_REACTIVATE(TPSVCINFO *p);
|
||||
|
||||
#endif /* CARD_REACTIVATE_H */
|
||||
34
app/src/au/svc/CARD_REACTIVATE.pgc
Normal file
34
app/src/au/svc/CARD_REACTIVATE.pgc
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* CARD_REACTIVATE.pgc - au 모듈 서비스 CARD_REACTIVATE (one service = one file).
|
||||
* 카드 재활성화: 정지/동결/분실 상태의 원장을 ACTIVE 로 되돌리고, 분실·토큰
|
||||
* 폐기 사유로 걸린 블랙리스트 항목을 삭제한다(도난은 보존). RC=재활성 여부.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "CARD_REACTIVATE.h"
|
||||
|
||||
void CARD_REACTIVATE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
long restored;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (card[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL UPDATE card_limit SET status = 'ACTIVE', updated_at = now()
|
||||
WHERE card_no = :h_card AND status IN ('SUSPEND','FROZEN','LOST');
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
restored = (sqlca.sqlcode == 100) ? 0 : 1;
|
||||
|
||||
EXEC SQL DELETE FROM au_blacklist
|
||||
WHERE card_no = :h_card AND reason IN ('LOST','TOKEN_REVOKED');
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
userlog("CARD_REACTIVATE card=%s restored=%ld", card, restored);
|
||||
setl(b, T_RC, restored);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/CARD_STATE_HIST.h
Normal file
20
app/src/au/svc/CARD_STATE_HIST.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* CARD_STATE_HIST.h - au 서비스 CARD_STATE_HIST 카피북 (copybook / record header).
|
||||
* 요청: 카드. 응답: 상태별 분포 문자열/총건수/상태수
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef CARD_STATE_HIST_H
|
||||
#define CARD_STATE_HIST_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_card_state_hist_rec_t;
|
||||
|
||||
void CARD_STATE_HIST(TPSVCINFO *p);
|
||||
|
||||
#endif /* CARD_STATE_HIST_H */
|
||||
43
app/src/au/svc/CARD_STATE_HIST.pgc
Normal file
43
app/src/au/svc/CARD_STATE_HIST.pgc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* CARD_STATE_HIST.pgc - au 모듈 서비스 CARD_STATE_HIST (one service = one file).
|
||||
* 카드 승인상태 이력 분포: 카드의 전체 승인 건을 상태(status)별로 집계하는
|
||||
* 커서를 돌며 "상태=건수;" 분포 문자열과 총건수/상태종류 수를 만든다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "CARD_STATE_HIST.h"
|
||||
|
||||
void CARD_STATE_HIST(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], dist[256] = "", item[32];
|
||||
long total = 0, kinds = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt;
|
||||
char h_card[24], h_st[4];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (card[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL DECLARE cur_cshist CURSOR FOR
|
||||
SELECT status, count(*) FROM au_authorization
|
||||
WHERE card_no = :h_card GROUP BY status ORDER BY count(*) DESC;
|
||||
EXEC SQL OPEN cur_cshist;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH cur_cshist INTO :h_st, :h_cnt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cur_cshist; FAIL(b); }
|
||||
kinds++;
|
||||
total += h_cnt;
|
||||
snprintf(item, sizeof(item), "%s=%ld;", h_st, h_cnt);
|
||||
if (strlen(dist) + strlen(item) < sizeof(dist) - 1) strcat(dist, item);
|
||||
}
|
||||
EXEC SQL CLOSE cur_cshist;
|
||||
|
||||
Bchg(b, T_STR1, 0, dist, 0L);
|
||||
setl(b, T_COUNT, total);
|
||||
setl(b, T_ARG1, kinds);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/CARD_STOLEN_REG.h
Normal file
20
app/src/au/svc/CARD_STOLEN_REG.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* CARD_STOLEN_REG.h - au 서비스 CARD_STOLEN_REG 카피북 (copybook / record header).
|
||||
* 요청: 카드/사유/영업일. 응답: 도난등록+부정로그 ID
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef CARD_STOLEN_REG_H
|
||||
#define CARD_STOLEN_REG_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_card_stolen_reg_rec_t;
|
||||
|
||||
void CARD_STOLEN_REG(TPSVCINFO *p);
|
||||
|
||||
#endif /* CARD_STOLEN_REG_H */
|
||||
40
app/src/au/svc/CARD_STOLEN_REG.pgc
Normal file
40
app/src/au/svc/CARD_STOLEN_REG.pgc
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* CARD_STOLEN_REG.pgc - au 모듈 서비스 CARD_STOLEN_REG (one service = one file).
|
||||
* 도난 등록: 원장 상태를 STOLEN 으로 전환하고 블랙리스트를 STOLEN 사유로
|
||||
* 갱신한 뒤, 최고점(999) 부정거래 로그를 남겨 사후추적 근거를 만든다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "CARD_STOLEN_REG.h"
|
||||
|
||||
void CARD_STOLEN_REG(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], reason[128], bizdate[16];
|
||||
long fid;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
gets_(b, T_REASON, reason, sizeof(reason));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
if (card[0] == 0 || bizdate[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL UPDATE card_limit SET status = 'STOLEN', updated_at = now()
|
||||
WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
EXEC SQL INSERT INTO au_blacklist (card_no, reason)
|
||||
VALUES (:h_card, 'STOLEN')
|
||||
ON CONFLICT (card_no) DO UPDATE SET reason = 'STOLEN';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
fid = audb_insert_fraud(0, card, 999, "CARD_STOLEN", bizdate);
|
||||
if (fid < 0) FAIL(b);
|
||||
|
||||
userlog("CARD_STOLEN_REG 도난등록 card=%s fraud=%ld", card, fid);
|
||||
setl(b, T_ID1, fid);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/CHANNEL_POLICY.h
Normal file
20
app/src/au/svc/CHANNEL_POLICY.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* CHANNEL_POLICY.h - au 서비스 CHANNEL_POLICY 카피북 (copybook / record header).
|
||||
* 요청: 채널. 응답: 취소율/정책판정(ALLOW/THROTTLE)
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef CHANNEL_POLICY_H
|
||||
#define CHANNEL_POLICY_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_channel_policy_rec_t;
|
||||
|
||||
void CHANNEL_POLICY(TPSVCINFO *p);
|
||||
|
||||
#endif /* CHANNEL_POLICY_H */
|
||||
39
app/src/au/svc/CHANNEL_POLICY.pgc
Normal file
39
app/src/au/svc/CHANNEL_POLICY.pgc
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* CHANNEL_POLICY.pgc - au 모듈 서비스 CHANNEL_POLICY (one service = one file).
|
||||
* 채널별 승인 정책: 매입 원장에서 당일 해당 채널(POS/EDC/EDI/FOREIGN)의
|
||||
* 취소율(bps)을 계산해 15% 초과면 THROTTLE, 아니면 ALLOW 로 판정한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "CHANNEL_POLICY.h"
|
||||
|
||||
void CHANNEL_POLICY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16];
|
||||
long rate = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_all = 0, h_cxl = 0;
|
||||
char h_chan[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan));
|
||||
if (chan[0] == 0) strcpy(chan, "POS");
|
||||
strncpy(h_chan, chan, sizeof(h_chan)-1); h_chan[sizeof(h_chan)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT count(*), count(*) FILTER (WHERE status = 'C')
|
||||
INTO :h_all, :h_cxl
|
||||
FROM purchase WHERE channel = :h_chan AND biz_date = current_date;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
if (h_all > 0) rate = (h_cxl * 10000L) / h_all;
|
||||
setl(b, T_COUNT, h_all);
|
||||
setl(b, T_ARG1, rate);
|
||||
if (rate > 1500) {
|
||||
Bchg(b, T_STR1, 0, "THROTTLE", 0L);
|
||||
setl(b, T_RC, 1);
|
||||
} else {
|
||||
Bchg(b, T_STR1, 0, "ALLOW", 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/CHANNEL_STAT.h
Normal file
20
app/src/au/svc/CHANNEL_STAT.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* CHANNEL_STAT.h - au 서비스 CHANNEL_STAT 카피북 (copybook / record header).
|
||||
* 요청: 영업일. 응답: 채널별 분포/최다채널/총건수
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef CHANNEL_STAT_H
|
||||
#define CHANNEL_STAT_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_channel_stat_rec_t;
|
||||
|
||||
void CHANNEL_STAT(TPSVCINFO *p);
|
||||
|
||||
#endif /* CHANNEL_STAT_H */
|
||||
45
app/src/au/svc/CHANNEL_STAT.pgc
Normal file
45
app/src/au/svc/CHANNEL_STAT.pgc
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* CHANNEL_STAT.pgc - au 모듈 서비스 CHANNEL_STAT (one service = one file).
|
||||
* 채널별 매입 통계: 영업일 매입을 채널별로 그룹핑하는 커서를 순회하며
|
||||
* "채널=건수/금액;" 분포 문자열과 총건수, 최다 매출채널을 산출한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "CHANNEL_STAT.h"
|
||||
|
||||
void CHANNEL_STAT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16], mix[256] = "", top_chan[16] = "", item[48];
|
||||
long total = 0, top_amt = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt, h_amt;
|
||||
char h_bizdate[16], h_chan[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
if (bizdate[0] == 0) FAIL(b);
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
EXEC SQL DECLARE cur_chstat CURSOR FOR
|
||||
SELECT channel, count(*), coalesce(sum(amount),0)
|
||||
FROM purchase WHERE biz_date = :h_bizdate
|
||||
GROUP BY channel ORDER BY coalesce(sum(amount),0) DESC;
|
||||
EXEC SQL OPEN cur_chstat;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH cur_chstat INTO :h_chan, :h_cnt, :h_amt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cur_chstat; FAIL(b); }
|
||||
total += h_cnt;
|
||||
if (h_amt > top_amt) { top_amt = h_amt; strncpy(top_chan, h_chan, sizeof(top_chan)-1); }
|
||||
snprintf(item, sizeof(item), "%s=%ld/%ld;", h_chan, h_cnt, h_amt);
|
||||
if (strlen(mix) + strlen(item) < sizeof(mix) - 1) strcat(mix, item);
|
||||
}
|
||||
EXEC SQL CLOSE cur_chstat;
|
||||
|
||||
Bchg(b, T_STR1, 0, mix, 0L);
|
||||
Bchg(b, T_CHANNEL, 0, top_chan, 0L);
|
||||
setl(b, T_COUNT, total);
|
||||
setl(b, T_GROSS, top_amt);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/FRAUD_CASE_CLOSE.h
Normal file
20
app/src/au/svc/FRAUD_CASE_CLOSE.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* FRAUD_CASE_CLOSE.h - au 서비스 FRAUD_CASE_CLOSE 카피북 (copybook / record header).
|
||||
* 요청: 부정ID. 응답: 종결 결과
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef FRAUD_CASE_CLOSE_H
|
||||
#define FRAUD_CASE_CLOSE_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_fraud_case_close_rec_t;
|
||||
|
||||
void FRAUD_CASE_CLOSE(TPSVCINFO *p);
|
||||
|
||||
#endif /* FRAUD_CASE_CLOSE_H */
|
||||
27
app/src/au/svc/FRAUD_CASE_CLOSE.pgc
Normal file
27
app/src/au/svc/FRAUD_CASE_CLOSE.pgc
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* FRAUD_CASE_CLOSE.pgc - au 모듈 서비스 FRAUD_CASE_CLOSE (one service = one file).
|
||||
* 부정 케이스 종결: 미종결 부정로그의 사유 뒤에 '/CLOSED' 를 붙여 종결 표시
|
||||
* 한다. 이미 종결됐거나 존재하지 않으면 RC=1 로 알린다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "FRAUD_CASE_CLOSE.h"
|
||||
|
||||
void FRAUD_CASE_CLOSE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_fid;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_fid = getl(b, T_ID1);
|
||||
if (h_fid <= 0) FAIL(b);
|
||||
|
||||
EXEC SQL UPDATE au_fraud_log SET reason = reason || '/CLOSED'
|
||||
WHERE fraud_id = :h_fid AND reason NOT LIKE '%CLOSED%';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
|
||||
|
||||
userlog("FRAUD_CASE_CLOSE fraud=%ld 종결", h_fid);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/FRAUD_CASE_LIST.h
Normal file
20
app/src/au/svc/FRAUD_CASE_LIST.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* FRAUD_CASE_LIST.h - au 서비스 FRAUD_CASE_LIST 카피북 (copybook / record header).
|
||||
* 요청: 영업일. 응답: 상위 케이스 문자열/건수
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef FRAUD_CASE_LIST_H
|
||||
#define FRAUD_CASE_LIST_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_fraud_case_list_rec_t;
|
||||
|
||||
void FRAUD_CASE_LIST(TPSVCINFO *p);
|
||||
|
||||
#endif /* FRAUD_CASE_LIST_H */
|
||||
41
app/src/au/svc/FRAUD_CASE_LIST.pgc
Normal file
41
app/src/au/svc/FRAUD_CASE_LIST.pgc
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* FRAUD_CASE_LIST.pgc - au 모듈 서비스 FRAUD_CASE_LIST (one service = one file).
|
||||
* 부정 케이스 상위목록: 영업일 부정로그를 점수 내림차순 상위 5건 커서로
|
||||
* 뽑아 "카드:점수;" 목록 문자열과 케이스 건수를 만든다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "FRAUD_CASE_LIST.h"
|
||||
|
||||
void FRAUD_CASE_LIST(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16], list[256] = "", item[40];
|
||||
long cnt = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_score;
|
||||
char h_bizdate[16], h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
if (bizdate[0] == 0) FAIL(b);
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
EXEC SQL DECLARE cur_fclist CURSOR FOR
|
||||
SELECT card_no, score FROM au_fraud_log
|
||||
WHERE biz_date = :h_bizdate ORDER BY score DESC LIMIT 5;
|
||||
EXEC SQL OPEN cur_fclist;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH cur_fclist INTO :h_card, :h_score;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cur_fclist; FAIL(b); }
|
||||
cnt++;
|
||||
snprintf(item, sizeof(item), "%s:%ld;", h_card, h_score);
|
||||
if (strlen(list) + strlen(item) < sizeof(list) - 1) strcat(list, item);
|
||||
}
|
||||
EXEC SQL CLOSE cur_fclist;
|
||||
|
||||
Bchg(b, T_STR1, 0, list, 0L);
|
||||
setl(b, T_COUNT, cnt);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/FRAUD_RULE_INTL.h
Normal file
20
app/src/au/svc/FRAUD_RULE_INTL.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* FRAUD_RULE_INTL.h - au 서비스 FRAUD_RULE_INTL 카피북 (copybook / record header).
|
||||
* 요청: 카드/영업일. 응답: 고액건수/적발ID
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef FRAUD_RULE_INTL_H
|
||||
#define FRAUD_RULE_INTL_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_fraud_rule_intl_rec_t;
|
||||
|
||||
void FRAUD_RULE_INTL(TPSVCINFO *p);
|
||||
|
||||
#endif /* FRAUD_RULE_INTL_H */
|
||||
43
app/src/au/svc/FRAUD_RULE_INTL.pgc
Normal file
43
app/src/au/svc/FRAUD_RULE_INTL.pgc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* FRAUD_RULE_INTL.pgc - au 모듈 서비스 FRAUD_RULE_INTL (one service = one file).
|
||||
* 고액(해외성) 이상거래 룰: 최근 1일 100만원 초과 승인이 3건 이상이면
|
||||
* 고액 반복으로 보고 점수(720 + 초과*25)로 적발한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "FRAUD_RULE_INTL.h"
|
||||
|
||||
void FRAUD_RULE_INTL(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], bizdate[16];
|
||||
long score, fid;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt = 0, h_sum = 0;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
if (card[0] == 0 || bizdate[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0) INTO :h_cnt, :h_sum
|
||||
FROM au_authorization
|
||||
WHERE card_no = :h_card AND amount > 1000000
|
||||
AND created_at >= now() - interval '1 day';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_sum);
|
||||
if (h_cnt < 3) { setl(b, T_RC, 0); OK(b); }
|
||||
|
||||
score = 720 + (h_cnt - 3) * 25;
|
||||
if (score > 999) score = 999;
|
||||
fid = audb_insert_fraud(0, card, score, "RULE_HIGH_AMT", bizdate);
|
||||
if (fid < 0) FAIL(b);
|
||||
|
||||
userlog("FRAUD_RULE_INTL card=%s cnt=%ld sum=%ld", card, h_cnt, h_sum);
|
||||
setl(b, T_ID1, fid);
|
||||
setl(b, T_RC, 1);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/FRAUD_RULE_MCC.h
Normal file
20
app/src/au/svc/FRAUD_RULE_MCC.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* FRAUD_RULE_MCC.h - au 서비스 FRAUD_RULE_MCC 카피북 (copybook / record header).
|
||||
* 요청: 카드/영업일. 응답: 관찰가맹 건수/적발ID
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef FRAUD_RULE_MCC_H
|
||||
#define FRAUD_RULE_MCC_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_fraud_rule_mcc_rec_t;
|
||||
|
||||
void FRAUD_RULE_MCC(TPSVCINFO *p);
|
||||
|
||||
#endif /* FRAUD_RULE_MCC_H */
|
||||
41
app/src/au/svc/FRAUD_RULE_MCC.pgc
Normal file
41
app/src/au/svc/FRAUD_RULE_MCC.pgc
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* FRAUD_RULE_MCC.pgc - au 모듈 서비스 FRAUD_RULE_MCC (one service = one file).
|
||||
* 관찰가맹 이상거래 룰: 카드의 당일 승인 중 상태가 WATCH 인 가맹점 건수를
|
||||
* 서브쿼리로 세어 2건 이상이면 고위험 가맹 반복으로 적발(점수 760)한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "FRAUD_RULE_MCC.h"
|
||||
|
||||
void FRAUD_RULE_MCC(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], bizdate[16];
|
||||
long fid;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt = 0;
|
||||
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));
|
||||
if (card[0] == 0 || bizdate[0] == 0) FAIL(b);
|
||||
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(*) INTO :h_cnt
|
||||
FROM au_authorization a
|
||||
WHERE a.card_no = :h_card AND a.biz_date = :h_bizdate
|
||||
AND a.merchant_id IN (SELECT merchant_id FROM merchant WHERE status = 'WATCH');
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
if (h_cnt < 2) { setl(b, T_RC, 0); OK(b); }
|
||||
|
||||
fid = audb_insert_fraud(0, card, 760, "RULE_WATCH_MCC", bizdate);
|
||||
if (fid < 0) FAIL(b);
|
||||
|
||||
userlog("FRAUD_RULE_MCC card=%s watch=%ld", card, h_cnt);
|
||||
setl(b, T_ID1, fid);
|
||||
setl(b, T_RC, 1);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/FRAUD_RULE_NIGHT.h
Normal file
20
app/src/au/svc/FRAUD_RULE_NIGHT.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* FRAUD_RULE_NIGHT.h - au 서비스 FRAUD_RULE_NIGHT 카피북 (copybook / record header).
|
||||
* 요청: 카드/영업일. 응답: 심야건수/적발ID
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef FRAUD_RULE_NIGHT_H
|
||||
#define FRAUD_RULE_NIGHT_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_fraud_rule_night_rec_t;
|
||||
|
||||
void FRAUD_RULE_NIGHT(TPSVCINFO *p);
|
||||
|
||||
#endif /* FRAUD_RULE_NIGHT_H */
|
||||
42
app/src/au/svc/FRAUD_RULE_NIGHT.pgc
Normal file
42
app/src/au/svc/FRAUD_RULE_NIGHT.pgc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* FRAUD_RULE_NIGHT.pgc - au 모듈 서비스 FRAUD_RULE_NIGHT (one service = one file).
|
||||
* 심야 이상거래 룰: 최근 3일 심야시간대(23~06시) 승인 시도가 6건 이상이면
|
||||
* 건수 비례 점수(650 + 초과*15)로 부정거래 로그에 적발한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "FRAUD_RULE_NIGHT.h"
|
||||
|
||||
void FRAUD_RULE_NIGHT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24], bizdate[16];
|
||||
long score, fid;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt = 0;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
if (card[0] == 0 || bizdate[0] == 0) FAIL(b);
|
||||
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
|
||||
AND created_at >= now() - interval '3 days'
|
||||
AND (EXTRACT(HOUR FROM created_at) >= 23 OR EXTRACT(HOUR FROM created_at) < 6);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
if (h_cnt < 6) { setl(b, T_RC, 0); OK(b); }
|
||||
|
||||
score = 650 + (h_cnt - 6) * 15;
|
||||
if (score > 999) score = 999;
|
||||
fid = audb_insert_fraud(0, card, score, "RULE_NIGHT", bizdate);
|
||||
if (fid < 0) FAIL(b);
|
||||
|
||||
userlog("FRAUD_RULE_NIGHT card=%s night=%ld score=%ld", card, h_cnt, score);
|
||||
setl(b, T_ID1, fid);
|
||||
setl(b, T_RC, 1);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/FRAUD_SCORE_SUM.h
Normal file
20
app/src/au/svc/FRAUD_SCORE_SUM.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* FRAUD_SCORE_SUM.h - au 서비스 FRAUD_SCORE_SUM 카피북 (copybook / record header).
|
||||
* 요청: 카드. 응답: 적발수/점수합/최고점수/위험등급
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef FRAUD_SCORE_SUM_H
|
||||
#define FRAUD_SCORE_SUM_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_fraud_score_sum_rec_t;
|
||||
|
||||
void FRAUD_SCORE_SUM(TPSVCINFO *p);
|
||||
|
||||
#endif /* FRAUD_SCORE_SUM_H */
|
||||
38
app/src/au/svc/FRAUD_SCORE_SUM.pgc
Normal file
38
app/src/au/svc/FRAUD_SCORE_SUM.pgc
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* FRAUD_SCORE_SUM.pgc - au 모듈 서비스 FRAUD_SCORE_SUM (one service = one file).
|
||||
* 카드 위험도 종합: 카드의 부정 적발 건수/점수합/최고점수를 집계해 최고점수
|
||||
* 구간으로 LOW/MID/HIGH/CRITICAL 위험등급을 매겨 응답한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "FRAUD_SCORE_SUM.h"
|
||||
|
||||
void FRAUD_SCORE_SUM(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
const char *grade;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt = 0, h_sum = 0, h_max = 0;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (card[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT count(*), coalesce(sum(score),0), coalesce(max(score),0)
|
||||
INTO :h_cnt, :h_sum, :h_max
|
||||
FROM au_fraud_log WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
if (h_max >= 900) grade = "CRITICAL";
|
||||
else if (h_max >= 700) grade = "HIGH";
|
||||
else if (h_max >= 400) grade = "MID";
|
||||
else grade = "LOW";
|
||||
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_ARG1, h_sum);
|
||||
setl(b, T_ARG2, h_max);
|
||||
Bchg(b, T_STR1, 0, (char *)grade, 0L);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/KEY_ROTATE_LOG.h
Normal file
20
app/src/au/svc/KEY_ROTATE_LOG.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* KEY_ROTATE_LOG.h - au 서비스 KEY_ROTATE_LOG 카피북 (copybook / record header).
|
||||
* 요청: 키버전(T_ARG1). 응답: 차기버전/파생키값
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef KEY_ROTATE_LOG_H
|
||||
#define KEY_ROTATE_LOG_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_key_rotate_log_rec_t;
|
||||
|
||||
void KEY_ROTATE_LOG(TPSVCINFO *p);
|
||||
|
||||
#endif /* KEY_ROTATE_LOG_H */
|
||||
30
app/src/au/svc/KEY_ROTATE_LOG.pgc
Normal file
30
app/src/au/svc/KEY_ROTATE_LOG.pgc
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* KEY_ROTATE_LOG.pgc - au 모듈 서비스 KEY_ROTATE_LOG (one service = one file).
|
||||
* 암호키 회전 로그: 요청 키버전(T_ARG1)의 차기 버전을 산출하고 키식별자
|
||||
* 문자열에서 파생 체크값(문자합 mod 9973)을 계산한다(순수 연산, DB 접근 없음).
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "KEY_ROTATE_LOG.h"
|
||||
|
||||
void KEY_ROTATE_LOG(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char keyid[64];
|
||||
long cur, next, chk = 0;
|
||||
int i, len;
|
||||
|
||||
cur = getl(b, T_ARG1);
|
||||
gets_(b, T_KEY1, keyid, sizeof(keyid));
|
||||
if (keyid[0] == 0) FAIL(b);
|
||||
|
||||
next = (cur < 0) ? 1 : cur + 1;
|
||||
len = (int)strlen(keyid);
|
||||
for (i = 0; i < len; i++)
|
||||
chk = (chk * 31 + (unsigned char)keyid[i]) % 9973;
|
||||
|
||||
userlog("KEY_ROTATE_LOG key=%s v%ld->v%ld chk=%ld", keyid, cur, next, chk);
|
||||
setl(b, T_ARG2, next);
|
||||
setl(b, T_ARG3, chk);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/LIMIT_ADJUST.h
Normal file
20
app/src/au/svc/LIMIT_ADJUST.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* LIMIT_ADJUST.h - au 서비스 LIMIT_ADJUST 카피북 (copybook / record header).
|
||||
* 요청: 카드/증감(T_DELTA). 응답: 조정후 한도/결과
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef LIMIT_ADJUST_H
|
||||
#define LIMIT_ADJUST_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_limit_adjust_rec_t;
|
||||
|
||||
void LIMIT_ADJUST(TPSVCINFO *p);
|
||||
|
||||
#endif /* LIMIT_ADJUST_H */
|
||||
34
app/src/au/svc/LIMIT_ADJUST.pgc
Normal file
34
app/src/au/svc/LIMIT_ADJUST.pgc
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* LIMIT_ADJUST.pgc - au 모듈 서비스 LIMIT_ADJUST (one service = one file).
|
||||
* 한도 증감 조정: 요청 증감액(T_DELTA)을 일한도에 가감하되 음수 한도가 되지
|
||||
* 않도록 조건부 UPDATE 한다. 조건 불충족(음수화)이면 RC=1, 성공 시 새 한도.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "LIMIT_ADJUST.h"
|
||||
|
||||
void LIMIT_ADJUST(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_delta, h_new = 0;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
h_delta = getl(b, T_DELTA);
|
||||
if (card[0] == 0 || h_delta == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL UPDATE card_limit
|
||||
SET daily_limit = daily_limit + :h_delta, updated_at = now()
|
||||
WHERE card_no = :h_card AND daily_limit + :h_delta >= 0;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
|
||||
|
||||
EXEC SQL SELECT daily_limit INTO :h_new FROM card_limit WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_AMT1, h_new);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/LIMIT_CUMUL_INQ.h
Normal file
20
app/src/au/svc/LIMIT_CUMUL_INQ.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* LIMIT_CUMUL_INQ.h - au 서비스 LIMIT_CUMUL_INQ 카피북 (copybook / record header).
|
||||
* 요청: 카드. 응답: 누적건수/누적합계/최대단건
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef LIMIT_CUMUL_INQ_H
|
||||
#define LIMIT_CUMUL_INQ_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_limit_cumul_inq_rec_t;
|
||||
|
||||
void LIMIT_CUMUL_INQ(TPSVCINFO *p);
|
||||
|
||||
#endif /* LIMIT_CUMUL_INQ_H */
|
||||
31
app/src/au/svc/LIMIT_CUMUL_INQ.pgc
Normal file
31
app/src/au/svc/LIMIT_CUMUL_INQ.pgc
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* LIMIT_CUMUL_INQ.pgc - au 모듈 서비스 LIMIT_CUMUL_INQ (one service = one file).
|
||||
* 전(全)기간 누적 사용 조회: 카드의 전체 승인 이력에서 누적 건수/누적 합계/
|
||||
* 최대 단건 금액을 뽑아 준다(기간 제한 없음).
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "LIMIT_CUMUL_INQ.h"
|
||||
|
||||
void LIMIT_CUMUL_INQ(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt = 0, h_sum = 0, h_max = 0;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (card[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0), coalesce(max(amount),0)
|
||||
INTO :h_cnt, :h_sum, :h_max
|
||||
FROM au_authorization WHERE card_no = :h_card AND status IN ('A','M','S');
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_AMT1, h_sum);
|
||||
setl(b, T_AMT2, h_max);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/LIMIT_DAILY_INQ.h
Normal file
20
app/src/au/svc/LIMIT_DAILY_INQ.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* LIMIT_DAILY_INQ.h - au 서비스 LIMIT_DAILY_INQ 카피북 (copybook / record header).
|
||||
* 요청: 카드. 응답: 일한도/사용액/임시한도/가용액/상태
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef LIMIT_DAILY_INQ_H
|
||||
#define LIMIT_DAILY_INQ_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_limit_daily_inq_rec_t;
|
||||
|
||||
void LIMIT_DAILY_INQ(TPSVCINFO *p);
|
||||
|
||||
#endif /* LIMIT_DAILY_INQ_H */
|
||||
34
app/src/au/svc/LIMIT_DAILY_INQ.pgc
Normal file
34
app/src/au/svc/LIMIT_DAILY_INQ.pgc
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* LIMIT_DAILY_INQ.pgc - au 모듈 서비스 LIMIT_DAILY_INQ (one service = one file).
|
||||
* 일 한도 상세 조회: 원장에서 일한도/사용액/임시한도/상태를 한 번에 읽어
|
||||
* 가용액(일한도+임시한도-사용액)까지 계산해 응답한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "LIMIT_DAILY_INQ.h"
|
||||
|
||||
void LIMIT_DAILY_INQ(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_daily = 0, h_used = 0, h_temp = 0;
|
||||
char h_card[24], h_status[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (card[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
memset(h_status, 0, sizeof(h_status));
|
||||
|
||||
EXEC SQL SELECT daily_limit, used_amount, temp_limit, status
|
||||
INTO :h_daily, :h_used, :h_temp, :h_status
|
||||
FROM card_limit WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
|
||||
setl(b, T_AMT1, h_daily);
|
||||
setl(b, T_AMT2, h_used);
|
||||
setl(b, T_AMT3, h_temp);
|
||||
setl(b, T_AMT4, h_daily + h_temp - h_used);
|
||||
Bchg(b, T_STATUS, 0, h_status, 0L);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/LIMIT_EXHAUST_LST.h
Normal file
20
app/src/au/svc/LIMIT_EXHAUST_LST.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* LIMIT_EXHAUST_LST.h - au 서비스 LIMIT_EXHAUST_LST 카피북 (copybook / record header).
|
||||
* 요청: 기준율(T_ARG1). 응답: 소진카드 목록/건수
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef LIMIT_EXHAUST_LST_H
|
||||
#define LIMIT_EXHAUST_LST_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_limit_exhaust_lst_rec_t;
|
||||
|
||||
void LIMIT_EXHAUST_LST(TPSVCINFO *p);
|
||||
|
||||
#endif /* LIMIT_EXHAUST_LST_H */
|
||||
44
app/src/au/svc/LIMIT_EXHAUST_LST.pgc
Normal file
44
app/src/au/svc/LIMIT_EXHAUST_LST.pgc
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* LIMIT_EXHAUST_LST.pgc - au 모듈 서비스 LIMIT_EXHAUST_LST (one service = one file).
|
||||
* 한도 소진 카드 목록: 요청 기준율(bps, 기본 9000=90%) 이상으로 한도를 소진한
|
||||
* 카드를 커서로 골라 "카드:소진율;" 목록과 대상 건수를 만든다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "LIMIT_EXHAUST_LST.h"
|
||||
|
||||
void LIMIT_EXHAUST_LST(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char list[256] = "", item[40];
|
||||
long n = 0, thr;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_thr, h_bps;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
thr = getl(b, T_ARG1);
|
||||
if (thr <= 0) thr = 9000;
|
||||
h_thr = thr;
|
||||
|
||||
EXEC SQL DECLARE cur_exlst CURSOR FOR
|
||||
SELECT card_no, (used_amount * 10000 / nullif(daily_limit, 0)) AS bps
|
||||
FROM card_limit
|
||||
WHERE daily_limit > 0 AND used_amount * 10000 / daily_limit >= :h_thr
|
||||
ORDER BY bps DESC;
|
||||
EXEC SQL OPEN cur_exlst;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH cur_exlst INTO :h_card, :h_bps;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cur_exlst; FAIL(b); }
|
||||
n++;
|
||||
snprintf(item, sizeof(item), "%s:%ld;", h_card, h_bps);
|
||||
if (strlen(list) + strlen(item) < sizeof(list) - 1) strcat(list, item);
|
||||
}
|
||||
EXEC SQL CLOSE cur_exlst;
|
||||
|
||||
Bchg(b, T_STR1, 0, list, 0L);
|
||||
setl(b, T_COUNT, n);
|
||||
setl(b, T_ARG1, thr);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/LIMIT_FREEZE.h
Normal file
20
app/src/au/svc/LIMIT_FREEZE.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* LIMIT_FREEZE.h - au 서비스 LIMIT_FREEZE 카피북 (copybook / record header).
|
||||
* 요청: 카드. 응답: 동결 결과(T_RC)
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef LIMIT_FREEZE_H
|
||||
#define LIMIT_FREEZE_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_limit_freeze_rec_t;
|
||||
|
||||
void LIMIT_FREEZE(TPSVCINFO *p);
|
||||
|
||||
#endif /* LIMIT_FREEZE_H */
|
||||
31
app/src/au/svc/LIMIT_FREEZE.pgc
Normal file
31
app/src/au/svc/LIMIT_FREEZE.pgc
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* LIMIT_FREEZE.pgc - au 모듈 서비스 LIMIT_FREEZE (one service = one file).
|
||||
* 한도 동결: ACTIVE 상태의 카드 원장만 FROZEN 으로 전환한다. 이미 다른
|
||||
* 상태면 대상 아님(RC=1)으로 응답하고 관제 로그를 남긴다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "LIMIT_FREEZE.h"
|
||||
|
||||
void LIMIT_FREEZE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (card[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL UPDATE card_limit SET status = 'FROZEN', updated_at = now()
|
||||
WHERE card_no = :h_card AND status = 'ACTIVE';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (sqlca.sqlcode == 100) {
|
||||
userlog("LIMIT_FREEZE 대상아님 card=%s", card);
|
||||
setl(b, T_RC, 1);
|
||||
OK(b);
|
||||
}
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/LIMIT_MONTH_CHK.h
Normal file
20
app/src/au/svc/LIMIT_MONTH_CHK.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* LIMIT_MONTH_CHK.h - au 서비스 LIMIT_MONTH_CHK 카피북 (copybook / record header).
|
||||
* 요청: 카드/금액. 응답: 월누적/월한도/초과여부(T_RC)
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef LIMIT_MONTH_CHK_H
|
||||
#define LIMIT_MONTH_CHK_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_limit_month_chk_rec_t;
|
||||
|
||||
void LIMIT_MONTH_CHK(TPSVCINFO *p);
|
||||
|
||||
#endif /* LIMIT_MONTH_CHK_H */
|
||||
38
app/src/au/svc/LIMIT_MONTH_CHK.pgc
Normal file
38
app/src/au/svc/LIMIT_MONTH_CHK.pgc
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* LIMIT_MONTH_CHK.pgc - au 모듈 서비스 LIMIT_MONTH_CHK (one service = one file).
|
||||
* 월 한도 점검: 이번 달 승인(A/M/S) 누적액에 요청금액을 더해 월 한도
|
||||
* (일한도 x 25 영업일 근사)를 넘는지 판정한다(RC=1 초과).
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "LIMIT_MONTH_CHK.h"
|
||||
|
||||
void LIMIT_MONTH_CHK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
long amount, cap = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_month = 0, h_daily = 0;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
amount = getl(b, T_AMOUNT);
|
||||
if (card[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT coalesce(sum(amount),0) INTO :h_month
|
||||
FROM au_authorization
|
||||
WHERE card_no = :h_card AND status IN ('A','M','S')
|
||||
AND biz_date >= date_trunc('month', current_date);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
EXEC SQL SELECT daily_limit INTO :h_daily FROM card_limit WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
|
||||
cap = h_daily * 25;
|
||||
setl(b, T_AMT1, h_month);
|
||||
setl(b, T_AMT2, cap);
|
||||
setl(b, T_RC, (h_month + amount > cap) ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/LIMIT_MONTH_INQ.h
Normal file
20
app/src/au/svc/LIMIT_MONTH_INQ.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* LIMIT_MONTH_INQ.h - au 서비스 LIMIT_MONTH_INQ 카피북 (copybook / record header).
|
||||
* 요청: 카드. 응답: 월건수/월합계/월평균
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef LIMIT_MONTH_INQ_H
|
||||
#define LIMIT_MONTH_INQ_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_limit_month_inq_rec_t;
|
||||
|
||||
void LIMIT_MONTH_INQ(TPSVCINFO *p);
|
||||
|
||||
#endif /* LIMIT_MONTH_INQ_H */
|
||||
34
app/src/au/svc/LIMIT_MONTH_INQ.pgc
Normal file
34
app/src/au/svc/LIMIT_MONTH_INQ.pgc
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* LIMIT_MONTH_INQ.pgc - au 모듈 서비스 LIMIT_MONTH_INQ (one service = one file).
|
||||
* 월 누적 사용 조회: 이번 달 승인건 기준으로 건수/합계/평균단가를 한 번의
|
||||
* 집계로 산출해 내려준다(카드 실적 리포트 용).
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "LIMIT_MONTH_INQ.h"
|
||||
|
||||
void LIMIT_MONTH_INQ(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt = 0, h_sum = 0, h_avg = 0;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (card[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0),
|
||||
CAST(coalesce(avg(amount),0) AS bigint)
|
||||
INTO :h_cnt, :h_sum, :h_avg
|
||||
FROM au_authorization
|
||||
WHERE card_no = :h_card AND status IN ('A','M','S')
|
||||
AND biz_date >= date_trunc('month', current_date);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_AMT1, h_sum);
|
||||
setl(b, T_AMT2, h_avg);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/LIMIT_OVER_ALERT.h
Normal file
20
app/src/au/svc/LIMIT_OVER_ALERT.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* LIMIT_OVER_ALERT.h - au 서비스 LIMIT_OVER_ALERT 카피북 (copybook / record header).
|
||||
* 요청: 카드. 응답: 소진율(bps)/잔여/경보여부
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef LIMIT_OVER_ALERT_H
|
||||
#define LIMIT_OVER_ALERT_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_limit_over_alert_rec_t;
|
||||
|
||||
void LIMIT_OVER_ALERT(TPSVCINFO *p);
|
||||
|
||||
#endif /* LIMIT_OVER_ALERT_H */
|
||||
37
app/src/au/svc/LIMIT_OVER_ALERT.pgc
Normal file
37
app/src/au/svc/LIMIT_OVER_ALERT.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* LIMIT_OVER_ALERT.pgc - au 모듈 서비스 LIMIT_OVER_ALERT (one service = one file).
|
||||
* 한도 소진 임박 알림: 사용액/일한도를 bps 로 환산해 90% 이상이면 경보
|
||||
* (RC=1)와 관제 로그를 내고, 잔여 한도액도 함께 응답한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "LIMIT_OVER_ALERT.h"
|
||||
|
||||
void LIMIT_OVER_ALERT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
long bps = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_daily = 0, h_used = 0;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (card[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT daily_limit, used_amount INTO :h_daily, :h_used
|
||||
FROM card_limit WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
|
||||
if (h_daily > 0) bps = (h_used * 10000L) / h_daily;
|
||||
setl(b, T_ARG1, bps);
|
||||
setl(b, T_AMT1, h_daily - h_used);
|
||||
if (bps >= 9000) {
|
||||
userlog("LIMIT_OVER_ALERT 소진임박 card=%s %ldbps", card, bps);
|
||||
setl(b, T_RC, 1);
|
||||
} else {
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/LIMIT_PERTX_CHK.h
Normal file
20
app/src/au/svc/LIMIT_PERTX_CHK.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* LIMIT_PERTX_CHK.h - au 서비스 LIMIT_PERTX_CHK 카피북 (copybook / record header).
|
||||
* 요청: 카드/금액. 응답: 건별한도/초과여부
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef LIMIT_PERTX_CHK_H
|
||||
#define LIMIT_PERTX_CHK_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_limit_pertx_chk_rec_t;
|
||||
|
||||
void LIMIT_PERTX_CHK(TPSVCINFO *p);
|
||||
|
||||
#endif /* LIMIT_PERTX_CHK_H */
|
||||
37
app/src/au/svc/LIMIT_PERTX_CHK.pgc
Normal file
37
app/src/au/svc/LIMIT_PERTX_CHK.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* LIMIT_PERTX_CHK.pgc - au 모듈 서비스 LIMIT_PERTX_CHK (one service = one file).
|
||||
* 건별(1회) 한도 점검: 일한도의 20% 를 건별 상한으로 삼아 요청 단건 금액이
|
||||
* 이를 넘으면 차단(RC=1)한다. 초과 시 관제 로그를 남긴다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "LIMIT_PERTX_CHK.h"
|
||||
|
||||
void LIMIT_PERTX_CHK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
long amount, cap;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_daily = 0;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
amount = getl(b, T_AMOUNT);
|
||||
if (card[0] == 0 || amount <= 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT daily_limit INTO :h_daily FROM card_limit WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode == 100) FAIL(b);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
cap = h_daily / 5;
|
||||
setl(b, T_AMT1, cap);
|
||||
if (amount > cap) {
|
||||
userlog("LIMIT_PERTX_CHK 초과 card=%s req=%ld cap=%ld", card, amount, cap);
|
||||
setl(b, T_RC, 1);
|
||||
} else {
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/LIMIT_TIER_INQ.h
Normal file
20
app/src/au/svc/LIMIT_TIER_INQ.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* LIMIT_TIER_INQ.h - au 서비스 LIMIT_TIER_INQ 카피북 (copybook / record header).
|
||||
* 요청: 카드. 응답: 한도등급 문자열/일한도
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef LIMIT_TIER_INQ_H
|
||||
#define LIMIT_TIER_INQ_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_limit_tier_inq_rec_t;
|
||||
|
||||
void LIMIT_TIER_INQ(TPSVCINFO *p);
|
||||
|
||||
#endif /* LIMIT_TIER_INQ_H */
|
||||
34
app/src/au/svc/LIMIT_TIER_INQ.pgc
Normal file
34
app/src/au/svc/LIMIT_TIER_INQ.pgc
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* LIMIT_TIER_INQ.pgc - au 모듈 서비스 LIMIT_TIER_INQ (one service = one file).
|
||||
* 한도 등급 조회: 일한도 구간으로 BASIC/SILVER/GOLD/PLATINUM 등급을 매겨
|
||||
* 등급 문자열과 원 한도를 함께 응답한다(마케팅/우대 판정 근거).
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "LIMIT_TIER_INQ.h"
|
||||
|
||||
void LIMIT_TIER_INQ(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
const char *tier;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_daily = 0;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (card[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT daily_limit INTO :h_daily FROM card_limit WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
|
||||
if (h_daily <= 1000000) tier = "BASIC";
|
||||
else if (h_daily <= 3000000) tier = "SILVER";
|
||||
else if (h_daily <= 5000000) tier = "GOLD";
|
||||
else tier = "PLATINUM";
|
||||
|
||||
Bchg(b, T_STR1, 0, (char *)tier, 0L);
|
||||
setl(b, T_AMT1, h_daily);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/LIMIT_UNFREEZE.h
Normal file
20
app/src/au/svc/LIMIT_UNFREEZE.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* LIMIT_UNFREEZE.h - au 서비스 LIMIT_UNFREEZE 카피북 (copybook / record header).
|
||||
* 요청: 카드. 응답: 동결해제 결과(T_RC)
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef LIMIT_UNFREEZE_H
|
||||
#define LIMIT_UNFREEZE_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_limit_unfreeze_rec_t;
|
||||
|
||||
void LIMIT_UNFREEZE(TPSVCINFO *p);
|
||||
|
||||
#endif /* LIMIT_UNFREEZE_H */
|
||||
26
app/src/au/svc/LIMIT_UNFREEZE.pgc
Normal file
26
app/src/au/svc/LIMIT_UNFREEZE.pgc
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* LIMIT_UNFREEZE.pgc - au 모듈 서비스 LIMIT_UNFREEZE (one service = one file).
|
||||
* 한도 동결 해제: FROZEN 상태의 카드 원장만 ACTIVE 로 되돌린다. 대상이
|
||||
* 없으면 RC=1, 성공하면 RC=0 을 rowcount 로 판정해 응답한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "LIMIT_UNFREEZE.h"
|
||||
|
||||
void LIMIT_UNFREEZE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char card[24];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_card[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_KEY1, card, sizeof(card));
|
||||
if (card[0] == 0) FAIL(b);
|
||||
strncpy(h_card, card, sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
|
||||
|
||||
EXEC SQL UPDATE card_limit SET status = 'ACTIVE', updated_at = now()
|
||||
WHERE card_no = :h_card AND status = 'FROZEN';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_RC, (sqlca.sqlcode == 100) ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/MCC_AUTH_STAT.h
Normal file
20
app/src/au/svc/MCC_AUTH_STAT.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* MCC_AUTH_STAT.h - au 서비스 MCC_AUTH_STAT 카피북 (copybook / record header).
|
||||
* 요청: 영업일. 응답: 업종별 금액 분포/최다업종
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef MCC_AUTH_STAT_H
|
||||
#define MCC_AUTH_STAT_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_mcc_auth_stat_rec_t;
|
||||
|
||||
void MCC_AUTH_STAT(TPSVCINFO *p);
|
||||
|
||||
#endif /* MCC_AUTH_STAT_H */
|
||||
44
app/src/au/svc/MCC_AUTH_STAT.pgc
Normal file
44
app/src/au/svc/MCC_AUTH_STAT.pgc
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* MCC_AUTH_STAT.pgc - au 모듈 서비스 MCC_AUTH_STAT (one service = one file).
|
||||
* 업종별 매입 금액 통계: 영업일 매입을 업종(category)별 합계로 그룹핑하는
|
||||
* 커서를 돌며 "업종=금액;" 문자열과 총액, 최다 매출 업종을 뽑는다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT); advertised by au_svr.
|
||||
*/
|
||||
#include "MCC_AUTH_STAT.h"
|
||||
|
||||
void MCC_AUTH_STAT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16], mix[256] = "", top_cat[32] = "", item[48];
|
||||
long grand = 0, top = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_amt;
|
||||
char h_bizdate[16], h_cat[32];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
if (bizdate[0] == 0) FAIL(b);
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
EXEC SQL DECLARE cur_mccstat CURSOR FOR
|
||||
SELECT category, coalesce(sum(amount),0)
|
||||
FROM purchase WHERE biz_date = :h_bizdate
|
||||
GROUP BY category ORDER BY coalesce(sum(amount),0) DESC LIMIT 8;
|
||||
EXEC SQL OPEN cur_mccstat;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH cur_mccstat INTO :h_cat, :h_amt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cur_mccstat; FAIL(b); }
|
||||
grand += h_amt;
|
||||
if (h_amt > top) { top = h_amt; strncpy(top_cat, h_cat, sizeof(top_cat)-1); }
|
||||
snprintf(item, sizeof(item), "%s=%ld;", h_cat, h_amt);
|
||||
if (strlen(mix) + strlen(item) < sizeof(mix) - 1) strcat(mix, item);
|
||||
}
|
||||
EXEC SQL CLOSE cur_mccstat;
|
||||
|
||||
Bchg(b, T_STR1, 0, mix, 0L);
|
||||
Bchg(b, T_CATEGORY, 0, top_cat, 0L);
|
||||
setl(b, T_GROSS, grand);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/au/svc/MCC_POLICY.h
Normal file
20
app/src/au/svc/MCC_POLICY.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* MCC_POLICY.h - au 서비스 MCC_POLICY 카피북 (copybook / record header).
|
||||
* 요청: 업종. 응답: 건수/합계/고위험 정책판정
|
||||
* 공통 베이스(au_svc.h)에서 ATMI/UBF 런타임과 UBF 헬퍼/tpreturn 매크로를 상속한다.
|
||||
*/
|
||||
#ifndef MCC_POLICY_H
|
||||
#define MCC_POLICY_H
|
||||
|
||||
#include "au_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char card_no[24];
|
||||
long v_amount;
|
||||
long v_count;
|
||||
long v_result;
|
||||
} au_mcc_policy_rec_t;
|
||||
|
||||
void MCC_POLICY(TPSVCINFO *p);
|
||||
|
||||
#endif /* MCC_POLICY_H */
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue