규모확장 Wave B: 전 11모듈 svc 75→133·batch 35→46 (BAIS 온라인 1:1)

- svc 825→1,463 (모듈당 133), batch 385→506 (모듈당 46) — 전부 새 고유 실업무 로직
  + 카피북 헤더, 디스패처 133 advertise, 한글 기능설명(매니페스트 추출)
- BAIS As-Is 대비: 온라인 1,463 vs 1,466(99.8%), 배치 506 vs 503(초과)
- 화면 매니페스트 1,463 재생성
- 검증: build DONE modules=11 batches=506, 12서버 runok, xadmin psc 1,466 AVAIL,
  매입체인 XA 커밋, 신규서비스 실데이터 스모크, 전 코퍼스 .pgc 클론 0

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
hyeongwoo-choi 2026-07-20 22:55:47 +00:00
parent ea90bef264
commit c62d91b7a7
1526 changed files with 59213 additions and 12 deletions

View file

@ -0,0 +1,59 @@
/*
* mm_acct_scan_batch.pgc - 정산계좌 형식 점검 배치 (커서 + C 검증 + XA).
*
* 활성 가맹점의 정산계좌를 순회하며 C 코드로 숫자 10~16자리 형식을 검증하고
* 위반 건에 ACCT_BAD 이력을 남긴다(정산 오류 예방). ONE global XA transaction.
* host 변수는 mm_acct_scan_cpy.h 를 EXEC SQL INCLUDE.
* Usage: mm_acct_scan_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mm_dbio.h"
static int acct_bad(const char *a)
{
size_t i, len = strlen(a);
if (len < 10 || len > 16) return 1;
for (i = 0; i < len; i++)
if (a[i] < '0' || a[i] > '9') return 1;
return 0;
}
int main(int argc, char **argv)
{
(void)argc; (void)argv;
EXEC SQL INCLUDE mm_acct_scan_cpy;
b_bad = 0; b_scanned = 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 acsn CURSOR FOR
SELECT merchant_id, settle_acct FROM mm_merchant_ext
WHERE status = 'ACTIVE' AND settle_acct <> ''
ORDER BY merchant_id;
EXEC SQL OPEN acsn;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH acsn INTO :b_merch, :b_acct;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE acsn; tpabort(0); return 1; }
b_scanned++;
if (!acct_bad(b_acct)) continue;
if (mmdb_insert_merch_hist(b_merch, "ACCT_BAD", b_acct, "FORMAT", "배치 계좌 형식 위반") < 0) {
EXEC SQL CLOSE acsn; tpabort(0); return 1;
}
b_bad++;
}
EXEC SQL CLOSE acsn;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_acct_scan_batch COMMIT: 점검=%ld 위반=%ld건\n", b_scanned, b_bad);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,7 @@
/* mm_acct_scan_cpy.h - mm_acct_scan_batch 전용 카피북 (host 변수 선언). */
EXEC SQL BEGIN DECLARE SECTION;
char b_merch[64];
char b_acct[40];
long b_bad;
long b_scanned;
EXEC SQL END DECLARE SECTION;

View file

@ -0,0 +1,51 @@
/*
* mm_apply_rescore_batch.pgc - 심사 신청 서류 재점검 배치 (커서 + XA).
*
* APPLIED 상태 가맹점 중 사업자번호가 10자리가 아닌 건을 자동으로 HOLD 전환하고
* APPLY_HOLD 이력을 남긴다(서류 보완 요청). ONE global XA transaction.
* host 변수는 mm_apply_rescore_cpy.h 를 EXEC SQL INCLUDE.
* Usage: mm_apply_rescore_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mm_dbio.h"
int main(int argc, char **argv)
{
(void)argc; (void)argv;
EXEC SQL INCLUDE mm_apply_rescore_cpy;
b_held = 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 ars CURSOR FOR
SELECT merchant_id, biz_reg_no FROM mm_merchant_ext
WHERE status = 'APPLIED' AND length(biz_reg_no) <> 10
ORDER BY merchant_id;
EXEC SQL OPEN ars;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH ars INTO :b_merch, :b_biz;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE ars; tpabort(0); return 1; }
EXEC SQL UPDATE mm_merchant_ext SET status = 'HOLD', updated_at = now()
WHERE merchant_id = :b_merch;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE ars; tpabort(0); return 1; }
if (mmdb_insert_merch_hist(b_merch, "APPLY_HOLD", "APPLIED", "HOLD", "배치 서류 미비 보류") < 0) {
EXEC SQL CLOSE ars; tpabort(0); return 1;
}
b_held++;
}
EXEC SQL CLOSE ars;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_apply_rescore_batch COMMIT: 보류전환=%ld건\n", b_held);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,6 @@
/* mm_apply_rescore_cpy.h - mm_apply_rescore_batch 전용 카피북 (host 변수 선언). */
EXEC SQL BEGIN DECLARE SECTION;
char b_merch[64];
char b_biz[16];
long b_held;
EXEC SQL END DECLARE SECTION;

View file

@ -0,0 +1,57 @@
/*
* mm_biz_hibernate_batch.pgc - 무거래 가맹점 휴면 전환 배치 (LEFT JOIN 커서 + XA).
*
* 최근 N일간 집계 매출이 전혀 없는 활성 가맹점을 DORMANT로 전환하고 DORMANT 이력을
* 남긴다(자동 휴면). ONE global XA transaction.
* host 변수는 mm_biz_hibernate_cpy.h 를 EXEC SQL INCLUDE.
* Usage: mm_biz_hibernate_batch [DAYS=180]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mm_dbio.h"
int main(int argc, char **argv)
{
EXEC SQL INCLUDE mm_biz_hibernate_cpy;
b_hibernated = 0;
b_days = (argc > 1) ? atol(argv[1]) : 180;
if (b_days < 1) b_days = 180;
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 hib CURSOR FOR
SELECT me.merchant_id
FROM mm_merchant_ext me
LEFT JOIN merchant_summary ms
ON ms.merchant_id = me.merchant_id AND ms.biz_date >= current_date - :b_days
WHERE me.status = 'ACTIVE'
GROUP BY me.merchant_id
HAVING coalesce(sum(ms.gross_amount), 0) = 0
ORDER BY me.merchant_id;
EXEC SQL OPEN hib;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH hib INTO :b_merch;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE hib; tpabort(0); return 1; }
EXEC SQL UPDATE mm_merchant_ext SET status = 'DORMANT', updated_at = now()
WHERE merchant_id = :b_merch;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE hib; tpabort(0); return 1; }
if (mmdb_insert_merch_hist(b_merch, "DORMANT", "ACTIVE", "DORMANT", "무거래 자동 휴면") < 0) {
EXEC SQL CLOSE hib; tpabort(0); return 1;
}
b_hibernated++;
}
EXEC SQL CLOSE hib;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_biz_hibernate_batch COMMIT: 기간=%ld일 휴면=%ld건\n", b_days, b_hibernated);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,6 @@
/* mm_biz_hibernate_cpy.h - mm_biz_hibernate_batch 전용 카피북 (host 변수 선언). */
EXEC SQL BEGIN DECLARE SECTION;
long b_days;
char b_merch[64];
long b_hibernated;
EXEC SQL END DECLARE SECTION;

View file

@ -0,0 +1,55 @@
/*
* mm_contract_expire_batch.pgc - 만기 경과 계약 만료 처리 배치 (커서 + XA).
*
* 각 가맹점의 최신 CONTRACT 이력 만기일이 오늘 이전이고 아직 CONTRACT_EXP가
* 기록되지 않은 건에 대해 CONTRACT_EXP 이력을 적재한다(만료 확정). ONE XA txn.
* host 변수는 mm_contract_expire_cpy.h 를 EXEC SQL INCLUDE.
* Usage: mm_contract_expire_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mm_dbio.h"
int main(int argc, char **argv)
{
(void)argc; (void)argv;
EXEC SQL INCLUDE mm_contract_expire_cpy;
b_expired = 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 cex CURSOR FOR
SELECT h.merchant_id, h.after_val
FROM mm_merch_hist h
WHERE h.action = 'CONTRACT'
AND h.hist_id = (SELECT max(h2.hist_id) FROM mm_merch_hist h2
WHERE h2.merchant_id = h.merchant_id AND h2.action = 'CONTRACT')
AND h.after_val < to_char(current_date, 'YYYYMMDD')
AND NOT EXISTS (SELECT 1 FROM mm_merch_hist e
WHERE e.merchant_id = h.merchant_id AND e.action = 'CONTRACT_EXP'
AND e.hist_id > h.hist_id)
ORDER BY h.merchant_id;
EXEC SQL OPEN cex;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH cex INTO :b_merch, :b_end;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cex; tpabort(0); return 1; }
if (mmdb_insert_merch_hist(b_merch, "CONTRACT_EXP", b_end, "EXPIRED", "만기 경과 자동 만료") < 0) {
EXEC SQL CLOSE cex; tpabort(0); return 1;
}
b_expired++;
}
EXEC SQL CLOSE cex;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_contract_expire_batch COMMIT: 만료=%ld건\n", b_expired);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,6 @@
/* mm_contract_expire_cpy.h - mm_contract_expire_batch 전용 카피북 (host 변수 선언). */
EXEC SQL BEGIN DECLARE SECTION;
char b_merch[64];
char b_end[16];
long b_expired;
EXEC SQL END DECLARE SECTION;

View file

