Phase 2c: 전 11모듈 per-service 레거시 구조 분해·확장 (실동작 유지)

- 10개 모듈(au py rc st lg cl mm vl mg cm)을 ac 템플릿대로 분해:
  svc/ 30 서비스 .pgc + 카피북 .h, 얇은 <mod>_svr 디스패처
  dbio/ ~25 .pgc(+.h), batch/ ~17 .pgc, run/ ~17 .sh (모듈마다)
- 파일: svc 330 + dbio 276 + batch 187 + run 187, 총 소스 1602본
- 서비스별 고유 실로직(정규화 md5), build.sh 자동발견(inline/split 양립)
- 통합 검증: build DONE modules=11 servers=11 batches=187, 12서버 runok,
  333 서비스 AVAIL, 매입체인 XA 커밋(status=S), prepared_xacts=0

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
forge-bot 2026-07-19 11:58:44 +00:00
parent c3b99a8b75
commit fd8b418c6e
1404 changed files with 30322 additions and 5994 deletions

View file

@ -0,0 +1,34 @@
/*
* mm_acct_check_batch.pgc - 정산계좌 미설정 가맹점 점검 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, the EXEC SQL work runs on that branch, then tpcommit drives XA 2PC.
* Usage: mm_acct_check_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
long rows = 0; (void)rows; (void)argc; (void)argv;
EXEC SQL BEGIN DECLARE SECTION;
long h_missing;
EXEC SQL END DECLARE SECTION;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT count(*) INTO :h_missing FROM mm_merchant_ext
WHERE (settle_acct IS NULL OR settle_acct = '') AND status = 'ACTIVE';
if (sqlca.sqlcode < 0) { fprintf(stderr, "mm_acct_check_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_acct_check_batch COMMIT: 계좌미설정=%ld\n", h_missing);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,43 @@
/*
* mm_bin_load_batch.pgc - 발급사별 BIN 적재 현황 배치 (커서) (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, the EXEC SQL work runs on that branch, then tpcommit drives XA 2PC.
* Usage: mm_bin_load_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
long rows = 0; (void)rows; (void)argc; (void)argv;
EXEC SQL BEGIN DECLARE SECTION;
char h_issuer[32]; long h_cnt;
EXEC SQL END DECLARE SECTION;
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 bic CURSOR FOR
SELECT issuer_cd, count(*) FROM mm_bin GROUP BY issuer_cd ORDER BY issuer_cd;
EXEC SQL OPEN bic;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH bic INTO :h_issuer, :h_cnt;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bic; tpabort(0); return 1; }
rows++;
}
EXEC SQL CLOSE bic;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mm_bin_load_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_bin_load_batch COMMIT: 발급사구간=%ld\n", rows);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,34 @@
/*
* mm_code_sync_batch.pgc - 공통코드 활성 수 동기화 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, the EXEC SQL work runs on that branch, then tpcommit drives XA 2PC.
* Usage: mm_code_sync_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
long rows = 0; (void)rows; (void)argc; (void)argv;
EXEC SQL BEGIN DECLARE SECTION;
long h_grp, h_code;
EXEC SQL END DECLARE SECTION;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT count(DISTINCT code_group), count(*) INTO :h_grp, :h_code
FROM mm_code WHERE status = 'ACTIVE';
if (sqlca.sqlcode < 0) { fprintf(stderr, "mm_code_sync_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_code_sync_batch COMMIT: 코드그룹=%ld 활성코드=%ld\n", h_grp, h_code);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,34 @@
/*
* mm_dedup_batch.pgc - 동일 상호 가맹점 중복 점검 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, the EXEC SQL work runs on that branch, then tpcommit drives XA 2PC.
* Usage: mm_dedup_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
long rows = 0; (void)rows; (void)argc; (void)argv;
EXEC SQL BEGIN DECLARE SECTION;
long h_dupgrp;
EXEC SQL END DECLARE SECTION;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT count(*) INTO :h_dupgrp FROM
(SELECT name FROM mm_merchant_ext GROUP BY name HAVING count(*) > 1) t;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mm_dedup_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_dedup_batch COMMIT: 중복상호그룹=%ld\n", h_dupgrp);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,34 @@
/*
* mm_dormant_batch.pgc - 휴면 가맹점 탐지 배치 (N일 미갱신) (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, the EXEC SQL work runs on that branch, then tpcommit drives XA 2PC.
* Usage: mm_dormant_batch [DAYS]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
long rows = 0; (void)rows; (void)argc; (void)argv;
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt, h_days = (argc > 1) ? atol(argv[1]) : 180;
EXEC SQL END DECLARE SECTION;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_merchant_ext
WHERE status = 'ACTIVE' AND updated_at < now() - (:h_days || ' days')::interval;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mm_dormant_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_dormant_batch COMMIT: days=%ld 휴면=%ld\n", h_days, h_cnt);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,34 @@
/*
* mm_feerate_avg_batch.pgc - 가맹점 수수료율 평균 통계 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, the EXEC SQL work runs on that branch, then tpcommit drives XA 2PC.
* Usage: mm_feerate_avg_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
long rows = 0; (void)rows; (void)argc; (void)argv;
EXEC SQL BEGIN DECLARE SECTION;
long h_min, h_max, h_avg;
EXEC SQL END DECLARE SECTION;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT coalesce(min(rate_bps),0), coalesce(max(rate_bps),0),
coalesce(round(avg(rate_bps)),0) INTO :h_min, :h_max, :h_avg FROM mm_fee_rate;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mm_feerate_avg_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_feerate_avg_batch COMMIT: min=%ld max=%ld avg=%ld\n", h_min, h_max, h_avg);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,43 @@
/*
* mm_fx_snapshot_batch.pgc - 환율 마스터 스냅샷 배치 (커서) (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, the EXEC SQL work runs on that branch, then tpcommit drives XA 2PC.
* Usage: mm_fx_snapshot_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
long rows = 0; (void)rows; (void)argc; (void)argv;
EXEC SQL BEGIN DECLARE SECTION;
char h_ccy[8]; long h_rate;
EXEC SQL END DECLARE SECTION;
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 fxc CURSOR FOR
SELECT ccy, rate_bps FROM mm_fx_rate ORDER BY ccy;
EXEC SQL OPEN fxc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH fxc INTO :h_ccy, :h_rate;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE fxc; tpabort(0); return 1; }
rows++;
}
EXEC SQL CLOSE fxc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mm_fx_snapshot_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_fx_snapshot_batch COMMIT: 통화=%ld\n", rows);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,48 @@
/*
* mm_grade_dist_batch.pgc - 가맹점 등급 분포 배치 (커서 + upsert) (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, the EXEC SQL work runs on that branch, then tpcommit drives XA 2PC.
* Usage: mm_grade_dist_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
long rows = 0; (void)rows; (void)argc; (void)argv;
EXEC SQL BEGIN DECLARE SECTION;
char h_grade[8], h_date[16]; long h_cnt;
EXEC SQL END DECLARE SECTION;
strncpy(h_date, (argc > 1) ? argv[1] : "2026-07-19", sizeof(h_date)-1); h_date[sizeof(h_date)-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 gdc CURSOR FOR
SELECT grade, count(*) FROM mm_merchant_ext GROUP BY grade ORDER BY grade;
EXEC SQL OPEN gdc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH gdc INTO :h_grade, :h_cnt;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE gdc; tpabort(0); return 1; }
EXEC SQL INSERT INTO mm_grade_dist (dist_date, grade, merch_cnt)
VALUES (:h_date, :h_grade, :h_cnt)
ON CONFLICT (dist_date, grade) DO UPDATE SET merch_cnt = EXCLUDED.merch_cnt;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE gdc; tpabort(0); return 1; }
rows++;
}
EXEC SQL CLOSE gdc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mm_grade_dist_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_grade_dist_batch COMMIT: date=%s 등급=%ld\n", h_date, rows);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,35 @@
/*
* mm_holiday_batch.pgc - 연도별 공휴일 건수 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, the EXEC SQL work runs on that branch, then tpcommit drives XA 2PC.
* Usage: mm_holiday_batch [YEAR]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
long rows = 0; (void)rows; (void)argc; (void)argv;
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt; char h_year[8];
EXEC SQL END DECLARE SECTION;
strncpy(h_year, (argc > 1) ? argv[1] : "2026", sizeof(h_year)-1); h_year[sizeof(h_year)-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 SELECT count(*) INTO :h_cnt FROM mm_holiday
WHERE to_char(holiday_date, 'YYYY') = :h_year;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mm_holiday_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_holiday_batch COMMIT: year=%s 공휴일=%ld\n", h_year, h_cnt);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,44 @@
/*
* mm_issuer_stat_batch.pgc - 국가별 발급사 통계 배치 (커서) (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, the EXEC SQL work runs on that branch, then tpcommit drives XA 2PC.
* Usage: mm_issuer_stat_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
long rows = 0; (void)rows; (void)argc; (void)argv;
EXEC SQL BEGIN DECLARE SECTION;
char h_country[8]; long h_cnt;
EXEC SQL END DECLARE SECTION;
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 isc CURSOR FOR
SELECT country, count(*) FROM mm_issuer WHERE status = 'ACTIVE'
GROUP BY country ORDER BY country;
EXEC SQL OPEN isc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH isc INTO :h_country, :h_cnt;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE isc; tpabort(0); return 1; }
rows++;
}
EXEC SQL CLOSE isc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mm_issuer_stat_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_issuer_stat_batch COMMIT: 국가구간=%ld\n", rows);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,33 @@
/*
* mm_limit_audit_batch.pgc - 일한도 초과 위험 가맹점 감사 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, the EXEC SQL work runs on that branch, then tpcommit drives XA 2PC.
* Usage: mm_limit_audit_batch [THRESHOLD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
long rows = 0; (void)rows; (void)argc; (void)argv;
EXEC SQL BEGIN DECLARE SECTION;
long h_over, h_thr = (argc > 1) ? atol(argv[1]) : 500000000;
EXEC SQL END DECLARE SECTION;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT count(*) INTO :h_over FROM mm_limit WHERE daily_limit > :h_thr;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mm_limit_audit_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_limit_audit_batch COMMIT: threshold=%ld 초과=%ld\n", h_thr, h_over);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,33 @@
/*
* mm_mcc_risk_batch.pgc - MCC 위험도 합계 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, the EXEC SQL work runs on that branch, then tpcommit drives XA 2PC.
* Usage: mm_mcc_risk_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
long rows = 0; (void)rows; (void)argc; (void)argv;
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt, h_risk;
EXEC SQL END DECLARE SECTION;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT count(*), coalesce(sum(risk_level),0) INTO :h_cnt, :h_risk FROM mm_mcc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mm_mcc_risk_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_mcc_risk_batch COMMIT: MCC=%ld 위험합=%ld\n", h_cnt, h_risk);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,34 @@
/*
* mm_merch_count_batch.pgc - 전체 가맹점 마스터 건수 집계 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, the EXEC SQL work runs on that branch, then tpcommit drives XA 2PC.
* Usage: mm_merch_count_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
long rows = 0; (void)rows; (void)argc; (void)argv;
EXEC SQL BEGIN DECLARE SECTION;
long h_total, h_active;
EXEC SQL END DECLARE SECTION;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT count(*), count(*) FILTER (WHERE status = 'ACTIVE')
INTO :h_total, :h_active FROM mm_merchant_ext;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mm_merch_count_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_merch_count_batch COMMIT: total=%ld active=%ld\n", h_total, h_active);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,38 @@
/*
* mm_summary_batch.pgc - 마스터 종합 요약 배치 (다중 집계) (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, the EXEC SQL work runs on that branch, then tpcommit drives XA 2PC.
* Usage: mm_summary_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
long rows = 0; (void)rows; (void)argc; (void)argv;
EXEC SQL BEGIN DECLARE SECTION;
long h_merch, h_bin, h_code, h_issuer;
EXEC SQL END DECLARE SECTION;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT
(SELECT count(*) FROM mm_merchant_ext),
(SELECT count(*) FROM mm_bin),
(SELECT count(*) FROM mm_code),
(SELECT count(*) FROM mm_issuer)
INTO :h_merch, :h_bin, :h_code, :h_issuer;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mm_summary_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_summary_batch COMMIT: merch=%ld bin=%ld code=%ld issuer=%ld\n", h_merch, h_bin, h_code, h_issuer);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,43 @@
/*
* mm_terminal_stat_batch.pgc - 단말 모델별 통계 배치 (커서) (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, the EXEC SQL work runs on that branch, then tpcommit drives XA 2PC.
* Usage: mm_terminal_stat_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
long rows = 0; (void)rows; (void)argc; (void)argv;
EXEC SQL BEGIN DECLARE SECTION;
char h_model[32]; long h_cnt;
EXEC SQL END DECLARE SECTION;
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 tmc CURSOR FOR
SELECT model, count(*) FROM mm_terminal GROUP BY model ORDER BY model;
EXEC SQL OPEN tmc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH tmc INTO :h_model, :h_cnt;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE tmc; tpabort(0); return 1; }
rows++;
}
EXEC SQL CLOSE tmc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mm_terminal_stat_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_terminal_stat_batch COMMIT: 모델구간=%ld\n", rows);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,12 @@
/*
* mm_acct_dbio.h - + copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_ACCT_DBIO_H
#define MM_ACCT_DBIO_H
int mmdb_settle_acct(const char *merch, char *acct_out /*>=64*/);
long mmdb_missing_acct_count(void);
#endif /* MM_ACCT_DBIO_H */

