규모확장 Wave A: 전 11모듈 svc 30→75·batch 22→35 + 전 모듈 운영데이터 시드
- svc 330→825 (모듈당 +45 고유 실업무: chargeback·재매입·심사워크플로·전문유형별· 대사세분·정산시뮬·지급재처리·복식결산·마감워크플로·마스터심사·검증룰·전문라우팅 등) - batch 242→385 (모듈당 +13), 카피북 헤더·디스패처 advertise 전 75 반영 - db/schema.d/95-module-seed.sql: 전 모듈 테이블 운영데이터(au 8.4k·st 15.9k·mg 16.9k· lg 14.6k·rc 7.7k·py 2.9k·vl 8.5k·cm 10.4k 등, 총 ~171k행) — base 거래와 정합 - 화면 매니페스트 825 재생성, 큐 메모리 튜닝(NDRX_MSGMAX 50→30) - 검증: build DONE modules=11 batches=385, 12서버 runok, xadmin psc 828 AVAIL, 매입체인 XA 커밋(status=S), 새서비스 시드데이터 스모크(ACQ_MERCHSUM/RC_STATS 실값), 전 코퍼스 .pgc 클론 0, 헤드리스 스크린샷 확인 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
19acf4ed96
commit
ea90bef264
1292 changed files with 53968 additions and 20 deletions
59
app/src/mg/batch/mg_chanload_batch.pgc
Normal file
59
app/src/mg/batch/mg_chanload_batch.pgc
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* mg_chanload_batch.pgc - mg 채널 부하 점유율 순위 배치 (커서 + XA).
|
||||
*
|
||||
* 채널별 당일 건수x금액 합성 부하지수를 커서로 내림차순 순회하며
|
||||
* 순위표와 최대 부하 채널의 점유율(%) 을 산출한다 (채널 부하 감시).
|
||||
* Usage: mg_chanload_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_chanload_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
long rank = 0, share;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_chan[16];
|
||||
long h_cnt, h_load;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_chanload_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
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; }
|
||||
|
||||
/* 부하지수 = 건수*1000 + 금액/10000 (건수 우선, 금액 보정) */
|
||||
EXEC SQL DECLARE clb CURSOR FOR
|
||||
SELECT channel, count(*),
|
||||
count(*) * 1000 + coalesce(sum(amount),0) / 10000
|
||||
FROM mg_msg_log WHERE biz_date = :h_bizdate
|
||||
GROUP BY channel
|
||||
ORDER BY 3 DESC;
|
||||
EXEC SQL OPEN clb;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH clb INTO :h_chan, :h_cnt, :h_load;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE clb; tpabort(0); return 1; }
|
||||
rank++;
|
||||
rec.channels++;
|
||||
rec.grand_total += h_load;
|
||||
if (rank == 1) { rec.top_load = h_load; strncpy(rec.top_chan, h_chan, sizeof(rec.top_chan)-1); }
|
||||
printf(" %ld위 [%s] 건수=%ld 부하지수=%ld\n", rank, h_chan, h_cnt, h_load);
|
||||
}
|
||||
EXEC SQL CLOSE clb;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
share = (rec.grand_total > 0) ? (rec.top_load * 100L) / rec.grand_total : 0;
|
||||
printf(">>> mg_chanload_batch COMMIT: bizdate=%s 채널=%ld개 1위=%s 점유율=%ld%%\n",
|
||||
bizdate, rec.channels, rec.top_chan[0] ? rec.top_chan : "-", share);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
53
app/src/mg/batch/mg_dupscan_batch.pgc
Normal file
53
app/src/mg/batch/mg_dupscan_batch.pgc
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* mg_dupscan_batch.pgc - mg 중복 STAN 전문 전수 스캔 배치 (커서 + XA).
|
||||
*
|
||||
* GROUP BY stan HAVING count(*)>1 커서로 당일 중복 순번 그룹을 전수 조사해
|
||||
* 그룹 수/중복 전문 수/최다 중복 STAN 을 리포트한다 (중복전문 검출의 일배치판).
|
||||
* Usage: mg_dupscan_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_dupscan_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_stan, h_cnt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_dupscan_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
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 dsc CURSOR FOR
|
||||
SELECT stan, count(*) FROM mg_msg_log
|
||||
WHERE biz_date = :h_bizdate
|
||||
GROUP BY stan HAVING count(*) > 1
|
||||
ORDER BY count(*) DESC;
|
||||
EXEC SQL OPEN dsc;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH dsc INTO :h_stan, :h_cnt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE dsc; tpabort(0); return 1; }
|
||||
rec.dup_groups++;
|
||||
rec.dup_msgs += h_cnt - 1; /* 원본 1건 제외한 중복분 */
|
||||
if (h_cnt > rec.worst_cnt) { rec.worst_cnt = h_cnt; rec.worst_stan = h_stan; }
|
||||
}
|
||||
EXEC SQL CLOSE dsc;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_dupscan_batch COMMIT: bizdate=%s 중복그룹=%ld 중복전문=%ld 최다STAN=%ld(%ld건)\n",
|
||||
bizdate, rec.dup_groups, rec.dup_msgs, rec.worst_stan, rec.worst_cnt);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
55
app/src/mg/batch/mg_gapfill_batch.pgc
Normal file
55
app/src/mg/batch/mg_gapfill_batch.pgc
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* mg_gapfill_batch.pgc - mg STAN 순번 갭 정밀 탐지 배치 (커서 + XA).
|
||||
*
|
||||
* 당일 고유 STAN 을 오름차순 커서로 훑으며 이전 순번과의 간격을 재서
|
||||
* 갭 개수와 최대 결번 폭을 찾아낸다 (순번 갭 검출의 일배치판).
|
||||
* Usage: mg_gapfill_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_gapfill_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
long prev = -1;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_stan;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_gapfill_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
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 gfc CURSOR FOR
|
||||
SELECT DISTINCT stan FROM mg_msg_log
|
||||
WHERE biz_date = :h_bizdate ORDER BY stan;
|
||||
EXEC SQL OPEN gfc;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH gfc INTO :h_stan;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE gfc; tpabort(0); return 1; }
|
||||
rec.scanned++;
|
||||
if (prev >= 0 && h_stan - prev > 1) { /* 연속이 깨진 지점 = 결번 구간 */
|
||||
rec.gaps++;
|
||||
if (h_stan - prev - 1 > rec.widest) rec.widest = h_stan - prev - 1;
|
||||
}
|
||||
prev = h_stan;
|
||||
}
|
||||
EXEC SQL CLOSE gfc;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_gapfill_batch COMMIT: bizdate=%s 스캔=%ld 갭구간=%ld 최대결번폭=%ld\n",
|
||||
bizdate, rec.scanned, rec.gaps, rec.widest);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
54
app/src/mg/batch/mg_hourstat_batch.pgc
Normal file
54
app/src/mg/batch/mg_hourstat_batch.pgc
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* mg_hourstat_batch.pgc - mg 시간대별 전문량 집계 배치 (커서 + XA).
|
||||
*
|
||||
* created_at 의 시(hour) 단위로 당일 전문을 묶어 시간대별 건수를 뽑고
|
||||
* 피크아워와 그 비중을 리포트한다 (시간대 세분 통계의 일배치판).
|
||||
* Usage: mg_hourstat_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_hourstat_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_hour, h_cnt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_hourstat_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
rec.peak_hour = -1;
|
||||
|
||||
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 hsc CURSOR FOR
|
||||
SELECT extract(hour FROM created_at)::int, count(*)
|
||||
FROM mg_msg_log WHERE biz_date = :h_bizdate
|
||||
GROUP BY 1 ORDER BY 1;
|
||||
EXEC SQL OPEN hsc;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH hsc INTO :h_hour, :h_cnt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE hsc; tpabort(0); return 1; }
|
||||
rec.hours++;
|
||||
rec.total += h_cnt;
|
||||
printf(" [%02ld시] %ld건\n", h_hour, h_cnt);
|
||||
if (h_cnt > rec.peak_cnt) { rec.peak_cnt = h_cnt; rec.peak_hour = h_hour; }
|
||||
}
|
||||
EXEC SQL CLOSE hsc;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_hourstat_batch COMMIT: bizdate=%s 활동시간대=%ld 총=%ld 피크=%ld시(%ld건)\n",
|
||||
bizdate, rec.hours, rec.total, rec.peak_hour, rec.peak_cnt);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
53
app/src/mg/batch/mg_keyver_batch.pgc
Normal file
53
app/src/mg/batch/mg_keyver_batch.pgc
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* mg_keyver_batch.pgc - mg 세대키 일괄 승급/세션키 재발급 배치 (2단계 갱신 + XA).
|
||||
*
|
||||
* KEYVER 카운터를 한 번 올린 뒤 UP 채널 전부의 세션키를 새 세대
|
||||
* "Kvvvv-<채널>" 로 재발급한다 (키 전환의 전 채널 일괄판).
|
||||
* Usage: mg_keyver_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_keyver_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_kv;
|
||||
char h_prefix[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_keyver_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
(void)bizdate; /* 키 승급은 영업일 무관 전 채널 대상 */
|
||||
|
||||
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; }
|
||||
|
||||
/* 1단계: 세대키 번호 승급 */
|
||||
EXEC SQL UPDATE mg_seq SET seq_val = seq_val + 1, updated_at = now()
|
||||
WHERE seq_name = 'KEYVER'
|
||||
RETURNING seq_val INTO :h_kv;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] == 0) {
|
||||
fprintf(stderr, "KEYVER 승급 FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1;
|
||||
}
|
||||
rec.new_keyver = h_kv;
|
||||
|
||||
/* 2단계: UP 채널 세션키 재발급 (채널명이 키 꼬리에 박혀 채널별로 달라짐) */
|
||||
sprintf(h_prefix, "K%04ld-", h_kv);
|
||||
EXEC SQL UPDATE mg_channel
|
||||
SET session_key = :h_prefix || channel, updated_at = now()
|
||||
WHERE status = 'UP';
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "세션키 재발급 FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
rec.rekeyed = (long)sqlca.sqlerrd[2];
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_keyver_batch COMMIT: 신규 키버전=%ld 재발급 채널=%ld개\n",
|
||||
rec.new_keyver, rec.rekeyed);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
61
app/src/mg/batch/mg_macaudit_batch.pgc
Normal file
61
app/src/mg/batch/mg_macaudit_batch.pgc
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* mg_macaudit_batch.pgc - mg MAC 누락 전문 감사/보정 배치 (행단위 커서 갱신 + XA).
|
||||
*
|
||||
* mac 이 비어 있는 당일 전문을 커서로 돌며 raw_msg 로 가산 체크섬을 재계산해
|
||||
* 행마다 채워 넣는다 (무결성 사후 보정: MG_MAC 계열과 동일 알고리즘).
|
||||
* Usage: mg_macaudit_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_macaudit_batch.h"
|
||||
|
||||
/* 가산 체크섬 4-hex (온라인 MG_MAC 과 같은 계열, 배치측 독립 구현). */
|
||||
static void mac_stamp(const char *s, char *out)
|
||||
{
|
||||
unsigned int a = 0; int i;
|
||||
for (i = 0; s[i]; i++) a = (a + (unsigned char)s[i] * 31u) & 0xFFFF;
|
||||
sprintf(out, "%04X", a);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_raw[512], h_mac[8];
|
||||
long h_id;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_macaudit_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
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 mab CURSOR FOR
|
||||
SELECT msg_id, raw_msg FROM mg_msg_log
|
||||
WHERE biz_date = :h_bizdate AND mac = '' AND raw_msg <> '';
|
||||
EXEC SQL OPEN mab;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH mab INTO :h_id, :h_raw;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE mab; tpabort(0); return 1; }
|
||||
rec.audited++;
|
||||
mac_stamp(h_raw, h_mac);
|
||||
EXEC SQL UPDATE mg_msg_log SET mac = :h_mac WHERE msg_id = :h_id;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "보정 FAIL msg_id=%ld [%d]\n", h_id, sqlca.sqlcode); EXEC SQL CLOSE mab; tpabort(0); return 1; }
|
||||
rec.stamped++;
|
||||
}
|
||||
EXEC SQL CLOSE mab;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_macaudit_batch COMMIT: bizdate=%s 감사=%ld건 보정=%ld건\n",
|
||||
bizdate, rec.audited, rec.stamped);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
56
app/src/mg/batch/mg_mtimix_batch.pgc
Normal file
56
app/src/mg/batch/mg_mtimix_batch.pgc
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* mg_mtimix_batch.pgc - mg 전문유형(MTI) 구성비 산출 배치 (커서 + XA).
|
||||
*
|
||||
* MTI 별로 당일 전문을 묶어 유형 가짓수와 금융전문(02xx/04xx) 대
|
||||
* 망관리전문(08xx) 비중을 가른다 (전문유형 세분 통계의 일배치판).
|
||||
* Usage: mg_mtimix_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_mtimix_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
long pct;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_mti[8];
|
||||
long h_cnt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_mtimix_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
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 mmx CURSOR FOR
|
||||
SELECT mti, count(*) FROM mg_msg_log
|
||||
WHERE biz_date = :h_bizdate
|
||||
GROUP BY mti ORDER BY mti;
|
||||
EXEC SQL OPEN mmx;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH mmx INTO :h_mti, :h_cnt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE mmx; tpabort(0); return 1; }
|
||||
rec.kinds++;
|
||||
rec.total += h_cnt;
|
||||
if (h_mti[1] == '8') rec.net_cnt += h_cnt; /* 08xx = 망관리 */
|
||||
else rec.fin_cnt += h_cnt; /* 그 외 = 금융/취소/정산 */
|
||||
printf(" [MTI %.4s] %ld건\n", h_mti, h_cnt);
|
||||
}
|
||||
EXEC SQL CLOSE mmx;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
pct = (rec.total > 0) ? (rec.fin_cnt * 100L) / rec.total : 0;
|
||||
printf(">>> mg_mtimix_batch COMMIT: bizdate=%s 유형=%ld 총=%ld 금융=%ld(%ld%%) 망관리=%ld\n",
|
||||
bizdate, rec.kinds, rec.total, rec.fin_cnt, pct, rec.net_cnt);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
63
app/src/mg/batch/mg_panaudit_batch.pgc
Normal file
63
app/src/mg/batch/mg_panaudit_batch.pgc
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* mg_panaudit_batch.pgc - mg 비마스킹 PAN 적발/마스킹 배치 (행단위 커서 갱신 + XA).
|
||||
*
|
||||
* pan 에 '*' 가 전혀 없는(=평문 의심) 당일 전문을 커서로 적발해
|
||||
* BIN(앞6)/뒤4 보존 마스킹으로 행마다 덮어쓴다 (정보보호 일제 점검).
|
||||
* Usage: mg_panaudit_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_panaudit_batch.h"
|
||||
|
||||
/* 앞6/뒤4 보존, 나머지 '*' 치환 (12자리 미만은 전부 '*'). */
|
||||
static void pan_conceal(const char *in, char *out)
|
||||
{
|
||||
int i, n = (int)strlen(in);
|
||||
if (n > 19) n = 19;
|
||||
for (i = 0; i < n; i++)
|
||||
out[i] = (n >= 12 && (i < 6 || i >= n - 4)) ? in[i] : '*';
|
||||
out[n] = 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_pan[24], h_masked[24];
|
||||
long h_id;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_panaudit_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
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 pab CURSOR FOR
|
||||
SELECT msg_id, pan FROM mg_msg_log
|
||||
WHERE biz_date = :h_bizdate AND pan <> '' AND position('*' in pan) = 0;
|
||||
EXEC SQL OPEN pab;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH pab INTO :h_id, :h_pan;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE pab; tpabort(0); return 1; }
|
||||
rec.inspected++;
|
||||
pan_conceal(h_pan, h_masked);
|
||||
EXEC SQL UPDATE mg_msg_log SET pan = :h_masked WHERE msg_id = :h_id;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "마스킹 FAIL msg_id=%ld [%d]\n", h_id, sqlca.sqlcode); EXEC SQL CLOSE pab; tpabort(0); return 1; }
|
||||
rec.masked++;
|
||||
}
|
||||
EXEC SQL CLOSE pab;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_panaudit_batch COMMIT: bizdate=%s 적발=%ld건 마스킹=%ld건\n",
|
||||
bizdate, rec.inspected, rec.masked);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
50
app/src/mg/batch/mg_qagesweep_batch.pgc
Normal file
50
app/src/mg/batch/mg_qagesweep_batch.pgc
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* mg_qagesweep_batch.pgc - mg 장기체류 큐 재시도 소진 스윕 배치 (2단계 갱신 + XA).
|
||||
*
|
||||
* 10분 넘게 대기(Q)한 큐 항목의 retry_cnt 를 올리고, 재시도 3회를 소진한
|
||||
* 항목은 실패(F)로 확정한다 (큐 체류시간 기반 단계적 포기 정책).
|
||||
* Usage: mg_qagesweep_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_qagesweep_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_qagesweep_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
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; }
|
||||
|
||||
/* 1단계: 10분 이상 체류한 대기 항목 재시도 카운트 증가 */
|
||||
EXEC SQL UPDATE mg_queue
|
||||
SET retry_cnt = retry_cnt + 1, updated_at = now()
|
||||
WHERE biz_date = :h_bizdate AND status = 'Q'
|
||||
AND updated_at < now() - interval '10 minutes';
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "재시도 가산 FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
rec.bumped = (long)sqlca.sqlerrd[2];
|
||||
|
||||
/* 2단계: 재시도 소진(>=3) 항목 실패 확정 */
|
||||
EXEC SQL UPDATE mg_queue
|
||||
SET status = 'F', updated_at = now()
|
||||
WHERE biz_date = :h_bizdate AND status = 'Q' AND retry_cnt >= 3;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "실패 확정 FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
rec.failed = (long)sqlca.sqlerrd[2];
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_qagesweep_batch COMMIT: bizdate=%s 재시도가산=%ld건 실패확정=%ld건\n",
|
||||
bizdate, rec.bumped, rec.failed);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
58
app/src/mg/batch/mg_rcdist_batch.pgc
Normal file
58
app/src/mg/batch/mg_rcdist_batch.pgc
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* mg_rcdist_batch.pgc - mg 응답코드 분포 리포트 배치 (커서 + XA).
|
||||
*
|
||||
* rc 별 GROUP BY 커서로 당일 정상(00)/거절 분포와 최빈 거절코드를 뽑아
|
||||
* 거절 코드 급증을 조기에 드러낸다 (응답코드 세분 통계의 일배치판).
|
||||
* Usage: mg_rcdist_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_rcdist_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
long top_cnt = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_rc[4];
|
||||
long h_cnt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_rcdist_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
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 rdb CURSOR FOR
|
||||
SELECT rc, count(*) FROM mg_msg_log
|
||||
WHERE biz_date = :h_bizdate
|
||||
GROUP BY rc ORDER BY count(*) DESC, rc;
|
||||
EXEC SQL OPEN rdb;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH rdb INTO :h_rc, :h_cnt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE rdb; tpabort(0); return 1; }
|
||||
rec.kinds++;
|
||||
if (h_rc[0] == '0' && h_rc[1] == '0') {
|
||||
rec.ok_cnt += h_cnt;
|
||||
} else {
|
||||
rec.bad_cnt += h_cnt;
|
||||
if (h_cnt > top_cnt) { top_cnt = h_cnt; strncpy(rec.top_rc, h_rc, 3); rec.top_rc[3] = 0; }
|
||||
}
|
||||
printf(" [rc %.2s] %ld건\n", h_rc, h_cnt);
|
||||
}
|
||||
EXEC SQL CLOSE rdb;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_rcdist_batch COMMIT: bizdate=%s 코드=%ld종 정상=%ld 거절=%ld 최빈거절=%s\n",
|
||||
bizdate, rec.kinds, rec.ok_cnt, rec.bad_cnt, rec.top_rc[0] ? rec.top_rc : "-");
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
45
app/src/mg/batch/mg_reroute_batch.pgc
Normal file
45
app/src/mg/batch/mg_reroute_batch.pgc
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* mg_reroute_batch.pgc - mg 미라우팅 전문 기본룰 보충 배치 (INSERT..SELECT + XA).
|
||||
*
|
||||
* 당일 원장에 나타난 채널/MTI 조합 중 활성 라우팅 룰이 하나도 없는 조합을
|
||||
* 찾아 기본 목적지 ACQUIRE(우선순위 900) 룰을 자동 보충한다.
|
||||
* Usage: mg_reroute_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_reroute_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_reroute_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
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; }
|
||||
|
||||
/* 원장에 존재하나 활성 룰이 없는 채널/MTI 조합에 최후순위 기본룰 보충 */
|
||||
EXEC SQL INSERT INTO mg_route (route_id, channel, mti, dest, priority, active, biz_date)
|
||||
SELECT nextval('mg_route_seq'), s.channel, s.mti, 'ACQUIRE', 900, true, CAST(:h_bizdate AS date)
|
||||
FROM (SELECT DISTINCT channel, mti FROM mg_msg_log WHERE biz_date = :h_bizdate) s
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM mg_route r
|
||||
WHERE r.channel = s.channel AND r.mti = s.mti AND r.active = true
|
||||
);
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "기본룰 보충 FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
rec.added_rules = (long)sqlca.sqlerrd[2];
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_reroute_batch COMMIT: bizdate=%s 보충된 기본룰=%ld건\n", bizdate, rec.added_rules);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
60
app/src/mg/batch/mg_seqsync_batch.pgc
Normal file
60
app/src/mg/batch/mg_seqsync_batch.pgc
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* mg_seqsync_batch.pgc - mg 채널 last_stan 원장 동기화 배치 (커서 + 대사 갱신 + XA).
|
||||
*
|
||||
* 채널마다 원장의 당일 최대 STAN 을 구해 채널 테이블의 last_stan 과 대조하고,
|
||||
* 뒤처진 채널만 골라 원장 기준으로 전진 동기화한다 (순번 감사 후속 조치).
|
||||
* Usage: mg_seqsync_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_seqsync_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_chan[16];
|
||||
long h_last, h_maxstan;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_seqsync_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
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 ssb CURSOR FOR
|
||||
SELECT c.channel, c.last_stan, coalesce(max(m.stan),0)
|
||||
FROM mg_channel c
|
||||
LEFT JOIN mg_msg_log m ON m.channel = c.channel AND m.biz_date = :h_bizdate
|
||||
GROUP BY c.channel, c.last_stan
|
||||
ORDER BY c.channel;
|
||||
EXEC SQL OPEN ssb;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH ssb INTO :h_chan, :h_last, :h_maxstan;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE ssb; tpabort(0); return 1; }
|
||||
rec.checked++;
|
||||
if (h_maxstan > h_last) { /* 채널이 원장보다 뒤처짐 -> 전진 */
|
||||
EXEC SQL UPDATE mg_channel
|
||||
SET last_stan = :h_maxstan, updated_at = now()
|
||||
WHERE channel = :h_chan;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "동기화 FAIL %s [%d]\n", h_chan, sqlca.sqlcode); EXEC SQL CLOSE ssb; tpabort(0); return 1; }
|
||||
rec.synced++;
|
||||
printf(" [%s] last_stan %ld -> %ld\n", h_chan, h_last, h_maxstan);
|
||||
}
|
||||
}
|
||||
EXEC SQL CLOSE ssb;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_seqsync_batch COMMIT: bizdate=%s 점검=%ld채널 동기화=%ld채널\n",
|
||||
bizdate, rec.checked, rec.synced);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
49
app/src/mg/batch/mg_timeout_batch.pgc
Normal file
49
app/src/mg/batch/mg_timeout_batch.pgc
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* mg_timeout_batch.pgc - mg 응답지연 전문 일괄 타임아웃 배치 (XA 단일 갱신 배치).
|
||||
*
|
||||
* mg_seq(TMOUTSEC) 임계초를 읽어, 그 시간을 넘긴 수신(R) 상태 전문을
|
||||
* rc=68/N 으로 한 문장에 전이시킨다 (MG_TIMEOUT 스윕의 일배치 대량판).
|
||||
* Usage: mg_timeout_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "mg_timeout_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_sec;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
mg_timeout_rec_t rec;
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
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; }
|
||||
|
||||
h_sec = 60; /* 설정 없으면 60초 기본 */
|
||||
EXEC SQL SELECT seq_val INTO :h_sec FROM mg_seq WHERE seq_name = 'TMOUTSEC';
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "TMOUTSEC 조회 FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
if (h_sec <= 0) h_sec = 60;
|
||||
rec.threshold_sec = h_sec;
|
||||
|
||||
EXEC SQL UPDATE mg_msg_log
|
||||
SET rc = '68', status = 'N'
|
||||
WHERE biz_date = :h_bizdate AND status = 'R'
|
||||
AND created_at < now() - (:h_sec * interval '1 second');
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "타임아웃 전이 FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
rec.expired = (long)sqlca.sqlerrd[2];
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> mg_timeout_batch COMMIT: bizdate=%s 임계=%ld초 만료전이=%ld건\n",
|
||||
bizdate, rec.threshold_sec, rec.expired);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
10
app/src/mg/dbio/mg_chanload_batch.h
Normal file
10
app/src/mg/dbio/mg_chanload_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_chanload_batch.h - mg mg_chanload_batch 배치 전용 카피북 (copybook). mg 채널 부하 점유율 순위 배치
|
||||
* 배치 집계 결과 레코드 + 기본 영업일 상수. Included by mg_chanload_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_CHANLOAD_BATCH_H
|
||||
#define MG_CHANLOAD_BATCH_H
|
||||
|
||||
typedef struct { long channels; long grand_total; long top_load; char top_chan[16]; } mg_chanload_rec_t;
|
||||
|
||||
#endif /* MG_CHANLOAD_BATCH_H */
|
||||
10
app/src/mg/dbio/mg_dupscan_batch.h
Normal file
10
app/src/mg/dbio/mg_dupscan_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_dupscan_batch.h - mg mg_dupscan_batch 배치 전용 카피북 (copybook). mg 중복 STAN 전문 전수 스캔 배치
|
||||
* 배치 집계 결과 레코드 + 기본 영업일 상수. Included by mg_dupscan_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_DUPSCAN_BATCH_H
|
||||
#define MG_DUPSCAN_BATCH_H
|
||||
|
||||
typedef struct { long dup_groups; long dup_msgs; long worst_stan; long worst_cnt; } mg_dupscan_rec_t;
|
||||
|
||||
#endif /* MG_DUPSCAN_BATCH_H */
|
||||
10
app/src/mg/dbio/mg_gapfill_batch.h
Normal file
10
app/src/mg/dbio/mg_gapfill_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_gapfill_batch.h - mg mg_gapfill_batch 배치 전용 카피북 (copybook). mg STAN 순번 갭 정밀 탐지 배치
|
||||
* 배치 집계 결과 레코드 + 기본 영업일 상수. Included by mg_gapfill_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_GAPFILL_BATCH_H
|
||||
#define MG_GAPFILL_BATCH_H
|
||||
|
||||
typedef struct { long scanned; long gaps; long widest; } mg_gapfill_rec_t;
|
||||
|
||||
#endif /* MG_GAPFILL_BATCH_H */
|
||||
10
app/src/mg/dbio/mg_hourstat_batch.h
Normal file
10
app/src/mg/dbio/mg_hourstat_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_hourstat_batch.h - mg mg_hourstat_batch 배치 전용 카피북 (copybook). mg 시간대별 전문량 집계 배치
|
||||
* 배치 집계 결과 레코드 + 기본 영업일 상수. Included by mg_hourstat_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_HOURSTAT_BATCH_H
|
||||
#define MG_HOURSTAT_BATCH_H
|
||||
|
||||
typedef struct { long hours; long peak_hour; long peak_cnt; long total; } mg_hourstat_rec_t;
|
||||
|
||||
#endif /* MG_HOURSTAT_BATCH_H */
|
||||
10
app/src/mg/dbio/mg_keyver_batch.h
Normal file
10
app/src/mg/dbio/mg_keyver_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_keyver_batch.h - mg mg_keyver_batch 배치 전용 카피북 (copybook). mg 세대키 일괄 승급/세션키 재발급 배치
|
||||
* 배치 집계 결과 레코드 + 기본 영업일 상수. Included by mg_keyver_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_KEYVER_BATCH_H
|
||||
#define MG_KEYVER_BATCH_H
|
||||
|
||||
typedef struct { long new_keyver; long rekeyed; } mg_keyver_rec_t;
|
||||
|
||||
#endif /* MG_KEYVER_BATCH_H */
|
||||
10
app/src/mg/dbio/mg_macaudit_batch.h
Normal file
10
app/src/mg/dbio/mg_macaudit_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_macaudit_batch.h - mg mg_macaudit_batch 배치 전용 카피북 (copybook). mg MAC 누락 전문 감사/보정 배치
|
||||
* 배치 집계 결과 레코드 + 기본 영업일 상수. Included by mg_macaudit_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_MACAUDIT_BATCH_H
|
||||
#define MG_MACAUDIT_BATCH_H
|
||||
|
||||
typedef struct { long audited; long stamped; } mg_macaudit_rec_t;
|
||||
|
||||
#endif /* MG_MACAUDIT_BATCH_H */
|
||||
10
app/src/mg/dbio/mg_mtimix_batch.h
Normal file
10
app/src/mg/dbio/mg_mtimix_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_mtimix_batch.h - mg mg_mtimix_batch 배치 전용 카피북 (copybook). mg 전문유형(MTI) 구성비 산출 배치
|
||||
* 배치 집계 결과 레코드 + 기본 영업일 상수. Included by mg_mtimix_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_MTIMIX_BATCH_H
|
||||
#define MG_MTIMIX_BATCH_H
|
||||
|
||||
typedef struct { long kinds; long total; long fin_cnt; long net_cnt; } mg_mtimix_rec_t;
|
||||
|
||||
#endif /* MG_MTIMIX_BATCH_H */
|
||||
10
app/src/mg/dbio/mg_panaudit_batch.h
Normal file
10
app/src/mg/dbio/mg_panaudit_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_panaudit_batch.h - mg mg_panaudit_batch 배치 전용 카피북 (copybook). mg 비마스킹 PAN 적발/마스킹 배치
|
||||
* 배치 집계 결과 레코드 + 기본 영업일 상수. Included by mg_panaudit_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_PANAUDIT_BATCH_H
|
||||
#define MG_PANAUDIT_BATCH_H
|
||||
|
||||
typedef struct { long inspected; long masked; } mg_panaudit_rec_t;
|
||||
|
||||
#endif /* MG_PANAUDIT_BATCH_H */
|
||||
10
app/src/mg/dbio/mg_qagesweep_batch.h
Normal file
10
app/src/mg/dbio/mg_qagesweep_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_qagesweep_batch.h - mg mg_qagesweep_batch 배치 전용 카피북 (copybook). mg 장기체류 큐 재시도 소진 스윕 배치
|
||||
* 배치 집계 결과 레코드 + 기본 영업일 상수. Included by mg_qagesweep_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_QAGESWEEP_BATCH_H
|
||||
#define MG_QAGESWEEP_BATCH_H
|
||||
|
||||
typedef struct { long bumped; long failed; } mg_qagesweep_rec_t;
|
||||
|
||||
#endif /* MG_QAGESWEEP_BATCH_H */
|
||||
10
app/src/mg/dbio/mg_rcdist_batch.h
Normal file
10
app/src/mg/dbio/mg_rcdist_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_rcdist_batch.h - mg mg_rcdist_batch 배치 전용 카피북 (copybook). mg 응답코드 분포 리포트 배치
|
||||
* 배치 집계 결과 레코드 + 기본 영업일 상수. Included by mg_rcdist_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_RCDIST_BATCH_H
|
||||
#define MG_RCDIST_BATCH_H
|
||||
|
||||
typedef struct { long kinds; long ok_cnt; long bad_cnt; char top_rc[4]; } mg_rcdist_rec_t;
|
||||
|
||||
#endif /* MG_RCDIST_BATCH_H */
|
||||
10
app/src/mg/dbio/mg_reroute_batch.h
Normal file
10
app/src/mg/dbio/mg_reroute_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_reroute_batch.h - mg mg_reroute_batch 배치 전용 카피북 (copybook). mg 미라우팅 전문 기본룰 보충 배치
|
||||
* 배치 집계 결과 레코드 + 기본 영업일 상수. Included by mg_reroute_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_REROUTE_BATCH_H
|
||||
#define MG_REROUTE_BATCH_H
|
||||
|
||||
typedef struct { long added_rules; } mg_reroute_rec_t;
|
||||
|
||||
#endif /* MG_REROUTE_BATCH_H */
|
||||
10
app/src/mg/dbio/mg_seqsync_batch.h
Normal file
10
app/src/mg/dbio/mg_seqsync_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_seqsync_batch.h - mg mg_seqsync_batch 배치 전용 카피북 (copybook). mg 채널 last_stan 원장 동기화 배치
|
||||
* 배치 집계 결과 레코드 + 기본 영업일 상수. Included by mg_seqsync_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_SEQSYNC_BATCH_H
|
||||
#define MG_SEQSYNC_BATCH_H
|
||||
|
||||
typedef struct { long checked; long synced; } mg_seqsync_rec_t;
|
||||
|
||||
#endif /* MG_SEQSYNC_BATCH_H */
|
||||
10
app/src/mg/dbio/mg_timeout_batch.h
Normal file
10
app/src/mg/dbio/mg_timeout_batch.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* mg_timeout_batch.h - mg mg_timeout_batch 배치 전용 카피북 (copybook). mg 응답지연 전문 일괄 타임아웃 배치
|
||||
* 배치 집계 결과 레코드 + 기본 영업일 상수. Included by mg_timeout_batch.pgc.
|
||||
*/
|
||||
#ifndef MG_TIMEOUT_BATCH_H
|
||||
#define MG_TIMEOUT_BATCH_H
|
||||
|
||||
typedef struct { long threshold_sec; long expired; } mg_timeout_rec_t;
|
||||
|
||||
#endif /* MG_TIMEOUT_BATCH_H */
|
||||
|
|
@ -2,13 +2,13 @@
|
|||
* mg_svr.pgc - mg (전문게이트웨이 / message gateway) MODULE SERVER (thin dispatcher).
|
||||
*
|
||||
* The legacy "one module server, many services" pattern: this binary owns NO
|
||||
* business logic. Each of mg's 30 online services now lives in its own file
|
||||
* business logic. Each of mg's 75 online services now lives in its own file
|
||||
* (app/src/mg/svc/<SVCNAME>.pgc) with its own copybook header
|
||||
* (app/src/mg/svc/<SVCNAME>.h); those objects are archived into libmgsvc.a
|
||||
* and linked into this server. Here we only:
|
||||
* - include every service copybook (for the extern prototypes),
|
||||
* - tpopen() the ECPG XA RM,
|
||||
* - tpadvertise() all 30 services from a {name, fn} table,
|
||||
* - tpadvertise() all 75 services from a {name, fn} table,
|
||||
* - tpclose() at shutdown.
|
||||
*
|
||||
* XA: the connection is opened once by tpopen() (ECPG XA switch libndrxxaecpg.so);
|
||||
|
|
@ -49,6 +49,60 @@
|
|||
#include "MG_CHANSTAT.h"
|
||||
#include "MG_STATUS.h"
|
||||
#include "MG_CONFIRM.h"
|
||||
/* --- 전문유형별 처리 (0100/0110/0200/0210/0400/0420/0800) --- */
|
||||
#include "MG_AUTHREQ.h"
|
||||
#include "MG_AUTHRSP.h"
|
||||
#include "MG_CAPTURE.h"
|
||||
#include "MG_CAPRSP.h"
|
||||
#include "MG_REVERSAL.h"
|
||||
#include "MG_REVADVICE.h"
|
||||
#include "MG_NETMGMT.h"
|
||||
/* --- 채널별 어댑터 / 전문 재조립 --- */
|
||||
#include "MG_VAN1ADPT.h"
|
||||
#include "MG_VAN2ADPT.h"
|
||||
#include "MG_DIRECTADPT.h"
|
||||
#include "MG_REASM.h"
|
||||
/* --- MAC 세분 / 키 관리 --- */
|
||||
#include "MG_MACGEN.h"
|
||||
#include "MG_MACVERIFY.h"
|
||||
#include "MG_KEYROTATE.h"
|
||||
#include "MG_KEYSTATUS.h"
|
||||
/* --- 타임아웃 / 중복·순번 검출 --- */
|
||||
#include "MG_TIMEOUT.h"
|
||||
#include "MG_TIMEOUTSET.h"
|
||||
#include "MG_DUPCHK.h"
|
||||
#include "MG_GAPSCAN.h"
|
||||
#include "MG_SEQAUDIT.h"
|
||||
/* --- 전문 변환 (내부<->ISO) / 라우팅 룰 관리 --- */
|
||||
#include "MG_TOISO.h"
|
||||
#include "MG_FROMISO.h"
|
||||
#include "MG_RTADD.h"
|
||||
#include "MG_RTDROP.h"
|
||||
#include "MG_RTLIST.h"
|
||||
#include "MG_RTSWITCH.h"
|
||||
/* --- 채널 상태 모니터/절체 --- */
|
||||
#include "MG_CHANOPEN.h"
|
||||
#include "MG_CHANCLOSE.h"
|
||||
#include "MG_CHANSWITCH.h"
|
||||
#include "MG_CHANHEALTH.h"
|
||||
/* --- 전문 통계 세분 --- */
|
||||
#include "MG_STATMTI.h"
|
||||
#include "MG_STATHOUR.h"
|
||||
#include "MG_STATDIR.h"
|
||||
#include "MG_STATRC.h"
|
||||
/* --- 오류전문 재처리 워크플로 / 트래픽 제어 --- */
|
||||
#include "MG_ERRRETRY.h"
|
||||
#include "MG_ERRLIST.h"
|
||||
#include "MG_ERRPURGE.h"
|
||||
#include "MG_THROTTLE.h"
|
||||
#include "MG_TPSCHECK.h"
|
||||
/* --- 검증·마스킹 / 정산집계 전문 / 큐 모니터 --- */
|
||||
#include "MG_PANMASK.h"
|
||||
#include "MG_AMTCHECK.h"
|
||||
#include "MG_ADVICE.h"
|
||||
#include "MG_SETTLEREQ.h"
|
||||
#include "MG_SETTLERSP.h"
|
||||
#include "MG_QDEPTH.h"
|
||||
|
||||
/* ----- advertise table: {service name, function} (fn is extern from its file) */
|
||||
static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
|
||||
|
|
@ -67,6 +121,29 @@ static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
|
|||
{"MG_DEQUEUE", MG_DEQUEUE}, {"MG_RETRY", MG_RETRY},
|
||||
{"MG_STATS", MG_STATS}, {"MG_CHANSTAT", MG_CHANSTAT},
|
||||
{"MG_STATUS", MG_STATUS}, {"MG_CONFIRM", MG_CONFIRM},
|
||||
{"MG_AUTHREQ", MG_AUTHREQ}, {"MG_AUTHRSP", MG_AUTHRSP},
|
||||
{"MG_CAPTURE", MG_CAPTURE}, {"MG_CAPRSP", MG_CAPRSP},
|
||||
{"MG_REVERSAL", MG_REVERSAL}, {"MG_REVADVICE", MG_REVADVICE},
|
||||
{"MG_NETMGMT", MG_NETMGMT}, {"MG_VAN1ADPT", MG_VAN1ADPT},
|
||||
{"MG_VAN2ADPT", MG_VAN2ADPT}, {"MG_DIRECTADPT", MG_DIRECTADPT},
|
||||
{"MG_REASM", MG_REASM}, {"MG_MACGEN", MG_MACGEN},
|
||||
{"MG_MACVERIFY", MG_MACVERIFY}, {"MG_KEYROTATE", MG_KEYROTATE},
|
||||
{"MG_KEYSTATUS", MG_KEYSTATUS}, {"MG_TIMEOUT", MG_TIMEOUT},
|
||||
{"MG_TIMEOUTSET", MG_TIMEOUTSET}, {"MG_DUPCHK", MG_DUPCHK},
|
||||
{"MG_GAPSCAN", MG_GAPSCAN}, {"MG_SEQAUDIT", MG_SEQAUDIT},
|
||||
{"MG_TOISO", MG_TOISO}, {"MG_FROMISO", MG_FROMISO},
|
||||
{"MG_RTADD", MG_RTADD}, {"MG_RTDROP", MG_RTDROP},
|
||||
{"MG_RTLIST", MG_RTLIST}, {"MG_RTSWITCH", MG_RTSWITCH},
|
||||
{"MG_CHANOPEN", MG_CHANOPEN}, {"MG_CHANCLOSE", MG_CHANCLOSE},
|
||||
{"MG_CHANSWITCH", MG_CHANSWITCH}, {"MG_CHANHEALTH", MG_CHANHEALTH},
|
||||
{"MG_STATMTI", MG_STATMTI}, {"MG_STATHOUR", MG_STATHOUR},
|
||||
{"MG_STATDIR", MG_STATDIR}, {"MG_STATRC", MG_STATRC},
|
||||
{"MG_ERRRETRY", MG_ERRRETRY}, {"MG_ERRLIST", MG_ERRLIST},
|
||||
{"MG_ERRPURGE", MG_ERRPURGE}, {"MG_THROTTLE", MG_THROTTLE},
|
||||
{"MG_TPSCHECK", MG_TPSCHECK}, {"MG_PANMASK", MG_PANMASK},
|
||||
{"MG_AMTCHECK", MG_AMTCHECK}, {"MG_ADVICE", MG_ADVICE},
|
||||
{"MG_SETTLEREQ", MG_SETTLEREQ}, {"MG_SETTLERSP", MG_SETTLERSP},
|
||||
{"MG_QDEPTH", MG_QDEPTH},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
|||
12
app/src/mg/svc/MG_ADVICE.h
Normal file
12
app/src/mg/svc/MG_ADVICE.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_ADVICE.h - mg (전문게이트웨이) 서비스 MG_ADVICE 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_ADVICE_H
|
||||
#define MG_ADVICE_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_ADVICE(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_ADVICE_H */
|
||||
39
app/src/mg/svc/MG_ADVICE.pgc
Normal file
39
app/src/mg/svc/MG_ADVICE.pgc
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* MG_ADVICE.pgc - mg 모듈 서비스 MG_ADVICE (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_ADVICE.h"
|
||||
|
||||
/* 72. MG_ADVICE - 0220 매입 어드바이스 수신: 응답이 필요 없는 통지 전문이라
|
||||
* 즉시 수용(A) 적재하고, 당일 누적 어드바이스 건수를 회신해 폭주를 감시. */
|
||||
void MG_ADVICE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], raw[512], bizdate[16];
|
||||
long stan, msg_id, amount;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_biz[16];
|
||||
long h_advcnt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH02");
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
amount = getl(b, T_AMOUNT);
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0220", chan, "IN", "000000", "", amount,
|
||||
"", "00", raw, "A", bizdate) < 0) FAIL(b);
|
||||
|
||||
strncpy(h_biz, bizdate, sizeof(h_biz)-1); h_biz[sizeof(h_biz)-1] = 0;
|
||||
EXEC SQL SELECT count(*) INTO :h_advcnt
|
||||
FROM mg_msg_log WHERE mti = '0220' AND biz_date = :h_biz;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
setl(b, T_ID1, msg_id);
|
||||
setl(b, T_COUNT, h_advcnt);
|
||||
setl(b, T_RC, (h_advcnt > 1000) ? 1 : 0); /* 어드바이스 폭주 경보 */
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_AMTCHECK.h
Normal file
12
app/src/mg/svc/MG_AMTCHECK.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_AMTCHECK.h - mg (전문게이트웨이) 서비스 MG_AMTCHECK 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_AMTCHECK_H
|
||||
#define MG_AMTCHECK_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_AMTCHECK(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_AMTCHECK_H */
|
||||
31
app/src/mg/svc/MG_AMTCHECK.pgc
Normal file
31
app/src/mg/svc/MG_AMTCHECK.pgc
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* MG_AMTCHECK.pgc - mg 모듈 서비스 MG_AMTCHECK (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_AMTCHECK.h"
|
||||
|
||||
/* 71. MG_AMTCHECK - 전문 금액/카드 사전검증: 금액 범위(0 < 금액 <= 한도)와
|
||||
* PAN Luhn 을 한 번에 검사해 게이트웨이 입구에서 불량 전문을 걸러낸다. */
|
||||
void MG_AMTCHECK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char pan[24];
|
||||
long amount, limit, rc = 0;
|
||||
|
||||
amount = getl(b, T_AMOUNT);
|
||||
limit = getl(b, T_AMT4); if (limit <= 0) limit = 100000000L; /* 기본 한도 1억 */
|
||||
gets_(b, T_STR5, pan, sizeof(pan));
|
||||
|
||||
if (amount <= 0) rc = 13; /* 13 = 금액 오류 */
|
||||
else if (amount > limit) rc = 61; /* 61 = 한도 초과 */
|
||||
else if (pan[0] && !acq_luhn_ok(pan)) rc = 14; /* 14 = 무효 카드번호 */
|
||||
|
||||
if (rc != 0)
|
||||
userlog("MG_AMTCHECK 거절 rc=%ld 금액=%ld 한도=%ld", rc, amount, limit);
|
||||
|
||||
setl(b, T_AMT4, limit);
|
||||
setl(b, T_RC, rc);
|
||||
if (rc != 0) FAIL(b);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_AUTHREQ.h
Normal file
12
app/src/mg/svc/MG_AUTHREQ.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_AUTHREQ.h - mg (전문게이트웨이) 서비스 MG_AUTHREQ 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_AUTHREQ_H
|
||||
#define MG_AUTHREQ_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_AUTHREQ(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_AUTHREQ_H */
|
||||
50
app/src/mg/svc/MG_AUTHREQ.pgc
Normal file
50
app/src/mg/svc/MG_AUTHREQ.pgc
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* MG_AUTHREQ.pgc - mg 모듈 서비스 MG_AUTHREQ (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_AUTHREQ.h"
|
||||
|
||||
/* ----- service-local pure helper(s) ----- */
|
||||
/* PAN 앞6/뒤4 만 남기고 '*' 마스킹 (승인요청 로그 저장용). */
|
||||
static void mg_authreq_mask(const char *pan, char *out /* >= 20 */)
|
||||
{
|
||||
int i, n = (int)strlen(pan);
|
||||
for (i = 0; i < n && i < 19; i++)
|
||||
out[i] = (i < 6 || i >= n - 4) ? pan[i] : '*';
|
||||
out[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
/* 31. MG_AUTHREQ - 0100 승인요청 전문 수신: 고정길이 파싱(MTI/처리코드/금액/PAN),
|
||||
* PAN Luhn 검증 후 수신 원장 적재. Luhn 실패 시 rc=14(무효카드)로 기록. */
|
||||
void MG_AUTHREQ(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], raw[512], bizdate[16], proc[8], pan[24], masked[24], rc[4];
|
||||
long stan, msg_id, amount, n;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
n = (long)strlen(raw);
|
||||
|
||||
/* 0100 고정길이: [0..3]=MTI(0100 강제) [4..9]=처리코드 [10..21]=금액 [22..37]=PAN */
|
||||
memset(proc, 0, sizeof(proc)); memset(pan, 0, sizeof(pan));
|
||||
if (n >= 10) strncpy(proc, raw + 4, 6); else strcpy(proc, "000000");
|
||||
amount = (n >= 22) ? atol(raw + 10) : getl(b, T_AMOUNT);
|
||||
if (n >= 38) strncpy(pan, raw + 22, 16);
|
||||
|
||||
strcpy(rc, (pan[0] && !acq_luhn_ok(pan)) ? "14" : "00");
|
||||
mg_authreq_mask(pan, masked);
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0100", chan, "IN", proc, "", amount,
|
||||
masked, rc, raw, "R", bizdate) < 0) FAIL(b);
|
||||
sets_(b, T_STR2, rc);
|
||||
sets_(b, T_STR5, masked);
|
||||
setl(b, T_ID1, msg_id);
|
||||
setl(b, T_ARG1, stan);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_AUTHRSP.h
Normal file
12
app/src/mg/svc/MG_AUTHRSP.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_AUTHRSP.h - mg (전문게이트웨이) 서비스 MG_AUTHRSP 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_AUTHRSP_H
|
||||
#define MG_AUTHRSP_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_AUTHRSP(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_AUTHRSP_H */
|
||||
34
app/src/mg/svc/MG_AUTHRSP.pgc
Normal file
34
app/src/mg/svc/MG_AUTHRSP.pgc
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* MG_AUTHRSP.pgc - mg 모듈 서비스 MG_AUTHRSP (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_AUTHRSP.h"
|
||||
|
||||
/* 32. MG_AUTHRSP - 0110 승인응답 생성: 승인한도(5천만원) 초과 시 rc=61 거절,
|
||||
* 이내면 rc=00 승인. 원 0100 전문의 rc/상태를 갱신하고 0110 송신 로그 적재. */
|
||||
void MG_AUTHRSP(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], bizdate[16], rc[4];
|
||||
long orig_id, stan, msg_id, amount;
|
||||
const long AUTH_LIMIT = 50000000L; /* 건당 승인한도 5천만원 */
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
orig_id = getl(b, T_ID1);
|
||||
amount = getl(b, T_AMOUNT);
|
||||
|
||||
strcpy(rc, (amount > AUTH_LIMIT) ? "61" : "00"); /* 61 = 한도초과 */
|
||||
|
||||
if (orig_id > 0 && mgdb_update_msg_rc(orig_id, rc, "C") < 0) FAIL(b);
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0110", chan, "OUT", "000000", "", amount,
|
||||
"", rc, "", "S", bizdate) < 0) FAIL(b);
|
||||
sets_(b, T_STR2, rc);
|
||||
setl(b, T_ID2, msg_id);
|
||||
setl(b, T_RC, (rc[0] == '0' && rc[1] == '0') ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_CAPRSP.h
Normal file
12
app/src/mg/svc/MG_CAPRSP.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_CAPRSP.h - mg (전문게이트웨이) 서비스 MG_CAPRSP 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_CAPRSP_H
|
||||
#define MG_CAPRSP_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_CAPRSP(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_CAPRSP_H */
|
||||
35
app/src/mg/svc/MG_CAPRSP.pgc
Normal file
35
app/src/mg/svc/MG_CAPRSP.pgc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* MG_CAPRSP.pgc - mg 모듈 서비스 MG_CAPRSP (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_CAPRSP.h"
|
||||
|
||||
/* 34. MG_CAPRSP - 0210 매입응답 처리: STAN 으로 원 0200 전문을 찾아
|
||||
* 확인(C) 전이시키고 0210 송신 로그 적재. 원거래 없으면 rc=25. */
|
||||
void MG_CAPRSP(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], bizdate[16];
|
||||
long stan, orig_id, msg_id, out_stan;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH02");
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
stan = getl(b, T_ARG1);
|
||||
|
||||
orig_id = mgdb_find_msg_by_stan(stan);
|
||||
if (orig_id < 0) { /* 25 = 원거래 없음 */
|
||||
setl(b, T_RC, 25);
|
||||
OK(b);
|
||||
}
|
||||
if (mgdb_update_msg_rc(orig_id, "00", "C") < 0) FAIL(b);
|
||||
|
||||
out_stan = mgdb_next_stan(); if (out_stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, out_stan, "0210", chan, "OUT", "000000", "", 0,
|
||||
"", "00", "", "S", bizdate) < 0) FAIL(b);
|
||||
setl(b, T_ID1, orig_id);
|
||||
setl(b, T_ID2, msg_id);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_CAPTURE.h
Normal file
12
app/src/mg/svc/MG_CAPTURE.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_CAPTURE.h - mg (전문게이트웨이) 서비스 MG_CAPTURE 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_CAPTURE_H
|
||||
#define MG_CAPTURE_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_CAPTURE(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_CAPTURE_H */
|
||||
35
app/src/mg/svc/MG_CAPTURE.pgc
Normal file
35
app/src/mg/svc/MG_CAPTURE.pgc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* MG_CAPTURE.pgc - mg 모듈 서비스 MG_CAPTURE (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_CAPTURE.h"
|
||||
|
||||
/* 33. MG_CAPTURE - 0200 매입요청 전문 처리: MDR(bps) 수수료/정산액을 산출해
|
||||
* 수신 원장에 적재하고 수수료 내역을 회신 (전문게이트웨이 매입 접수). */
|
||||
void MG_CAPTURE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], raw[512], bizdate[16];
|
||||
long stan, msg_id, amount, bps, fee, net;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH02");
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
amount = getl(b, T_AMOUNT);
|
||||
bps = getl(b, T_ARG2); if (bps <= 0) bps = 25; /* 기본 MDR 0.25% */
|
||||
|
||||
if (amount <= 0) { setl(b, T_RC, 13); OK(b); } /* 13 = 금액오류 */
|
||||
fee = acq_fee(amount, bps);
|
||||
net = amount - fee;
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0200", chan, "IN", "000000", "", amount,
|
||||
"", "00", raw, "R", bizdate) < 0) FAIL(b);
|
||||
setl(b, T_FEE, fee);
|
||||
setl(b, T_NET, net);
|
||||
setl(b, T_ID1, msg_id);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_CHANCLOSE.h
Normal file
12
app/src/mg/svc/MG_CHANCLOSE.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_CHANCLOSE.h - mg (전문게이트웨이) 서비스 MG_CHANCLOSE 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_CHANCLOSE_H
|
||||
#define MG_CHANCLOSE_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_CHANCLOSE(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_CHANCLOSE_H */
|
||||
36
app/src/mg/svc/MG_CHANCLOSE.pgc
Normal file
36
app/src/mg/svc/MG_CHANCLOSE.pgc
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* MG_CHANCLOSE.pgc - mg 모듈 서비스 MG_CHANCLOSE (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_CHANCLOSE.h"
|
||||
|
||||
/* 58. MG_CHANCLOSE - 채널 폐쇄: 채널을 DOWN 으로 내리고 세션키를 폐기하되,
|
||||
* 그 채널에 대기(Q) 중인 송신 큐 잔량을 세어 함께 회신 (폐쇄 영향도). */
|
||||
void MG_CHANCLOSE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16];
|
||||
long h_pending;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, h_chan, sizeof(h_chan)); if (h_chan[0] == 0) strcpy(h_chan, "CH01");
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :h_pending
|
||||
FROM mg_queue WHERE channel = :h_chan AND status = 'Q';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
EXEC SQL UPDATE mg_channel
|
||||
SET status = 'DOWN', session_key = '', updated_at = now()
|
||||
WHERE channel = :h_chan;
|
||||
if (sqlca.sqlcode < 0) { userlog("MG_CHANCLOSE 폐쇄 FAIL [%d]", sqlca.sqlcode); FAIL(b); }
|
||||
if (sqlca.sqlerrd[2] == 0) { setl(b, T_RC, 25); FAIL(b); } /* 미등록 채널 */
|
||||
|
||||
if (h_pending > 0)
|
||||
userlog("MG_CHANCLOSE %s 폐쇄: 대기 큐 %ld건 잔류", h_chan, h_pending);
|
||||
sets_(b, T_STATUS, "DOWN");
|
||||
setl(b, T_COUNT, h_pending);
|
||||
setl(b, T_RC, (h_pending > 0) ? 1 : 0); /* 잔량 있으면 경고 */
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_CHANHEALTH.h
Normal file
12
app/src/mg/svc/MG_CHANHEALTH.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_CHANHEALTH.h - mg (전문게이트웨이) 서비스 MG_CHANHEALTH 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_CHANHEALTH_H
|
||||
#define MG_CHANHEALTH_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_CHANHEALTH(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_CHANHEALTH_H */
|
||||
51
app/src/mg/svc/MG_CHANHEALTH.pgc
Normal file
51
app/src/mg/svc/MG_CHANHEALTH.pgc
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* MG_CHANHEALTH.pgc - mg 모듈 서비스 MG_CHANHEALTH (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_CHANHEALTH.h"
|
||||
|
||||
/* 60. MG_CHANHEALTH - 채널 종합 건강점검: 상태(UP 여부) + 당일 오류율(bps) +
|
||||
* 큐 적체를 합산한 0~100 건강점수를 산출 (60 미만이면 절체 권고 rc=1). */
|
||||
void MG_CHANHEALTH(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long score, err_bps, up;
|
||||
char status[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16], h_bizdate[16];
|
||||
long h_total, h_err, h_backlog;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, h_chan, sizeof(h_chan)); if (h_chan[0] == 0) strcpy(h_chan, "CH01");
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
if (mgdb_get_channel_status(h_chan, status) < 0) { setl(b, T_RC, 25); FAIL(b); }
|
||||
up = (strcmp(status, "UP") == 0) ? 1 : 0;
|
||||
|
||||
EXEC SQL SELECT count(*),
|
||||
coalesce(sum(CASE WHEN rc <> '00' THEN 1 ELSE 0 END),0)
|
||||
INTO :h_total, :h_err
|
||||
FROM mg_msg_log WHERE channel = :h_chan AND biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :h_backlog
|
||||
FROM mg_queue WHERE channel = :h_chan AND status IN ('Q','F');
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
err_bps = (h_total > 0) ? (h_err * 10000L) / h_total : 0;
|
||||
|
||||
/* 점수: 기본 100, 다운 -50, 오류율 100bps당 -10 (최대 -30), 적체 10건당 -5 (최대 -20) */
|
||||
score = 100;
|
||||
if (!up) score -= 50;
|
||||
score -= (err_bps / 100L) * 10L > 30 ? 30 : (err_bps / 100L) * 10L;
|
||||
score -= (h_backlog / 10L) * 5L > 20 ? 20 : (h_backlog / 10L) * 5L;
|
||||
if (score < 0) score = 0;
|
||||
|
||||
sets_(b, T_STATUS, status);
|
||||
setl(b, T_ARG3, err_bps);
|
||||
setl(b, T_ARG7, h_backlog);
|
||||
setl(b, T_ARG8, score);
|
||||
setl(b, T_RC, (score < 60) ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_CHANOPEN.h
Normal file
12
app/src/mg/svc/MG_CHANOPEN.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_CHANOPEN.h - mg (전문게이트웨이) 서비스 MG_CHANOPEN 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_CHANOPEN_H
|
||||
#define MG_CHANOPEN_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_CHANOPEN(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_CHANOPEN_H */
|
||||
33
app/src/mg/svc/MG_CHANOPEN.pgc
Normal file
33
app/src/mg/svc/MG_CHANOPEN.pgc
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* MG_CHANOPEN.pgc - mg 모듈 서비스 MG_CHANOPEN (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_CHANOPEN.h"
|
||||
|
||||
/* 57. MG_CHANOPEN - 채널 개통: DOWN 채널만 UP 으로 올리고 sign-on 시각을 기록.
|
||||
* 이미 UP 이면 rc=1 (이중 개통 무해화), 미등록 채널이면 rc=25. */
|
||||
void MG_CHANOPEN(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], cur[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
if (mgdb_get_channel_status(chan, cur) < 0) { setl(b, T_RC, 25); FAIL(b); }
|
||||
if (strcmp(cur, "UP") == 0) { sets_(b, T_STATUS, cur); setl(b, T_RC, 1); OK(b); }
|
||||
|
||||
strncpy(h_chan, chan, sizeof(h_chan)-1); h_chan[sizeof(h_chan)-1] = 0;
|
||||
EXEC SQL UPDATE mg_channel
|
||||
SET status = 'UP', signon_at = now(), updated_at = now()
|
||||
WHERE channel = :h_chan;
|
||||
if (sqlca.sqlcode < 0) { userlog("MG_CHANOPEN 개통 FAIL [%d]", sqlca.sqlcode); FAIL(b); }
|
||||
|
||||
userlog("MG_CHANOPEN 채널 개통 %s (%s -> UP)", chan, cur);
|
||||
sets_(b, T_STATUS, "UP");
|
||||
sets_(b, T_STR5, cur); /* 개통 전 상태 */
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_CHANSWITCH.h
Normal file
12
app/src/mg/svc/MG_CHANSWITCH.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_CHANSWITCH.h - mg (전문게이트웨이) 서비스 MG_CHANSWITCH 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_CHANSWITCH_H
|
||||
#define MG_CHANSWITCH_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_CHANSWITCH(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_CHANSWITCH_H */
|
||||
48
app/src/mg/svc/MG_CHANSWITCH.pgc
Normal file
48
app/src/mg/svc/MG_CHANSWITCH.pgc
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* MG_CHANSWITCH.pgc - mg 모듈 서비스 MG_CHANSWITCH (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_CHANSWITCH.h"
|
||||
|
||||
/* 59. MG_CHANSWITCH - 채널 절체: 주채널을 DOWN, 예비채널을 UP 으로 한 트랜잭션
|
||||
* 안에서 뒤집고, 주채널 대기 큐를 예비채널로 이관 (게이트웨이 페일오버). */
|
||||
void MG_CHANSWITCH(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char pri[16], bak[16];
|
||||
long moved;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_pri[16], h_bak[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, pri, sizeof(pri)); if (pri[0] == 0) strcpy(pri, "CH01");
|
||||
gets_(b, T_STR2, bak, sizeof(bak)); if (bak[0] == 0) strcpy(bak, "CH02");
|
||||
if (strcmp(pri, bak) == 0) { setl(b, T_RC, 30); FAIL(b); } /* 자기 자신 절체 불가 */
|
||||
|
||||
strncpy(h_pri, pri, sizeof(h_pri)-1); h_pri[sizeof(h_pri)-1] = 0;
|
||||
strncpy(h_bak, bak, sizeof(h_bak)-1); h_bak[sizeof(h_bak)-1] = 0;
|
||||
|
||||
EXEC SQL UPDATE mg_channel SET status = 'DOWN', updated_at = now()
|
||||
WHERE channel = :h_pri;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (sqlca.sqlerrd[2] == 0) { setl(b, T_RC, 25); FAIL(b); }
|
||||
|
||||
EXEC SQL UPDATE mg_channel SET status = 'UP', signon_at = now(), updated_at = now()
|
||||
WHERE channel = :h_bak;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (sqlca.sqlerrd[2] == 0) { setl(b, T_RC, 25); FAIL(b); }
|
||||
|
||||
/* 주채널에 물려 있던 대기 전문을 예비채널로 이관 */
|
||||
EXEC SQL UPDATE mg_queue SET channel = :h_bak, updated_at = now()
|
||||
WHERE channel = :h_pri AND status = 'Q';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
moved = (long)sqlca.sqlerrd[2];
|
||||
|
||||
userlog("MG_CHANSWITCH 절체 %s -> %s (큐 이관 %ld건)", pri, bak, moved);
|
||||
sets_(b, T_STR5, pri);
|
||||
sets_(b, T_STR2, bak);
|
||||
setl(b, T_COUNT, moved);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_DIRECTADPT.h
Normal file
12
app/src/mg/svc/MG_DIRECTADPT.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_DIRECTADPT.h - mg (전문게이트웨이) 서비스 MG_DIRECTADPT 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_DIRECTADPT_H
|
||||
#define MG_DIRECTADPT_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_DIRECTADPT(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_DIRECTADPT_H */
|
||||
45
app/src/mg/svc/MG_DIRECTADPT.pgc
Normal file
45
app/src/mg/svc/MG_DIRECTADPT.pgc
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* MG_DIRECTADPT.pgc - mg 모듈 서비스 MG_DIRECTADPT (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_DIRECTADPT.h"
|
||||
|
||||
/* ----- service-local pure helper(s) ----- */
|
||||
/* 구간 [s, s+n) 이 전부 십진 숫자인지 검사 (직연동 전문 필드 검증). */
|
||||
static int mg_direct_digits(const char *s, int n)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n; i++)
|
||||
if (s[i] < '0' || s[i] > '9') return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* 40. MG_DIRECTADPT - 직연동 채널 어댑터: 이미 내부 고정길이 포맷이므로 변환 없이
|
||||
* 길이(>=22)와 MTI(4)/처리코드(6)/금액(12) 숫자 여부만 엄격 검증. */
|
||||
void MG_DIRECTADPT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char raw[512], mti[8];
|
||||
long n, amount;
|
||||
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
n = (long)strlen(raw);
|
||||
|
||||
if (n < 22) { setl(b, T_RC, 31); FAIL(b); } /* 길이 부족 */
|
||||
if (!mg_direct_digits(raw, 4)) { setl(b, T_RC, 32); FAIL(b); } /* MTI 오류 */
|
||||
if (!mg_direct_digits(raw + 4, 6)) { setl(b, T_RC, 33); FAIL(b); } /* 처리코드 오류 */
|
||||
if (!mg_direct_digits(raw + 10, 12)) { setl(b, T_RC, 34); FAIL(b); } /* 금액 오류 */
|
||||
|
||||
memset(mti, 0, sizeof(mti));
|
||||
strncpy(mti, raw, 4);
|
||||
amount = atol(raw + 10);
|
||||
|
||||
sets_(b, T_STR1, mti);
|
||||
setl(b, T_AMOUNT, amount);
|
||||
sets_(b, T_CHANNEL, "CH03"); /* 직연동 = CH03 고정 매핑 */
|
||||
setl(b, T_COUNT, n);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_DUPCHK.h
Normal file
12
app/src/mg/svc/MG_DUPCHK.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_DUPCHK.h - mg (전문게이트웨이) 서비스 MG_DUPCHK 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_DUPCHK_H
|
||||
#define MG_DUPCHK_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_DUPCHK(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_DUPCHK_H */
|
||||
35
app/src/mg/svc/MG_DUPCHK.pgc
Normal file
35
app/src/mg/svc/MG_DUPCHK.pgc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* MG_DUPCHK.pgc - mg 모듈 서비스 MG_DUPCHK (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_DUPCHK.h"
|
||||
|
||||
/* 48. MG_DUPCHK - 중복전문 검출: 동일 STAN 이 당일 원장에 이미 몇 건인지 세어
|
||||
* 2건 이상이면 중복(rc=94) 판정. 중복 초과분 건수를 함께 회신. */
|
||||
void MG_DUPCHK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_stan, h_cnt;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
h_stan = getl(b, T_ARG1);
|
||||
if (h_stan <= 0) { setl(b, T_RC, 13); FAIL(b); }
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :h_cnt
|
||||
FROM mg_msg_log WHERE stan = :h_stan AND biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
if (h_cnt > 1) {
|
||||
userlog("MG_DUPCHK 중복 STAN=%ld 건수=%ld", h_stan, h_cnt);
|
||||
setl(b, T_RC, 94); /* 94 = 중복 전문 */
|
||||
} else {
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_ARG2, (h_cnt > 1) ? h_cnt - 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_ERRLIST.h
Normal file
12
app/src/mg/svc/MG_ERRLIST.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_ERRLIST.h - mg (전문게이트웨이) 서비스 MG_ERRLIST 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_ERRLIST_H
|
||||
#define MG_ERRLIST_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_ERRLIST(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_ERRLIST_H */
|
||||
33
app/src/mg/svc/MG_ERRLIST.pgc
Normal file
33
app/src/mg/svc/MG_ERRLIST.pgc
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* MG_ERRLIST.pgc - mg 모듈 서비스 MG_ERRLIST (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_ERRLIST.h"
|
||||
|
||||
/* 66. MG_ERRLIST - 오류전문 대기목록 요약: 당일 NACK(N) 전문의 건수, 금액합,
|
||||
* 가장 오래된/최신 msg_id 를 회신 (재처리 워크플로의 조회 단계). */
|
||||
void MG_ERRLIST(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_cnt, h_sum, h_first, h_last;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0),
|
||||
coalesce(min(msg_id),0), coalesce(max(msg_id),0)
|
||||
INTO :h_cnt, :h_sum, :h_first, :h_last
|
||||
FROM mg_msg_log
|
||||
WHERE biz_date = :h_bizdate AND status = 'N';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_sum);
|
||||
setl(b, T_ID1, h_first); /* 가장 오래된 오류전문부터 재처리 */
|
||||
setl(b, T_ID2, h_last);
|
||||
setl(b, T_RC, (h_cnt > 0) ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_ERRPURGE.h
Normal file
12
app/src/mg/svc/MG_ERRPURGE.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_ERRPURGE.h - mg (전문게이트웨이) 서비스 MG_ERRPURGE 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_ERRPURGE_H
|
||||
#define MG_ERRPURGE_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_ERRPURGE(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_ERRPURGE_H */
|
||||
35
app/src/mg/svc/MG_ERRPURGE.pgc
Normal file
35
app/src/mg/svc/MG_ERRPURGE.pgc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* MG_ERRPURGE.pgc - mg 모듈 서비스 MG_ERRPURGE (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_ERRPURGE.h"
|
||||
|
||||
/* 67. MG_ERRPURGE - 오류전문 폐기: 재처리를 포기한 당일 NACK(N) 전문 중
|
||||
* 무결성 실패(96)/중복(94) 등 지정 rc 만 골라 삭제 (워크플로 종결 단계). */
|
||||
void MG_ERRPURGE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char rcsel[4];
|
||||
long purged;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_rc[4];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
gets_(b, T_STR2, rcsel, sizeof(rcsel));
|
||||
if (rcsel[0] == 0) strcpy(rcsel, "96"); /* 기본: 무결성 실패 전문만 폐기 */
|
||||
strncpy(h_rc, rcsel, sizeof(h_rc)-1); h_rc[sizeof(h_rc)-1] = 0;
|
||||
|
||||
if (h_rc[0] == '0' && h_rc[1] == '0') { setl(b, T_RC, 30); FAIL(b); } /* 정상 전문 폐기 금지 */
|
||||
|
||||
EXEC SQL DELETE FROM mg_msg_log
|
||||
WHERE biz_date = :h_bizdate AND status = 'N' AND rc = :h_rc;
|
||||
if (sqlca.sqlcode < 0) { userlog("MG_ERRPURGE 삭제 FAIL [%d]", sqlca.sqlcode); FAIL(b); }
|
||||
purged = (long)sqlca.sqlerrd[2];
|
||||
|
||||
userlog("MG_ERRPURGE rc=%s 폐기 %ld건", rcsel, purged);
|
||||
setl(b, T_COUNT, purged);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_ERRRETRY.h
Normal file
12
app/src/mg/svc/MG_ERRRETRY.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_ERRRETRY.h - mg (전문게이트웨이) 서비스 MG_ERRRETRY 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_ERRRETRY_H
|
||||
#define MG_ERRRETRY_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_ERRRETRY(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_ERRRETRY_H */
|
||||
41
app/src/mg/svc/MG_ERRRETRY.pgc
Normal file
41
app/src/mg/svc/MG_ERRRETRY.pgc
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* MG_ERRRETRY.pgc - mg 모듈 서비스 MG_ERRRETRY (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_ERRRETRY.h"
|
||||
|
||||
/* 65. MG_ERRRETRY - 오류전문 단건 재처리: NACK(N) 된 전문을 rc=00/R 로 리셋하고
|
||||
* 원문 그대로 송신 큐에 재적재 (오류전문 재처리 워크플로의 실행 단계). */
|
||||
void MG_ERRRETRY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long msg_id, qid;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id, h_stan;
|
||||
char h_status[4], h_chan[16], h_mti[8], h_raw[512], h_biz[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
msg_id = getl(b, T_ID1);
|
||||
if (msg_id <= 0) { setl(b, T_RC, 13); FAIL(b); }
|
||||
h_id = msg_id;
|
||||
|
||||
EXEC SQL SELECT status, stan, channel, mti, raw_msg, to_char(biz_date,'YYYY-MM-DD')
|
||||
INTO :h_status, :h_stan, :h_chan, :h_mti, :h_raw, :h_biz
|
||||
FROM mg_msg_log WHERE msg_id = :h_id;
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 25); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
if (h_status[0] != 'N') { setl(b, T_RC, 1); OK(b); } /* 오류 상태 아님 = 재처리 불필요 */
|
||||
|
||||
EXEC SQL UPDATE mg_msg_log SET rc = '00', status = 'R' WHERE msg_id = :h_id;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
qid = mgdb_next_queue_id(); if (qid < 0) FAIL(b);
|
||||
if (mgdb_enqueue(qid, h_stan, h_chan, h_mti, h_raw, h_biz) < 0) FAIL(b);
|
||||
|
||||
userlog("MG_ERRRETRY 재처리 msg_id=%ld -> queue_id=%ld", msg_id, qid);
|
||||
setl(b, T_ID2, qid);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_FROMISO.h
Normal file
12
app/src/mg/svc/MG_FROMISO.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_FROMISO.h - mg (전문게이트웨이) 서비스 MG_FROMISO 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_FROMISO_H
|
||||
#define MG_FROMISO_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_FROMISO(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_FROMISO_H */
|
||||
33
app/src/mg/svc/MG_FROMISO.pgc
Normal file
33
app/src/mg/svc/MG_FROMISO.pgc
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* MG_FROMISO.pgc - mg 모듈 서비스 MG_FROMISO (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_FROMISO.h"
|
||||
|
||||
/* 52. MG_FROMISO - ISO -> 내부전문 변환: 고정길이 ISO 전문을 잘라
|
||||
* 콜론 구분 내부포맷 "MTI:처리코드:금액" 으로 풀어낸다 (선행 0 제거). */
|
||||
void MG_FROMISO(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char iso[512], mti[8], proc[8], internal[64];
|
||||
long amount, n;
|
||||
|
||||
gets_(b, T_STR3, iso, sizeof(iso));
|
||||
n = (long)strlen(iso);
|
||||
if (n < 22) { setl(b, T_RC, 31); FAIL(b); } /* 최소 22바이트 필요 */
|
||||
|
||||
memset(mti, 0, sizeof(mti)); memset(proc, 0, sizeof(proc));
|
||||
strncpy(mti, iso, 4);
|
||||
strncpy(proc, iso + 4, 6);
|
||||
amount = atol(iso + 10); /* atol 이 선행 0 제거 */
|
||||
|
||||
sprintf(internal, "%.4s:%.6s:%ld", mti, proc, amount);
|
||||
sets_(b, T_STR3, internal);
|
||||
sets_(b, T_STR1, mti);
|
||||
sets_(b, T_STR4, proc);
|
||||
setl(b, T_AMOUNT, amount);
|
||||
setl(b, T_COUNT, (long)strlen(internal));
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_GAPSCAN.h
Normal file
12
app/src/mg/svc/MG_GAPSCAN.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_GAPSCAN.h - mg (전문게이트웨이) 서비스 MG_GAPSCAN 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_GAPSCAN_H
|
||||
#define MG_GAPSCAN_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_GAPSCAN(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_GAPSCAN_H */
|
||||
35
app/src/mg/svc/MG_GAPSCAN.pgc
Normal file
35
app/src/mg/svc/MG_GAPSCAN.pgc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* MG_GAPSCAN.pgc - mg 모듈 서비스 MG_GAPSCAN (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_GAPSCAN.h"
|
||||
|
||||
/* 49. MG_GAPSCAN - STAN 순번 갭 검출: 당일 최소~최대 순번 구간 폭에서 실제
|
||||
* 고유 순번 수를 빼 유실(갭) 개수를 산출. 갭 존재 시 rc=1. */
|
||||
void MG_GAPSCAN(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long gaps;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_min, h_max, h_uniq;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL SELECT coalesce(min(stan),0), coalesce(max(stan),0), count(DISTINCT stan)
|
||||
INTO :h_min, :h_max, :h_uniq
|
||||
FROM mg_msg_log WHERE biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
gaps = (h_uniq > 0) ? (h_max - h_min + 1) - h_uniq : 0;
|
||||
if (gaps > 0) userlog("MG_GAPSCAN 순번 갭 %ld건 (구간 %ld..%ld)", gaps, h_min, h_max);
|
||||
|
||||
setl(b, T_ARG1, h_min);
|
||||
setl(b, T_ARG2, h_max);
|
||||
setl(b, T_COUNT, h_uniq);
|
||||
setl(b, T_ARG6, gaps);
|
||||
setl(b, T_RC, (gaps > 0) ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_KEYROTATE.h
Normal file
12
app/src/mg/svc/MG_KEYROTATE.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_KEYROTATE.h - mg (전문게이트웨이) 서비스 MG_KEYROTATE 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_KEYROTATE_H
|
||||
#define MG_KEYROTATE_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_KEYROTATE(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_KEYROTATE_H */
|
||||
30
app/src/mg/svc/MG_KEYROTATE.pgc
Normal file
30
app/src/mg/svc/MG_KEYROTATE.pgc
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* MG_KEYROTATE.pgc - mg 모듈 서비스 MG_KEYROTATE (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_KEYROTATE.h"
|
||||
|
||||
/* 44. MG_KEYROTATE - 키 전환(교체): KEYVER 카운터를 올려 새 세대키 번호를 따고,
|
||||
* 대상 채널의 세션키를 "Kvvvv-ssss" 형식으로 재발급 (키교환 후속 절차). */
|
||||
void MG_KEYROTATE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], newkey[24];
|
||||
long kv, sess, stan;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
|
||||
kv = mgdb_seq_bump("KEYVER"); if (kv < 0) FAIL(b);
|
||||
sess = mgdb_seq_bump("SESSION"); if (sess < 0) FAIL(b);
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
|
||||
sprintf(newkey, "K%04ld-%04ld", kv, sess);
|
||||
if (mgdb_set_channel_session(chan, newkey, stan) < 0) FAIL(b);
|
||||
|
||||
userlog("MG_KEYROTATE 채널=%s 키버전=%ld 세션=%ld", chan, kv, sess);
|
||||
sets_(b, T_KEY1, newkey);
|
||||
setl(b, T_ARG3, kv);
|
||||
setl(b, T_ARG2, sess);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_KEYSTATUS.h
Normal file
12
app/src/mg/svc/MG_KEYSTATUS.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_KEYSTATUS.h - mg (전문게이트웨이) 서비스 MG_KEYSTATUS 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_KEYSTATUS_H
|
||||
#define MG_KEYSTATUS_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_KEYSTATUS(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_KEYSTATUS_H */
|
||||
37
app/src/mg/svc/MG_KEYSTATUS.pgc
Normal file
37
app/src/mg/svc/MG_KEYSTATUS.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* MG_KEYSTATUS.pgc - mg 모듈 서비스 MG_KEYSTATUS (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_KEYSTATUS.h"
|
||||
|
||||
/* 45. MG_KEYSTATUS - 키 상태 조회: 현재 키버전(KEYVER)과 채널의 세션키/사인온
|
||||
* 시각 유무를 함께 회신 (키 전환 필요 여부 판단용 열람 전용 서비스). */
|
||||
void MG_KEYSTATUS(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_kv, h_has_signon;
|
||||
char h_chan[16], h_skey[64];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
strncpy(h_chan, chan, sizeof(h_chan)-1); h_chan[sizeof(h_chan)-1] = 0;
|
||||
|
||||
h_kv = 0;
|
||||
EXEC SQL SELECT seq_val INTO :h_kv FROM mg_seq WHERE seq_name = 'KEYVER';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
EXEC SQL SELECT session_key, CASE WHEN signon_at IS NULL THEN 0 ELSE 1 END
|
||||
INTO :h_skey, :h_has_signon
|
||||
FROM mg_channel WHERE channel = :h_chan;
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 25); FAIL(b); } /* 미등록 채널 */
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
sets_(b, T_KEY1, h_skey);
|
||||
setl(b, T_ARG3, h_kv);
|
||||
setl(b, T_ARG4, h_has_signon);
|
||||
setl(b, T_RC, (h_skey[0] == 0) ? 1 : 0); /* 세션키 미발급이면 1 */
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_MACGEN.h
Normal file
12
app/src/mg/svc/MG_MACGEN.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_MACGEN.h - mg (전문게이트웨이) 서비스 MG_MACGEN 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_MACGEN_H
|
||||
#define MG_MACGEN_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_MACGEN(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_MACGEN_H */
|
||||
45
app/src/mg/svc/MG_MACGEN.pgc
Normal file
45
app/src/mg/svc/MG_MACGEN.pgc
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* MG_MACGEN.pgc - mg 모듈 서비스 MG_MACGEN (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_MACGEN.h"
|
||||
|
||||
/* ----- service-local pure helper(s) ----- */
|
||||
/* XOR-회전 8-hex MAC: 키버전을 시드로 섞어 세대별로 값이 달라진다. */
|
||||
static void mg_macgen_calc(const char *s, long keyver, char *out /* >= 9 */)
|
||||
{
|
||||
unsigned long acc = 0x9E3779B9UL ^ (unsigned long)keyver;
|
||||
int i;
|
||||
for (i = 0; s[i]; i++) {
|
||||
acc ^= (unsigned char)s[i];
|
||||
acc = (acc << 5) | (acc >> 27); /* 5비트 좌회전 */
|
||||
}
|
||||
sprintf(out, "%08lX", acc & 0xFFFFFFFFUL);
|
||||
}
|
||||
|
||||
|
||||
/* 42. MG_MACGEN - 세대키 기반 MAC 생성: 현재 키버전(mg_seq KEYVER)을 시드로
|
||||
* XOR-회전 MAC 을 만들어 회신 (검증은 MG_MACVERIFY 가 담당). */
|
||||
void MG_MACGEN(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char raw[512], mac[12];
|
||||
long keyver;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_kv;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
if (raw[0] == 0) { setl(b, T_RC, 30); FAIL(b); }
|
||||
|
||||
EXEC SQL SELECT seq_val INTO :h_kv FROM mg_seq WHERE seq_name = 'KEYVER';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
keyver = (sqlca.sqlcode == 100) ? 0 : h_kv;
|
||||
|
||||
mg_macgen_calc(raw, keyver, mac);
|
||||
sets_(b, T_KEY1, mac);
|
||||
setl(b, T_ARG3, keyver);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_MACVERIFY.h
Normal file
12
app/src/mg/svc/MG_MACVERIFY.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_MACVERIFY.h - mg (전문게이트웨이) 서비스 MG_MACVERIFY 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_MACVERIFY_H
|
||||
#define MG_MACVERIFY_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_MACVERIFY(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_MACVERIFY_H */
|
||||
50
app/src/mg/svc/MG_MACVERIFY.pgc
Normal file
50
app/src/mg/svc/MG_MACVERIFY.pgc
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* MG_MACVERIFY.pgc - mg 모듈 서비스 MG_MACVERIFY (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_MACVERIFY.h"
|
||||
|
||||
/* ----- service-local pure helper(s) ----- */
|
||||
/* MG_MAC 과 동일 계열의 가산 체크섬 (검증측 독립 구현, 4-hex). */
|
||||
static void mg_macverify_sum(const char *s, char *out /* >= 5 */)
|
||||
{
|
||||
unsigned int v = 0; int i;
|
||||
for (i = 0; s[i]; i++) v = (v + (unsigned char)s[i] * 31u) & 0xFFFF;
|
||||
sprintf(out, "%04X", v);
|
||||
}
|
||||
|
||||
|
||||
/* 43. MG_MACVERIFY - 수신전문 MAC 검증: 원장의 raw_msg 로 MAC 을 재계산해
|
||||
* 저장된 mac 과 대조. 불일치면 rc=96/상태 N(무결성 실패) 전이. */
|
||||
void MG_MACVERIFY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char calc[8];
|
||||
long msg_id;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id;
|
||||
char h_mac[16], h_raw[512];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
msg_id = getl(b, T_ID1);
|
||||
if (msg_id <= 0) { setl(b, T_RC, 25); FAIL(b); }
|
||||
|
||||
h_id = msg_id;
|
||||
EXEC SQL SELECT mac, raw_msg INTO :h_mac, :h_raw
|
||||
FROM mg_msg_log WHERE msg_id = :h_id;
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 25); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
mg_macverify_sum(h_raw, calc);
|
||||
if (strncmp(h_mac, calc, 4) == 0) {
|
||||
setl(b, T_RC, 0); /* MAC 일치 */
|
||||
} else {
|
||||
EXEC SQL UPDATE mg_msg_log SET rc = '96', status = 'N' WHERE msg_id = :h_id;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
userlog("MG_MACVERIFY 무결성 실패 msg_id=%ld 저장=%s 계산=%s", msg_id, h_mac, calc);
|
||||
setl(b, T_RC, 96);
|
||||
}
|
||||
sets_(b, T_KEY2, calc);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_NETMGMT.h
Normal file
12
app/src/mg/svc/MG_NETMGMT.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_NETMGMT.h - mg (전문게이트웨이) 서비스 MG_NETMGMT 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_NETMGMT_H
|
||||
#define MG_NETMGMT_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_NETMGMT(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_NETMGMT_H */
|
||||
39
app/src/mg/svc/MG_NETMGMT.pgc
Normal file
39
app/src/mg/svc/MG_NETMGMT.pgc
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* MG_NETMGMT.pgc - mg 모듈 서비스 MG_NETMGMT (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_NETMGMT.h"
|
||||
|
||||
/* 37. MG_NETMGMT - 0800 망관리 전문 라우터: 처리코드 001=사인온(UP),
|
||||
* 002=사인오프(DOWN), 301=에코(상태유지). 처리 후 0810 응답 MTI 회신. */
|
||||
void MG_NETMGMT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], proc[8], bizdate[16], rc[4];
|
||||
long stan, msg_id;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_STR4, proc, sizeof(proc)); if (proc[0] == 0) strcpy(proc, "301");
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
|
||||
strcpy(rc, "00");
|
||||
if (strncmp(proc, "001", 3) == 0) {
|
||||
if (mgdb_set_channel_status(chan, "UP") < 0) FAIL(b);
|
||||
} else if (strncmp(proc, "002", 3) == 0) {
|
||||
if (mgdb_set_channel_status(chan, "DOWN") < 0) FAIL(b);
|
||||
} else if (strncmp(proc, "301", 3) == 0) {
|
||||
/* 에코: 상태 변경 없음, 수신 자체가 생존 신호 */
|
||||
} else {
|
||||
strcpy(rc, "12"); /* 12 = 무효 처리코드 */
|
||||
}
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0800", chan, "IN", proc, "", 0,
|
||||
"", rc, "", "R", bizdate) < 0) FAIL(b);
|
||||
sets_(b, T_STR1, "0810");
|
||||
sets_(b, T_STR2, rc);
|
||||
setl(b, T_ID1, msg_id);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_PANMASK.h
Normal file
12
app/src/mg/svc/MG_PANMASK.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_PANMASK.h - mg (전문게이트웨이) 서비스 MG_PANMASK 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_PANMASK_H
|
||||
#define MG_PANMASK_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_PANMASK(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_PANMASK_H */
|
||||
52
app/src/mg/svc/MG_PANMASK.pgc
Normal file
52
app/src/mg/svc/MG_PANMASK.pgc
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* MG_PANMASK.pgc - mg 모듈 서비스 MG_PANMASK (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_PANMASK.h"
|
||||
|
||||
/* ----- service-local pure helper(s) ----- */
|
||||
/* BIN(앞6)/뒤4 보존 마스킹. 12자리 미만 짧은 PAN 은 전체 마스킹. */
|
||||
static int mg_panmask_apply(const char *pan, char *out /* >= 20 */)
|
||||
{
|
||||
int i, n = (int)strlen(pan);
|
||||
if (n > 19) n = 19;
|
||||
if (n < 12) {
|
||||
for (i = 0; i < n; i++) out[i] = '*';
|
||||
out[n] = 0;
|
||||
return 1; /* 비정상 길이 표시 */
|
||||
}
|
||||
for (i = 0; i < n; i++)
|
||||
out[i] = (i < 6 || i >= n - 4) ? pan[i] : '*';
|
||||
out[n] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* 70. MG_PANMASK - PAN 마스킹: 카드번호를 BIN/뒤4자리만 남겨 가리고, msg_id 가
|
||||
* 주어지면 원장의 pan 컬럼도 마스킹본으로 덮어쓴다 (정보보호 후처리). */
|
||||
void MG_PANMASK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char pan[24], masked[24];
|
||||
int shortpan;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id;
|
||||
char h_pan[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_STR5, pan, sizeof(pan));
|
||||
if (pan[0] == 0) { setl(b, T_RC, 30); FAIL(b); }
|
||||
|
||||
shortpan = mg_panmask_apply(pan, masked);
|
||||
sets_(b, T_STR5, masked);
|
||||
|
||||
h_id = getl(b, T_ID1);
|
||||
if (h_id > 0) {
|
||||
strncpy(h_pan, masked, sizeof(h_pan)-1); h_pan[sizeof(h_pan)-1] = 0;
|
||||
EXEC SQL UPDATE mg_msg_log SET pan = :h_pan WHERE msg_id = :h_id;
|
||||
if (sqlca.sqlcode < 0) { userlog("MG_PANMASK 원장 마스킹 FAIL [%d]", sqlca.sqlcode); FAIL(b); }
|
||||
}
|
||||
setl(b, T_RC, shortpan); /* 1 = 길이 비정상 PAN 이었음 */
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_QDEPTH.h
Normal file
12
app/src/mg/svc/MG_QDEPTH.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_QDEPTH.h - mg (전문게이트웨이) 서비스 MG_QDEPTH 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_QDEPTH_H
|
||||
#define MG_QDEPTH_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_QDEPTH(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_QDEPTH_H */
|
||||
37
app/src/mg/svc/MG_QDEPTH.pgc
Normal file
37
app/src/mg/svc/MG_QDEPTH.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* MG_QDEPTH.pgc - mg 모듈 서비스 MG_QDEPTH (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_QDEPTH.h"
|
||||
|
||||
/* 75. MG_QDEPTH - 송수신 큐 깊이 조회: 대기(Q)/송신(S)/완료(D)/실패(F) 상태별
|
||||
* 건수와 최대 재시도 횟수를 한 집계로 회신 (큐 적체 대시보드). */
|
||||
void MG_QDEPTH(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_q, h_s, h_d, h_f, h_maxretry;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL SELECT
|
||||
coalesce(sum(CASE WHEN status = 'Q' THEN 1 ELSE 0 END),0),
|
||||
coalesce(sum(CASE WHEN status = 'S' THEN 1 ELSE 0 END),0),
|
||||
coalesce(sum(CASE WHEN status = 'D' THEN 1 ELSE 0 END),0),
|
||||
coalesce(sum(CASE WHEN status = 'F' THEN 1 ELSE 0 END),0),
|
||||
coalesce(max(retry_cnt),0)
|
||||
INTO :h_q, :h_s, :h_d, :h_f, :h_maxretry
|
||||
FROM mg_queue WHERE biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
setl(b, T_ARG1, h_q);
|
||||
setl(b, T_ARG2, h_s);
|
||||
setl(b, T_ARG3, h_d);
|
||||
setl(b, T_ARG4, h_f);
|
||||
setl(b, T_ARG7, h_maxretry);
|
||||
setl(b, T_RC, (h_q + h_f > 100) ? 1 : 0); /* 적체+실패 100건 초과 경보 */
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_REASM.h
Normal file
12
app/src/mg/svc/MG_REASM.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_REASM.h - mg (전문게이트웨이) 서비스 MG_REASM 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_REASM_H
|
||||
#define MG_REASM_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_REASM(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_REASM_H */
|
||||
40
app/src/mg/svc/MG_REASM.pgc
Normal file
40
app/src/mg/svc/MG_REASM.pgc
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* MG_REASM.pgc - mg 모듈 서비스 MG_REASM (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_REASM.h"
|
||||
|
||||
/* 41. MG_REASM - 분할전문 재조립: 세그먼트 T_STR5~T_STR8 (최대 4편) 을 순서대로
|
||||
* 이어붙여 원 전문을 복원. 기대 편수(T_ARG1)와 실제 편수 불일치 시 rc=35. */
|
||||
void MG_REASM(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char seg[4][128], full[512];
|
||||
long expect, got = 0, total = 0;
|
||||
int i;
|
||||
BFLDID segf[4];
|
||||
segf[0] = T_STR5; segf[1] = T_STR6; segf[2] = T_STR7; segf[3] = T_STR8;
|
||||
|
||||
expect = getl(b, T_ARG1); if (expect <= 0 || expect > 4) expect = 4;
|
||||
|
||||
full[0] = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
gets_(b, segf[i], seg[i], sizeof(seg[i]));
|
||||
if (seg[i][0] == 0) break; /* 첫 빈 세그먼트에서 종료 */
|
||||
got++;
|
||||
total += (long)strlen(seg[i]);
|
||||
strcat(full, seg[i]);
|
||||
}
|
||||
|
||||
if (got != expect) { /* 편수 불일치 = 재조립 실패 */
|
||||
userlog("MG_REASM 편수 불일치 기대=%ld 수신=%ld", expect, got);
|
||||
setl(b, T_RC, 35);
|
||||
FAIL(b);
|
||||
}
|
||||
sets_(b, T_STR3, full);
|
||||
setl(b, T_COUNT, got);
|
||||
setl(b, T_ARG2, total);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_REVADVICE.h
Normal file
12
app/src/mg/svc/MG_REVADVICE.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_REVADVICE.h - mg (전문게이트웨이) 서비스 MG_REVADVICE 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_REVADVICE_H
|
||||
#define MG_REVADVICE_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_REVADVICE(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_REVADVICE_H */
|
||||
41
app/src/mg/svc/MG_REVADVICE.pgc
Normal file
41
app/src/mg/svc/MG_REVADVICE.pgc
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* MG_REVADVICE.pgc - mg 모듈 서비스 MG_REVADVICE (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_REVADVICE.h"
|
||||
|
||||
/* 36. MG_REVADVICE - 0420 취소 어드바이스 수신: 통지성 전문이므로 무조건 수용(A),
|
||||
* 적재 후 채널 last_stan 을 수신 STAN 까지 전진시켜 순번 동기 유지. */
|
||||
void MG_REVADVICE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], bizdate[16], raw[512];
|
||||
long stan, msg_id, amount;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_stan;
|
||||
char h_chan[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
gets_(b, T_STR3, raw, sizeof(raw));
|
||||
amount = getl(b, T_AMOUNT);
|
||||
|
||||
stan = getl(b, T_ARG1);
|
||||
if (stan <= 0) { stan = mgdb_next_stan(); if (stan < 0) FAIL(b); }
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0420", chan, "IN", "170000", "", -amount,
|
||||
"", "00", raw, "A", bizdate) < 0) FAIL(b);
|
||||
|
||||
h_stan = stan;
|
||||
strncpy(h_chan, chan, sizeof(h_chan)-1); h_chan[sizeof(h_chan)-1] = 0;
|
||||
EXEC SQL UPDATE mg_channel
|
||||
SET last_stan = greatest(last_stan, :h_stan), updated_at = now()
|
||||
WHERE channel = :h_chan;
|
||||
if (sqlca.sqlcode < 0) { userlog("MG_REVADVICE 순번동기 FAIL [%d]", sqlca.sqlcode); FAIL(b); }
|
||||
|
||||
setl(b, T_ID1, msg_id);
|
||||
setl(b, T_ARG1, stan);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_REVERSAL.h
Normal file
12
app/src/mg/svc/MG_REVERSAL.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_REVERSAL.h - mg (전문게이트웨이) 서비스 MG_REVERSAL 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_REVERSAL_H
|
||||
#define MG_REVERSAL_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_REVERSAL(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_REVERSAL_H */
|
||||
39
app/src/mg/svc/MG_REVERSAL.pgc
Normal file
39
app/src/mg/svc/MG_REVERSAL.pgc
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* MG_REVERSAL.pgc - mg 모듈 서비스 MG_REVERSAL (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_REVERSAL.h"
|
||||
|
||||
/* 35. MG_REVERSAL - 0400 취소요청 처리: 원전문을 STAN 으로 찾아 rc=17(고객취소)
|
||||
* 확정 전이 후, 음수 금액의 0400 수신 로그를 별도 적재 (취소 원장). */
|
||||
void MG_REVERSAL(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], bizdate[16];
|
||||
long stan, orig_id, msg_id, rev_stan, amount;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_oid;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
stan = getl(b, T_ARG1);
|
||||
amount = getl(b, T_AMOUNT);
|
||||
|
||||
orig_id = mgdb_find_msg_by_stan(stan);
|
||||
if (orig_id < 0) { setl(b, T_RC, 25); OK(b); } /* 원거래 없음 */
|
||||
|
||||
h_oid = orig_id;
|
||||
EXEC SQL UPDATE mg_msg_log SET rc = '17', status = 'C' WHERE msg_id = :h_oid;
|
||||
if (sqlca.sqlcode < 0) { userlog("MG_REVERSAL 원전문 취소전이 FAIL [%d]", sqlca.sqlcode); FAIL(b); }
|
||||
|
||||
rev_stan = mgdb_next_stan(); if (rev_stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, rev_stan, "0400", chan, "IN", "170000", "", -amount,
|
||||
"", "00", "", "R", bizdate) < 0) FAIL(b);
|
||||
setl(b, T_ID1, orig_id);
|
||||
setl(b, T_ID2, msg_id);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_RTADD.h
Normal file
12
app/src/mg/svc/MG_RTADD.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_RTADD.h - mg (전문게이트웨이) 서비스 MG_RTADD 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_RTADD_H
|
||||
#define MG_RTADD_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_RTADD(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_RTADD_H */
|
||||
35
app/src/mg/svc/MG_RTADD.pgc
Normal file
35
app/src/mg/svc/MG_RTADD.pgc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* MG_RTADD.pgc - mg 모듈 서비스 MG_RTADD (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_RTADD.h"
|
||||
|
||||
/* 53. MG_RTADD - 라우팅 룰 등록: 채널+MTI -> 목적지 룰을 신규 채번해 추가.
|
||||
* 동일 채널/MTI 활성 룰이 이미 있으면 rc=1 로 중복 등록을 알린다. */
|
||||
void MG_RTADD(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], mti[8], dest[64], bizdate[16], old_dest[64];
|
||||
long prio, dup = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_rid;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
|
||||
gets_(b, T_STR1, mti, sizeof(mti)); if (mti[0] == 0) strcpy(mti, "0200");
|
||||
gets_(b, T_STR3, dest, sizeof(dest));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
prio = getl(b, T_ARG4); if (prio <= 0) prio = 100;
|
||||
if (dest[0] == 0) { setl(b, T_RC, 30); FAIL(b); }
|
||||
|
||||
if (mgdb_lookup_route(chan, mti, old_dest) == 0) dup = 1; /* 기존 활성 룰 존재 */
|
||||
|
||||
EXEC SQL SELECT nextval('mg_route_seq') INTO :h_rid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (mgdb_insert_route(h_rid, chan, mti, dest, prio, bizdate) < 0) FAIL(b);
|
||||
|
||||
setl(b, T_ID1, h_rid);
|
||||
setl(b, T_RC, dup);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_RTDROP.h
Normal file
12
app/src/mg/svc/MG_RTDROP.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_RTDROP.h - mg (전문게이트웨이) 서비스 MG_RTDROP 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_RTDROP_H
|
||||
#define MG_RTDROP_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_RTDROP(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_RTDROP_H */
|
||||
30
app/src/mg/svc/MG_RTDROP.pgc
Normal file
30
app/src/mg/svc/MG_RTDROP.pgc
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* MG_RTDROP.pgc - mg 모듈 서비스 MG_RTDROP (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_RTDROP.h"
|
||||
|
||||
/* 54. MG_RTDROP - 라우팅 룰 비활성: 채널+MTI 의 활성 룰을 전부 내려서
|
||||
* 라우팅에서 제외. 내린 룰 수를 회신하고 대상이 없으면 rc=25. */
|
||||
void MG_RTDROP(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long dropped;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16], h_mti[8];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, h_chan, sizeof(h_chan)); if (h_chan[0] == 0) strcpy(h_chan, "CH01");
|
||||
gets_(b, T_STR1, h_mti, sizeof(h_mti)); if (h_mti[0] == 0) strcpy(h_mti, "0200");
|
||||
|
||||
EXEC SQL UPDATE mg_route SET active = false
|
||||
WHERE channel = :h_chan AND mti = :h_mti AND active = true;
|
||||
if (sqlca.sqlcode < 0) { userlog("MG_RTDROP 비활성 FAIL [%d]", sqlca.sqlcode); FAIL(b); }
|
||||
dropped = (long)sqlca.sqlerrd[2];
|
||||
|
||||
if (dropped == 0) { setl(b, T_RC, 25); OK(b); } /* 내릴 룰 없음 */
|
||||
setl(b, T_COUNT, dropped);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_RTLIST.h
Normal file
12
app/src/mg/svc/MG_RTLIST.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_RTLIST.h - mg (전문게이트웨이) 서비스 MG_RTLIST 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_RTLIST_H
|
||||
#define MG_RTLIST_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_RTLIST(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_RTLIST_H */
|
||||
47
app/src/mg/svc/MG_RTLIST.pgc
Normal file
47
app/src/mg/svc/MG_RTLIST.pgc
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* MG_RTLIST.pgc - mg 모듈 서비스 MG_RTLIST (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_RTLIST.h"
|
||||
|
||||
/* 55. MG_RTLIST - 라우팅 룰 열람 요약: 채널의 활성/비활성 룰 수와 최우선(최소)
|
||||
* priority 의 목적지를 커서로 훑어 회신 (룰 대시보드용). */
|
||||
void MG_RTLIST(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long act = 0, inact = 0, best_prio = -1;
|
||||
char best_dest[64];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16], h_dest[64];
|
||||
long h_prio, h_active;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, h_chan, sizeof(h_chan)); if (h_chan[0] == 0) strcpy(h_chan, "CH01");
|
||||
best_dest[0] = 0;
|
||||
|
||||
EXEC SQL DECLARE rtl CURSOR FOR
|
||||
SELECT dest, priority, CASE WHEN active THEN 1 ELSE 0 END
|
||||
FROM mg_route WHERE channel = :h_chan ORDER BY priority;
|
||||
EXEC SQL OPEN rtl;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH rtl INTO :h_dest, :h_prio, :h_active;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE rtl; FAIL(b); }
|
||||
if (h_active) {
|
||||
act++;
|
||||
if (best_prio < 0) { best_prio = h_prio; strncpy(best_dest, h_dest, sizeof(best_dest)-1); }
|
||||
} else {
|
||||
inact++;
|
||||
}
|
||||
}
|
||||
EXEC SQL CLOSE rtl;
|
||||
|
||||
sets_(b, T_STR3, best_dest);
|
||||
setl(b, T_ARG4, (best_prio < 0) ? 0 : best_prio);
|
||||
setl(b, T_COUNT, act);
|
||||
setl(b, T_ARG7, inact);
|
||||
setl(b, T_RC, (act == 0) ? 1 : 0); /* 활성 룰 전무 = 경고 */
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_RTSWITCH.h
Normal file
12
app/src/mg/svc/MG_RTSWITCH.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_RTSWITCH.h - mg (전문게이트웨이) 서비스 MG_RTSWITCH 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_RTSWITCH_H
|
||||
#define MG_RTSWITCH_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_RTSWITCH(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_RTSWITCH_H */
|
||||
37
app/src/mg/svc/MG_RTSWITCH.pgc
Normal file
37
app/src/mg/svc/MG_RTSWITCH.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* MG_RTSWITCH.pgc - mg 모듈 서비스 MG_RTSWITCH (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_RTSWITCH.h"
|
||||
|
||||
/* 56. MG_RTSWITCH - 라우팅 목적지 절체: 채널+MTI 활성 룰의 dest 를 새 목적지로
|
||||
* 일괄 교체 (장애 우회). 교체 전 목적지를 T_STR5 로 돌려줘 원복을 돕는다. */
|
||||
void MG_RTSWITCH(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char prev[64];
|
||||
long switched;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16], h_mti[8], h_new[64];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, h_chan, sizeof(h_chan)); if (h_chan[0] == 0) strcpy(h_chan, "CH01");
|
||||
gets_(b, T_STR1, h_mti, sizeof(h_mti)); if (h_mti[0] == 0) strcpy(h_mti, "0200");
|
||||
gets_(b, T_STR3, h_new, sizeof(h_new));
|
||||
if (h_new[0] == 0) { setl(b, T_RC, 30); FAIL(b); }
|
||||
|
||||
if (mgdb_lookup_route(h_chan, h_mti, prev) < 0) { setl(b, T_RC, 25); FAIL(b); }
|
||||
if (strcmp(prev, h_new) == 0) { setl(b, T_RC, 1); OK(b); } /* 이미 그 목적지 */
|
||||
|
||||
EXEC SQL UPDATE mg_route SET dest = :h_new
|
||||
WHERE channel = :h_chan AND mti = :h_mti AND active = true;
|
||||
if (sqlca.sqlcode < 0) { userlog("MG_RTSWITCH 절체 FAIL [%d]", sqlca.sqlcode); FAIL(b); }
|
||||
switched = (long)sqlca.sqlerrd[2];
|
||||
|
||||
userlog("MG_RTSWITCH %s/%s: %s -> %s (%ld룰)", h_chan, h_mti, prev, h_new, switched);
|
||||
sets_(b, T_STR5, prev);
|
||||
setl(b, T_COUNT, switched);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_SEQAUDIT.h
Normal file
12
app/src/mg/svc/MG_SEQAUDIT.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_SEQAUDIT.h - mg (전문게이트웨이) 서비스 MG_SEQAUDIT 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_SEQAUDIT_H
|
||||
#define MG_SEQAUDIT_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_SEQAUDIT(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_SEQAUDIT_H */
|
||||
40
app/src/mg/svc/MG_SEQAUDIT.pgc
Normal file
40
app/src/mg/svc/MG_SEQAUDIT.pgc
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* MG_SEQAUDIT.pgc - mg 모듈 서비스 MG_SEQAUDIT (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_SEQAUDIT.h"
|
||||
|
||||
/* 50. MG_SEQAUDIT - 채널 순번 감사: 채널이 기억하는 last_stan 과 원장의 실제
|
||||
* 최대 STAN 을 대조해 어긋난 폭(드리프트)을 회신. 어긋나면 rc=1. */
|
||||
void MG_SEQAUDIT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long drift;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_last, h_maxstan;
|
||||
char h_chan[16], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, h_chan, sizeof(h_chan)); if (h_chan[0] == 0) strcpy(h_chan, "CH01");
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL SELECT last_stan INTO :h_last FROM mg_channel WHERE channel = :h_chan;
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 25); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
EXEC SQL SELECT coalesce(max(stan),0) INTO :h_maxstan
|
||||
FROM mg_msg_log WHERE channel = :h_chan AND biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
drift = h_maxstan - h_last;
|
||||
if (drift != 0)
|
||||
userlog("MG_SEQAUDIT 채널=%s 드리프트=%ld (채널=%ld 원장=%ld)",
|
||||
h_chan, drift, h_last, h_maxstan);
|
||||
|
||||
setl(b, T_ARG1, h_last);
|
||||
setl(b, T_ARG2, h_maxstan);
|
||||
setl(b, T_ARG6, drift);
|
||||
setl(b, T_RC, (drift != 0) ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_SETTLEREQ.h
Normal file
12
app/src/mg/svc/MG_SETTLEREQ.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_SETTLEREQ.h - mg (전문게이트웨이) 서비스 MG_SETTLEREQ 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_SETTLEREQ_H
|
||||
#define MG_SETTLEREQ_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_SETTLEREQ(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_SETTLEREQ_H */
|
||||
43
app/src/mg/svc/MG_SETTLEREQ.pgc
Normal file
43
app/src/mg/svc/MG_SETTLEREQ.pgc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* MG_SETTLEREQ.pgc - mg 모듈 서비스 MG_SETTLEREQ (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_SETTLEREQ.h"
|
||||
|
||||
/* 73. MG_SETTLEREQ - 0500 정산집계 요청 생성: 당일 채널의 수신 0200 건수/금액을
|
||||
* 집계해 대사 원문("C:건수:합계")으로 삼은 0500 송신 전문을 적재. */
|
||||
void MG_SETTLEREQ(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], bizdate[16], recon[64];
|
||||
long stan, msg_id;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16], h_biz[16];
|
||||
long h_cnt, h_sum;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH02");
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
strncpy(h_chan, chan, sizeof(h_chan)-1); h_chan[sizeof(h_chan)-1] = 0;
|
||||
strncpy(h_biz, bizdate, sizeof(h_biz)-1); h_biz[sizeof(h_biz)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0)
|
||||
INTO :h_cnt, :h_sum
|
||||
FROM mg_msg_log
|
||||
WHERE channel = :h_chan AND biz_date = :h_biz
|
||||
AND mti = '0200' AND direction = 'IN';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
sprintf(recon, "C:%ld:%ld", h_cnt, h_sum); /* 대사 원문 */
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0500", chan, "OUT", "920000", "", h_sum,
|
||||
"", "00", recon, "S", bizdate) < 0) FAIL(b);
|
||||
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_sum);
|
||||
setl(b, T_ID1, msg_id);
|
||||
sets_(b, T_STR3, recon);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_SETTLERSP.h
Normal file
12
app/src/mg/svc/MG_SETTLERSP.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_SETTLERSP.h - mg (전문게이트웨이) 서비스 MG_SETTLERSP 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_SETTLERSP_H
|
||||
#define MG_SETTLERSP_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_SETTLERSP(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_SETTLERSP_H */
|
||||
50
app/src/mg/svc/MG_SETTLERSP.pgc
Normal file
50
app/src/mg/svc/MG_SETTLERSP.pgc
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* MG_SETTLERSP.pgc - mg 모듈 서비스 MG_SETTLERSP (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_SETTLERSP.h"
|
||||
|
||||
/* 74. MG_SETTLERSP - 0510 정산집계 응답 대사: 상대기관이 보낸 건수/합계를 당일
|
||||
* 자체 집계와 대조해 일치 rc=00, 불일치 rc=95(대사불일치)로 판정 적재. */
|
||||
void MG_SETTLERSP(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char chan[16], bizdate[16], rc[4];
|
||||
long their_cnt, their_sum, stan, msg_id;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_chan[16], h_biz[16];
|
||||
long h_cnt, h_sum;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH02");
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
their_cnt = getl(b, T_COUNT); /* 상대기관 집계 건수 */
|
||||
their_sum = getl(b, T_GROSS); /* 상대기관 집계 합계 */
|
||||
|
||||
strncpy(h_chan, chan, sizeof(h_chan)-1); h_chan[sizeof(h_chan)-1] = 0;
|
||||
strncpy(h_biz, bizdate, sizeof(h_biz)-1); h_biz[sizeof(h_biz)-1] = 0;
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0)
|
||||
INTO :h_cnt, :h_sum
|
||||
FROM mg_msg_log
|
||||
WHERE channel = :h_chan AND biz_date = :h_biz
|
||||
AND mti = '0200' AND direction = 'IN';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
strcpy(rc, (their_cnt == h_cnt && their_sum == h_sum) ? "00" : "95");
|
||||
if (rc[0] == '9')
|
||||
userlog("MG_SETTLERSP 대사 불일치 채널=%s 건수 %ld/%ld 합계 %ld/%ld",
|
||||
chan, their_cnt, h_cnt, their_sum, h_sum);
|
||||
|
||||
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
|
||||
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
|
||||
if (mgdb_insert_msg(msg_id, stan, "0510", chan, "IN", "920000", "", their_sum,
|
||||
"", rc, "", "C", bizdate) < 0) FAIL(b);
|
||||
|
||||
sets_(b, T_STR2, rc);
|
||||
setl(b, T_ARG1, h_cnt);
|
||||
setl(b, T_AMT1, h_sum);
|
||||
setl(b, T_ID1, msg_id);
|
||||
setl(b, T_RC, (rc[0] == '0') ? 0 : 95);
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_STATDIR.h
Normal file
12
app/src/mg/svc/MG_STATDIR.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_STATDIR.h - mg (전문게이트웨이) 서비스 MG_STATDIR 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_STATDIR_H
|
||||
#define MG_STATDIR_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_STATDIR(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_STATDIR_H */
|
||||
38
app/src/mg/svc/MG_STATDIR.pgc
Normal file
38
app/src/mg/svc/MG_STATDIR.pgc
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* MG_STATDIR.pgc - mg 모듈 서비스 MG_STATDIR (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_STATDIR.h"
|
||||
|
||||
/* 63. MG_STATDIR - 송수신 방향별 통계: 당일 IN/OUT 각각의 건수와 금액합,
|
||||
* 그리고 수신 대비 송신 응답률(%) 을 산출 (미응답 적체 감시). */
|
||||
void MG_STATDIR(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long rsp_pct;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_in_cnt, h_in_sum, h_out_cnt, h_out_sum;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL SELECT
|
||||
coalesce(sum(CASE WHEN direction = 'IN' THEN 1 ELSE 0 END),0),
|
||||
coalesce(sum(CASE WHEN direction = 'IN' THEN amount ELSE 0 END),0),
|
||||
coalesce(sum(CASE WHEN direction = 'OUT' THEN 1 ELSE 0 END),0),
|
||||
coalesce(sum(CASE WHEN direction = 'OUT' THEN amount ELSE 0 END),0)
|
||||
INTO :h_in_cnt, :h_in_sum, :h_out_cnt, :h_out_sum
|
||||
FROM mg_msg_log WHERE biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
rsp_pct = (h_in_cnt > 0) ? (h_out_cnt * 100L) / h_in_cnt : 100;
|
||||
setl(b, T_ARG1, h_in_cnt);
|
||||
setl(b, T_AMT1, h_in_sum);
|
||||
setl(b, T_ARG2, h_out_cnt);
|
||||
setl(b, T_AMT2, h_out_sum);
|
||||
setl(b, T_ARG8, rsp_pct);
|
||||
setl(b, T_RC, (rsp_pct < 90) ? 1 : 0); /* 응답률 90% 미만 = 경고 */
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_STATHOUR.h
Normal file
12
app/src/mg/svc/MG_STATHOUR.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_STATHOUR.h - mg (전문게이트웨이) 서비스 MG_STATHOUR 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_STATHOUR_H
|
||||
#define MG_STATHOUR_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_STATHOUR(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_STATHOUR_H */
|
||||
42
app/src/mg/svc/MG_STATHOUR.pgc
Normal file
42
app/src/mg/svc/MG_STATHOUR.pgc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* MG_STATHOUR.pgc - mg 모듈 서비스 MG_STATHOUR (one service = one file).
|
||||
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
|
||||
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
|
||||
*/
|
||||
#include "MG_STATHOUR.h"
|
||||
|
||||
/* 62. MG_STATHOUR - 시간대별 통계: 요청 시(0~23)의 당일 건수/금액합과 함께
|
||||
* 당일 최다 유입 시간대(피크아워)를 커서 없이 집계 질의로 회신. */
|
||||
void MG_STATHOUR(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long hour;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_hour, h_cnt, h_sum, h_peak;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
hour = getl(b, T_ARG5);
|
||||
if (hour < 0 || hour > 23) hour = 0;
|
||||
h_hour = hour;
|
||||
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0)
|
||||
INTO :h_cnt, :h_sum
|
||||
FROM mg_msg_log
|
||||
WHERE biz_date = :h_bizdate
|
||||
AND extract(hour FROM created_at) = :h_hour;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
h_peak = -1;
|
||||
EXEC SQL SELECT extract(hour FROM created_at)::int INTO :h_peak
|
||||
FROM mg_msg_log WHERE biz_date = :h_bizdate
|
||||
GROUP BY 1 ORDER BY count(*) DESC, 1 LIMIT 1;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_sum);
|
||||
setl(b, T_ARG5, hour);
|
||||
setl(b, T_ARG6, h_peak); /* -1 = 당일 전문 없음 */
|
||||
OK(b);
|
||||
}
|
||||
12
app/src/mg/svc/MG_STATMTI.h
Normal file
12
app/src/mg/svc/MG_STATMTI.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* MG_STATMTI.h - mg (전문게이트웨이) 서비스 MG_STATMTI 카피북 (copybook / record header).
|
||||
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
|
||||
*/
|
||||
#ifndef MG_STATMTI_H
|
||||
#define MG_STATMTI_H
|
||||
|
||||
#include "mg_svc.h"
|
||||
|
||||
void MG_STATMTI(TPSVCINFO *p);
|
||||
|
||||
#endif /* MG_STATMTI_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