@ -0,0 +1,51 @@
/*
* mm_fee_align_batch.pgc - 요율 마스터 미보유 가맹점 기본 요율 생성 배치 (JOIN 커서 + XA).
*
* CREDIT 요율(mm_fee_rate)이 없는 활성 가맹점에 대해 base merchant.mdr_bps(없으면 25bps)를
* 기본 요율로 생성한다(요율 마스터 공백 보정). ONE global XA transaction.
* host 변수는 mm_fee_align_cpy.h 를 EXEC SQL INCLUDE.
* Usage: mm_fee_align_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
(void)argc; (void)argv;
EXEC SQL INCLUDE mm_fee_align_cpy;
b_aligned = 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 fal CURSOR FOR
SELECT me.merchant_id, coalesce(m.mdr_bps, 25)
FROM mm_merchant_ext me
LEFT JOIN merchant m ON m.merchant_id = me.merchant_id
WHERE me.status = 'ACTIVE'
AND NOT EXISTS (SELECT 1 FROM mm_fee_rate f
WHERE f.merchant_id = me.merchant_id AND f.card_type = 'CREDIT')
ORDER BY me.merchant_id;
EXEC SQL OPEN fal;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH fal INTO :b_merch, :b_bps;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE fal; tpabort(0); return 1; }
EXEC SQL INSERT INTO mm_fee_rate (merchant_id, card_type, rate_bps)
VALUES (:b_merch, 'CREDIT', :b_bps);
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE fal; tpabort(0); return 1; }
b_aligned++;
}
EXEC SQL CLOSE fal;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_fee_align_batch COMMIT: 기본요율 생성=%ld건\n", b_aligned);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,6 @@
/* mm_fee_align_cpy.h - mm_fee_align_batch 전용 카피북 (host 변수 선언). */
EXEC SQL BEGIN DECLARE SECTION;
char b_merch[64];
long b_bps;
long b_aligned;
EXEC SQL END DECLARE SECTION;

View file

@ -0,0 +1,51 @@
/*
* mm_limit_seed_batch.pgc - 한도 마스터 미보유 가맹점 기본 한도 생성 배치 (커서 + XA).
*
* 활성 가맹점 중 mm_limit 행이 없는 건에 대해 기본 한도(일 1억/월 30억/건 1천만)를
* 생성한다(한도 마스터 정합성 보정). ONE global XA transaction.
* host 변수는 mm_limit_seed_cpy.h 를 EXEC SQL INCLUDE.
* Usage: mm_limit_seed_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
(void)argc; (void)argv;
EXEC SQL INCLUDE mm_limit_seed_cpy;
b_seeded = 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 lsd CURSOR FOR
SELECT me.merchant_id FROM mm_merchant_ext me
WHERE me.status = 'ACTIVE'
AND NOT EXISTS (SELECT 1 FROM mm_limit l WHERE l.merchant_id = me.merchant_id)
ORDER BY me.merchant_id;
EXEC SQL OPEN lsd;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH lsd INTO :b_merch;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE lsd; tpabort(0); return 1; }
EXEC SQL INSERT INTO mm_limit (merchant_id, daily_limit, monthly_limit, per_txn_limit)
VALUES (:b_merch, 100000000, 3000000000, 10000000);
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE lsd; tpabort(0); return 1; }
b_seeded++;
}
EXEC SQL CLOSE lsd;
EXEC SQL SELECT count(*) INTO :b_total FROM mm_limit;
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_limit_seed_batch COMMIT: 신규한도=%ld 전체한도행=%ld\n", b_seeded, b_total);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,6 @@
/* mm_limit_seed_cpy.h - mm_limit_seed_batch 전용 카피북 (host 변수 선언). */
EXEC SQL BEGIN DECLARE SECTION;
char b_merch[64];
long b_seeded;
long b_total;
EXEC SQL END DECLARE SECTION;

View file

@ -0,0 +1,52 @@
/*
* mm_mcc_flag_batch.pgc - 고위험 업종 가맹점 플래그 배치 (JOIN 커서 + XA).
*
* 리스크 등급이 기준 이상인 MCC를 쓰는 활성 가맹점에 MCC_FLAG 이력을 남겨
* 모니터링 대상으로 표시한다. ONE global XA transaction.
* host 변수는 mm_mcc_flag_cpy.h 를 EXEC SQL INCLUDE.
* Usage: mm_mcc_flag_batch [MINRISK=4]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mm_dbio.h"
int main(int argc, char **argv)
{
char memo[48];
EXEC SQL INCLUDE mm_mcc_flag_cpy;
b_flagged = 0;
b_minrisk = (argc > 1) ? atol(argv[1]) : 4;
if (b_minrisk < 1 || b_minrisk > 5) b_minrisk = 4;
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 mfl CURSOR FOR
SELECT me.merchant_id, me.mcc, m.risk_level
FROM mm_merchant_ext me JOIN mm_mcc m ON m.mcc = me.mcc
WHERE me.status = 'ACTIVE' AND m.risk_level >= :b_minrisk
ORDER BY me.merchant_id;
EXEC SQL OPEN mfl;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH mfl INTO :b_merch, :b_mcc, :b_risk;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE mfl; tpabort(0); return 1; }
snprintf(memo, sizeof(memo), "MCC %s 위험 %ld", b_mcc, b_risk);
if (mmdb_insert_merch_hist(b_merch, "MCC_FLAG", "", b_mcc, memo) < 0) {
EXEC SQL CLOSE mfl; tpabort(0); return 1;
}
b_flagged++;
}
EXEC SQL CLOSE mfl;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_mcc_flag_batch COMMIT: 기준위험>=%ld 플래그=%ld건\n", b_minrisk, b_flagged);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,8 @@
/* mm_mcc_flag_cpy.h - mm_mcc_flag_batch 전용 카피북 (host 변수 선언). */
EXEC SQL BEGIN DECLARE SECTION;
long b_minrisk;
char b_merch[64];
char b_mcc[8];
long b_risk;
long b_flagged;
EXEC SQL END DECLARE SECTION;

View file

@ -0,0 +1,54 @@
/*
* mm_rate_expire_batch.pgc - 장기 미결 요율 요청 자동 반려 배치 (커서 + XA).
*
* 접수 후 N일이 지나도록 승인/반려로 종결되지 않은 RATE_REQ를 자동 RATE_REJ 처리한다.
* (SLA 초과 요청 정리). ONE global XA transaction.
* host 변수는 mm_rate_expire_cpy.h 를 EXEC SQL INCLUDE.
* Usage: mm_rate_expire_batch [DAYS=14]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mm_dbio.h"
int main(int argc, char **argv)
{
EXEC SQL INCLUDE mm_rate_expire_cpy;
b_rejected = 0;
b_days = (argc > 1) ? atol(argv[1]) : 14;
if (b_days < 1) b_days = 14;
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 rex CURSOR FOR
SELECT DISTINCT r.merchant_id
FROM mm_merch_hist r
WHERE r.action = 'RATE_REQ'
AND r.created_at < now() - (:b_days || ' days')::interval
AND NOT EXISTS (SELECT 1 FROM mm_merch_hist d
WHERE d.merchant_id = r.merchant_id
AND d.action IN ('RATE_APV', 'RATE_REJ') AND d.hist_id > r.hist_id)
ORDER BY r.merchant_id;
EXEC SQL OPEN rex;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH rex INTO :b_merch;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE rex; tpabort(0); return 1; }
if (mmdb_insert_merch_hist(b_merch, "RATE_REJ", "PENDING", "EXPIRED", "SLA 초과 자동 반려") < 0) {
EXEC SQL CLOSE rex; tpabort(0); return 1;
}
b_rejected++;
}
EXEC SQL CLOSE rex;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_rate_expire_batch COMMIT: 기준=%ld일 자동반려=%ld건\n", b_days, b_rejected);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,6 @@
/* mm_rate_expire_cpy.h - mm_rate_expire_batch 전용 카피북 (host 변수 선언). */
EXEC SQL BEGIN DECLARE SECTION;
long b_days;
char b_merch[64];
long b_rejected;
EXEC SQL END DECLARE SECTION;

View file

@ -0,0 +1,49 @@
/*
* mm_rel_count_batch.pgc - 대표 가맹점별 하위 수 집계 배치 (커서 + XA).
*
* MERCH_REL 활성 관계를 대표(code_name) 기준으로 집계하여 각 대표 가맹점에
* REL_CNT 이력을 남긴다(하위 규모 스냅샷). ONE global XA transaction.
* host 변수는 mm_rel_count_cpy.h 를 EXEC SQL INCLUDE.
* Usage: mm_rel_count_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mm_dbio.h"
int main(int argc, char **argv)
{
(void)argc; (void)argv;
EXEC SQL INCLUDE mm_rel_count_cpy;
b_groups = 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 rct CURSOR FOR
SELECT code_name, count(*) FROM mm_code
WHERE code_group = 'MERCH_REL' AND status = 'ACTIVE'
GROUP BY code_name ORDER BY code_name;
EXEC SQL OPEN rct;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH rct INTO :b_parent, :b_children;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE rct; tpabort(0); return 1; }
snprintf(b_memo, sizeof(b_memo), "하위 %ld개", b_children);
if (mmdb_insert_merch_hist(b_parent, "REL_CNT", "", b_memo, "하위 규모 집계") < 0) {
EXEC SQL CLOSE rct; tpabort(0); return 1;
}
b_groups++;
}
EXEC SQL CLOSE rct;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_rel_count_batch COMMIT: 대표 %ld개 집계\n", b_groups);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,7 @@
/* mm_rel_count_cpy.h - mm_rel_count_batch 전용 카피북 (host 변수 선언). */
EXEC SQL BEGIN DECLARE SECTION;
char b_parent[64];
long b_children;
char b_memo[64];
long b_groups;
EXEC SQL END DECLARE SECTION;

View file