View file

@ -0,0 +1,31 @@
/*
* mm_acct_dbio.pgc - 정산계좌 조회 + 미설정 수 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_acct_dbio.h"
int mmdb_settle_acct(const char *merch, char *acct_out)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_acct[64];
EXEC SQL END DECLARE SECTION;
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT coalesce(settle_acct, '') INTO :h_acct FROM mm_merchant_ext
WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) { userlog("mmdb_settle_acct FAIL [%d]", sqlca.sqlcode); return -1; }
strncpy(acct_out, h_acct, 63); acct_out[63] = 0;
return 0;
}
long mmdb_missing_acct_count(void)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_merchant_ext
WHERE (settle_acct IS NULL OR settle_acct = '') AND status = 'ACTIVE';
if (sqlca.sqlcode < 0) { userlog("mmdb_missing_acct_count FAIL [%d]", sqlca.sqlcode); return -1; }
return h_cnt;
}

View file

@ -0,0 +1,11 @@
/*
* mm_bin_count_dbio.h - BIN copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_BIN_COUNT_DBIO_H
#define MM_BIN_COUNT_DBIO_H
long mmdb_bin_by_issuer(const char *issuer);
#endif /* MM_BIN_COUNT_DBIO_H */

View file

@ -0,0 +1,18 @@
/*
* mm_bin_count_dbio.pgc - 발급사별 BIN 건수 집계 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_bin_count_dbio.h"
long mmdb_bin_by_issuer(const char *issuer)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt; char h_issuer[32];
EXEC SQL END DECLARE SECTION;
strncpy(h_issuer, issuer, sizeof(h_issuer)-1); h_issuer[sizeof(h_issuer)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_bin WHERE issuer_cd = :h_issuer AND status = 'ACTIVE';
if (sqlca.sqlcode < 0) { userlog("mmdb_bin_by_issuer FAIL [%d]", sqlca.sqlcode); return -1; }
return h_cnt;
}

View file

@ -0,0 +1,11 @@
/*
* mm_bin_query_dbio.h - BIN (/) copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_BIN_QUERY_DBIO_H
#define MM_BIN_QUERY_DBIO_H
int mmdb_bin_issuer(const char *bin, char *issuer_out /*>=32*/);
#endif /* MM_BIN_QUERY_DBIO_H */

View file

@ -0,0 +1,19 @@
/*
* mm_bin_query_dbio.pgc - BIN 마스터 조회 (발급사/브랜드) (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_bin_query_dbio.h"
int mmdb_bin_issuer(const char *bin, char *issuer_out)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bin[16], h_issuer[32];
EXEC SQL END DECLARE SECTION;
strncpy(h_bin, bin, sizeof(h_bin)-1); h_bin[sizeof(h_bin)-1] = 0;
EXEC SQL SELECT issuer_cd INTO :h_issuer FROM mm_bin WHERE bin = :h_bin;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) { userlog("mmdb_bin_issuer FAIL [%d]", sqlca.sqlcode); return -1; }
strncpy(issuer_out, h_issuer, 31); issuer_out[31] = 0;
return 0;
}

View file

@ -0,0 +1,11 @@
/*
* mm_code_active_dbio.h - copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_CODE_ACTIVE_DBIO_H
#define MM_CODE_ACTIVE_DBIO_H
long mmdb_code_active_count(const char *grp);
#endif /* MM_CODE_ACTIVE_DBIO_H */

View file

@ -0,0 +1,19 @@
/*
* mm_code_active_dbio.pgc - 코드그룹 활성 코드 수 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_code_active_dbio.h"
long mmdb_code_active_count(const char *grp)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt; char h_grp[32];
EXEC SQL END DECLARE SECTION;
strncpy(h_grp, grp, sizeof(h_grp)-1); h_grp[sizeof(h_grp)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_code
WHERE code_group = :h_grp AND status = 'ACTIVE';
if (sqlca.sqlcode < 0) { userlog("mmdb_code_active_count FAIL [%d]", sqlca.sqlcode); return -1; }
return h_cnt;
}

View file

@ -0,0 +1,11 @@
/*
* mm_code_query_dbio.h - copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_CODE_QUERY_DBIO_H
#define MM_CODE_QUERY_DBIO_H
int mmdb_code_name(const char *grp, const char *code, char *name_out /*>=64*/);
#endif /* MM_CODE_QUERY_DBIO_H */

View file

@ -0,0 +1,21 @@
/*
* mm_code_query_dbio.pgc - 공통코드 명칭 조회 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_code_query_dbio.h"
int mmdb_code_name(const char *grp, const char *code, char *name_out)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_grp[32], h_code[32], h_name[64];
EXEC SQL END DECLARE SECTION;
strncpy(h_grp, grp, sizeof(h_grp)-1); h_grp[sizeof(h_grp)-1] = 0;
strncpy(h_code, code, sizeof(h_code)-1); h_code[sizeof(h_code)-1] = 0;
EXEC SQL SELECT code_name INTO :h_name FROM mm_code
WHERE code_group = :h_grp AND code = :h_code;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) { userlog("mmdb_code_name FAIL [%d]", sqlca.sqlcode); return -1; }
strncpy(name_out, h_name, 63); name_out[63] = 0;
return 0;
}

View file

@ -0,0 +1,11 @@
/*
* mm_dormant_dbio.h - (N일 ) copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_DORMANT_DBIO_H
#define MM_DORMANT_DBIO_H
long mmdb_dormant_count(long days);
#endif /* MM_DORMANT_DBIO_H */

View file

@ -0,0 +1,18 @@
/*
* mm_dormant_dbio.pgc - 휴면 가맹점 수 (N일 미갱신) (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_dormant_dbio.h"
long mmdb_dormant_count(long days)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt, h_days = days;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_merchant_ext
WHERE status = 'ACTIVE' AND updated_at < now() - (:h_days || ' days')::interval;
if (sqlca.sqlcode < 0) { userlog("mmdb_dormant_count FAIL [%d]", sqlca.sqlcode); return -1; }
return h_cnt;
}

View file

@ -0,0 +1,11 @@
/*
* mm_feerate_stat_dbio.h - copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_FEERATE_STAT_DBIO_H
#define MM_FEERATE_STAT_DBIO_H
long mmdb_feerate_avg(const char *merch);
#endif /* MM_FEERATE_STAT_DBIO_H */

View file

@ -0,0 +1,19 @@
/*
* mm_feerate_stat_dbio.pgc - 가맹점 평균 수수료율 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_feerate_stat_dbio.h"
long mmdb_feerate_avg(const char *merch)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_avg; char h_merch[64];
EXEC SQL END DECLARE SECTION;
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT coalesce(round(avg(rate_bps)),0) INTO :h_avg FROM mm_fee_rate
WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0) { userlog("mmdb_feerate_avg FAIL [%d]", sqlca.sqlcode); return -1; }
return h_avg;
}

View file

@ -0,0 +1,11 @@
/*
* mm_fx_count_dbio.h - copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_FX_COUNT_DBIO_H
#define MM_FX_COUNT_DBIO_H
long mmdb_fx_ccy_count(void);
#endif /* MM_FX_COUNT_DBIO_H */

View file

@ -0,0 +1,17 @@
/*
* mm_fx_count_dbio.pgc - 등록 통화 종류 수 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_fx_count_dbio.h"
long mmdb_fx_ccy_count(void)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT count(DISTINCT ccy) INTO :h_cnt FROM mm_fx_rate;
if (sqlca.sqlcode < 0) { userlog("mmdb_fx_ccy_count FAIL [%d]", sqlca.sqlcode); return -1; }
return h_cnt;
}

View file

@ -0,0 +1,12 @@
/*
* mm_fx_query_dbio.h - + copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_FX_QUERY_DBIO_H
#define MM_FX_QUERY_DBIO_H
long mmdb_fx_rate(const char *ccy);
long mmdb_fx_to_krw(const char *ccy, long amt);
#endif /* MM_FX_QUERY_DBIO_H */

View file

@ -0,0 +1,25 @@
/*
* mm_fx_query_dbio.pgc - 환율 조회 + 원화 환산 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_fx_query_dbio.h"
long mmdb_fx_rate(const char *ccy)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_rate; char h_ccy[8];
EXEC SQL END DECLARE SECTION;
strncpy(h_ccy, ccy, sizeof(h_ccy)-1); h_ccy[sizeof(h_ccy)-1] = 0;
EXEC SQL SELECT rate_bps INTO :h_rate FROM mm_fx_rate WHERE ccy = :h_ccy;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) { userlog("mmdb_fx_rate FAIL [%d]", sqlca.sqlcode); return -1; }
return h_rate;
}
long mmdb_fx_to_krw(const char *ccy, long amt)
{
long rate = mmdb_fx_rate(ccy);
if (rate < 0) return -1;
return amt * rate / 100;
}

View file

@ -0,0 +1,11 @@
/*
* mm_grade_count_dbio.h - copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_GRADE_COUNT_DBIO_H
#define MM_GRADE_COUNT_DBIO_H
long mmdb_grade_count(const char *grade);
#endif /* MM_GRADE_COUNT_DBIO_H */