@ -0,0 +1,60 @@
/*
* mm_risk_score_batch.pgc - 전 가맹점 리스크 점수 재산정 배치 (JOIN 커서 + C 산정 + XA).
*
* 가맹점 등급/상태/MCC 위험도를 조합해 리스크 점수를 산출하고 밴드(LOW/MID/HIGH)를
* RISK 이력으로 적재한다(온라인 MM_RISK_SCORE와 동일 공식). ONE global XA transaction.
* host 변수는 mm_risk_score_cpy.h 를 EXEC SQL INCLUDE.
* Usage: mm_risk_score_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mm_dbio.h"
int main(int argc, char **argv)
{
long score;
const char *band;
char memo[48];
(void)argc; (void)argv;
EXEC SQL INCLUDE mm_risk_score_cpy;
b_scored = 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 rsc CURSOR FOR
SELECT me.merchant_id, me.grade, me.status, coalesce(m.risk_level, 1)
FROM mm_merchant_ext me
LEFT JOIN mm_mcc m ON m.mcc = me.mcc
WHERE me.status <> 'DELETED'
ORDER BY me.merchant_id;
EXEC SQL OPEN rsc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH rsc INTO :b_merch, :b_grade, :b_stat, :b_risk;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE rsc; tpabort(0); return 1; }
score = b_risk * 20;
if (b_grade[0] == 'C') score += 20;
else if (b_grade[0] == 'B') score += 10;
if (strcmp(b_stat, "ACTIVE") != 0) score += 15;
if (score > 100) score = 100;
band = (score >= 70) ? "HIGH" : (score >= 40) ? "MID" : "LOW";
snprintf(memo, sizeof(memo), "리스크 %ld", score);
if (mmdb_insert_merch_hist(b_merch, "RISK", "", (char *)band, memo) < 0) {
EXEC SQL CLOSE rsc; tpabort(0); return 1;
}
b_scored++;
}
EXEC SQL CLOSE rsc;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_risk_score_batch COMMIT: 재산정=%ld건\n", b_scored);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,8 @@
/* mm_risk_score_cpy.h - mm_risk_score_batch 전용 카피북 (host 변수 선언). */
EXEC SQL BEGIN DECLARE SECTION;
char b_merch[64];
char b_grade[8];
char b_stat[16];
long b_risk;
long b_scored;
EXEC SQL END DECLARE SECTION;

View file

@ -0,0 +1,34 @@
/*
* mm_term_retire_batch.pgc - 비활성 단말 일괄 폐기 배치 (set-based UPDATE + XA).
*
* 개통 해지되어 INACTIVE로 남은 단말을 일괄 RETIRED로 확정한다. 활성/이미폐기 단말은
* 건드리지 않는다. ONE global XA transaction. host 변수는 mm_term_retire_cpy.h.
* Usage: mm_term_retire_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
(void)argc; (void)argv;
EXEC SQL INCLUDE mm_term_retire_cpy;
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 UPDATE mm_terminal SET status = 'RETIRED' WHERE status = 'INACTIVE';
if (sqlca.sqlcode < 0) { fprintf(stderr, "UPDATE FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
b_retired = sqlca.sqlerrd[2];
EXEC SQL SELECT count(*) INTO :b_remain FROM mm_terminal WHERE status = 'ACTIVE';
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mm_term_retire_batch COMMIT: 폐기=%ld 잔여활성=%ld\n", b_retired, b_remain);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,5 @@
/* mm_term_retire_cpy.h - mm_term_retire_batch 전용 카피북 (host 변수 선언). */
EXEC SQL BEGIN DECLARE SECTION;
long b_retired;
long b_remain;
EXEC SQL END DECLARE SECTION;

View file

@ -92,6 +92,66 @@
#include "MM_BIZNO_CHECK.h"
#include "MM_BIZNO_UPD.h"
/* ----- 신규 마스터 서비스 58종 (단말 생애주기/심사/계약/제휴/관계/MCC/요율/휴폐업/계좌/리스크/감사/정합성) */
#include "MM_TERM_INSTALL.h"
#include "MM_TERM_SWAP.h"
#include "MM_TERM_ACTIVATE.h"
#include "MM_TERM_DEACT.h"
#include "MM_TERM_RETIRE.h"
#include "MM_TERM_REASSIGN.h"
#include "MM_TERM_MODEL_UPD.h"
#include "MM_TERM_LIST.h"
#include "MM_TERM_HIST.h"
#include "MM_APPLY_HOLD.h"
#include "MM_APPLY_RESUME.h"
#include "MM_APPLY_DOCCHK.h"
#include "MM_APPLY_SCORE.h"
#include "MM_APPLY_ASSIGN.h"
#include "MM_APPLY_WITHDRAW.h"
#include "MM_APPLY_CNT.h"
#include "MM_CONTRACT_AMEND.h"
#include "MM_CONTRACT_SUSPEND.h"
#include "MM_CONTRACT_REACT.h"
#include "MM_CONTRACT_HIST.h"
#include "MM_CONTRACT_EXPCHK.h"
#include "MM_PARTNER_UPD.h"
#include "MM_PARTNER_LIST.h"
#include "MM_AGENT_REG.h"
#include "MM_AGENT_INQ.h"
#include "MM_AGENT_STATUS.h"
#include "MM_BRANCH_REG.h"
#include "MM_BRANCH_INQ.h"
#include "MM_BRANCH_LIST.h"
#include "MM_REL_PARENT.h"
#include "MM_REL_CHILDREN.h"
#include "MM_REL_MOVE.h"
#include "MM_REL_VERIFY.h"
#include "MM_MCC_DEL.h"
#include "MM_MCC_ASSIGN.h"
#include "MM_MCC_RISKSET.h"
#include "MM_MCC_CNT.h"
#include "MM_RATE_STATUS.h"
#include "MM_RATE_HIST.h"
#include "MM_RATE_CANCEL.h"
#include "MM_RATE_PENDING.h"
#include "MM_MERCH_DORMANT.h"
#include "MM_BIZ_SUSPEND.h"
#include "MM_BIZ_REOPEN.h"
#include "MM_BIZ_CLOSE.h"
#include "MM_ACCT_REG.h"
#include "MM_ACCT_INQ.h"
#include "MM_ACCT_MASK.h"
#include "MM_RISK_SCORE.h"
#include "MM_RISK_SET.h"
#include "MM_RISK_INQ.h"
#include "MM_GRADE_HIST.h"
#include "MM_AUDIT_STAT.h"
#include "MM_AUDIT_DIFF.h"
#include "MM_CHK_ACCT.h"
#include "MM_CHK_MCC.h"
#include "MM_CHK_ORPHAN.h"
#include "MM_CHK_GRADE.h"
/* ----- 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},
@ -169,6 +229,64 @@ static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
{"MM_CODEMAP_DEL", MM_CODEMAP_DEL},
{"MM_BIZNO_CHECK", MM_BIZNO_CHECK},
{"MM_BIZNO_UPD", MM_BIZNO_UPD},
{"MM_TERM_INSTALL", MM_TERM_INSTALL},
{"MM_TERM_SWAP", MM_TERM_SWAP},
{"MM_TERM_ACTIVATE", MM_TERM_ACTIVATE},
{"MM_TERM_DEACT", MM_TERM_DEACT},
{"MM_TERM_RETIRE", MM_TERM_RETIRE},
{"MM_TERM_REASSIGN", MM_TERM_REASSIGN},
{"MM_TERM_MODEL_UPD", MM_TERM_MODEL_UPD},
{"MM_TERM_LIST", MM_TERM_LIST},
{"MM_TERM_HIST", MM_TERM_HIST},
{"MM_APPLY_HOLD", MM_APPLY_HOLD},
{"MM_APPLY_RESUME", MM_APPLY_RESUME},
{"MM_APPLY_DOCCHK", MM_APPLY_DOCCHK},
{"MM_APPLY_SCORE", MM_APPLY_SCORE},
{"MM_APPLY_ASSIGN", MM_APPLY_ASSIGN},
{"MM_APPLY_WITHDRAW", MM_APPLY_WITHDRAW},
{"MM_APPLY_CNT", MM_APPLY_CNT},
{"MM_CONTRACT_AMEND", MM_CONTRACT_AMEND},
{"MM_CONTRACT_SUSPEND", MM_CONTRACT_SUSPEND},
{"MM_CONTRACT_REACT", MM_CONTRACT_REACT},
{"MM_CONTRACT_HIST", MM_CONTRACT_HIST},
{"MM_CONTRACT_EXPCHK", MM_CONTRACT_EXPCHK},
{"MM_PARTNER_UPD", MM_PARTNER_UPD},
{"MM_PARTNER_LIST", MM_PARTNER_LIST},
{"MM_AGENT_REG", MM_AGENT_REG},
{"MM_AGENT_INQ", MM_AGENT_INQ},
{"MM_AGENT_STATUS", MM_AGENT_STATUS},
{"MM_BRANCH_REG", MM_BRANCH_REG},
{"MM_BRANCH_INQ", MM_BRANCH_INQ},
{"MM_BRANCH_LIST", MM_BRANCH_LIST},
{"MM_REL_PARENT", MM_REL_PARENT},
{"MM_REL_CHILDREN", MM_REL_CHILDREN},
{"MM_REL_MOVE", MM_REL_MOVE},
{"MM_REL_VERIFY", MM_REL_VERIFY},
{"MM_MCC_DEL", MM_MCC_DEL},
{"MM_MCC_ASSIGN", MM_MCC_ASSIGN},
{"MM_MCC_RISKSET", MM_MCC_RISKSET},
{"MM_MCC_CNT", MM_MCC_CNT},
{"MM_RATE_STATUS", MM_RATE_STATUS},
{"MM_RATE_HIST", MM_RATE_HIST},
{"MM_RATE_CANCEL", MM_RATE_CANCEL},
{"MM_RATE_PENDING", MM_RATE_PENDING},
{"MM_MERCH_DORMANT", MM_MERCH_DORMANT},
{"MM_BIZ_SUSPEND", MM_BIZ_SUSPEND},
{"MM_BIZ_REOPEN", MM_BIZ_REOPEN},
{"MM_BIZ_CLOSE", MM_BIZ_CLOSE},
{"MM_ACCT_REG", MM_ACCT_REG},
{"MM_ACCT_INQ", MM_ACCT_INQ},
{"MM_ACCT_MASK", MM_ACCT_MASK},
{"MM_RISK_SCORE", MM_RISK_SCORE},
{"MM_RISK_SET", MM_RISK_SET},
{"MM_RISK_INQ", MM_RISK_INQ},
{"MM_GRADE_HIST", MM_GRADE_HIST},
{"MM_AUDIT_STAT", MM_AUDIT_STAT},
{"MM_AUDIT_DIFF", MM_AUDIT_DIFF},
{"MM_CHK_ACCT", MM_CHK_ACCT},
{"MM_CHK_MCC", MM_CHK_MCC},
{"MM_CHK_ORPHAN", MM_CHK_ORPHAN},
{"MM_CHK_GRADE", MM_CHK_GRADE},
{NULL, NULL}
};

View file

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

View file

@ -0,0 +1,29 @@
/*
* MM_ACCT_INQ.pgc - mm 모듈 서비스 MM_ACCT_INQ (one service = one file).
* 기능: 정산계좌 원문 조회 (등록 여부 판정 포함).
* 입력: T_MERCHANT. 출력: T_STR1=계좌번호, T_ARG1=1이면 등록됨 0이면 미등록.
* RC: 0=조회, 1=가맹점 없음.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_ACCT_INQ.h"
void MM_ACCT_INQ(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64];
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_acct[40];
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 settle_acct INTO :h_acct FROM mm_merchant_ext WHERE merchant_id = :h_merch;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
Bchg(b, T_STR1, 0, h_acct, 0L);
setl(b, T_ARG1, h_acct[0] != 0 ? 1 : 0);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,35 @@
/*
* MM_ACCT_MASK.pgc - mm 모듈 서비스 MM_ACCT_MASK (one service = one file).
* 기능: 정산계좌 마스킹 조회 (앞3 뒤2만 노출, 중간은 * 처리하여 반환 - 개인정보 보호).
* 입력: T_MERCHANT. 출력: T_STR1=마스킹된 계좌.
* RC: 0=조회, 1=가맹점 없음, 2=계좌 미등록.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_ACCT_MASK.h"
void MM_ACCT_MASK(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], masked[40];
size_t i, len;
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_acct[40];
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 settle_acct INTO :h_acct FROM mm_merchant_ext WHERE merchant_id = :h_merch;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
len = strlen(h_acct);
if (len == 0) { setl(b, T_RC, 2); OK(b); }
for (i = 0; i < len; i++)
masked[i] = (i < 3 || i >= len - 2) ? h_acct[i] : '*';
masked[len] = 0;
Bchg(b, T_STR1, 0, masked, 0L);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,38 @@
/*
* MM_ACCT_REG.pgc - mm 모듈 서비스 MM_ACCT_REG (one service = one file).
* 기능: 정산계좌 등록/변경 (숫자 10~16자리 형식 검증 통과분만 마스터에 반영, 검증 이력 기록).
* 입력: T_MERCHANT, T_STR1=계좌번호. RC: 0=등록, 1=가맹점 없음, 3=형식 오류.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_ACCT_REG.h"
void MM_ACCT_REG(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], acct[40];
size_t i, len;
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_acct[40];
long h_exist;
EXEC SQL END DECLARE SECTION;
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_STR1, acct, sizeof(acct));
len = strlen(acct);
if (len < 10 || len > 16) { setl(b, T_RC, 3); OK(b); }
for (i = 0; i < len; i++)
if (acct[i] < '0' || acct[i] > '9') { setl(b, T_RC, 3); OK(b); }
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 SELECT count(*) INTO :h_exist FROM mm_merchant_ext WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0) FAIL(b);
if (h_exist == 0) { setl(b, T_RC, 1); OK(b); }
EXEC SQL UPDATE mm_merchant_ext SET settle_acct = :h_acct, updated_at = now()
WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0) FAIL(b);
if (mmdb_insert_merch_hist(h_merch, "ACCT_REG", "", h_acct, "정산계좌 등록") < 0) FAIL(b);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,31 @@
/*
* MM_AGENT_INQ.pgc - mm 모듈 서비스 MM_AGENT_INQ (one service = one file).
* 기능: 모집인 단건 조회 (AGENT 코드그룹에서 명칭/상태 반환).
* 입력: T_KEY1=모집인 코드. 출력: T_STR1=명칭, T_STATUS=상태.
* RC: 0=조회, 1=모집인 없음.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_AGENT_INQ.h"
void MM_AGENT_INQ(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char code[16];
EXEC SQL BEGIN DECLARE SECTION;
char h_code[16], h_name[64], h_stat[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_KEY1, code, sizeof(code));
if (code[0] == 0) { setl(b, T_RC, 3); OK(b); }
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_stat
FROM mm_code WHERE code_group = 'AGENT' AND code = :h_code;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
Bchg(b, T_STR1, 0, h_name, 0L);
Bchg(b, T_STATUS, 0, h_stat, 0L);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,41 @@
/*
* MM_AGENT_REG.pgc - mm 모듈 서비스 MM_AGENT_REG (one service = one file).
* 기능: 모집인 등록 (AGENT 코드그룹 upsert, 소속 제휴사 코드를 T_STR2로 검증).
* 입력: T_KEY1=모집인 코드, T_STR1=모집인명, T_STR2=소속 제휴사 코드(선택).
* RC: 0=등록, 3=필수값 누락, 2=소속 제휴사 미존재.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_AGENT_REG.h"
void MM_AGENT_REG(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char code[16], name[64], pcode[16];
EXEC SQL BEGIN DECLARE SECTION;
char h_code[16], h_name[64], h_pcode[16];
long h_pok;
EXEC SQL END DECLARE SECTION;
gets_(b, T_KEY1, code, sizeof(code));
gets_(b, T_STR1, name, sizeof(name));
gets_(b, T_STR2, pcode, sizeof(pcode));
if (code[0] == 0 || name[0] == 0) { setl(b, T_RC, 3); OK(b); }
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;
strncpy(h_pcode, pcode, sizeof(h_pcode)-1); h_pcode[sizeof(h_pcode)-1] = 0;
if (h_pcode[0] != 0) {
EXEC SQL SELECT count(*) INTO :h_pok FROM mm_code
WHERE code_group = 'PARTNER' AND code = :h_pcode;
if (sqlca.sqlcode < 0) FAIL(b);
if (h_pok == 0) { setl(b, T_RC, 2); OK(b); }
}
EXEC SQL INSERT INTO mm_code (code_group, code, code_name, status)
VALUES ('AGENT', :h_code, :h_name, 'ACTIVE')
ON CONFLICT (code_group, code)
DO UPDATE SET code_name = EXCLUDED.code_name, status = 'ACTIVE';
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,36 @@
/*
* MM_AGENT_STATUS.pgc - mm 모듈 서비스 MM_AGENT_STATUS (one service = one file).
* 기능: 모집인 상태 변경 (ACTIVE/SUSPENDED/RETIRED 허용값 검증 후 갱신).
* 입력: T_KEY1=모집인 코드, T_STATUS=신규 상태.
* RC: 0=변경, 1=모집인 없음, 3=허용되지 않는 상태값.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_AGENT_STATUS.h"
void MM_AGENT_STATUS(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char code[16], stat[16];
EXEC SQL BEGIN DECLARE SECTION;
char h_code[16], h_stat[16];
long h_exist;
EXEC SQL END DECLARE SECTION;
gets_(b, T_KEY1, code, sizeof(code));
gets_(b, T_STATUS, stat, sizeof(stat));
if (strcmp(stat, "ACTIVE") != 0 && strcmp(stat, "SUSPENDED") != 0
&& strcmp(stat, "RETIRED") != 0) { setl(b, T_RC, 3); OK(b); }
strncpy(h_code, code, sizeof(h_code)-1); h_code[sizeof(h_code)-1] = 0;
strncpy(h_stat, stat, sizeof(h_stat)-1); h_stat[sizeof(h_stat)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_exist FROM mm_code
WHERE code_group = 'AGENT' AND code = :h_code;
if (sqlca.sqlcode < 0) FAIL(b);
if (h_exist == 0) { setl(b, T_RC, 1); OK(b); }
EXEC SQL UPDATE mm_code SET status = :h_stat
WHERE code_group = 'AGENT' AND code = :h_code;
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,31 @@
/*
* MM_APPLY_ASSIGN.pgc - mm 모듈 서비스 MM_APPLY_ASSIGN (one service = one file).
* 기능: 심사 담당자 배정 (담당자 코드를 REVIEWER 매핑 이력에 기록).
* 입력: T_MERCHANT, T_STR1=담당자 코드. RC: 0=배정, 1=신청 건 없음, 3=담당자 누락, 4=최종 상태(배정 불가).
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_APPLY_ASSIGN.h"
void MM_APPLY_ASSIGN(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], rev[32];
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_rev[32], h_stat[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_STR1, rev, sizeof(rev));
if (rev[0] == 0) { setl(b, T_RC, 3); OK(b); }
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
strncpy(h_rev, rev, sizeof(h_rev)-1); h_rev[sizeof(h_rev)-1] = 0;
EXEC SQL SELECT status INTO :h_stat FROM mm_merchant_ext WHERE merchant_id = :h_merch;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
if (strcmp(h_stat, "APPLIED") != 0 && strcmp(h_stat, "HOLD") != 0) { setl(b, T_RC, 4); OK(b); }
if (mmdb_insert_merch_hist(h_merch, "APPLY_ASSIGN", "", h_rev, "심사 담당자 배정") < 0) FAIL(b);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,34 @@
/*
* MM_APPLY_CNT.pgc - mm 모듈 서비스 MM_APPLY_CNT (one service = one file).
* 기능: 심사 상태별 신청 건수 집계 (대시보드용, 특정 상태 또는 전 워크플로 상태).
* 입력: T_STR1=상태 필터(빈값이면 심사 대상 전체 APPLIED+HOLD). 출력: T_COUNT.
* RC: 항상 0.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_APPLY_CNT.h"
void MM_APPLY_CNT(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char filt[16];
EXEC SQL BEGIN DECLARE SECTION;
char h_filt[16];
long h_cnt;
EXEC SQL END DECLARE SECTION;
gets_(b, T_STR1, filt, sizeof(filt));
strncpy(h_filt, filt, sizeof(h_filt)-1); h_filt[sizeof(h_filt)-1] = 0;
if (h_filt[0] == 0) {
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_merchant_ext
WHERE status IN ('APPLIED', 'HOLD');
} else {
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_merchant_ext
WHERE status = :h_filt;
}
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_cnt);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,38 @@
/*
* MM_APPLY_DOCCHK.pgc - mm 모듈 서비스 MM_APPLY_DOCCHK (one service = one file).
* 기능: 심사 서류 접수 확인 (필수 마스터 필드 충족도 점검, 심사 서브단계).
* 사업자번호/상호/MCC 충족 여부를 점수화(0~3). 3점이면 서류 완비.
* 입력: T_MERCHANT. 출력: T_ARG1=충족 항목수(0~3), T_STR1=DOC_OK/DOC_LACK.
* RC: 0=조회, 1=신청 건 없음.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_APPLY_DOCCHK.h"
void MM_APPLY_DOCCHK(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64];
int score = 0;
const char *verdict;
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_biz[16], h_name[64], h_mcc[8];
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 biz_reg_no, name, mcc INTO :h_biz, :h_name, :h_mcc
FROM mm_merchant_ext WHERE merchant_id = :h_merch;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
if (strlen(h_biz) == 10) score++;
if (h_name[0] != 0) score++;
if (h_mcc[0] != 0 && strcmp(h_mcc, "0000") != 0) score++;
verdict = (score == 3) ? "DOC_OK" : "DOC_LACK";
Bchg(b, T_STR1, 0, (char *)verdict, 0L);
setl(b, T_ARG1, score);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,34 @@
/*
* MM_APPLY_HOLD.pgc - mm 모듈 서비스 MM_APPLY_HOLD (one service = one file).
* 기능: 심사 진행 중 신청 건 보류 (APPLIED->HOLD, 사유 이력 기록).
* 입력: T_MERCHANT, T_REASON=보류 사유(기본 "서류 보완 대기").
* RC: 0=보류, 1=신청 건 없음, 4=심사중(APPLIED) 상태 아님.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_APPLY_HOLD.h"
void MM_APPLY_HOLD(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], reason[128];
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_stat[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_REASON, reason, sizeof(reason));
if (reason[0] == 0) strcpy(reason, "서류 보완 대기");
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT status INTO :h_stat FROM mm_merchant_ext WHERE merchant_id = :h_merch;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
if (strcmp(h_stat, "APPLIED") != 0) { setl(b, T_RC, 4); OK(b); }
EXEC SQL UPDATE mm_merchant_ext SET status = 'HOLD', updated_at = now()
WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0) FAIL(b);
if (mmdb_insert_merch_hist(h_merch, "APPLY_HOLD", "APPLIED", "HOLD", reason) < 0) FAIL(b);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,38 @@
/*
* MM_APPLY_RESUME.pgc - mm 모듈 서비스 MM_APPLY_RESUME (one service = one file).
* 기능: 보류된 심사 재개 (HOLD->APPLIED, 심사 대기열 복귀).
* 입력: T_MERCHANT. 출력: T_ARG1=해당 가맹점 누적 보류 횟수.
* RC: 0=재개, 1=신청 건 없음, 4=보류(HOLD) 상태 아님.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_APPLY_RESUME.h"
void MM_APPLY_RESUME(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64];
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_stat[16];
long h_holds;
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 status INTO :h_stat FROM mm_merchant_ext WHERE merchant_id = :h_merch;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
if (strcmp(h_stat, "HOLD") != 0) { setl(b, T_RC, 4); OK(b); }
EXEC SQL SELECT count(*) INTO :h_holds FROM mm_merch_hist
WHERE merchant_id = :h_merch AND action = 'APPLY_HOLD';
if (sqlca.sqlcode < 0) FAIL(b);
EXEC SQL UPDATE mm_merchant_ext SET status = 'APPLIED', updated_at = now()
WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0) FAIL(b);
if (mmdb_insert_merch_hist(h_merch, "APPLY_RESUME", "HOLD", "APPLIED", "심사 재개") < 0) FAIL(b);
setl(b, T_ARG1, h_holds);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,44 @@
/*
* MM_APPLY_SCORE.pgc - mm 모듈 서비스 MM_APPLY_SCORE (one service = one file).
* 기능: 심사 점수 산정 (MCC 리스크 + 서류 완비도 가중 합산, 등급 예비판정).
* 점수 = 100 - MCC위험*15 - 서류미비항목*20. 60미만 REVIEW, 이상 PASS.
* 입력: T_MERCHANT. 출력: T_ARG1=점수, T_STR1=PASS/REVIEW. RC: 1=신청 건 없음.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_APPLY_SCORE.h"
void MM_APPLY_SCORE(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], memo[64];
long score;
const char *verdict;
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_biz[16], h_mcc[8];
long h_risk;
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 biz_reg_no, mcc INTO :h_biz, :h_mcc
FROM mm_merchant_ext WHERE merchant_id = :h_merch;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
h_risk = 1;
EXEC SQL SELECT risk_level INTO :h_risk FROM mm_mcc WHERE mcc = :h_mcc;
if (sqlca.sqlcode < 0) FAIL(b);
score = 100 - h_risk * 15;
if (strlen(h_biz) != 10) score -= 20;
if (score < 0) score = 0;
verdict = (score >= 60) ? "PASS" : "REVIEW";
snprintf(memo, sizeof(memo), "심사점수 %ld", score);
if (mmdb_insert_merch_hist(h_merch, "APPLY_SCORE", "", (char *)verdict, memo) < 0) FAIL(b);
Bchg(b, T_STR1, 0, (char *)verdict, 0L);
setl(b, T_ARG1, score);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,34 @@
/*
* MM_APPLY_WITHDRAW.pgc - mm 모듈 서비스 MM_APPLY_WITHDRAW (one service = one file).
* 기능: 신청 철회 (신청/보류 단계 건을 WITHDRAWN 처리, 활성 가맹점은 철회 불가).
* 입력: T_MERCHANT, T_REASON=철회 사유(기본 "신청인 철회").
* RC: 0=철회, 1=신청 건 없음, 4=철회 불가 상태(ACTIVE 등).
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_APPLY_WITHDRAW.h"
void MM_APPLY_WITHDRAW(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], reason[128];
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_stat[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_REASON, reason, sizeof(reason));
if (reason[0] == 0) strcpy(reason, "신청인 철회");
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT status INTO :h_stat FROM mm_merchant_ext WHERE merchant_id = :h_merch;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
if (strcmp(h_stat, "APPLIED") != 0 && strcmp(h_stat, "HOLD") != 0) { setl(b, T_RC, 4); OK(b); }
EXEC SQL UPDATE mm_merchant_ext SET status = 'WITHDRAWN', updated_at = now()
WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0) FAIL(b);
if (mmdb_insert_merch_hist(h_merch, "APPLY_WD", h_stat, "WITHDRAWN", reason) < 0) FAIL(b);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,32 @@
/*
* MM_AUDIT_DIFF.pgc - mm 모듈 서비스 MM_AUDIT_DIFF (one service = one file).
* 기능: 마스터 최근 변경 전후 비교 (가장 최신 이력 1건의 액션/이전값/이후값 반환).
* 입력: T_MERCHANT. 출력: T_STR1=액션, T_STR2=이전값, T_STR3=이후값.
* RC: 0=조회, 1=이력 없음.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_AUDIT_DIFF.h"
void MM_AUDIT_DIFF(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64];
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_act[32], h_bef[128], h_aft[128];
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 action, before_val, after_val INTO :h_act, :h_bef, :h_aft
FROM mm_merch_hist WHERE merchant_id = :h_merch
ORDER BY hist_id DESC LIMIT 1;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
Bchg(b, T_STR1, 0, h_act, 0L);
Bchg(b, T_STR2, 0, h_bef, 0L);
Bchg(b, T_STR3, 0, h_aft, 0L);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,30 @@
/*
* MM_AUDIT_STAT.pgc - mm 모듈 서비스 MM_AUDIT_STAT (one service = one file).
* 기능: 전 마스터 감사 통계 (특정 액션의 전체 발생 건수 + 관련 가맹점 수 집계).
* 입력: T_STR1=액션(빈값이면 전체 이력). 출력: T_COUNT=이력 건수, T_ARG1=관련 가맹점 수.
* RC: 항상 0.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_AUDIT_STAT.h"
void MM_AUDIT_STAT(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char act[32];
EXEC SQL BEGIN DECLARE SECTION;
char h_act[32];
long h_cnt, h_merch;
EXEC SQL END DECLARE SECTION;
gets_(b, T_STR1, act, sizeof(act));
strncpy(h_act, act, sizeof(h_act)-1); h_act[sizeof(h_act)-1] = 0;
EXEC SQL SELECT count(*), count(DISTINCT merchant_id) INTO :h_cnt, :h_merch
FROM mm_merch_hist WHERE (:h_act = '' OR action = :h_act);
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_cnt);
setl(b, T_ARG1, h_merch);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,41 @@
/*
* MM_BIZ_CLOSE.pgc - mm 모듈 서비스 MM_BIZ_CLOSE (one service = one file).
* 기능: 폐업 확정 처리 (상태 CLOSED, 미결 계약 잔여 여부를 함께 점검하여 경고 코드 반환).
* 입력: T_MERCHANT, T_REASON=사유(기본 "폐업 확정"). 출력: T_ARG1=미만기 계약 수.
* RC: 0=폐업, 1=가맹점 없음, 2=이미 폐업/삭제, 6=폐업했으나 미만기 계약 잔존(후속 정리 필요).
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_BIZ_CLOSE.h"
void MM_BIZ_CLOSE(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], reason[128];
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_stat[16];
long h_open;
EXEC SQL END DECLARE SECTION;
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_REASON, reason, sizeof(reason));
if (reason[0] == 0) strcpy(reason, "폐업 확정");
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT status INTO :h_stat FROM mm_merchant_ext WHERE merchant_id = :h_merch;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
if (strcmp(h_stat, "CLOSED") == 0 || strcmp(h_stat, "DELETED") == 0) { setl(b, T_RC, 2); OK(b); }
EXEC SQL SELECT count(*) INTO :h_open FROM mm_merch_hist
WHERE merchant_id = :h_merch AND action = 'CONTRACT'
AND after_val > to_char(current_date, 'YYYYMMDD');
if (sqlca.sqlcode < 0) FAIL(b);
EXEC SQL UPDATE mm_merchant_ext SET status = 'CLOSED', updated_at = now()
WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0) FAIL(b);
if (mmdb_insert_merch_hist(h_merch, "BIZ_CLOSE", h_stat, "CLOSED", reason) < 0) FAIL(b);
setl(b, T_ARG1, h_open);
setl(b, T_RC, h_open > 0 ? 6 : 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,35 @@
/*
* MM_BIZ_REOPEN.pgc - mm 모듈 서비스 MM_BIZ_REOPEN (one service = one file).
* 기능: 재개업 처리 (SUSPENDED/DORMANT 가맹점을 ACTIVE로 복귀, 폐업/삭제 건은 불가).
* 입력: T_MERCHANT. 출력: T_STR1=복귀 직전 상태.
* RC: 0=재개, 1=가맹점 없음, 4=재개 대상 상태 아님(이미 활성/폐업 등).
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_BIZ_REOPEN.h"
void MM_BIZ_REOPEN(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64];
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_stat[16];
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 status INTO :h_stat FROM mm_merchant_ext WHERE merchant_id = :h_merch;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
if (strcmp(h_stat, "SUSPENDED") != 0 && strcmp(h_stat, "DORMANT") != 0) {
Bchg(b, T_STR1, 0, h_stat, 0L); setl(b, T_RC, 4); OK(b);
}
EXEC SQL UPDATE mm_merchant_ext SET status = 'ACTIVE', updated_at = now()
WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0) FAIL(b);
if (mmdb_insert_merch_hist(h_merch, "BIZ_REOPEN", h_stat, "ACTIVE", "재개업 처리") < 0) FAIL(b);
Bchg(b, T_STR1, 0, h_stat, 0L);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,40 @@
/*
* MM_BIZ_SUSPEND.pgc - mm 모듈 서비스 MM_BIZ_SUSPEND (one service = one file).
* 기능: 휴업 신고 처리 (ACTIVE 가맹점을 SUSPENDED로, 소속 활성 단말도 함께 정지).
* 입력: T_MERCHANT, T_REASON=사유(기본 "휴업 신고"). 출력: T_COUNT=정지된 단말 수.
* RC: 0=휴업, 1=가맹점 없음, 2=활성 아님.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_BIZ_SUSPEND.h"
void MM_BIZ_SUSPEND(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], reason[128];
long nterm;
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_stat[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_REASON, reason, sizeof(reason));
if (reason[0] == 0) strcpy(reason, "휴업 신고");
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT status INTO :h_stat FROM mm_merchant_ext WHERE merchant_id = :h_merch;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
if (strcmp(h_stat, "ACTIVE") != 0) { setl(b, T_RC, 2); OK(b); }
EXEC SQL UPDATE mm_merchant_ext SET status = 'SUSPENDED', updated_at = now()
WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0) FAIL(b);
EXEC SQL UPDATE mm_terminal SET status = 'INACTIVE'
WHERE merchant_id = :h_merch AND status = 'ACTIVE';
if (sqlca.sqlcode < 0) FAIL(b);
nterm = sqlca.sqlerrd[2];
if (mmdb_insert_merch_hist(h_merch, "BIZ_SUSPEND", "ACTIVE", "SUSPENDED", reason) < 0) FAIL(b);
setl(b, T_COUNT, nterm);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,32 @@
/*
* MM_BRANCH_INQ.pgc - mm 모듈 서비스 MM_BRANCH_INQ (one service = one file).
* 기능: 영업점 조회 ("명칭|상위코드" 저장값을 명칭만 분리하여 반환).
* 입력: T_KEY1=영업점 코드. 출력: T_STR1=영업점명(파이프 앞부분).
* RC: 0=조회, 1=영업점 없음.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_BRANCH_INQ.h"
void MM_BRANCH_INQ(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char code[16], *bar;
EXEC SQL BEGIN DECLARE SECTION;
char h_code[16], h_nm[80];
EXEC SQL END DECLARE SECTION;
gets_(b, T_KEY1, code, sizeof(code));
if (code[0] == 0) { setl(b, T_RC, 3); OK(b); }
strncpy(h_code, code, sizeof(h_code)-1); h_code[sizeof(h_code)-1] = 0;
EXEC SQL SELECT code_name INTO :h_nm FROM mm_code
WHERE code_group = 'BRANCH' AND code = :h_code;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
bar = strchr(h_nm, '|');
if (bar != NULL) *bar = 0;
Bchg(b, T_STR1, 0, h_nm, 0L);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,27 @@
/*
* MM_BRANCH_LIST.pgc - mm 모듈 서비스 MM_BRANCH_LIST (one service = one file).
* 기능: 영업점 계층 요약 (전체 수 + 최상위(상위=-) 영업점 수 집계).
* 출력: T_COUNT=전체 영업점 수, T_ARG1=최상위 영업점 수.
* RC: 항상 0.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_BRANCH_LIST.h"
void MM_BRANCH_LIST(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
EXEC SQL BEGIN DECLARE SECTION;
long h_all, h_top;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT count(*),
count(*) FILTER (WHERE code_name LIKE '%|-')
INTO :h_all, :h_top
FROM mm_code WHERE code_group = 'BRANCH' AND status = 'ACTIVE';
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_all);
setl(b, T_ARG1, h_top);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,35 @@
/*
* MM_BRANCH_REG.pgc - mm 모듈 서비스 MM_BRANCH_REG (one service = one file).
* 기능: 영업점 마스터 등록 (BRANCH 코드그룹 upsert, 상위 영업점 코드를 code_name에 저장).
* 입력: T_KEY1=영업점 코드, T_STR1=영업점명, T_KEY2=상위 영업점(선택).
* RC: 0=등록, 3=필수값 누락, 3=자기 자신을 상위로 지정 불가.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_BRANCH_REG.h"
void MM_BRANCH_REG(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char code[16], name[64], parent[16], nm[80];
EXEC SQL BEGIN DECLARE SECTION;
char h_code[16], h_nm[80];
EXEC SQL END DECLARE SECTION;
gets_(b, T_KEY1, code, sizeof(code));
gets_(b, T_STR1, name, sizeof(name));
gets_(b, T_KEY2, parent, sizeof(parent));
if (code[0] == 0 || name[0] == 0) { setl(b, T_RC, 3); OK(b); }
if (parent[0] != 0 && strcmp(parent, code) == 0) { setl(b, T_RC, 3); OK(b); }
/* code_name에 "명칭|상위코드" 형태로 계층 정보를 함께 저장 */
snprintf(nm, sizeof(nm), "%s|%s", name, parent[0] ? parent : "-");
strncpy(h_code, code, sizeof(h_code)-1); h_code[sizeof(h_code)-1] = 0;
strncpy(h_nm, nm, sizeof(h_nm)-1); h_nm[sizeof(h_nm)-1] = 0;
EXEC SQL INSERT INTO mm_code (code_group, code, code_name, status)
VALUES ('BRANCH', :h_code, :h_nm, 'ACTIVE')
ON CONFLICT (code_group, code)
DO UPDATE SET code_name = EXCLUDED.code_name, status = 'ACTIVE';
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,27 @@
/*
* MM_CHK_ACCT.pgc - mm 모듈 서비스 MM_CHK_ACCT (one service = one file).
* 기능: 정합성 점검 - 정산계좌 미등록 활성 가맹점 적발 (정산 지급 리스크 사전 탐지).
* 출력: T_COUNT=계좌 미등록 활성 가맹점 수, T_ARG1=활성 가맹점 총수.
* RC: 0=결함 없음, 7=미등록 건 존재.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_CHK_ACCT.h"
void MM_CHK_ACCT(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
EXEC SQL BEGIN DECLARE SECTION;
long h_bad, h_all;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT
count(*) FILTER (WHERE settle_acct = ''), count(*)
INTO :h_bad, :h_all
FROM mm_merchant_ext WHERE status = 'ACTIVE';
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_bad);
setl(b, T_ARG1, h_all);
setl(b, T_RC, h_bad > 0 ? 7 : 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,37 @@
/*
* MM_CHK_GRADE.pgc - mm 모듈 서비스 MM_CHK_GRADE (one service = one file).
* 기능: 정합성 점검 - 마스터 등급과 누적 매출 기준 산정 등급의 불일치 적발.
* 기준: S>=10억, A>=3억, B>=5천만, 그 외 C. 활성 가맹점 대상.
* 출력: T_COUNT=불일치 가맹점 수, T_ARG1=점검 대상 총수. RC: 0=정합, 7=불일치 존재.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_CHK_GRADE.h"
void MM_CHK_GRADE(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
EXEC SQL BEGIN DECLARE SECTION;
long h_bad, h_all;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT count(*),
count(*) FILTER (WHERE me.grade <> calc.g)
INTO :h_all, :h_bad
FROM mm_merchant_ext me
JOIN LATERAL (
SELECT CASE
WHEN coalesce(s.g, 0) >= 1000000000 THEN 'S'
WHEN coalesce(s.g, 0) >= 300000000 THEN 'A'
WHEN coalesce(s.g, 0) >= 50000000 THEN 'B'
ELSE 'C' END AS g
FROM (SELECT sum(gross_amount) AS g FROM merchant_summary
WHERE merchant_id = me.merchant_id) s
) calc ON true
WHERE me.status = 'ACTIVE';
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_bad);
setl(b, T_ARG1, h_all);
setl(b, T_RC, h_bad > 0 ? 7 : 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,28 @@
/*
* MM_CHK_MCC.pgc - mm 모듈 서비스 MM_CHK_MCC (one service = one file).
* 기능: 정합성 점검 - MCC 마스터에 없는 업종코드를 참조하는 가맹점 적발 (외래키 무결성).
* 출력: T_COUNT=고아 MCC 참조 가맹점 수, T_ARG1=적발된 서로 다른 MCC 종류 수.
* RC: 0=결함 없음, 7=고아 참조 존재.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_CHK_MCC.h"
void MM_CHK_MCC(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt, h_kinds;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT count(*), count(DISTINCT me.mcc) INTO :h_cnt, :h_kinds
FROM mm_merchant_ext me
WHERE me.status <> 'DELETED'
AND me.mcc <> '0000'
AND NOT EXISTS (SELECT 1 FROM mm_mcc m WHERE m.mcc = me.mcc);
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_cnt);
setl(b, T_ARG1, h_kinds);
setl(b, T_RC, h_cnt > 0 ? 7 : 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,31 @@
/*
* MM_CHK_ORPHAN.pgc - mm 모듈 서비스 MM_CHK_ORPHAN (one service = one file).
* 기능: 정합성 점검 - 대표가 비활성/부재인 대표-하위 관계 적발 (MERCH_REL 고아 링크).
* 출력: T_COUNT=결함 관계 수, T_ARG1=활성 관계 총수.
* RC: 0=결함 없음, 7=고아 관계 존재.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_CHK_ORPHAN.h"
void MM_CHK_ORPHAN(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
EXEC SQL BEGIN DECLARE SECTION;
long h_bad, h_all;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT count(*) INTO :h_all FROM mm_code
WHERE code_group = 'MERCH_REL' AND status = 'ACTIVE';
if (sqlca.sqlcode < 0) FAIL(b);
EXEC SQL SELECT count(*) INTO :h_bad FROM mm_code rel
WHERE rel.code_group = 'MERCH_REL' AND rel.status = 'ACTIVE'
AND NOT EXISTS (SELECT 1 FROM mm_merchant_ext me
WHERE me.merchant_id = rel.code_name AND me.status = 'ACTIVE');
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_bad);
setl(b, T_ARG1, h_all);
setl(b, T_RC, h_bad > 0 ? 7 : 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,45 @@
/*
* MM_CONTRACT_AMEND.pgc - mm 모듈 서비스 MM_CONTRACT_AMEND (one service = one file).
* 기능: 유효 계약의 조건 변경 (만기일 연장/단축, 변경 전후를 이력에 함께 기록).
* 입력: T_MERCHANT, T_ARG1=연장 개월(음수면 단축, -60~60). 출력: T_STR1=신 만기일.
* RC: 0=변경, 1=유효 계약 없음, 3=개월 범위 오류, 4=변경 결과가 과거일.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_CONTRACT_AMEND.h"
void MM_CONTRACT_AMEND(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], beforev[32];
long mon;
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_cur[16], h_new[16];
long h_mon, h_future;
EXEC SQL END DECLARE SECTION;
gets_(b, T_MERCHANT, merch, sizeof(merch));
mon = getl(b, T_ARG1);
if (mon < -60 || mon > 60 || mon == 0) { setl(b, T_RC, 3); OK(b); }
h_mon = mon;
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT after_val INTO :h_cur FROM mm_merch_hist
WHERE merchant_id = :h_merch AND action = 'CONTRACT'
ORDER BY hist_id DESC LIMIT 1;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
EXEC SQL SELECT to_char(to_date(:h_cur, 'YYYYMMDD') + :h_mon * interval '1 month', 'YYYYMMDD')
INTO :h_new;
if (sqlca.sqlcode < 0) FAIL(b);
EXEC SQL SELECT CASE WHEN to_date(:h_new, 'YYYYMMDD') > current_date THEN 1 ELSE 0 END
INTO :h_future;
if (sqlca.sqlcode < 0) FAIL(b);
if (h_future == 0) { setl(b, T_RC, 4); OK(b); }
strncpy(beforev, h_cur, sizeof(beforev)-1); beforev[sizeof(beforev)-1] = 0;
if (mmdb_insert_merch_hist(h_merch, "CONTRACT", beforev, h_new, "계약 조건 변경") < 0) FAIL(b);
Bchg(b, T_STR1, 0, h_new, 0L);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,40 @@
/*
* MM_CONTRACT_EXPCHK.pgc - mm 모듈 서비스 MM_CONTRACT_EXPCHK (one service = one file).
* 기능: 만기 임박 점검 (최신 계약 만기일까지 남은 일수 산출, 갱신 필요 판정).
* 입력: T_MERCHANT, T_ARG1=임박 기준 일수(기본 30). 출력: T_STR1=만기일, T_ARG1=잔여 일수.
* RC: 0=정상, 1=계약 없음, 5=이미 만기 경과, 6=임박(갱신 권고).
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_CONTRACT_EXPCHK.h"
void MM_CONTRACT_EXPCHK(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64];
long thresh;
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_end[16];
long h_days;
EXEC SQL END DECLARE SECTION;
gets_(b, T_MERCHANT, merch, sizeof(merch));
thresh = getl(b, T_ARG1);
if (thresh <= 0) thresh = 30;
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT after_val INTO :h_end FROM mm_merch_hist
WHERE merchant_id = :h_merch AND action = 'CONTRACT'
ORDER BY hist_id DESC LIMIT 1;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
EXEC SQL SELECT (to_date(:h_end, 'YYYYMMDD') - current_date) INTO :h_days;
if (sqlca.sqlcode < 0) FAIL(b);
Bchg(b, T_STR1, 0, h_end, 0L);
setl(b, T_ARG1, h_days);
if (h_days < 0) { setl(b, T_RC, 5); OK(b); }
if (h_days <= thresh) { setl(b, T_RC, 6); OK(b); }
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,31 @@
/*
* MM_CONTRACT_HIST.pgc - mm 모듈 서비스 MM_CONTRACT_HIST (one service = one file).
* 기능: 가맹점 계약 변경 이력 요약 (체결/변경 횟수 + 최신 만기일 반환).
* 입력: T_MERCHANT. 출력: T_COUNT=CONTRACT 이력 건수, T_STR1=최신 만기일(없으면 빈값).
* RC: 항상 0.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_CONTRACT_HIST.h"
void MM_CONTRACT_HIST(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64];
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_last[16];
long h_cnt;
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;
h_last[0] = 0;
EXEC SQL SELECT count(*), coalesce(max(after_val), '') INTO :h_cnt, :h_last
FROM mm_merch_hist WHERE merchant_id = :h_merch AND action = 'CONTRACT';
if (sqlca.sqlcode < 0) FAIL(b);
Bchg(b, T_STR1, 0, h_last, 0L);
setl(b, T_COUNT, h_cnt);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,32 @@
/*
* MM_CONTRACT_REACT.pgc - mm 모듈 서비스 MM_CONTRACT_REACT (one service = one file).
* 기능: 정지된 계약 재개 (미해제 CONTRACT_SUSP가 있을 때만 CONTRACT_REACT 기록).
* 입력: T_MERCHANT. RC: 0=재개, 1=정지 상태 아님(재개할 대상 없음).
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_CONTRACT_REACT.h"
void MM_CONTRACT_REACT(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64];
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64];
long h_susp;
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_susp FROM mm_merch_hist s
WHERE s.merchant_id = :h_merch AND s.action = 'CONTRACT_SUSP'
AND NOT EXISTS (SELECT 1 FROM mm_merch_hist r
WHERE r.merchant_id = s.merchant_id
AND r.action = 'CONTRACT_REACT' AND r.hist_id > s.hist_id);
if (sqlca.sqlcode < 0) FAIL(b);
if (h_susp == 0) { setl(b, T_RC, 1); OK(b); }
if (mmdb_insert_merch_hist(h_merch, "CONTRACT_REACT", "SUSPENDED", "ACTIVE", "계약 재개") < 0) FAIL(b);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,41 @@
/*
* MM_CONTRACT_SUSPEND.pgc - mm 모듈 서비스 MM_CONTRACT_SUSPEND (one service = one file).
* 기능: 계약 일시정지 (활성 가맹점을 유지하되 CONTRACT_SUSP 이력 마킹, 중복 정지 차단).
* 입력: T_MERCHANT, T_REASON=정지 사유(기본 "계약 일시정지").
* RC: 0=정지, 1=유효 계약 없음, 4=이미 정지 상태.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_CONTRACT_SUSPEND.h"
void MM_CONTRACT_SUSPEND(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], reason[128];
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64];
long h_has, h_susp;
EXEC SQL END DECLARE SECTION;
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_REASON, reason, sizeof(reason));
if (reason[0] == 0) strcpy(reason, "계약 일시정지");
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_has FROM mm_merch_hist
WHERE merchant_id = :h_merch AND action = 'CONTRACT';
if (sqlca.sqlcode < 0) FAIL(b);
if (h_has == 0) { setl(b, T_RC, 1); OK(b); }
/* 마지막 정지/재개 이력을 비교하여 현재 정지 상태이면 차단 */
EXEC SQL SELECT count(*) INTO :h_susp FROM mm_merch_hist s
WHERE s.merchant_id = :h_merch AND s.action = 'CONTRACT_SUSP'
AND NOT EXISTS (SELECT 1 FROM mm_merch_hist r
WHERE r.merchant_id = s.merchant_id
AND r.action = 'CONTRACT_REACT' AND r.hist_id > s.hist_id);
if (sqlca.sqlcode < 0) FAIL(b);
if (h_susp > 0) { setl(b, T_RC, 4); OK(b); }
if (mmdb_insert_merch_hist(h_merch, "CONTRACT_SUSP", "", "SUSPENDED", reason) < 0) FAIL(b);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,34 @@
/*
* MM_GRADE_HIST.pgc - mm 모듈 서비스 MM_GRADE_HIST (one service = one file).
* 기능: 등급 변경 이력 요약 (등급 관련 이력 건수 + 마스터 현행 등급 반환).
* 대상 액션: GRADE / GRADE_DEM (강등) / GRADE_ADJ. 입력: T_MERCHANT.
* 출력: T_COUNT=등급 변경 건수, T_STR1=현행 등급. RC: 1=가맹점 없음.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_GRADE_HIST.h"
void MM_GRADE_HIST(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64];
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_grade[8];
long h_cnt;
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 grade INTO :h_grade FROM mm_merchant_ext WHERE merchant_id = :h_merch;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_merch_hist
WHERE merchant_id = :h_merch AND action IN ('GRADE', 'GRADE_DEM', 'GRADE_ADJ');
if (sqlca.sqlcode < 0) FAIL(b);
Bchg(b, T_STR1, 0, h_grade, 0L);
setl(b, T_COUNT, h_cnt);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,41 @@
/*
* MM_MCC_ASSIGN.pgc - mm 모듈 서비스 MM_MCC_ASSIGN (one service = one file).
* 기능: 가맹점 업종(MCC) 재배정 (마스터에 등록된 MCC로만 변경, 변경 이력 기록).
* 입력: T_MERCHANT, T_STR1=신규 MCC. 출력: T_STR2=기존 MCC.
* RC: 0=배정, 1=가맹점 없음, 2=MCC 마스터 미등록, 4=동일 MCC.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_MCC_ASSIGN.h"
void MM_MCC_ASSIGN(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], mcc[8];
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_mcc[8], h_old[8];
long h_valid;
EXEC SQL END DECLARE SECTION;
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_STR1, mcc, sizeof(mcc));
if (mcc[0] == 0) { setl(b, T_RC, 3); OK(b); }
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
strncpy(h_mcc, mcc, sizeof(h_mcc)-1); h_mcc[sizeof(h_mcc)-1] = 0;
EXEC SQL SELECT mcc INTO :h_old FROM mm_merchant_ext WHERE merchant_id = :h_merch;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
Bchg(b, T_STR2, 0, h_old, 0L);
if (strcmp(h_old, h_mcc) == 0) { setl(b, T_RC, 4); OK(b); }
EXEC SQL SELECT count(*) INTO :h_valid FROM mm_mcc WHERE mcc = :h_mcc;
if (sqlca.sqlcode < 0) FAIL(b);
if (h_valid == 0) { setl(b, T_RC, 2); OK(b); }
EXEC SQL UPDATE mm_merchant_ext SET mcc = :h_mcc, updated_at = now()
WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0) FAIL(b);
if (mmdb_insert_merch_hist(h_merch, "MCC_ASSIGN", h_old, h_mcc, "업종코드 재배정") < 0) FAIL(b);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,34 @@
/*
* MM_MCC_CNT.pgc - mm 모듈 서비스 MM_MCC_CNT (one service = one file).
* 기능: 특정 MCC를 사용하는 가맹점 수 + 해당 MCC 리스크 등급 동시 반환.
* 입력: T_STR1=MCC. 출력: T_COUNT=사용 가맹점 수, T_ARG1=리스크 등급.
* RC: 0=조회, 1=MCC 마스터 미등록.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_MCC_CNT.h"
void MM_MCC_CNT(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char mcc[8];
EXEC SQL BEGIN DECLARE SECTION;
char h_mcc[8];
long h_risk, h_cnt;
EXEC SQL END DECLARE SECTION;
gets_(b, T_STR1, mcc, sizeof(mcc));
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 == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
EXEC SQL SELECT count(*) INTO :h_cnt FROM mm_merchant_ext
WHERE mcc = :h_mcc AND status <> 'DELETED';
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_cnt);
setl(b, T_ARG1, h_risk);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,37 @@
/*
* MM_MCC_DEL.pgc - mm 모듈 서비스 MM_MCC_DEL (one service = one file).
* 기능: MCC 업종코드 삭제 (참조하는 가맹점이 없을 때만 물리 삭제, 안전 삭제).
* 입력: T_STR1=MCC 코드. 출력: T_COUNT=참조 가맹점 수(삭제 실패 시 진단용).
* RC: 0=삭제, 1=MCC 없음, 4=참조 가맹점 존재로 삭제 불가.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_MCC_DEL.h"
void MM_MCC_DEL(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char mcc[8];
EXEC SQL BEGIN DECLARE SECTION;
char h_mcc[8];
long h_exist, h_ref;
EXEC SQL END DECLARE SECTION;
gets_(b, T_STR1, mcc, sizeof(mcc));
if (mcc[0] == 0) { setl(b, T_RC, 3); OK(b); }
strncpy(h_mcc, mcc, sizeof(h_mcc)-1); h_mcc[sizeof(h_mcc)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_exist FROM mm_mcc WHERE mcc = :h_mcc;
if (sqlca.sqlcode < 0) FAIL(b);
if (h_exist == 0) { setl(b, T_RC, 1); OK(b); }
EXEC SQL SELECT count(*) INTO :h_ref FROM mm_merchant_ext
WHERE mcc = :h_mcc AND status <> 'DELETED';
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_ref);
if (h_ref > 0) { setl(b, T_RC, 4); OK(b); }
EXEC SQL DELETE FROM mm_mcc WHERE mcc = :h_mcc;
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,35 @@
/*
* MM_MCC_RISKSET.pgc - mm 모듈 서비스 MM_MCC_RISKSET (one service = one file).
* 기능: MCC 리스크 등급 설정 (1~5 범위 검증 후 mm_mcc.risk_level 갱신).
* 입력: T_STR1=MCC, T_ARG1=리스크 등급(1~5). 출력: T_ARG2=이전 등급.
* RC: 0=변경, 1=MCC 없음, 3=등급 범위 오류.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_MCC_RISKSET.h"
void MM_MCC_RISKSET(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char mcc[8];
long lvl;
EXEC SQL BEGIN DECLARE SECTION;
char h_mcc[8];
long h_lvl, h_old;
EXEC SQL END DECLARE SECTION;
gets_(b, T_STR1, mcc, sizeof(mcc));
lvl = getl(b, T_ARG1);
if (lvl < 1 || lvl > 5) { setl(b, T_RC, 3); OK(b); }
h_lvl = lvl;
strncpy(h_mcc, mcc, sizeof(h_mcc)-1); h_mcc[sizeof(h_mcc)-1] = 0;
EXEC SQL SELECT risk_level INTO :h_old FROM mm_mcc WHERE mcc = :h_mcc;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
EXEC SQL UPDATE mm_mcc SET risk_level = :h_lvl WHERE mcc = :h_mcc;
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_ARG2, h_old);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,42 @@
/*
* MM_MERCH_DORMANT.pgc - mm 모듈 서비스 MM_MERCH_DORMANT (one service = one file).
* 기능: 장기 무거래 가맹점 휴면 전환 (ACTIVE->DORMANT, 최근 집계 매출 0 확인).
* 입력: T_MERCHANT, T_REASON=사유(기본 "장기 무거래 휴면"). 출력: T_GROSS=최근 누적 매출.
* RC: 0=휴면, 1=가맹점 없음, 2=활성 아님, 4=최근 매출 존재로 휴면 불가.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_MERCH_DORMANT.h"
void MM_MERCH_DORMANT(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], reason[128];
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_stat[16];
long h_gross;
EXEC SQL END DECLARE SECTION;
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_REASON, reason, sizeof(reason));
if (reason[0] == 0) strcpy(reason, "장기 무거래 휴면");
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
EXEC SQL SELECT status INTO :h_stat FROM mm_merchant_ext WHERE merchant_id = :h_merch;
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
if (strcmp(h_stat, "ACTIVE") != 0) { setl(b, T_RC, 2); OK(b); }
EXEC SQL SELECT coalesce(sum(gross_amount), 0) INTO :h_gross
FROM merchant_summary
WHERE merchant_id = :h_merch AND biz_date >= current_date - 90;
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_GROSS, h_gross);
if (h_gross > 0) { setl(b, T_RC, 4); OK(b); }
EXEC SQL UPDATE mm_merchant_ext SET status = 'DORMANT', updated_at = now()
WHERE merchant_id = :h_merch;
if (sqlca.sqlcode < 0) FAIL(b);
if (mmdb_insert_merch_hist(h_merch, "DORMANT", "ACTIVE", "DORMANT", reason) < 0) FAIL(b);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,27 @@
/*
* MM_PARTNER_LIST.pgc - mm 모듈 서비스 MM_PARTNER_LIST (one service = one file).
* 기능: 활성 제휴사 총수 조회 (PARTNER 코드그룹 중 ACTIVE 상태 집계).
* 출력: T_COUNT=활성 제휴사 수, T_ARG1=전체(상태 무관) 수.
* RC: 항상 0.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_PARTNER_LIST.h"
void MM_PARTNER_LIST(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
EXEC SQL BEGIN DECLARE SECTION;
long h_active, h_all;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT
count(*) FILTER (WHERE status = 'ACTIVE'), count(*)
INTO :h_active, :h_all
FROM mm_code WHERE code_group = 'PARTNER';
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_active);
setl(b, T_ARG1, h_all);
setl(b, T_RC, 0);
OK(b);
}

View file

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

View file

@ -0,0 +1,36 @@
/*
* MM_PARTNER_UPD.pgc - mm 모듈 서비스 MM_PARTNER_UPD (one service = one file).
* 기능: 제휴사 마스터 명칭/표시순서 변경 (PARTNER 코드그룹, 기존 건만 갱신).
* 입력: T_KEY1=제휴사 코드, T_STR1=신규 명칭, T_ARG1=신규 순서.
* RC: 0=변경, 1=제휴사 없음, 3=명칭 누락.
* caller의 XA 브랜치에서 실행(EXEC SQL CONNECT 없음); mm_svr가 tpadvertise 한다.
*/
#include "MM_PARTNER_UPD.h"
void MM_PARTNER_UPD(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char code[16], name[64];
EXEC SQL BEGIN DECLARE SECTION;
char h_code[16], h_name[64];
long h_sort, h_exist;
EXEC SQL END DECLARE SECTION;
gets_(b, T_KEY1, code, sizeof(code));
gets_(b, T_STR1, name, sizeof(name));
h_sort = getl(b, T_ARG1);
if (name[0] == 0) { setl(b, T_RC, 3); OK(b); }
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 SELECT count(*) INTO :h_exist FROM mm_code
WHERE code_group = 'PARTNER' AND code = :h_code;
if (sqlca.sqlcode < 0) FAIL(b);
if (h_exist == 0) { setl(b, T_RC, 1); OK(b); }
EXEC SQL UPDATE mm_code SET code_name = :h_name, sort_order = :h_sort
WHERE code_group = 'PARTNER' AND code = :h_code;
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_RC, 0);
OK(b);
}

View file

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

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