View file

@ -0,0 +1,19 @@
/*
* mm_grade_count_dbio.pgc - 등급별 가맹점 수 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_grade_count_dbio.h"
long mmdb_grade_count(const char *grade)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt; char h_grade[8];
EXEC SQL END DECLARE SECTION;
strncpy(h_grade, grade, sizeof(h_grade)-1); h_grade[sizeof(h_grade)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_merchant_ext
WHERE grade = :h_grade AND status = 'ACTIVE';
if (sqlca.sqlcode < 0) { userlog("mmdb_grade_count FAIL [%d]", sqlca.sqlcode); return -1; }
return h_cnt;
}

View file

@ -0,0 +1,11 @@
/*
* mm_grade_stat_dbio.h - upsert copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_GRADE_STAT_DBIO_H
#define MM_GRADE_STAT_DBIO_H
int mmdb_upsert_grade_stat(const char *statdate, const char *grade, long cnt);
#endif /* MM_GRADE_STAT_DBIO_H */

View file

@ -0,0 +1,22 @@
/*
* mm_grade_stat_dbio.pgc - 등급 통계 upsert (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_grade_stat_dbio.h"
int mmdb_upsert_grade_stat(const char *statdate, const char *grade, long cnt)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt = cnt; char h_date[16], h_grade[8];
EXEC SQL END DECLARE SECTION;
strncpy(h_date, statdate, sizeof(h_date)-1); h_date[sizeof(h_date)-1] = 0;
strncpy(h_grade, grade, sizeof(h_grade)-1); h_grade[sizeof(h_grade)-1] = 0;
EXEC SQL INSERT INTO mm_grade_stat (stat_date, grade, merch_cnt)
VALUES (:h_date, :h_grade, :h_cnt)
ON CONFLICT (stat_date, grade) DO UPDATE
SET merch_cnt = EXCLUDED.merch_cnt, updated_at = now();
if (sqlca.sqlcode < 0) { userlog("mmdb_upsert_grade_stat FAIL [%d]", sqlca.sqlcode); return -1; }
return 0;
}

View file

@ -0,0 +1,12 @@
/*
* mm_hist_query_dbio.h - / copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_HIST_QUERY_DBIO_H
#define MM_HIST_QUERY_DBIO_H
long mmdb_hist_count(const char *merch);
int mmdb_last_action(const char *merch, char *act_out /*>=16*/);
#endif /* MM_HIST_QUERY_DBIO_H */

View file

@ -0,0 +1,31 @@
/*
* mm_hist_query_dbio.pgc - 가맹점 변경 이력 건수/최근액션 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_hist_query_dbio.h"
long mmdb_hist_count(const char *merch)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt; char h_merch[64];
EXEC SQL END DECLARE SECTION;
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_merch_hist WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0) { userlog("mmdb_hist_count FAIL [%d]", sqlca.sqlcode); return -1; }
return h_cnt;
}
int mmdb_last_action(const char *merch, char *act_out)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_act[16];
EXEC SQL END DECLARE SECTION;
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT action INTO :h_act FROM mm_merch_hist
WHERE merchant_id = :h_merch ORDER BY hist_id DESC LIMIT 1;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) { userlog("mmdb_last_action FAIL [%d]", sqlca.sqlcode); return -1; }
strncpy(act_out, h_act, 15); act_out[15] = 0;
return 0;
}

View file

@ -0,0 +1,11 @@
/*
* mm_holiday_dbio.h - / copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_HOLIDAY_DBIO_H
#define MM_HOLIDAY_DBIO_H
int mmdb_is_holiday(const char *date);
#endif /* MM_HOLIDAY_DBIO_H */

View file

@ -0,0 +1,18 @@
/*
* mm_holiday_dbio.pgc - 영업일/공휴일 판정 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_holiday_dbio.h"
int mmdb_is_holiday(const char *date)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt; char h_date[16];
EXEC SQL END DECLARE SECTION;
strncpy(h_date, date, sizeof(h_date)-1); h_date[sizeof(h_date)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_holiday WHERE holiday_date = :h_date;
if (sqlca.sqlcode < 0) { userlog("mmdb_is_holiday FAIL [%d]", sqlca.sqlcode); return -1; }
return (h_cnt > 0) ? 1 : 0;
}

View file

@ -0,0 +1,11 @@
/*
* mm_issuer_count_dbio.h - copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_ISSUER_COUNT_DBIO_H
#define MM_ISSUER_COUNT_DBIO_H
long mmdb_issuer_by_country(const char *country);
#endif /* MM_ISSUER_COUNT_DBIO_H */

View file

@ -0,0 +1,19 @@
/*
* mm_issuer_count_dbio.pgc - 국가별 발급사 수 집계 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_issuer_count_dbio.h"
long mmdb_issuer_by_country(const char *country)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt; char h_country[8];
EXEC SQL END DECLARE SECTION;
strncpy(h_country, country, sizeof(h_country)-1); h_country[sizeof(h_country)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_issuer
WHERE country = :h_country AND status = 'ACTIVE';
if (sqlca.sqlcode < 0) { userlog("mmdb_issuer_by_country FAIL [%d]", sqlca.sqlcode); return -1; }
return h_cnt;
}

View file

@ -0,0 +1,11 @@
/*
* mm_issuer_query_dbio.h - / copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_ISSUER_QUERY_DBIO_H
#define MM_ISSUER_QUERY_DBIO_H
int mmdb_issuer_country(const char *cd, char *country_out /*>=8*/);
#endif /* MM_ISSUER_QUERY_DBIO_H */

View file

@ -0,0 +1,19 @@
/*
* mm_issuer_query_dbio.pgc - 발급사 국가/상태 조회 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_issuer_query_dbio.h"
int mmdb_issuer_country(const char *cd, char *country_out)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_cd[32], h_country[8];
EXEC SQL END DECLARE SECTION;
strncpy(h_cd, cd, sizeof(h_cd)-1); h_cd[sizeof(h_cd)-1] = 0;
EXEC SQL SELECT country INTO :h_country FROM mm_issuer WHERE issuer_cd = :h_cd;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) { userlog("mmdb_issuer_country FAIL [%d]", sqlca.sqlcode); return -1; }
strncpy(country_out, h_country, 7); country_out[7] = 0;
return 0;
}

View file

@ -0,0 +1,11 @@
/*
* mm_limit_bump_dbio.h - copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_LIMIT_BUMP_DBIO_H
#define MM_LIMIT_BUMP_DBIO_H
int mmdb_bump_daily_limit(const char *merch, long delta);
#endif /* MM_LIMIT_BUMP_DBIO_H */

View file

@ -0,0 +1,19 @@
/*
* mm_limit_bump_dbio.pgc - 가맹점 일한도 증감 반영 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_limit_bump_dbio.h"
int mmdb_bump_daily_limit(const char *merch, long delta)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_delta = delta; char h_merch[64];
EXEC SQL END DECLARE SECTION;
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL UPDATE mm_limit SET daily_limit = daily_limit + :h_delta, updated_at = now()
WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) { userlog("mmdb_bump_daily_limit FAIL [%d]", sqlca.sqlcode); return -1; }
return 0;
}

View file

@ -0,0 +1,11 @@
/*
* mm_limit_query_dbio.h - copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_LIMIT_QUERY_DBIO_H
#define MM_LIMIT_QUERY_DBIO_H
long mmdb_daily_limit(const char *merch);
#endif /* MM_LIMIT_QUERY_DBIO_H */

View file

@ -0,0 +1,18 @@
/*
* mm_limit_query_dbio.pgc - 가맹점 일한도 조회 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_limit_query_dbio.h"
long mmdb_daily_limit(const char *merch)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_lim = 0; char h_merch[64];
EXEC SQL END DECLARE SECTION;
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT daily_limit INTO :h_lim FROM mm_limit WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) { userlog("mmdb_daily_limit FAIL [%d]", sqlca.sqlcode); return -1; }
return h_lim;
}

View file

@ -0,0 +1,12 @@
/*
* mm_mcc_dbio.h - MCC copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_MCC_DBIO_H
#define MM_MCC_DBIO_H
long mmdb_mcc_risk(const char *mcc);
int mmdb_mcc_name(const char *mcc, char *name_out /*>=64*/);
#endif /* MM_MCC_DBIO_H */

View file

@ -0,0 +1,30 @@
/*
* mm_mcc_dbio.pgc - MCC 업종 위험도 조회 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_mcc_dbio.h"
long mmdb_mcc_risk(const char *mcc)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_risk; char h_mcc[16];
EXEC SQL END DECLARE SECTION;
strncpy(h_mcc, mcc, sizeof(h_mcc)-1); h_mcc[sizeof(h_mcc)-1] = 0;
EXEC SQL SELECT risk_level INTO :h_risk FROM mm_mcc WHERE mcc = :h_mcc;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) { userlog("mmdb_mcc_risk FAIL [%d]", sqlca.sqlcode); return -1; }
return h_risk;
}
int mmdb_mcc_name(const char *mcc, char *name_out)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_mcc[16], h_name[64];
EXEC SQL END DECLARE SECTION;
strncpy(h_mcc, mcc, sizeof(h_mcc)-1); h_mcc[sizeof(h_mcc)-1] = 0;
EXEC SQL SELECT mcc_name INTO :h_name FROM mm_mcc WHERE mcc = :h_mcc;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) { userlog("mmdb_mcc_name FAIL [%d]", sqlca.sqlcode); return -1; }
strncpy(name_out, h_name, 63); name_out[63] = 0;
return 0;
}

View file

@ -0,0 +1,12 @@
/*
* mm_merch_total_dbio.h - / copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_MERCH_TOTAL_DBIO_H
#define MM_MERCH_TOTAL_DBIO_H
long mmdb_merch_total(void);
long mmdb_merch_by_status(const char *status);
#endif /* MM_MERCH_TOTAL_DBIO_H */

View file

@ -0,0 +1,28 @@
/*
* mm_merch_total_dbio.pgc - 전체/상태별 가맹점 수 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_merch_total_dbio.h"
long mmdb_merch_total(void)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_merchant_ext;
if (sqlca.sqlcode < 0) { userlog("mmdb_merch_total FAIL [%d]", sqlca.sqlcode); return -1; }
return h_cnt;
}
long mmdb_merch_by_status(const char *status)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt; char h_status[16];
EXEC SQL END DECLARE SECTION;
strncpy(h_status, status, sizeof(h_status)-1); h_status[sizeof(h_status)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_merchant_ext WHERE status = :h_status;
if (sqlca.sqlcode < 0) { userlog("mmdb_merch_by_status FAIL [%d]", sqlca.sqlcode); return -1; }
return h_cnt;
}

View file

@ -0,0 +1,11 @@
/*
* mm_status_dbio.h - copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_STATUS_DBIO_H
#define MM_STATUS_DBIO_H
int mmdb_merch_status(const char *merch, char *status_out /*>=16*/);
#endif /* MM_STATUS_DBIO_H */

View file

@ -0,0 +1,19 @@
/*
* mm_status_dbio.pgc - 가맹점 상태 조회 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_status_dbio.h"
int mmdb_merch_status(const char *merch, char *status_out)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_status[16];
EXEC SQL END DECLARE SECTION;
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT status INTO :h_status FROM mm_merchant_ext WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) { userlog("mmdb_merch_status FAIL [%d]", sqlca.sqlcode); return -1; }
strncpy(status_out, h_status, 15); status_out[15] = 0;
return 0;
}

View file

@ -0,0 +1,11 @@
/*
* mm_terminal_count_dbio.h - copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_TERMINAL_COUNT_DBIO_H
#define MM_TERMINAL_COUNT_DBIO_H
long mmdb_terminal_count(const char *merch);
#endif /* MM_TERMINAL_COUNT_DBIO_H */

View file

@ -0,0 +1,19 @@
/*
* mm_terminal_count_dbio.pgc - 가맹점 보유 단말 수 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_terminal_count_dbio.h"
long mmdb_terminal_count(const char *merch)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt; char h_merch[64];
EXEC SQL END DECLARE SECTION;
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_terminal
WHERE merchant_id = :h_merch AND status = 'ACTIVE';
if (sqlca.sqlcode < 0) { userlog("mmdb_terminal_count FAIL [%d]", sqlca.sqlcode); return -1; }
return h_cnt;
}

View file

@ -0,0 +1,11 @@
/*
* mm_terminal_query_dbio.h - copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_TERMINAL_QUERY_DBIO_H
#define MM_TERMINAL_QUERY_DBIO_H
int mmdb_terminal_merch(const char *term, char *merch_out /*>=64*/);
#endif /* MM_TERMINAL_QUERY_DBIO_H */

View file

@ -0,0 +1,19 @@
/*
* mm_terminal_query_dbio.pgc - 단말 소속 가맹점 조회 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_terminal_query_dbio.h"
int mmdb_terminal_merch(const char *term, char *merch_out)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_term[32], h_merch[64];
EXEC SQL END DECLARE SECTION;
strncpy(h_term, term, sizeof(h_term)-1); h_term[sizeof(h_term)-1] = 0;
EXEC SQL SELECT merchant_id INTO :h_merch FROM mm_terminal WHERE terminal_id = :h_term;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) { userlog("mmdb_terminal_merch FAIL [%d]", sqlca.sqlcode); return -1; }
strncpy(merch_out, h_merch, 63); merch_out[63] = 0;
return 0;
}

View file

@ -0,0 +1,11 @@
/*
* mm_touch_dbio.h - copybook (part of libmmdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MM_TOUCH_DBIO_H
#define MM_TOUCH_DBIO_H
int mmdb_touch_merch(const char *merch);
#endif /* MM_TOUCH_DBIO_H */

View file

@ -0,0 +1,18 @@
/*
* mm_touch_dbio.pgc - 가맹점 갱신시각 터치 (libmmdbio.a).
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "mm_touch_dbio.h"
int mmdb_touch_merch(const char *merch)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64];
EXEC SQL END DECLARE SECTION;
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL UPDATE mm_merchant_ext SET updated_at = now() WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) { userlog("mmdb_touch_merch FAIL [%d]", sqlca.sqlcode); return -1; }
return 0;
}

View file

@ -1,69 +1,84 @@
/*
* mm_svr.pgc - mm (마스터/master) MODULE SERVER.
* mm_svr.pgc - mm (마스터/master) MODULE SERVER (thin dispatcher).
*
* ONE binary that tpadvertise()s ALL ~30 online mm services (the real Tuxedo
* "one module server, many services" pattern). Every service is a distinct
* 마스터(기준정보) operation with genuine EXEC SQL (directly, or via the linked
* libmmdbio.a dbio layer) and common math from libacqcommon.a.
* The legacy "one module server, many services" pattern: this binary owns NO
* business logic. Each of mm's ~30 online services now lives in its own file
* (app/src/mm/svc/<SVCNAME>.pgc) with its own copybook header
* (app/src/mm/svc/<SVCNAME>.h); those objects are archived into libmmsvc.a and
* linked into this server. Here we only include every service copybook, tpopen()
* the ECPG XA RM, tpadvertise() all services from a {name, fn} table, tpclose().
*
* XA: the connection is opened once by tpopen() (ECPG XA switch libndrxxaecpg.so);
* there is NO EXEC SQL CONNECT. Each tpcall runs on this process's XA branch, so
* a service sees its OWN uncommitted writes but NOT a sibling branch's.
* there is NO EXEC SQL CONNECT. Each tpcall runs on this process's XA branch.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include <ubf.h>
#include <userlog.h>
#include <ndebug.h>
#include "acq.fd.h"
#include "mm_dbio.h"
#include "acq_common.h"
/* ----- small UBF helpers ------------------------------------------------- */
static long getl(UBFH *b, BFLDID f) { long v = 0; Bget(b, f, 0, (char *)&v, 0L); return v; }
static void gets_(UBFH *b, BFLDID f, char *out, int cap)
{ BFLDLEN l = cap; out[0] = 0; Bget(b, f, 0, out, &l); }
static void setl(UBFH *b, BFLDID f, long v) { Bchg(b, f, 0, (char *)&v, 0L); }
/* every mm service's copybook header (declares its prototype) */
#include "MM_MERCH_REG.h"
#include "MM_MERCH_UPD.h"
#include "MM_MERCH_INQ.h"
#include "MM_MERCH_DEL.h"
#include "MM_FEERATE_SET.h"
#include "MM_FEERATE_INQ.h"
#include "MM_FEERATE_HIST.h"
#include "MM_BIN_REG.h"
#include "MM_BIN_INQ.h"
#include "MM_LIMIT_SET.h"
#include "MM_LIMIT_INQ.h"
#include "MM_CODE_REG.h"
#include "MM_CODE_INQ.h"
#include "MM_ISSUER_REG.h"
#include "MM_ISSUER_INQ.h"
#include "MM_MERCH_STATUS.h"
#include "MM_MERCH_ACCT.h"
#include "MM_MERCH_GRADE.h"
#include "MM_TERMINAL_REG.h"
#include "MM_TERMINAL_INQ.h"
#include "MM_MCC_REG.h"
#include "MM_HOLIDAY_REG.h"
#include "MM_FX_REG.h"
#include "MM_FX_INQ.h"
#include "MM_MERCH_BULK.h"
#include "MM_VALIDATE.h"
#include "MM_MERCH_SUM.h"
#include "MM_CODE_CACHE.h"
#include "MM_STATUS.h"
#include "MM_CONFIRM.h"
#define FAIL(b) do { tpreturn(TPFAIL, 0, (char *)(b), 0L, 0L); return; } while (0)
#define OK(b) do { tpreturn(TPSUCCESS, 0, (char *)(b), 0L, 0L); return; } while (0)
/* ----- service prototypes ------------------------------------------------ */
void MM_MERCH_REG(TPSVCINFO *p); void MM_MERCH_UPD(TPSVCINFO *p);
void MM_MERCH_INQ(TPSVCINFO *p); void MM_MERCH_DEL(TPSVCINFO *p);
void MM_FEERATE_SET(TPSVCINFO *p); void MM_FEERATE_INQ(TPSVCINFO *p);
void MM_FEERATE_HIST(TPSVCINFO *p); void MM_BIN_REG(TPSVCINFO *p);
void MM_BIN_INQ(TPSVCINFO *p); void MM_LIMIT_SET(TPSVCINFO *p);
void MM_LIMIT_INQ(TPSVCINFO *p); void MM_CODE_REG(TPSVCINFO *p);
void MM_CODE_INQ(TPSVCINFO *p); void MM_ISSUER_REG(TPSVCINFO *p);
void MM_ISSUER_INQ(TPSVCINFO *p); void MM_MERCH_STATUS(TPSVCINFO *p);
void MM_MERCH_ACCT(TPSVCINFO *p); void MM_MERCH_GRADE(TPSVCINFO *p);
void MM_TERMINAL_REG(TPSVCINFO *p); void MM_TERMINAL_INQ(TPSVCINFO *p);
void MM_MCC_REG(TPSVCINFO *p); void MM_HOLIDAY_REG(TPSVCINFO *p);
void MM_FX_REG(TPSVCINFO *p); void MM_FX_INQ(TPSVCINFO *p);
void MM_MERCH_BULK(TPSVCINFO *p); void MM_VALIDATE(TPSVCINFO *p);
void MM_MERCH_SUM(TPSVCINFO *p); void MM_CODE_CACHE(TPSVCINFO *p);
void MM_STATUS(TPSVCINFO *p); void MM_CONFIRM(TPSVCINFO *p);
/* ----- advertise table (this is what "scales to 30" cleanly) ------------- */
/* ----- advertise table: {service name, function} (fn is extern from its file) */
static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
{"MM_MERCH_REG", MM_MERCH_REG}, {"MM_MERCH_UPD", MM_MERCH_UPD},
{"MM_MERCH_INQ", MM_MERCH_INQ}, {"MM_MERCH_DEL", MM_MERCH_DEL},
{"MM_FEERATE_SET", MM_FEERATE_SET}, {"MM_FEERATE_INQ", MM_FEERATE_INQ},
{"MM_FEERATE_HIST", MM_FEERATE_HIST}, {"MM_BIN_REG", MM_BIN_REG},
{"MM_BIN_INQ", MM_BIN_INQ}, {"MM_LIMIT_SET", MM_LIMIT_SET},
{"MM_LIMIT_INQ", MM_LIMIT_INQ}, {"MM_CODE_REG", MM_CODE_REG},
{"MM_CODE_INQ", MM_CODE_INQ}, {"MM_ISSUER_REG", MM_ISSUER_REG},
{"MM_ISSUER_INQ", MM_ISSUER_INQ}, {"MM_MERCH_STATUS", MM_MERCH_STATUS},
{"MM_MERCH_ACCT", MM_MERCH_ACCT}, {"MM_MERCH_GRADE", MM_MERCH_GRADE},
{"MM_TERMINAL_REG", MM_TERMINAL_REG}, {"MM_TERMINAL_INQ", MM_TERMINAL_INQ},
{"MM_MCC_REG", MM_MCC_REG}, {"MM_HOLIDAY_REG", MM_HOLIDAY_REG},
{"MM_FX_REG", MM_FX_REG}, {"MM_FX_INQ", MM_FX_INQ},
{"MM_MERCH_BULK", MM_MERCH_BULK}, {"MM_VALIDATE", MM_VALIDATE},
{"MM_MERCH_SUM", MM_MERCH_SUM}, {"MM_CODE_CACHE", MM_CODE_CACHE},
{"MM_STATUS", MM_STATUS}, {"MM_CONFIRM", MM_CONFIRM},
{"MM_MERCH_REG", MM_MERCH_REG},
{"MM_MERCH_UPD", MM_MERCH_UPD},
{"MM_MERCH_INQ", MM_MERCH_INQ},
{"MM_MERCH_DEL", MM_MERCH_DEL},
{"MM_FEERATE_SET", MM_FEERATE_SET},
{"MM_FEERATE_INQ", MM_FEERATE_INQ},
{"MM_FEERATE_HIST", MM_FEERATE_HIST},
{"MM_BIN_REG", MM_BIN_REG},
{"MM_BIN_INQ", MM_BIN_INQ},
{"MM_LIMIT_SET", MM_LIMIT_SET},
{"MM_LIMIT_INQ", MM_LIMIT_INQ},
{"MM_CODE_REG", MM_CODE_REG},
{"MM_CODE_INQ", MM_CODE_INQ},
{"MM_ISSUER_REG", MM_ISSUER_REG},
{"MM_ISSUER_INQ", MM_ISSUER_INQ},
{"MM_MERCH_STATUS", MM_MERCH_STATUS},
{"MM_MERCH_ACCT", MM_MERCH_ACCT},
{"MM_MERCH_GRADE", MM_MERCH_GRADE},
{"MM_TERMINAL_REG", MM_TERMINAL_REG},
{"MM_TERMINAL_INQ", MM_TERMINAL_INQ},
{"MM_MCC_REG", MM_MCC_REG},
{"MM_HOLIDAY_REG", MM_HOLIDAY_REG},
{"MM_FX_REG", MM_FX_REG},
{"MM_FX_INQ", MM_FX_INQ},
{"MM_MERCH_BULK", MM_MERCH_BULK},
{"MM_VALIDATE", MM_VALIDATE},
{"MM_MERCH_SUM", MM_MERCH_SUM},
{"MM_CODE_CACHE", MM_CODE_CACHE},
{"MM_STATUS", MM_STATUS},
{"MM_CONFIRM", MM_CONFIRM},
{NULL, NULL}
};
@ -90,566 +105,4 @@ void tpsvrdone(void)
userlog("mm_svr: tpsvrdone");
}
/* ========================================================================= */
/* 1. MM_MERCH_REG - 가맹점 확장 마스터 등록 (dbio upsert + 이력). */
/* ========================================================================= */
void MM_MERCH_REG(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], name[128], grade[8], acct[64];
gets_(b, T_MERCHANT, merch, sizeof(merch));
if (merch[0] == 0) { userlog("MM_MERCH_REG: T_MERCHANT 누락"); FAIL(b); }
gets_(b, T_STR1, name, sizeof(name)); if (name[0] == 0) strcpy(name, "무명가맹점");
gets_(b, T_STR2, grade, sizeof(grade)); if (grade[0] == 0) strcpy(grade, "C");
gets_(b, T_STR3, acct, sizeof(acct));
if (mmdb_insert_merchant(merch, name, grade, acct, "ACTIVE") < 0) FAIL(b);
if (mmdb_insert_merch_hist(merch, "REG", "", grade, "신규 등록") < 0) FAIL(b);
Bchg(b, T_STATUS, 0, "ACTIVE", 0L);
userlog("MM_MERCH_REG merch=%s grade=%s 등록", merch, grade);
OK(b);
}
/* 2. MM_MERCH_UPD - 가맹점명/계좌 수정 (직접 UPDATE + 이력). */
void MM_MERCH_UPD(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], name[128], acct[64];
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_name[128], h_acct[64];
EXEC SQL END DECLARE SECTION;
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_STR1, name, sizeof(name)); if (name[0] == 0) strcpy(name, "무명가맹점");
gets_(b, T_STR3, acct, sizeof(acct));
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
strncpy(h_name, name, sizeof(h_name)-1); h_name[sizeof(h_name)-1] = 0;
strncpy(h_acct, acct, sizeof(h_acct)-1); h_acct[sizeof(h_acct)-1] = 0;
EXEC SQL UPDATE mm_merchant_ext
SET name = :h_name, settle_acct = :h_acct, updated_at = now()
WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) {
userlog("MM_MERCH_UPD FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b);
}
if (mmdb_insert_merch_hist(merch, "UPD", "", name, "정보 수정") < 0) FAIL(b);
OK(b);
}
/* 3. MM_MERCH_INQ - 가맹점 마스터 조회 (dbio). */
void MM_MERCH_INQ(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], name[64], grade[8], status[16];
gets_(b, T_MERCHANT, merch, sizeof(merch));
if (mmdb_get_merchant(merch, name, grade, status) < 0) FAIL(b);
Bchg(b, T_STR1, 0, name, 0L);
Bchg(b, T_STR2, 0, grade, 0L);
Bchg(b, T_STATUS, 0, status, 0L);
OK(b);
}
/* 4. MM_MERCH_DEL - 가맹점 논리 삭제 (상태 DELETED + 이력). */
void MM_MERCH_DEL(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64];
gets_(b, T_MERCHANT, merch, sizeof(merch));
if (mmdb_update_merchant_status(merch, "DELETED") < 0) FAIL(b);
if (mmdb_insert_merch_hist(merch, "DEL", "ACTIVE", "DELETED", "논리 삭제") < 0) FAIL(b);
Bchg(b, T_STATUS, 0, "DELETED", 0L);
OK(b);
}
/* 5. MM_FEERATE_SET - 수수료율 설정 (dbio upsert + 이력). */
void MM_FEERATE_SET(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], ctype[16];
long bps;
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_STR4, ctype, sizeof(ctype)); if (ctype[0] == 0) strcpy(ctype, "CREDIT");
bps = getl(b, T_ARG1); if (bps <= 0) bps = 25;
if (mmdb_set_fee_rate(merch, ctype, bps) < 0) FAIL(b);
userlog("MM_FEERATE_SET merch=%s type=%s bps=%ld", merch, ctype, bps);
OK(b);
}
/* 6. MM_FEERATE_INQ - 수수료율 조회 (dbio). */
void MM_FEERATE_INQ(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], ctype[16];
long bps = 25;
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_STR4, ctype, sizeof(ctype)); if (ctype[0] == 0) strcpy(ctype, "CREDIT");
if (mmdb_get_fee_rate(merch, ctype, &bps) < 0) FAIL(b);
setl(b, T_ARG1, bps);
OK(b);
}
/* 7. MM_FEERATE_HIST - 수수료율 변경 이력 건수 (dbio). */
void MM_FEERATE_HIST(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64];
long cnt;
gets_(b, T_MERCHANT, merch, sizeof(merch));
cnt = mmdb_feerate_hist_count(merch);
if (cnt < 0) FAIL(b);
setl(b, T_COUNT, cnt);
OK(b);
}
/* 8. MM_BIN_REG - BIN 마스터 등록. */
void MM_BIN_REG(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char bin[16], issuer[32], brand[16];
EXEC SQL BEGIN DECLARE SECTION;
char h_bin[16], h_issuer[32], h_brand[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_KEY1, bin, sizeof(bin));
if (bin[0] == 0) { userlog("MM_BIN_REG: T_KEY1(bin) 누락"); FAIL(b); }
gets_(b, T_ISSUER, issuer, sizeof(issuer)); if (issuer[0] == 0) strcpy(issuer, "UNKNOWN");
gets_(b, T_STR5, brand, sizeof(brand)); if (brand[0] == 0) strcpy(brand, "LOCAL");
strncpy(h_bin, bin, sizeof(h_bin)-1); h_bin[sizeof(h_bin)-1] = 0;
strncpy(h_issuer, issuer, sizeof(h_issuer)-1); h_issuer[sizeof(h_issuer)-1] = 0;
strncpy(h_brand, brand, sizeof(h_brand)-1); h_brand[sizeof(h_brand)-1] = 0;
EXEC SQL INSERT INTO mm_bin (bin, issuer_cd, card_brand)
VALUES (:h_bin, :h_issuer, :h_brand)
ON CONFLICT (bin) DO UPDATE
SET issuer_cd = EXCLUDED.issuer_cd, card_brand = EXCLUDED.card_brand;
if (sqlca.sqlcode < 0) { userlog("MM_BIN_REG FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
OK(b);
}
/* 9. MM_BIN_INQ - BIN 조회. */
void MM_BIN_INQ(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char bin[16];
EXEC SQL BEGIN DECLARE SECTION;
char h_bin[16], h_issuer[32], h_status[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_KEY1, bin, sizeof(bin));
strncpy(h_bin, bin, sizeof(h_bin)-1); h_bin[sizeof(h_bin)-1] = 0;
EXEC SQL SELECT issuer_cd, status INTO :h_issuer, :h_status
FROM mm_bin WHERE bin = :h_bin;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
Bchg(b, T_ISSUER, 0, h_issuer, 0L);
Bchg(b, T_STATUS, 0, h_status, 0L);
OK(b);
}
/* 10. MM_LIMIT_SET - 가맹점 한도 설정 (upsert). */
void MM_LIMIT_SET(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
EXEC SQL BEGIN DECLARE SECTION;
long h_daily, h_monthly, h_pertxn;
char h_merch[64];
EXEC SQL END DECLARE SECTION;
char merch[64];
gets_(b, T_MERCHANT, merch, sizeof(merch));
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
h_daily = getl(b, T_AMT1); if (h_daily <= 0) h_daily = 100000000;
h_monthly = getl(b, T_AMT2); if (h_monthly <= 0) h_monthly = h_daily * 30;
h_pertxn = getl(b, T_AMT3); if (h_pertxn <= 0) h_pertxn = 10000000;
EXEC SQL INSERT INTO mm_limit
(merchant_id, daily_limit, monthly_limit, per_txn_limit)
VALUES (:h_merch, :h_daily, :h_monthly, :h_pertxn)
ON CONFLICT (merchant_id) DO UPDATE
SET daily_limit = EXCLUDED.daily_limit, monthly_limit = EXCLUDED.monthly_limit,
per_txn_limit = EXCLUDED.per_txn_limit, updated_at = now();
if (sqlca.sqlcode < 0) { userlog("MM_LIMIT_SET FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
OK(b);
}
/* 11. MM_LIMIT_INQ - 가맹점 한도 조회. */
void MM_LIMIT_INQ(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
EXEC SQL BEGIN DECLARE SECTION;
long h_daily, h_monthly, h_pertxn;
char h_merch[64];
EXEC SQL END DECLARE SECTION;
char merch[64];
gets_(b, T_MERCHANT, merch, sizeof(merch));
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT daily_limit, monthly_limit, per_txn_limit
INTO :h_daily, :h_monthly, :h_pertxn FROM mm_limit WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
setl(b, T_AMT1, h_daily); setl(b, T_AMT2, h_monthly); setl(b, T_AMT3, h_pertxn);
OK(b);
}
/* 12. MM_CODE_REG - 공통코드 등록. */
void MM_CODE_REG(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char grp[32], code[32], name[64];
EXEC SQL BEGIN DECLARE SECTION;
char h_grp[32], h_code[32], h_name[64];
EXEC SQL END DECLARE SECTION;
gets_(b, T_STR1, grp, sizeof(grp)); if (grp[0] == 0) strcpy(grp, "GEN");
gets_(b, T_KEY1, code, sizeof(code));
if (code[0] == 0) { userlog("MM_CODE_REG: T_KEY1(code) 누락"); FAIL(b); }
gets_(b, T_STR2, name, sizeof(name));
strncpy(h_grp, grp, sizeof(h_grp)-1); h_grp[sizeof(h_grp)-1] = 0;
strncpy(h_code, code, sizeof(h_code)-1); h_code[sizeof(h_code)-1] = 0;
strncpy(h_name, name, sizeof(h_name)-1); h_name[sizeof(h_name)-1] = 0;
EXEC SQL INSERT INTO mm_code (code_group, code, code_name)
VALUES (:h_grp, :h_code, :h_name)
ON CONFLICT (code_group, code) DO UPDATE SET code_name = EXCLUDED.code_name;
if (sqlca.sqlcode < 0) { userlog("MM_CODE_REG FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
OK(b);
}
/* 13. MM_CODE_INQ - 공통코드 조회. */
void MM_CODE_INQ(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char grp[32], code[32];
EXEC SQL BEGIN DECLARE SECTION;
char h_grp[32], h_code[32], h_name[64], h_status[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_STR1, grp, sizeof(grp)); if (grp[0] == 0) strcpy(grp, "GEN");
gets_(b, T_KEY1, code, sizeof(code));
strncpy(h_grp, grp, sizeof(h_grp)-1); h_grp[sizeof(h_grp)-1] = 0;
strncpy(h_code, code, sizeof(h_code)-1); h_code[sizeof(h_code)-1] = 0;
EXEC SQL SELECT code_name, status INTO :h_name, :h_status
FROM mm_code WHERE code_group = :h_grp AND code = :h_code;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
Bchg(b, T_STR2, 0, h_name, 0L);
Bchg(b, T_STATUS, 0, h_status, 0L);
OK(b);
}
/* 14. MM_ISSUER_REG - 발급사 마스터 등록. */
void MM_ISSUER_REG(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char cd[32], name[64], country[8];
EXEC SQL BEGIN DECLARE SECTION;
char h_cd[32], h_name[64], h_country[8];
EXEC SQL END DECLARE SECTION;
gets_(b, T_ISSUER, cd, sizeof(cd));
if (cd[0] == 0) { userlog("MM_ISSUER_REG: T_ISSUER 누락"); FAIL(b); }
gets_(b, T_STR1, name, sizeof(name));
gets_(b, T_STR2, country, sizeof(country)); if (country[0] == 0) strcpy(country, "KR");
strncpy(h_cd, cd, sizeof(h_cd)-1); h_cd[sizeof(h_cd)-1] = 0;
strncpy(h_name, name, sizeof(h_name)-1); h_name[sizeof(h_name)-1] = 0;
strncpy(h_country, country, sizeof(h_country)-1); h_country[sizeof(h_country)-1] = 0;
EXEC SQL INSERT INTO mm_issuer (issuer_cd, issuer_name, country)
VALUES (:h_cd, :h_name, :h_country)
ON CONFLICT (issuer_cd) DO UPDATE
SET issuer_name = EXCLUDED.issuer_name, country = EXCLUDED.country;
if (sqlca.sqlcode < 0) { userlog("MM_ISSUER_REG FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
OK(b);
}
/* 15. MM_ISSUER_INQ - 발급사 조회. */
void MM_ISSUER_INQ(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char cd[32];
EXEC SQL BEGIN DECLARE SECTION;
char h_cd[32], h_name[64], h_status[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_ISSUER, cd, sizeof(cd));
strncpy(h_cd, cd, sizeof(h_cd)-1); h_cd[sizeof(h_cd)-1] = 0;
EXEC SQL SELECT issuer_name, status INTO :h_name, :h_status
FROM mm_issuer WHERE issuer_cd = :h_cd;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
Bchg(b, T_STR1, 0, h_name, 0L);
Bchg(b, T_STATUS, 0, h_status, 0L);
OK(b);
}
/* 16. MM_MERCH_STATUS - 가맹점 상태 변경 (dbio + 이력). */
void MM_MERCH_STATUS(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], status[16];
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_STATUS, status, sizeof(status)); if (status[0] == 0) strcpy(status, "HOLD");
if (mmdb_update_merchant_status(merch, status) < 0) FAIL(b);
if (mmdb_insert_merch_hist(merch, "STATUS", "", status, "상태 변경") < 0) FAIL(b);
OK(b);
}
/* 17. MM_MERCH_ACCT - 정산계좌 변경 (직접 UPDATE + 이력). */
void MM_MERCH_ACCT(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], acct[64];
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_acct[64];
EXEC SQL END DECLARE SECTION;
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_STR3, acct, sizeof(acct));
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
strncpy(h_acct, acct, sizeof(h_acct)-1); h_acct[sizeof(h_acct)-1] = 0;
EXEC SQL UPDATE mm_merchant_ext SET settle_acct = :h_acct, updated_at = now()
WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
if (mmdb_insert_merch_hist(merch, "ACCT", "", acct, "계좌 변경") < 0) FAIL(b);
OK(b);
}
/* 18. MM_MERCH_GRADE - 가맹점 등급 변경 (dbio + 이력). */
void MM_MERCH_GRADE(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], grade[8];
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_STR2, grade, sizeof(grade)); if (grade[0] == 0) strcpy(grade, "C");
if (mmdb_update_merchant_grade(merch, grade) < 0) FAIL(b);
if (mmdb_insert_merch_hist(merch, "GRADE", "", grade, "등급 변경") < 0) FAIL(b);
Bchg(b, T_STR2, 0, grade, 0L);
OK(b);
}
/* 19. MM_TERMINAL_REG - 단말 마스터 등록. */
void MM_TERMINAL_REG(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char term[32], merch[64], model[32];
EXEC SQL BEGIN DECLARE SECTION;
char h_term[32], h_merch[64], h_model[32];
EXEC SQL END DECLARE SECTION;
gets_(b, T_STR5, term, sizeof(term));
if (term[0] == 0) { userlog("MM_TERMINAL_REG: T_STR5(terminal) 누락"); FAIL(b); }
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_STR6, model, sizeof(model)); if (model[0] == 0) strcpy(model, "STD");
strncpy(h_term, term, sizeof(h_term)-1); h_term[sizeof(h_term)-1] = 0;
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
strncpy(h_model, model, sizeof(h_model)-1); h_model[sizeof(h_model)-1] = 0;
EXEC SQL INSERT INTO mm_terminal (terminal_id, merchant_id, model)
VALUES (:h_term, :h_merch, :h_model)
ON CONFLICT (terminal_id) DO UPDATE
SET merchant_id = EXCLUDED.merchant_id, model = EXCLUDED.model;
if (sqlca.sqlcode < 0) { userlog("MM_TERMINAL_REG FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
OK(b);
}
/* 20. MM_TERMINAL_INQ - 단말 조회. */
void MM_TERMINAL_INQ(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char term[32];
EXEC SQL BEGIN DECLARE SECTION;
char h_term[32], h_merch[64], h_status[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_STR5, term, sizeof(term));
strncpy(h_term, term, sizeof(h_term)-1); h_term[sizeof(h_term)-1] = 0;
EXEC SQL SELECT merchant_id, status INTO :h_merch, :h_status
FROM mm_terminal WHERE terminal_id = :h_term;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
Bchg(b, T_STATUS, 0, h_status, 0L);
OK(b);
}
/* 21. MM_MCC_REG - MCC 업종 마스터 등록. */
void MM_MCC_REG(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char mcc[16], name[64];
EXEC SQL BEGIN DECLARE SECTION;
long h_risk;
char h_mcc[16], h_name[64];
EXEC SQL END DECLARE SECTION;
gets_(b, T_STR6, mcc, sizeof(mcc));
if (mcc[0] == 0) { userlog("MM_MCC_REG: T_STR6(mcc) 누락"); FAIL(b); }
gets_(b, T_STR1, name, sizeof(name));
h_risk = getl(b, T_ARG1); if (h_risk <= 0) h_risk = 1;
strncpy(h_mcc, mcc, sizeof(h_mcc)-1); h_mcc[sizeof(h_mcc)-1] = 0;
strncpy(h_name, name, sizeof(h_name)-1); h_name[sizeof(h_name)-1] = 0;
EXEC SQL INSERT INTO mm_mcc (mcc, mcc_name, risk_level)
VALUES (:h_mcc, :h_name, :h_risk)
ON CONFLICT (mcc) DO UPDATE
SET mcc_name = EXCLUDED.mcc_name, risk_level = EXCLUDED.risk_level;
if (sqlca.sqlcode < 0) { userlog("MM_MCC_REG FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
OK(b);
}
/* 22. MM_HOLIDAY_REG - 공휴일 마스터 등록. */
void MM_HOLIDAY_REG(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char hdate[16], name[64];
EXEC SQL BEGIN DECLARE SECTION;
char h_date[16], h_name[64];
EXEC SQL END DECLARE SECTION;
gets_(b, T_BIZDATE, hdate, sizeof(hdate));
if (hdate[0] == 0) { userlog("MM_HOLIDAY_REG: T_BIZDATE 누락"); FAIL(b); }
gets_(b, T_STR1, name, sizeof(name)); if (name[0] == 0) strcpy(name, "공휴일");
strncpy(h_date, hdate, sizeof(h_date)-1); h_date[sizeof(h_date)-1] = 0;
strncpy(h_name, name, sizeof(h_name)-1); h_name[sizeof(h_name)-1] = 0;
EXEC SQL INSERT INTO mm_holiday (holiday_date, holiday_name)
VALUES (:h_date, :h_name)
ON CONFLICT (holiday_date) DO UPDATE SET holiday_name = EXCLUDED.holiday_name;
if (sqlca.sqlcode < 0) { userlog("MM_HOLIDAY_REG FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
OK(b);
}
/* 23. MM_FX_REG - 환율 마스터 upsert. */
void MM_FX_REG(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char ccy[8];
EXEC SQL BEGIN DECLARE SECTION;
long h_rate;
char h_ccy[8];
EXEC SQL END DECLARE SECTION;
gets_(b, T_CCY, ccy, sizeof(ccy)); if (ccy[0] == 0) strcpy(ccy, "USD");
h_rate = getl(b, T_ARG2); if (h_rate <= 0) h_rate = 1350;
strncpy(h_ccy, ccy, sizeof(h_ccy)-1); h_ccy[sizeof(h_ccy)-1] = 0;
EXEC SQL INSERT INTO mm_fx_rate (ccy, rate_bps, base_date)
VALUES (:h_ccy, :h_rate, current_date)
ON CONFLICT (ccy) DO UPDATE
SET rate_bps = EXCLUDED.rate_bps, base_date = current_date, updated_at = now();
if (sqlca.sqlcode < 0) { userlog("MM_FX_REG FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
OK(b);
}
/* 24. MM_FX_INQ - 환율 조회 + 금액 환산 (rate_bps는 100 기준 bps). */
void MM_FX_INQ(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char ccy[8];
long fx_amt, krw;
EXEC SQL BEGIN DECLARE SECTION;
long h_rate;
char h_ccy[8];
EXEC SQL END DECLARE SECTION;
gets_(b, T_CCY, ccy, sizeof(ccy)); if (ccy[0] == 0) strcpy(ccy, "USD");
fx_amt = getl(b, T_FX_AMT);
strncpy(h_ccy, ccy, sizeof(h_ccy)-1); h_ccy[sizeof(h_ccy)-1] = 0;
EXEC SQL SELECT rate_bps INTO :h_rate FROM mm_fx_rate WHERE ccy = :h_ccy;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
krw = fx_amt * h_rate / 100;
setl(b, T_ARG2, h_rate);
setl(b, T_AMOUNT, krw);
OK(b);
}
/* 25. MM_MERCH_BULK - 가맹점 대량 등록 (T_COUNT개 파생 생성). */
void MM_MERCH_BULK(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char prefix[48], grade[8];
long n, i, made = 0;
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_name[128], h_grade[8];
EXEC SQL END DECLARE SECTION;
gets_(b, T_MERCHANT, prefix, sizeof(prefix)); if (prefix[0] == 0) strcpy(prefix, "MBULK");
gets_(b, T_STR2, grade, sizeof(grade)); if (grade[0] == 0) strcpy(grade, "C");
n = getl(b, T_COUNT); if (n < 1) n = 1; if (n > 1000) n = 1000;
strncpy(h_grade, grade, sizeof(h_grade)-1); h_grade[sizeof(h_grade)-1] = 0;
for (i = 1; i <= n; i++) {
snprintf(h_merch, sizeof(h_merch), "%s-%04ld", prefix, i);
snprintf(h_name, sizeof(h_name), "%s 지점%ld", prefix, i);
EXEC SQL INSERT INTO mm_merchant_ext (merchant_id, name, grade)
VALUES (:h_merch, :h_name, :h_grade)
ON CONFLICT (merchant_id) DO NOTHING;
if (sqlca.sqlcode < 0) { userlog("MM_MERCH_BULK FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
made++;
}
setl(b, T_COUNT, made);
userlog("MM_MERCH_BULK prefix=%s 생성=%ld", prefix, made);
OK(b);
}
/* 26. MM_VALIDATE - 가맹점 마스터 정합성 검사 (존재+수수료율 존재). */
void MM_VALIDATE(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64];
long rc = 0;
EXEC SQL BEGIN DECLARE SECTION;
long h_mcnt, h_fcnt;
char h_merch[64];
EXEC SQL END DECLARE SECTION;
gets_(b, T_MERCHANT, merch, sizeof(merch));
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_mcnt FROM mm_merchant_ext
WHERE merchant_id = :h_merch AND status = 'ACTIVE';
if (sqlca.sqlcode < 0) FAIL(b);
EXEC SQL SELECT count(*) INTO :h_fcnt FROM mm_fee_rate WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0) FAIL(b);
if (h_mcnt == 0) rc = 1; /* 마스터 없음/비활성 */
else if (h_fcnt == 0) rc = 2; /* 수수료율 미설정 */
setl(b, T_RC, rc);
OK(b);
}
/* 27. MM_MERCH_SUM - 상태별 가맹점 수 집계 (ACTIVE 기준). */
void MM_MERCH_SUM(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char status[16];
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt;
char h_status[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_STATUS, status, sizeof(status)); if (status[0] == 0) strcpy(status, "ACTIVE");
strncpy(h_status, status, sizeof(h_status)-1); h_status[sizeof(h_status)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_merchant_ext WHERE status = :h_status;
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_cnt);
OK(b);
}
/* 28. MM_CODE_CACHE - 코드그룹의 활성 코드 수 (캐시 워밍 시뮬). */
void MM_CODE_CACHE(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char grp[32];
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt;
char h_grp[32];
EXEC SQL END DECLARE SECTION;
gets_(b, T_STR1, grp, sizeof(grp)); if (grp[0] == 0) strcpy(grp, "CARD_TYPE");
strncpy(h_grp, grp, sizeof(h_grp)-1); h_grp[sizeof(h_grp)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_code
WHERE code_group = :h_grp AND status = 'ACTIVE';
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_cnt);
OK(b);
}
/* 29. MM_STATUS - 서비스 상태 (전체 가맹점 수, RC=0). */
void MM_STATUS(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_merchant_ext;
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_cnt);
setl(b, T_RC, 0);
Bchg(b, T_MSG, 0, "mm 마스터 서비스 정상", 0L);
OK(b);
}
/* 30. MM_CONFIRM - 가맹점 승인 확정 (상태 ACTIVE + 이력). */
void MM_CONFIRM(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64];
gets_(b, T_MERCHANT, merch, sizeof(merch));
if (mmdb_update_merchant_status(merch, "ACTIVE") < 0) FAIL(b);
if (mmdb_insert_merch_hist(merch, "STATUS", "HOLD", "ACTIVE", "승인 확정") < 0) FAIL(b);
Bchg(b, T_STATUS, 0, "ACTIVE", 0L);
OK(b);
}
/* vim: set ts=4 sw=4 et smartindent: */

View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_acct_check.sh - 정산계좌 미설정 점검 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_acct_check.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_acct_check.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_acct_check_batch

14
app/src/mm/run/run_bin_load.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_bin_load.sh - 발급사별 BIN 적재 현황 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_bin_load.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_bin_load.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_bin_load_batch

14
app/src/mm/run/run_code_sync.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_code_sync.sh - 공통코드 활성 수 동기화 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_code_sync.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_code_sync.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_code_sync_batch

14
app/src/mm/run/run_dedup.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_dedup.sh - 동일 상호 중복 점검 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_dedup.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_dedup.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_dedup_batch

14
app/src/mm/run/run_dormant.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_dormant.sh - 휴면 가맹점 탐지 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_dormant.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_dormant.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_dormant_batch "$ARG"

View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_feerate_avg.sh - 수수료율 평균 통계 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_feerate_avg.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_feerate_avg.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_feerate_avg_batch

View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_fx_snapshot.sh - 환율 마스터 스냅샷 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_fx_snapshot.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_fx_snapshot.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_fx_snapshot_batch

View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_grade_dist.sh - 가맹점 등급 분포 적재 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_grade_dist.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_grade_dist.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_grade_dist_batch "$BIZDATE"

View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_grade_recalc.sh - 가맹점 등급 재산정 배치 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_grade_recalc.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_grade_recalc.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_grade_recalc_batch "$BIZDATE"

14
app/src/mm/run/run_holiday.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_holiday.sh - 연도별 공휴일 건수 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_holiday.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_holiday.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_holiday_batch "$ARG"

View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_issuer_stat.sh - 국가별 발급사 통계 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_issuer_stat.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_issuer_stat.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_issuer_stat_batch

View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_limit_audit.sh - 일한도 초과 위험 감사 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_limit_audit.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_limit_audit.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_limit_audit_batch "$ARG"

14
app/src/mm/run/run_mcc_risk.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_mcc_risk.sh - MCC 위험도 합계 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_mcc_risk.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_mcc_risk.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_mcc_risk_batch

View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_merch_count.sh - 가맹점 마스터 건수 집계 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_merch_count.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_merch_count.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_merch_count_batch

14
app/src/mm/run/run_stat.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_stat.sh - 등급별 가맹점 통계 배치 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_stat.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_stat.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_stat_batch "$BIZDATE"

14
app/src/mm/run/run_summary.sh Executable file
View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_summary.sh - 마스터 종합 요약 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_summary.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_summary.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_summary_batch

View file

@ -0,0 +1,14 @@
#!/bin/bash
##
## run_terminal_stat.sh - 단말 모델별 통계 실행.
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 mm 배치를 실행.
## Usage: run_terminal_stat.sh [BIZDATE] [ARG]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
ARG="${2:-}"
echo "[run_terminal_stat.sh] BIZDATE=$BIZDATE ARG=$ARG"
exec /app/bin/mm_terminal_stat_batch

View file

@ -0,0 +1,12 @@
/*
* MM_BIN_INQ.h - mm MM_BIN_INQ (copybook / record header).
* UBF : T_ISSUER, T_KEY1, T_STATUS
*/
#ifndef MM_BIN_INQ_H
#define MM_BIN_INQ_H
#include "mm_svc.h"
void MM_BIN_INQ(TPSVCINFO *p);
#endif /* MM_BIN_INQ_H */

View file

@ -0,0 +1,24 @@
/*
* MM_BIN_INQ.pgc - mm 모듈 서비스 MM_BIN_INQ (one service = one file).
* 기능: BIN 조회.
* 기존 인라인 mm_svr.pgc에서 분리; caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음).
* mm_svr가 tpsvrinit에서 이 서비스를 tpadvertise 한다.
*/
#include "MM_BIN_INQ.h"
void MM_BIN_INQ(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char bin[16];
EXEC SQL BEGIN DECLARE SECTION;
char h_bin[16], h_issuer[32], h_status[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_KEY1, bin, sizeof(bin));
strncpy(h_bin, bin, sizeof(h_bin)-1); h_bin[sizeof(h_bin)-1] = 0;
EXEC SQL SELECT issuer_cd, status INTO :h_issuer, :h_status
FROM mm_bin WHERE bin = :h_bin;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
Bchg(b, T_ISSUER, 0, h_issuer, 0L);
Bchg(b, T_STATUS, 0, h_status, 0L);
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MM_BIN_REG.h - mm MM_BIN_REG (copybook / record header).
* UBF : T_ISSUER, T_KEY1, T_STR5
*/
#ifndef MM_BIN_REG_H
#define MM_BIN_REG_H
#include "mm_svc.h"
void MM_BIN_REG(TPSVCINFO *p);
#endif /* MM_BIN_REG_H */

View file

@ -0,0 +1,30 @@
/*
* MM_BIN_REG.pgc - mm 모듈 서비스 MM_BIN_REG (one service = one file).
* 기능: BIN 마스터 등록.
* 기존 인라인 mm_svr.pgc에서 분리; caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음).
* mm_svr가 tpsvrinit에서 이 서비스를 tpadvertise 한다.
*/
#include "MM_BIN_REG.h"
void MM_BIN_REG(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char bin[16], issuer[32], brand[16];
EXEC SQL BEGIN DECLARE SECTION;
char h_bin[16], h_issuer[32], h_brand[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_KEY1, bin, sizeof(bin));
if (bin[0] == 0) { userlog("MM_BIN_REG: T_KEY1(bin) 누락"); FAIL(b); }
gets_(b, T_ISSUER, issuer, sizeof(issuer)); if (issuer[0] == 0) strcpy(issuer, "UNKNOWN");
gets_(b, T_STR5, brand, sizeof(brand)); if (brand[0] == 0) strcpy(brand, "LOCAL");
strncpy(h_bin, bin, sizeof(h_bin)-1); h_bin[sizeof(h_bin)-1] = 0;
strncpy(h_issuer, issuer, sizeof(h_issuer)-1); h_issuer[sizeof(h_issuer)-1] = 0;
strncpy(h_brand, brand, sizeof(h_brand)-1); h_brand[sizeof(h_brand)-1] = 0;
EXEC SQL INSERT INTO mm_bin (bin, issuer_cd, card_brand)
VALUES (:h_bin, :h_issuer, :h_brand)
ON CONFLICT (bin) DO UPDATE
SET issuer_cd = EXCLUDED.issuer_cd, card_brand = EXCLUDED.card_brand;
if (sqlca.sqlcode < 0) { userlog("MM_BIN_REG FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MM_CODE_CACHE.h - mm MM_CODE_CACHE (copybook / record header).
* UBF : T_COUNT, T_STR1
*/
#ifndef MM_CODE_CACHE_H
#define MM_CODE_CACHE_H
#include "mm_svc.h"
void MM_CODE_CACHE(TPSVCINFO *p);
#endif /* MM_CODE_CACHE_H */

View file

@ -0,0 +1,24 @@
/*
* MM_CODE_CACHE.pgc - mm 모듈 서비스 MM_CODE_CACHE (one service = one file).
* 기능: 코드그룹의 활성 코드 수 (캐시 워밍 시뮬).
* 기존 인라인 mm_svr.pgc에서 분리; caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음).
* mm_svr가 tpsvrinit에서 이 서비스를 tpadvertise 한다.
*/
#include "MM_CODE_CACHE.h"
void MM_CODE_CACHE(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char grp[32];
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt;
char h_grp[32];
EXEC SQL END DECLARE SECTION;
gets_(b, T_STR1, grp, sizeof(grp)); if (grp[0] == 0) strcpy(grp, "CARD_TYPE");
strncpy(h_grp, grp, sizeof(h_grp)-1); h_grp[sizeof(h_grp)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_code
WHERE code_group = :h_grp AND status = 'ACTIVE';
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_cnt);
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MM_CODE_INQ.h - mm MM_CODE_INQ (copybook / record header).
* UBF : T_KEY1, T_STATUS, T_STR1, T_STR2
*/
#ifndef MM_CODE_INQ_H
#define MM_CODE_INQ_H
#include "mm_svc.h"
void MM_CODE_INQ(TPSVCINFO *p);
#endif /* MM_CODE_INQ_H */

View file

@ -0,0 +1,26 @@
/*
* MM_CODE_INQ.pgc - mm 모듈 서비스 MM_CODE_INQ (one service = one file).
* 기능: 공통코드 조회.
* 기존 인라인 mm_svr.pgc에서 분리; caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음).
* mm_svr가 tpsvrinit에서 이 서비스를 tpadvertise 한다.
*/
#include "MM_CODE_INQ.h"
void MM_CODE_INQ(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char grp[32], code[32];
EXEC SQL BEGIN DECLARE SECTION;
char h_grp[32], h_code[32], h_name[64], h_status[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_STR1, grp, sizeof(grp)); if (grp[0] == 0) strcpy(grp, "GEN");
gets_(b, T_KEY1, code, sizeof(code));
strncpy(h_grp, grp, sizeof(h_grp)-1); h_grp[sizeof(h_grp)-1] = 0;
strncpy(h_code, code, sizeof(h_code)-1); h_code[sizeof(h_code)-1] = 0;
EXEC SQL SELECT code_name, status INTO :h_name, :h_status
FROM mm_code WHERE code_group = :h_grp AND code = :h_code;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
Bchg(b, T_STR2, 0, h_name, 0L);
Bchg(b, T_STATUS, 0, h_status, 0L);
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MM_CODE_REG.h - mm MM_CODE_REG (copybook / record header).
* UBF : T_KEY1, T_STR1, T_STR2
*/
#ifndef MM_CODE_REG_H
#define MM_CODE_REG_H
#include "mm_svc.h"
void MM_CODE_REG(TPSVCINFO *p);
#endif /* MM_CODE_REG_H */

View file

@ -0,0 +1,28 @@
/*
* MM_CODE_REG.pgc - mm 모듈 서비스 MM_CODE_REG (one service = one file).
* 기능: 공통코드 등록.
* 기존 인라인 mm_svr.pgc에서 분리; caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음).
* mm_svr가 tpsvrinit에서 이 서비스를 tpadvertise 한다.
*/
#include "MM_CODE_REG.h"
void MM_CODE_REG(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char grp[32], code[32], name[64];
EXEC SQL BEGIN DECLARE SECTION;
char h_grp[32], h_code[32], h_name[64];
EXEC SQL END DECLARE SECTION;
gets_(b, T_STR1, grp, sizeof(grp)); if (grp[0] == 0) strcpy(grp, "GEN");
gets_(b, T_KEY1, code, sizeof(code));
if (code[0] == 0) { userlog("MM_CODE_REG: T_KEY1(code) 누락"); FAIL(b); }
gets_(b, T_STR2, name, sizeof(name));
strncpy(h_grp, grp, sizeof(h_grp)-1); h_grp[sizeof(h_grp)-1] = 0;
strncpy(h_code, code, sizeof(h_code)-1); h_code[sizeof(h_code)-1] = 0;
strncpy(h_name, name, sizeof(h_name)-1); h_name[sizeof(h_name)-1] = 0;
EXEC SQL INSERT INTO mm_code (code_group, code, code_name)
VALUES (:h_grp, :h_code, :h_name)
ON CONFLICT (code_group, code) DO UPDATE SET code_name = EXCLUDED.code_name;
if (sqlca.sqlcode < 0) { userlog("MM_CODE_REG FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MM_CONFIRM.h - mm MM_CONFIRM (copybook / record header).
* UBF : T_MERCHANT, T_STATUS
*/
#ifndef MM_CONFIRM_H
#define MM_CONFIRM_H
#include "mm_svc.h"
void MM_CONFIRM(TPSVCINFO *p);
#endif /* MM_CONFIRM_H */

View file

@ -0,0 +1,18 @@
/*
* MM_CONFIRM.pgc - mm 모듈 서비스 MM_CONFIRM (one service = one file).
* 기능: 가맹점 승인 확정 (상태 ACTIVE + 이력).
* 기존 인라인 mm_svr.pgc에서 분리; caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음).
* mm_svr가 tpsvrinit에서 이 서비스를 tpadvertise 한다.
*/
#include "MM_CONFIRM.h"
void MM_CONFIRM(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64];
gets_(b, T_MERCHANT, merch, sizeof(merch));
if (mmdb_update_merchant_status(merch, "ACTIVE") < 0) FAIL(b);
if (mmdb_insert_merch_hist(merch, "STATUS", "HOLD", "ACTIVE", "승인 확정") < 0) FAIL(b);
Bchg(b, T_STATUS, 0, "ACTIVE", 0L);
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MM_FEERATE_HIST.h - mm MM_FEERATE_HIST (copybook / record header).
* UBF : T_COUNT, T_MERCHANT
*/
#ifndef MM_FEERATE_HIST_H
#define MM_FEERATE_HIST_H
#include "mm_svc.h"
void MM_FEERATE_HIST(TPSVCINFO *p);
#endif /* MM_FEERATE_HIST_H */

View file

@ -0,0 +1,19 @@
/*
* MM_FEERATE_HIST.pgc - mm 모듈 서비스 MM_FEERATE_HIST (one service = one file).
* 기능: 수수료율 변경 이력 건수 (dbio).
* 기존 인라인 mm_svr.pgc에서 분리; caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음).
* mm_svr가 tpsvrinit에서 이 서비스를 tpadvertise 한다.
*/
#include "MM_FEERATE_HIST.h"
void MM_FEERATE_HIST(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64];
long cnt;
gets_(b, T_MERCHANT, merch, sizeof(merch));
cnt = mmdb_feerate_hist_count(merch);
if (cnt < 0) FAIL(b);
setl(b, T_COUNT, cnt);
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MM_FEERATE_INQ.h - mm MM_FEERATE_INQ (copybook / record header).
* UBF : T_ARG1, T_MERCHANT, T_STR4
*/
#ifndef MM_FEERATE_INQ_H
#define MM_FEERATE_INQ_H
#include "mm_svc.h"
void MM_FEERATE_INQ(TPSVCINFO *p);
#endif /* MM_FEERATE_INQ_H */

View file

@ -0,0 +1,19 @@
/*
* MM_FEERATE_INQ.pgc - mm 모듈 서비스 MM_FEERATE_INQ (one service = one file).
* 기능: 수수료율 조회 (dbio).
* 기존 인라인 mm_svr.pgc에서 분리; caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음).
* mm_svr가 tpsvrinit에서 이 서비스를 tpadvertise 한다.
*/
#include "MM_FEERATE_INQ.h"
void MM_FEERATE_INQ(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], ctype[16];
long bps = 25;
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_STR4, ctype, sizeof(ctype)); if (ctype[0] == 0) strcpy(ctype, "CREDIT");
if (mmdb_get_fee_rate(merch, ctype, &bps) < 0) FAIL(b);
setl(b, T_ARG1, bps);
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MM_FEERATE_SET.h - mm MM_FEERATE_SET (copybook / record header).
* UBF : T_ARG1, T_MERCHANT, T_STR4
*/
#ifndef MM_FEERATE_SET_H
#define MM_FEERATE_SET_H
#include "mm_svc.h"
void MM_FEERATE_SET(TPSVCINFO *p);
#endif /* MM_FEERATE_SET_H */

View file

@ -0,0 +1,20 @@
/*
* MM_FEERATE_SET.pgc - mm 모듈 서비스 MM_FEERATE_SET (one service = one file).
* 기능: 수수료율 설정 (dbio upsert + 이력).
* 기존 인라인 mm_svr.pgc에서 분리; caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음).
* mm_svr가 tpsvrinit에서 이 서비스를 tpadvertise 한다.
*/
#include "MM_FEERATE_SET.h"
void MM_FEERATE_SET(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], ctype[16];
long bps;
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_STR4, ctype, sizeof(ctype)); if (ctype[0] == 0) strcpy(ctype, "CREDIT");
bps = getl(b, T_ARG1); if (bps <= 0) bps = 25;
if (mmdb_set_fee_rate(merch, ctype, bps) < 0) FAIL(b);
userlog("MM_FEERATE_SET merch=%s type=%s bps=%ld", merch, ctype, bps);
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MM_FX_INQ.h - mm MM_FX_INQ (copybook / record header).
* UBF : T_AMOUNT, T_ARG2, T_CCY, T_FX_AMT
*/
#ifndef MM_FX_INQ_H
#define MM_FX_INQ_H
#include "mm_svc.h"
void MM_FX_INQ(TPSVCINFO *p);
#endif /* MM_FX_INQ_H */

View file

@ -0,0 +1,27 @@
/*
* MM_FX_INQ.pgc - mm 모듈 서비스 MM_FX_INQ (one service = one file).
* 기능: 환율 조회 + 금액 환산 (rate_bps는 100 기준 bps).
* 기존 인라인 mm_svr.pgc에서 분리; caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음).
* mm_svr가 tpsvrinit에서 이 서비스를 tpadvertise 한다.
*/
#include "MM_FX_INQ.h"
void MM_FX_INQ(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char ccy[8];
long fx_amt, krw;
EXEC SQL BEGIN DECLARE SECTION;
long h_rate;
char h_ccy[8];
EXEC SQL END DECLARE SECTION;
gets_(b, T_CCY, ccy, sizeof(ccy)); if (ccy[0] == 0) strcpy(ccy, "USD");
fx_amt = getl(b, T_FX_AMT);
strncpy(h_ccy, ccy, sizeof(h_ccy)-1); h_ccy[sizeof(h_ccy)-1] = 0;
EXEC SQL SELECT rate_bps INTO :h_rate FROM mm_fx_rate WHERE ccy = :h_ccy;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
krw = fx_amt * h_rate / 100;
setl(b, T_ARG2, h_rate);
setl(b, T_AMOUNT, krw);
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MM_FX_REG.h - mm MM_FX_REG (copybook / record header).
* UBF : T_ARG2, T_CCY
*/
#ifndef MM_FX_REG_H
#define MM_FX_REG_H
#include "mm_svc.h"
void MM_FX_REG(TPSVCINFO *p);
#endif /* MM_FX_REG_H */

Some files were not shown because too many files have changed in this diff Show more