규모확장 Wave A: 전 11모듈 svc 30→75·batch 22→35 + 전 모듈 운영데이터 시드
- svc 330→825 (모듈당 +45 고유 실업무: chargeback·재매입·심사워크플로·전문유형별· 대사세분·정산시뮬·지급재처리·복식결산·마감워크플로·마스터심사·검증룰·전문라우팅 등) - batch 242→385 (모듈당 +13), 카피북 헤더·디스패처 advertise 전 75 반영 - db/schema.d/95-module-seed.sql: 전 모듈 테이블 운영데이터(au 8.4k·st 15.9k·mg 16.9k· lg 14.6k·rc 7.7k·py 2.9k·vl 8.5k·cm 10.4k 등, 총 ~171k행) — base 거래와 정합 - 화면 매니페스트 825 재생성, 큐 메모리 튜닝(NDRX_MSGMAX 50→30) - 검증: build DONE modules=11 batches=385, 12서버 runok, xadmin psc 828 AVAIL, 매입체인 XA 커밋(status=S), 새서비스 시드데이터 스모크(ACQ_MERCHSUM/RC_STATS 실값), 전 코퍼스 .pgc 클론 0, 헤드리스 스크린샷 확인 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
19acf4ed96
commit
ea90bef264
1292 changed files with 53968 additions and 20 deletions
|
|
@ -50,6 +50,51 @@
|
|||
#include "ACQ_RELEASE.h"
|
||||
#include "ACQ_VOID.h"
|
||||
#include "ACQ_REFUND.h"
|
||||
#include "ACQ_CB_OPEN.h"
|
||||
#include "ACQ_CB_QRY.h"
|
||||
#include "ACQ_CB_DEFEND.h"
|
||||
#include "ACQ_CB_STAT.h"
|
||||
#include "ACQ_REBUY.h"
|
||||
#include "ACQ_PARTCXL.h"
|
||||
#include "ACQ_PARTRFND.h"
|
||||
#include "ACQ_SPLITPAY.h"
|
||||
#include "ACQ_SPLITQRY.h"
|
||||
#include "ACQ_CCYSUM.h"
|
||||
#include "ACQ_FXRATE.h"
|
||||
#include "ACQ_CTRYSUM.h"
|
||||
#include "ACQ_FEERECALC.h"
|
||||
#include "ACQ_FEEWAIVE.h"
|
||||
#include "ACQ_FEEHIST.h"
|
||||
#include "ACQ_CLAIMREG.h"
|
||||
#include "ACQ_CLAIMPROC.h"
|
||||
#include "ACQ_CLAIMQRY.h"
|
||||
#include "ACQ_CORRHIST.h"
|
||||
#include "ACQ_TAXREISSUE.h"
|
||||
#include "ACQ_TAXCXL.h"
|
||||
#include "ACQ_RETURN.h"
|
||||
#include "ACQ_REMATCH.h"
|
||||
#include "ACQ_BULKVERIFY.h"
|
||||
#include "ACQ_LIMITUSAGE.h"
|
||||
#include "ACQ_RESERVE.h"
|
||||
#include "ACQ_RESERVECXL.h"
|
||||
#include "ACQ_RESERVEQRY.h"
|
||||
#include "ACQ_PROMO.h"
|
||||
#include "ACQ_NOINTSHARE.h"
|
||||
#include "ACQ_DAYSTAT.h"
|
||||
#include "ACQ_WEEKSTAT.h"
|
||||
#include "ACQ_MONSTAT.h"
|
||||
#include "ACQ_CHANSTAT.h"
|
||||
#include "ACQ_ISSSTAT.h"
|
||||
#include "ACQ_ALERTCHK.h"
|
||||
#include "ACQ_EDIRESEND.h"
|
||||
#include "ACQ_SETTLEDUE.h"
|
||||
#include "ACQ_HOLDQRY.h"
|
||||
#include "ACQ_DUPSCAN.h"
|
||||
#include "ACQ_VELOCITY.h"
|
||||
#include "ACQ_TOPMERCH.h"
|
||||
#include "ACQ_NETCALC.h"
|
||||
#include "ACQ_APPRGAP.h"
|
||||
#include "ACQ_FXCONVERT.h"
|
||||
|
||||
/* ----- advertise table: {service name, function} (fn is extern from its file) */
|
||||
static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
|
||||
|
|
@ -68,6 +113,29 @@ static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
|
|||
{"ACQ_APPRMAP", ACQ_APPRMAP}, {"ACQ_SETTLELINK", ACQ_SETTLELINK},
|
||||
{"ACQ_HOLD", ACQ_HOLD}, {"ACQ_RELEASE", ACQ_RELEASE},
|
||||
{"ACQ_VOID", ACQ_VOID}, {"ACQ_REFUND", ACQ_REFUND},
|
||||
{"ACQ_CB_OPEN", ACQ_CB_OPEN}, {"ACQ_CB_QRY", ACQ_CB_QRY},
|
||||
{"ACQ_CB_DEFEND", ACQ_CB_DEFEND},{"ACQ_CB_STAT", ACQ_CB_STAT},
|
||||
{"ACQ_REBUY", ACQ_REBUY}, {"ACQ_PARTCXL", ACQ_PARTCXL},
|
||||
{"ACQ_PARTRFND", ACQ_PARTRFND}, {"ACQ_SPLITPAY", ACQ_SPLITPAY},
|
||||
{"ACQ_SPLITQRY", ACQ_SPLITQRY}, {"ACQ_CCYSUM", ACQ_CCYSUM},
|
||||
{"ACQ_FXRATE", ACQ_FXRATE}, {"ACQ_CTRYSUM", ACQ_CTRYSUM},
|
||||
{"ACQ_FEERECALC", ACQ_FEERECALC},{"ACQ_FEEWAIVE", ACQ_FEEWAIVE},
|
||||
{"ACQ_FEEHIST", ACQ_FEEHIST}, {"ACQ_CLAIMREG", ACQ_CLAIMREG},
|
||||
{"ACQ_CLAIMPROC", ACQ_CLAIMPROC},{"ACQ_CLAIMQRY", ACQ_CLAIMQRY},
|
||||
{"ACQ_CORRHIST", ACQ_CORRHIST}, {"ACQ_TAXREISSUE", ACQ_TAXREISSUE},
|
||||
{"ACQ_TAXCXL", ACQ_TAXCXL}, {"ACQ_RETURN", ACQ_RETURN},
|
||||
{"ACQ_REMATCH", ACQ_REMATCH}, {"ACQ_BULKVERIFY", ACQ_BULKVERIFY},
|
||||
{"ACQ_LIMITUSAGE", ACQ_LIMITUSAGE},{"ACQ_RESERVE", ACQ_RESERVE},
|
||||
{"ACQ_RESERVECXL", ACQ_RESERVECXL},{"ACQ_RESERVEQRY", ACQ_RESERVEQRY},
|
||||
{"ACQ_PROMO", ACQ_PROMO}, {"ACQ_NOINTSHARE", ACQ_NOINTSHARE},
|
||||
{"ACQ_DAYSTAT", ACQ_DAYSTAT}, {"ACQ_WEEKSTAT", ACQ_WEEKSTAT},
|
||||
{"ACQ_MONSTAT", ACQ_MONSTAT}, {"ACQ_CHANSTAT", ACQ_CHANSTAT},
|
||||
{"ACQ_ISSSTAT", ACQ_ISSSTAT}, {"ACQ_ALERTCHK", ACQ_ALERTCHK},
|
||||
{"ACQ_EDIRESEND", ACQ_EDIRESEND},{"ACQ_SETTLEDUE", ACQ_SETTLEDUE},
|
||||
{"ACQ_HOLDQRY", ACQ_HOLDQRY}, {"ACQ_DUPSCAN", ACQ_DUPSCAN},
|
||||
{"ACQ_VELOCITY", ACQ_VELOCITY}, {"ACQ_TOPMERCH", ACQ_TOPMERCH},
|
||||
{"ACQ_NETCALC", ACQ_NETCALC}, {"ACQ_APPRGAP", ACQ_APPRGAP},
|
||||
{"ACQ_FXCONVERT", ACQ_FXCONVERT},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
|||
57
app/src/ac/batch/ac_alert_batch.pgc
Normal file
57
app/src/ac/batch/ac_alert_batch.pgc
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* ac_alert_batch.pgc - ac 고액매입 경보 스캔 배치 (임계 커서, XA).
|
||||
*
|
||||
* ATMI client: 인자로 받은 임계금액(기본 500만원) 이상의 영업일 매입을
|
||||
* 개별 라인으로 뿜어내고, 경보 건수·최고액을 요약한다. 임계는 두 번째
|
||||
* 인자로 조정 가능해 운영 중 재기동 없이 스캔 수위를 바꾼다.
|
||||
* Usage: ac_alert_batch [YYYY-MM-DD] [임계금액]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "ac_alert_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ac_alert_ctx_t cx;
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_merch[64];
|
||||
long h_thr, h_pid, h_amt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
memset(&cx, 0, sizeof(cx));
|
||||
cx.threshold = (argc > 2) ? atol(argv[2]) : 5000000L;
|
||||
if (cx.threshold <= 0) cx.threshold = 5000000L;
|
||||
h_thr = cx.threshold;
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE alb_cur CURSOR FOR
|
||||
SELECT purchase_id, merchant_id, amount FROM purchase
|
||||
WHERE biz_date = :h_bizdate AND amount >= :h_thr AND status NOT IN ('C', 'V')
|
||||
ORDER BY amount DESC;
|
||||
EXEC SQL OPEN alb_cur;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "open FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH alb_cur INTO :h_pid, :h_merch, :h_amt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE alb_cur; fprintf(stderr, "fetch FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
cx.alerts++;
|
||||
if (h_amt > cx.peak) cx.peak = h_amt;
|
||||
printf(" ALERT pid=%ld merchant=%s amount=%ld\n", h_pid, h_merch, h_amt);
|
||||
}
|
||||
EXEC SQL CLOSE alb_cur;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> ac_alert_batch COMMIT: bizdate=%s thr=%ld alerts=%ld peak=%ld\n",
|
||||
bizdate, cx.threshold, cx.alerts, cx.peak);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
62
app/src/ac/batch/ac_apprgap_batch.pgc
Normal file
62
app/src/ac/batch/ac_apprgap_batch.pgc
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* ac_apprgap_batch.pgc - ac 승인-매입 갭 양방향 대사 배치 (2단 점검, XA).
|
||||
*
|
||||
* ATMI client: 승인 없는 매입 금액과 매입 없는 고아 승인 건수를 양방향으로
|
||||
* 재고, 거절(approved=false) 승인이 달린 매입 수까지 3개 지표를 산출한다.
|
||||
* 갭이 있으면 종료코드 2.
|
||||
* Usage: ac_apprgap_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "ac_apprgap_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ac_apprgap_ctx_t cx;
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_noap = 0, h_noamt = 0, h_orphan = 0, h_denied = 0;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
memset(&cx, 0, sizeof(cx));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(90, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
/* (1) 승인 없는 매입: 건수 + 금액 */
|
||||
EXEC SQL SELECT count(*), coalesce(sum(u.amount), 0)
|
||||
INTO :h_noap, :h_noamt
|
||||
FROM purchase u
|
||||
WHERE u.biz_date = :h_bizdate AND u.status NOT IN ('C', 'V', 'P')
|
||||
AND NOT EXISTS (SELECT 1 FROM approval a
|
||||
WHERE a.purchase_id = u.purchase_id AND a.approved = true);
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "noappr FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
|
||||
/* (2) 매입 없는 고아 승인 */
|
||||
EXEC SQL SELECT count(*) INTO :h_orphan
|
||||
FROM approval a LEFT JOIN purchase u ON u.purchase_id = a.purchase_id
|
||||
WHERE u.purchase_id IS NULL;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "orphan FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
|
||||
/* (3) 거절 승인이 달린 영업일 매입 */
|
||||
EXEC SQL SELECT count(DISTINCT u.purchase_id) INTO :h_denied
|
||||
FROM purchase u JOIN approval a ON a.purchase_id = u.purchase_id
|
||||
WHERE u.biz_date = :h_bizdate AND a.approved = false;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "ac_apprgap_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
cx.no_approval = h_noap; cx.no_appr_amt = h_noamt;
|
||||
cx.orphan_appr = h_orphan; cx.denied = h_denied;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> ac_apprgap_batch COMMIT: bizdate=%s no_appr=%ld(%ld) orphan=%ld denied=%ld\n",
|
||||
bizdate, cx.no_approval, cx.no_appr_amt, cx.orphan_appr, cx.denied);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return (cx.no_approval + cx.orphan_appr) > 0 ? 2 : 0;
|
||||
}
|
||||
59
app/src/ac/batch/ac_cbaging_batch.pgc
Normal file
59
app/src/ac/batch/ac_cbaging_batch.pgc
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* ac_cbaging_batch.pgc - ac 지불거절 경과일 aging 배치 (버킷 집계, XA).
|
||||
*
|
||||
* ATMI client: 한 글로벌 트랜잭션 안에서 CB 접수 건을 등록 경과일 기준
|
||||
* 3개 버킷(7일 미만/7~30일/30일 초과)으로 나눠 세고, 방어되지 않은 장기
|
||||
* 미제 건수를 함께 보고한다. tpcommit 이 XA 2PC 를 마무리한다.
|
||||
* Usage: ac_cbaging_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "ac_cbaging_batch.h"
|
||||
|
||||
/* 경과일을 aging 버킷 인덱스로 변환 */
|
||||
int acb_cb_bucket(long age_days)
|
||||
{
|
||||
if (age_days < 7) return 0;
|
||||
if (age_days <= 30) return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ac_cbaging_ctx_t cx;
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_fresh = 0, h_mid = 0, h_stale = 0, h_open = 0;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
memset(&cx, 0, sizeof(cx));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
strncpy(cx.base_date, bizdate, sizeof(cx.base_date)-1);
|
||||
|
||||
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(*) FILTER (WHERE CAST(:h_bizdate AS date) - biz_date < 7),
|
||||
count(*) FILTER (WHERE CAST(:h_bizdate AS date) - biz_date BETWEEN 7 AND 30),
|
||||
count(*) FILTER (WHERE CAST(:h_bizdate AS date) - biz_date > 30),
|
||||
count(*) FILTER (WHERE reason NOT LIKE 'DEFEND:%')
|
||||
INTO :h_fresh, :h_mid, :h_stale, :h_open
|
||||
FROM ac_cancel WHERE cancel_type = 'CB';
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "ac_cbaging_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
cx.fresh = h_fresh; cx.mid = h_mid; cx.stale = h_stale; cx.undefended = h_open;
|
||||
(void)acb_cb_bucket(31);
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> ac_cbaging_batch COMMIT: base=%s fresh=%ld mid=%ld stale=%ld undefended=%ld\n",
|
||||
cx.base_date, cx.fresh, cx.mid, cx.stale, cx.undefended);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
53
app/src/ac/batch/ac_ccysum_batch.pgc
Normal file
53
app/src/ac/batch/ac_ccysum_batch.pgc
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* ac_ccysum_batch.pgc - ac 통화별 해외매입 집계 배치 (통화 커서, XA).
|
||||
*
|
||||
* ATMI client: 영업일 해외매입 원장을 통화별로 그룹 집계해 통화마다
|
||||
* 건수/원통화합계/원화환산합계/평균환율을 한 줄씩 출력한다.
|
||||
* Usage: ac_ccysum_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "ac_ccysum_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ac_ccysum_ctx_t cx;
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_ccy[8];
|
||||
long h_n, h_fx, h_krw, h_rate;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
memset(&cx, 0, sizeof(cx));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE ccb_cur CURSOR FOR
|
||||
SELECT ccy, count(*), sum(fx_amount), sum(krw_amount), avg(rate_bps)::bigint
|
||||
FROM ac_fx WHERE biz_date = :h_bizdate
|
||||
GROUP BY ccy ORDER BY sum(krw_amount) DESC;
|
||||
EXEC SQL OPEN ccb_cur;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "open FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH ccb_cur INTO :h_ccy, :h_n, :h_fx, :h_krw, :h_rate;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE ccb_cur; fprintf(stderr, "fetch FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
printf(" ccy=%-4s n=%ld fx=%ld krw=%ld avg_rate=%ld\n", h_ccy, h_n, h_fx, h_krw, h_rate);
|
||||
cx.ccy_kinds++;
|
||||
cx.krw_total += h_krw;
|
||||
}
|
||||
EXEC SQL CLOSE ccb_cur;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> ac_ccysum_batch COMMIT: bizdate=%s ccy_kinds=%ld krw_total=%ld\n",
|
||||
bizdate, cx.ccy_kinds, cx.krw_total);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
52
app/src/ac/batch/ac_claimsweep_batch.pgc
Normal file
52
app/src/ac/batch/ac_claimsweep_batch.pgc
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* ac_claimsweep_batch.pgc - ac 장기 미제 클레임 정리 배치 (DELETE, XA).
|
||||
*
|
||||
* ATMI client: 기준일로부터 30일이 지난 미종결 클레임 행을 미매입 원장에서
|
||||
* 일괄 삭제(자동 종결)한다. 삭제 전 대상 건수를 세어 대조 출력한다.
|
||||
* Usage: ac_claimsweep_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "ac_claimsweep_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ac_claimsweep_ctx_t cx;
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_target = 0, h_deleted;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
memset(&cx, 0, sizeof(cx));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
/* 삭제 대상 사전 계수 (대조용) */
|
||||
EXEC SQL SELECT count(*) INTO :h_target FROM ac_unmatch
|
||||
WHERE reason LIKE 'CLAIM:%' AND biz_date < CAST(:h_bizdate AS date) - 30;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "count FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
|
||||
EXEC SQL DELETE FROM ac_unmatch
|
||||
WHERE reason LIKE 'CLAIM:%' AND biz_date < CAST(:h_bizdate AS date) - 30;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "ac_claimsweep_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
h_deleted = sqlca.sqlerrd[2];
|
||||
|
||||
cx.target = h_target; cx.deleted = h_deleted;
|
||||
if (cx.target != cx.deleted) {
|
||||
fprintf(stderr, "ac_claimsweep_batch MISMATCH target=%ld deleted=%ld\n", cx.target, cx.deleted);
|
||||
tpabort(0); return 1;
|
||||
}
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> ac_claimsweep_batch COMMIT: base=%s swept=%ld\n", bizdate, cx.deleted);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
48
app/src/ac/batch/ac_feewaive_batch.pgc
Normal file
48
app/src/ac/batch/ac_feewaive_batch.pgc
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* ac_feewaive_batch.pgc - ac 수수료 감면 총액 일 집계 배치 (사유별 분해, XA).
|
||||
*
|
||||
* ATMI client: 영업일의 음수 수수료 조정(감면)을 감면(WAIVE)/무이자 분담
|
||||
* (NOINT)/기타 사유로 분해 집계한다. 감면 총액은 부호를 뒤집어 보고한다.
|
||||
* Usage: ac_feewaive_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "ac_feewaive_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ac_feewaive_ctx_t cx;
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_waive = 0, h_noint = 0, h_etc = 0, h_rows = 0;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
memset(&cx, 0, sizeof(cx));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL SELECT
|
||||
coalesce(-sum(delta) FILTER (WHERE reason = 'WAIVE'), 0),
|
||||
coalesce(-sum(delta) FILTER (WHERE reason = 'NOINT'), 0),
|
||||
coalesce(-sum(delta) FILTER (WHERE reason NOT IN ('WAIVE', 'NOINT')), 0),
|
||||
count(*)
|
||||
INTO :h_waive, :h_noint, :h_etc, :h_rows
|
||||
FROM ac_fee_adj WHERE biz_date = :h_bizdate AND delta < 0;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "ac_feewaive_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
cx.waive_sum = h_waive; cx.noint_sum = h_noint; cx.etc_sum = h_etc; cx.rows = h_rows;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> ac_feewaive_batch COMMIT: bizdate=%s rows=%ld waive=%ld noint=%ld etc=%ld\n",
|
||||
bizdate, cx.rows, cx.waive_sum, cx.noint_sum, cx.etc_sum);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
68
app/src/ac/batch/ac_limitwatch_batch.pgc
Normal file
68
app/src/ac/batch/ac_limitwatch_batch.pgc
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* ac_limitwatch_batch.pgc - ac 가맹점 한도 임박 감시 배치 (조인 커서, XA).
|
||||
*
|
||||
* ATMI client: 영업일 사용액을 가맹점 일한도와 조인 집계해 소진율 90%
|
||||
* (9000bps)를 넘긴 가맹점을 골라 경고 라인을 출력한다. C 헬퍼가 소진율을
|
||||
* bps 로 환산한다.
|
||||
* Usage: ac_limitwatch_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "ac_limitwatch_batch.h"
|
||||
|
||||
/* 소진율 bps 계산 (한도 0 이면 만점 처리) */
|
||||
long acb_usage_bps(long used, long limit)
|
||||
{
|
||||
if (limit <= 0) return 10000L;
|
||||
return (used * 10000L) / limit;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ac_limitwatch_ctx_t cx;
|
||||
long bps;
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_merch[64];
|
||||
long h_used, h_limit;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
memset(&cx, 0, sizeof(cx));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE lwb_cur CURSOR FOR
|
||||
SELECT m.merchant_id, coalesce(sum(u.amount), 0), m.daily_limit
|
||||
FROM merchant m JOIN purchase u
|
||||
ON u.merchant_id = m.merchant_id AND u.biz_date = :h_bizdate
|
||||
AND u.status NOT IN ('C', 'V')
|
||||
GROUP BY m.merchant_id, m.daily_limit;
|
||||
EXEC SQL OPEN lwb_cur;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "open FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH lwb_cur INTO :h_merch, :h_used, :h_limit;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE lwb_cur; fprintf(stderr, "fetch FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
cx.scanned++;
|
||||
bps = acb_usage_bps(h_used, h_limit);
|
||||
if (bps > 9000L) {
|
||||
cx.warned++;
|
||||
printf(" ** 한도 임박 merchant=%s used=%ld limit=%ld usage=%ld bps\n",
|
||||
h_merch, h_used, h_limit, bps);
|
||||
}
|
||||
}
|
||||
EXEC SQL CLOSE lwb_cur;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> ac_limitwatch_batch COMMIT: bizdate=%s scanned=%ld warned=%ld\n",
|
||||
bizdate, cx.scanned, cx.warned);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
54
app/src/ac/batch/ac_promo_batch.pgc
Normal file
54
app/src/ac/batch/ac_promo_batch.pgc
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* ac_promo_batch.pgc - ac 프로모션 매입 집계 배치 (분류 집계 + 원장 대조, XA).
|
||||
*
|
||||
* ATMI client: 영업일 프로모션 분류(PROMO) 매입의 건수/총액과 면제 수수료
|
||||
* 추정액(가맹점 MDR 기준)을 집계하고, PROMO 원장 분개 합계와 대조한다.
|
||||
* Usage: ac_promo_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "ac_promo_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ac_promo_ctx_t cx;
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_n = 0, h_amt = 0, h_freefee = 0, h_ledger = 0;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
memset(&cx, 0, sizeof(cx));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
/* 프로모션 매입 + 면제 수수료 추정(MDR 재적용) */
|
||||
EXEC SQL SELECT count(*), coalesce(sum(u.amount), 0),
|
||||
coalesce(sum(u.amount * m.mdr_bps / 10000), 0)
|
||||
INTO :h_n, :h_amt, :h_freefee
|
||||
FROM purchase u JOIN merchant m ON m.merchant_id = u.merchant_id
|
||||
WHERE u.biz_date = :h_bizdate AND u.category = 'PROMO' AND u.status <> 'C';
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "promo agg FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
|
||||
/* PROMO 원장 분개 합계 대조 */
|
||||
EXEC SQL SELECT coalesce(sum(amount), 0) INTO :h_ledger
|
||||
FROM ledger WHERE entry_type = 'PROMO' AND biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "ac_promo_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
cx.promo_count = h_n; cx.promo_amount = h_amt;
|
||||
cx.waived_fee = h_freefee; cx.ledger_sum = h_ledger;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> ac_promo_batch COMMIT: bizdate=%s n=%ld amt=%ld waived_fee=%ld ledger=%ld %s\n",
|
||||
bizdate, cx.promo_count, cx.promo_amount, cx.waived_fee, cx.ledger_sum,
|
||||
cx.promo_amount == cx.ledger_sum ? "(대조 일치)" : "(대조 불일치)");
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
48
app/src/ac/batch/ac_reservepost_batch.pgc
Normal file
48
app/src/ac/batch/ac_reservepost_batch.pgc
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* ac_reservepost_batch.pgc - ac 매입 예약 전환 배치 (상태 전이, XA).
|
||||
*
|
||||
* ATMI client: 예약일이 도래한 예약(P) 매입을 접수(A)로 일괄 전환하고,
|
||||
* 전환 후에도 남은 미래 예약 건수를 세어 함께 보고한다.
|
||||
* Usage: ac_reservepost_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "ac_reservepost_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ac_reservepost_ctx_t cx;
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_left = 0;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
memset(&cx, 0, sizeof(cx));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
/* 예약일 도래 건 전환: P → A */
|
||||
EXEC SQL UPDATE purchase SET status = 'A', updated_at = now()
|
||||
WHERE status = 'P' AND biz_date <= CAST(:h_bizdate AS date);
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "ac_reservepost_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
cx.posted = sqlca.sqlerrd[2];
|
||||
|
||||
/* 미래 예약 잔량 */
|
||||
EXEC SQL SELECT count(*) INTO :h_left FROM purchase WHERE status = 'P';
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "left FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
cx.remaining = h_left;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> ac_reservepost_batch COMMIT: base=%s posted=%ld remaining=%ld\n",
|
||||
bizdate, cx.posted, cx.remaining);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
56
app/src/ac/batch/ac_settledue_batch.pgc
Normal file
56
app/src/ac/batch/ac_settledue_batch.pgc
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* ac_settledue_batch.pgc - ac 정산예정 대기열 집계 배치 (NOT EXISTS, XA).
|
||||
*
|
||||
* ATMI client: 대사완료(M) 상태이나 정산행이 아직 없는 매입을 가맹점별로
|
||||
* 묶어 정산예정액을 산출한다. 가맹점별 라인 출력 후 전체 합계로 마감.
|
||||
* Usage: ac_settledue_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "ac_settledue_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ac_settledue_ctx_t cx;
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_merch[64];
|
||||
long h_n, h_net;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
memset(&cx, 0, sizeof(cx));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(90, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE sdb_cur CURSOR FOR
|
||||
SELECT u.merchant_id, count(*), sum(u.net)
|
||||
FROM purchase u
|
||||
WHERE u.biz_date = :h_bizdate AND u.status = 'M'
|
||||
AND NOT EXISTS (SELECT 1 FROM settlement s WHERE s.purchase_id = u.purchase_id)
|
||||
GROUP BY u.merchant_id ORDER BY u.merchant_id;
|
||||
EXEC SQL OPEN sdb_cur;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "open FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH sdb_cur INTO :h_merch, :h_n, :h_net;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE sdb_cur; fprintf(stderr, "fetch FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
printf(" merchant=%s due_n=%ld due_net=%ld\n", h_merch, h_n, h_net);
|
||||
cx.merchants++;
|
||||
cx.due_count += h_n;
|
||||
cx.due_net += h_net;
|
||||
}
|
||||
EXEC SQL CLOSE sdb_cur;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> ac_settledue_batch COMMIT: bizdate=%s merchants=%ld due_n=%ld due_net=%ld\n",
|
||||
bizdate, cx.merchants, cx.due_count, cx.due_net);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
58
app/src/ac/batch/ac_splitpay_batch.pgc
Normal file
58
app/src/ac/batch/ac_splitpay_batch.pgc
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* ac_splitpay_batch.pgc - ac 분할납부 스케줄 정합 배치 (그룹 커서, XA).
|
||||
*
|
||||
* ATMI client: 영업일에 등록된 분할납부 스케줄을 매입 단위로 그룹 커서
|
||||
* 순회하며 스케줄 합계와 매입 원금의 불일치 건을 찾아낸다. 불일치가
|
||||
* 하나라도 있으면 종료코드 2 로 마감 라인에 신호를 준다.
|
||||
* Usage: ac_splitpay_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "ac_splitpay_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ac_splitpay_ctx_t cx;
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_pid, h_sched, h_orig;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
memset(&cx, 0, sizeof(cx));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(120, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE spb_cur CURSOR FOR
|
||||
SELECT i.purchase_id, sum(i.month_amount), max(u.amount)
|
||||
FROM ac_install i JOIN purchase u ON u.purchase_id = i.purchase_id
|
||||
WHERE i.biz_date = :h_bizdate
|
||||
GROUP BY i.purchase_id;
|
||||
EXEC SQL OPEN spb_cur;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "open FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH spb_cur INTO :h_pid, :h_sched, :h_orig;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE spb_cur; fprintf(stderr, "fetch FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
cx.plans++;
|
||||
cx.sched_total += h_sched;
|
||||
if (h_sched != h_orig) {
|
||||
cx.mismatch++;
|
||||
printf(" !! 스케줄 불일치 pid=%ld sched=%ld orig=%ld\n", h_pid, h_sched, h_orig);
|
||||
}
|
||||
}
|
||||
EXEC SQL CLOSE spb_cur;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> ac_splitpay_batch COMMIT: bizdate=%s plans=%ld sched_total=%ld mismatch=%ld\n",
|
||||
bizdate, cx.plans, cx.sched_total, cx.mismatch);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return cx.mismatch > 0 ? 2 : 0;
|
||||
}
|
||||
53
app/src/ac/batch/ac_taxneg_batch.pgc
Normal file
53
app/src/ac/batch/ac_taxneg_batch.pgc
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* ac_taxneg_batch.pgc - ac 세금계산서 상쇄 검증 배치 (부호 검증, XA).
|
||||
*
|
||||
* ATMI client: 영업일의 음수(취소) 세금계산서를 검사한다. 음수 계산서의
|
||||
* 부가세가 공급가의 10% 상쇄와 어긋난 건, 그리고 매입별 계산서 잔액이
|
||||
* 음수로 뒤집힌(과상쇄) 매입 수를 찾아 보고한다.
|
||||
* Usage: ac_taxneg_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "ac_taxneg_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ac_taxneg_ctx_t cx;
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_neg = 0, h_badvat = 0, h_over = 0;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
memset(&cx, 0, sizeof(cx));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
/* 음수 계산서 건수 + 부가세 상쇄식 위반 건수 */
|
||||
EXEC SQL SELECT count(*),
|
||||
count(*) FILTER (WHERE vat <> supply / 10)
|
||||
INTO :h_neg, :h_badvat
|
||||
FROM ac_tax_invoice WHERE biz_date = :h_bizdate AND supply < 0;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "neg scan FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
|
||||
/* 과상쇄: 매입별 공급가 잔액이 음수인 매입 수 */
|
||||
EXEC SQL SELECT count(*) INTO :h_over
|
||||
FROM (SELECT purchase_id FROM ac_tax_invoice
|
||||
GROUP BY purchase_id HAVING sum(supply) < 0) o;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "ac_taxneg_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
cx.neg_rows = h_neg; cx.bad_vat = h_badvat; cx.over_offset = h_over;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> ac_taxneg_batch COMMIT: bizdate=%s neg=%ld bad_vat=%ld over_offset=%ld\n",
|
||||
bizdate, cx.neg_rows, cx.bad_vat, cx.over_offset);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return (cx.bad_vat + cx.over_offset) > 0 ? 2 : 0;
|
||||
}
|
||||
61
app/src/ac/batch/ac_weekroll_batch.pgc
Normal file
61
app/src/ac/batch/ac_weekroll_batch.pgc
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* ac_weekroll_batch.pgc - ac 주간 가맹점 집계 롤업 배치 (INSERT..SELECT, XA).
|
||||
*
|
||||
* ATMI client: 기준일 포함 직전 7일 매입을 가맹점별로 롤업해 기준일 키의
|
||||
* merchant_summary 로 밀어넣는다(ON CONFLICT 갱신). 반영 행수와 주간
|
||||
* 총액을 되읽어 보고한다.
|
||||
* Usage: ac_weekroll_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "ac_weekroll_batch.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
ac_weekroll_ctx_t cx;
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_gross = 0;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
memset(&cx, 0, sizeof(cx));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(120, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
/* 주간 롤업: 직전 7일 → 기준일 키 upsert */
|
||||
EXEC SQL INSERT INTO merchant_summary (merchant_id, biz_date, txn_count, gross_amount, fee_amount, net_amount, updated_at)
|
||||
SELECT merchant_id, CAST(:h_bizdate AS date), count(*), sum(amount), sum(fee), sum(net), now()
|
||||
FROM purchase
|
||||
WHERE biz_date > CAST(:h_bizdate AS date) - 7
|
||||
AND biz_date <= CAST(:h_bizdate AS date)
|
||||
AND status NOT IN ('C', 'V', 'P')
|
||||
GROUP BY merchant_id
|
||||
ON CONFLICT (merchant_id, biz_date) DO UPDATE
|
||||
SET txn_count = EXCLUDED.txn_count,
|
||||
gross_amount = EXCLUDED.gross_amount,
|
||||
fee_amount = EXCLUDED.fee_amount,
|
||||
net_amount = EXCLUDED.net_amount,
|
||||
updated_at = now();
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "ac_weekroll_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
cx.rolled = sqlca.sqlerrd[2];
|
||||
|
||||
/* 반영 결과 되읽기 */
|
||||
EXEC SQL SELECT coalesce(sum(gross_amount), 0) INTO :h_gross
|
||||
FROM merchant_summary WHERE biz_date = CAST(:h_bizdate AS date);
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "readback FAIL [%d]\n", sqlca.sqlcode); tpabort(0); return 1; }
|
||||
cx.week_gross = h_gross;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> ac_weekroll_batch COMMIT: base=%s rolled=%ld week_gross=%ld\n",
|
||||
bizdate, cx.rolled, cx.week_gross);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
14
app/src/ac/dbio/ac_alert_batch.h
Normal file
14
app/src/ac/dbio/ac_alert_batch.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* ac_alert_batch.h - copybook for ac_alert_batch (XA client).
|
||||
* 고액매입 경보 스캔 구조체. Kept in dbio/ for -I resolution.
|
||||
*/
|
||||
#ifndef AC_ALERT_BATCH_H
|
||||
#define AC_ALERT_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
long threshold; /* 고액 임계금액 */
|
||||
long alerts; /* 경보 건수 */
|
||||
long peak; /* 최고 금액 */
|
||||
} ac_alert_ctx_t;
|
||||
|
||||
#endif /* AC_ALERT_BATCH_H */
|
||||
15
app/src/ac/dbio/ac_apprgap_batch.h
Normal file
15
app/src/ac/dbio/ac_apprgap_batch.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* ac_apprgap_batch.h - copybook for ac_apprgap_batch (XA client).
|
||||
* 승인-매입 갭 양방향 대사 구조체. Kept in dbio/ for -I resolution.
|
||||
*/
|
||||
#ifndef AC_APPRGAP_BATCH_H
|
||||
#define AC_APPRGAP_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
long no_approval; /* 승인 없는 매입 건수 */
|
||||
long no_appr_amt; /* 그 금액 */
|
||||
long orphan_appr; /* 매입 없는 승인 */
|
||||
long denied; /* 거절 승인 달린 매입 */
|
||||
} ac_apprgap_ctx_t;
|
||||
|
||||
#endif /* AC_APPRGAP_BATCH_H */
|
||||
18
app/src/ac/dbio/ac_cbaging_batch.h
Normal file
18
app/src/ac/dbio/ac_cbaging_batch.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* ac_cbaging_batch.h - copybook for ac_cbaging_batch (XA client).
|
||||
* 지불거절 aging 버킷 구조체 + 버킷 분류 헬퍼. Kept in dbio/ for -I resolution.
|
||||
*/
|
||||
#ifndef AC_CBAGING_BATCH_H
|
||||
#define AC_CBAGING_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
char base_date[16];
|
||||
long fresh; /* 경과 7일 미만 */
|
||||
long mid; /* 7~30일 */
|
||||
long stale; /* 30일 초과 */
|
||||
long undefended; /* 방어 미착수 건수 */
|
||||
} ac_cbaging_ctx_t;
|
||||
|
||||
int acb_cb_bucket(long age_days); /* 0=fresh, 1=mid, 2=stale */
|
||||
|
||||
#endif /* AC_CBAGING_BATCH_H */
|
||||
13
app/src/ac/dbio/ac_ccysum_batch.h
Normal file
13
app/src/ac/dbio/ac_ccysum_batch.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* ac_ccysum_batch.h - copybook for ac_ccysum_batch (XA client).
|
||||
* 통화별 해외매입 집계 구조체. Kept in dbio/ for -I resolution.
|
||||
*/
|
||||
#ifndef AC_CCYSUM_BATCH_H
|
||||
#define AC_CCYSUM_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
long ccy_kinds; /* 통화 종수 */
|
||||
long krw_total; /* 원화 환산 총액 */
|
||||
} ac_ccysum_ctx_t;
|
||||
|
||||
#endif /* AC_CCYSUM_BATCH_H */
|
||||
13
app/src/ac/dbio/ac_claimsweep_batch.h
Normal file
13
app/src/ac/dbio/ac_claimsweep_batch.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* ac_claimsweep_batch.h - copybook for ac_claimsweep_batch (XA client).
|
||||
* 장기 미제 클레임 정리 구조체. Kept in dbio/ for -I resolution.
|
||||
*/
|
||||
#ifndef AC_CLAIMSWEEP_BATCH_H
|
||||
#define AC_CLAIMSWEEP_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
long target; /* 삭제 대상 사전 계수 */
|
||||
long deleted; /* 실제 삭제 행 수 */
|
||||
} ac_claimsweep_ctx_t;
|
||||
|
||||
#endif /* AC_CLAIMSWEEP_BATCH_H */
|
||||
15
app/src/ac/dbio/ac_feewaive_batch.h
Normal file
15
app/src/ac/dbio/ac_feewaive_batch.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* ac_feewaive_batch.h - copybook for ac_feewaive_batch (XA client).
|
||||
* 수수료 감면 사유별 집계 구조체. Kept in dbio/ for -I resolution.
|
||||
*/
|
||||
#ifndef AC_FEEWAIVE_BATCH_H
|
||||
#define AC_FEEWAIVE_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
long rows; /* 감면(음수 delta) 행 수 */
|
||||
long waive_sum; /* WAIVE 감면 총액(양수 표기) */
|
||||
long noint_sum; /* 무이자 분담 총액 */
|
||||
long etc_sum; /* 기타 사유 총액 */
|
||||
} ac_feewaive_ctx_t;
|
||||
|
||||
#endif /* AC_FEEWAIVE_BATCH_H */
|
||||
15
app/src/ac/dbio/ac_limitwatch_batch.h
Normal file
15
app/src/ac/dbio/ac_limitwatch_batch.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* ac_limitwatch_batch.h - copybook for ac_limitwatch_batch (XA client).
|
||||
* 한도 임박 감시 구조체 + 소진율 헬퍼. Kept in dbio/ for -I resolution.
|
||||
*/
|
||||
#ifndef AC_LIMITWATCH_BATCH_H
|
||||
#define AC_LIMITWATCH_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
long scanned; /* 검사 가맹점 수 */
|
||||
long warned; /* 90% 초과 경고 수 */
|
||||
} ac_limitwatch_ctx_t;
|
||||
|
||||
long acb_usage_bps(long used, long limit);
|
||||
|
||||
#endif /* AC_LIMITWATCH_BATCH_H */
|
||||
15
app/src/ac/dbio/ac_promo_batch.h
Normal file
15
app/src/ac/dbio/ac_promo_batch.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* ac_promo_batch.h - copybook for ac_promo_batch (XA client).
|
||||
* 프로모션 매입 집계 구조체. Kept in dbio/ for -I resolution.
|
||||
*/
|
||||
#ifndef AC_PROMO_BATCH_H
|
||||
#define AC_PROMO_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
long promo_count;
|
||||
long promo_amount;
|
||||
long waived_fee; /* MDR 기준 면제 수수료 추정액 */
|
||||
long ledger_sum; /* PROMO 원장 분개 합계 */
|
||||
} ac_promo_ctx_t;
|
||||
|
||||
#endif /* AC_PROMO_BATCH_H */
|
||||
13
app/src/ac/dbio/ac_reservepost_batch.h
Normal file
13
app/src/ac/dbio/ac_reservepost_batch.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* ac_reservepost_batch.h - copybook for ac_reservepost_batch (XA client).
|
||||
* 매입 예약 전환 구조체. Kept in dbio/ for -I resolution.
|
||||
*/
|
||||
#ifndef AC_RESERVEPOST_BATCH_H
|
||||
#define AC_RESERVEPOST_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
long posted; /* P→A 전환 건수 */
|
||||
long remaining; /* 미래 예약 잔량 */
|
||||
} ac_reservepost_ctx_t;
|
||||
|
||||
#endif /* AC_RESERVEPOST_BATCH_H */
|
||||
14
app/src/ac/dbio/ac_settledue_batch.h
Normal file
14
app/src/ac/dbio/ac_settledue_batch.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* ac_settledue_batch.h - copybook for ac_settledue_batch (XA client).
|
||||
* 정산예정 대기열 집계 구조체. Kept in dbio/ for -I resolution.
|
||||
*/
|
||||
#ifndef AC_SETTLEDUE_BATCH_H
|
||||
#define AC_SETTLEDUE_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
long merchants; /* 정산 대기 가맹점 수 */
|
||||
long due_count; /* 정산예정 건수 */
|
||||
long due_net; /* 정산예정 총액 */
|
||||
} ac_settledue_ctx_t;
|
||||
|
||||
#endif /* AC_SETTLEDUE_BATCH_H */
|
||||
14
app/src/ac/dbio/ac_splitpay_batch.h
Normal file
14
app/src/ac/dbio/ac_splitpay_batch.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* ac_splitpay_batch.h - copybook for ac_splitpay_batch (XA client).
|
||||
* 분할납부 스케줄 정합 집계 구조체. Kept in dbio/ for -I resolution.
|
||||
*/
|
||||
#ifndef AC_SPLITPAY_BATCH_H
|
||||
#define AC_SPLITPAY_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
long plans; /* 검사한 분할 플랜 수 */
|
||||
long sched_total; /* 스케줄 금액 합계 */
|
||||
long mismatch; /* 원금 불일치 플랜 수 */
|
||||
} ac_splitpay_ctx_t;
|
||||
|
||||
#endif /* AC_SPLITPAY_BATCH_H */
|
||||
14
app/src/ac/dbio/ac_taxneg_batch.h
Normal file
14
app/src/ac/dbio/ac_taxneg_batch.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* ac_taxneg_batch.h - copybook for ac_taxneg_batch (XA client).
|
||||
* 음수 세금계산서 검증 구조체. Kept in dbio/ for -I resolution.
|
||||
*/
|
||||
#ifndef AC_TAXNEG_BATCH_H
|
||||
#define AC_TAXNEG_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
long neg_rows; /* 음수 계산서 건수 */
|
||||
long bad_vat; /* 부가세 상쇄식 위반 */
|
||||
long over_offset; /* 과상쇄 매입 수 */
|
||||
} ac_taxneg_ctx_t;
|
||||
|
||||
#endif /* AC_TAXNEG_BATCH_H */
|
||||
13
app/src/ac/dbio/ac_weekroll_batch.h
Normal file
13
app/src/ac/dbio/ac_weekroll_batch.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* ac_weekroll_batch.h - copybook for ac_weekroll_batch (XA client).
|
||||
* 주간 가맹점 롤업 구조체. Kept in dbio/ for -I resolution.
|
||||
*/
|
||||
#ifndef AC_WEEKROLL_BATCH_H
|
||||
#define AC_WEEKROLL_BATCH_H
|
||||
|
||||
typedef struct {
|
||||
long rolled; /* upsert 반영 행수 */
|
||||
long week_gross; /* 주간 총액 되읽기 */
|
||||
} ac_weekroll_ctx_t;
|
||||
|
||||
#endif /* AC_WEEKROLL_BATCH_H */
|
||||
23
app/src/ac/svc/ACQ_ALERTCHK.h
Normal file
23
app/src/ac/svc/ACQ_ALERTCHK.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* ACQ_ALERTCHK.h - ac 서비스 ACQ_ALERTCHK 카피북 (copybook / record header).
|
||||
* 매입 알림 점검 레코드.
|
||||
* Request fields: T_MERCHANT, T_BIZDATE, T_AMT1(임계금액; 0=기본 100만)
|
||||
* Response fields: T_RC(1=경보), T_MSG, T_ARG1(고액 건수), T_ARG2(보류 건수)
|
||||
*/
|
||||
#ifndef ACQ_ALERTCHK_H
|
||||
#define ACQ_ALERTCHK_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char merchant_id[64];
|
||||
char biz_date[16];
|
||||
long threshold; /* 고액 임계금액 */
|
||||
long big_count;
|
||||
long hold_count;
|
||||
char message[160];
|
||||
} ac_alertchk_rec_t;
|
||||
|
||||
void ACQ_ALERTCHK(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_ALERTCHK_H */
|
||||
43
app/src/ac/svc/ACQ_ALERTCHK.pgc
Normal file
43
app/src/ac/svc/ACQ_ALERTCHK.pgc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* ACQ_ALERTCHK.pgc - ac 모듈 서비스 ACQ_ALERTCHK (one service = one file).
|
||||
* 매입 알림 점검: 가맹점의 당일 고액거래(임계금액 이상)와 보류 적체 건수를
|
||||
* 점검해 경보 여부와 알림 메시지를 만들어 돌려준다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_ALERTCHK.h"
|
||||
|
||||
void ACQ_ALERTCHK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long threshold;
|
||||
char msg[160];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_thr, h_big = 0, h_hold = 0;
|
||||
char h_merch[64], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
threshold = getl(b, T_AMT1);
|
||||
if (threshold <= 0) threshold = 1000000L; /* 기본 임계: 100만원 */
|
||||
h_thr = threshold;
|
||||
gets_(b, T_MERCHANT, h_merch, sizeof(h_merch));
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL SELECT count(*) FILTER (WHERE amount >= :h_thr),
|
||||
count(*) FILTER (WHERE status = 'H')
|
||||
INTO :h_big, :h_hold
|
||||
FROM purchase WHERE merchant_id = :h_merch AND biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_ALERTCHK FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
if (h_big > 0 || h_hold > 0) {
|
||||
snprintf(msg, sizeof(msg), "ALERT merchant=%s big=%ld hold=%ld thr=%ld",
|
||||
h_merch, h_big, h_hold, threshold);
|
||||
Bchg(b, T_MSG, 0, msg, 0L);
|
||||
setl(b, T_RC, 1); /* 경보 */
|
||||
} else {
|
||||
Bchg(b, T_MSG, 0, "CLEAR", 0L);
|
||||
setl(b, T_RC, 0); /* 정상 */
|
||||
}
|
||||
setl(b, T_ARG1, h_big);
|
||||
setl(b, T_ARG2, h_hold);
|
||||
OK(b);
|
||||
}
|
||||
21
app/src/ac/svc/ACQ_APPRGAP.h
Normal file
21
app/src/ac/svc/ACQ_APPRGAP.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* ACQ_APPRGAP.h - ac 서비스 ACQ_APPRGAP 카피북 (copybook / record header).
|
||||
* 승인-매입 갭 점검 레코드.
|
||||
* Request fields: T_BIZDATE
|
||||
* Response fields: T_ARG1(무승인 매입), T_AMT1(금액), T_ARG2(고아 승인), T_RC
|
||||
*/
|
||||
#ifndef ACQ_APPRGAP_H
|
||||
#define ACQ_APPRGAP_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char biz_date[16];
|
||||
long no_approval; /* 승인 없는 매입 건수 */
|
||||
long no_appr_amt;
|
||||
long orphan_appr; /* 매입 없는 승인 건수 */
|
||||
} ac_apprgap_rec_t;
|
||||
|
||||
void ACQ_APPRGAP(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_APPRGAP_H */
|
||||
38
app/src/ac/svc/ACQ_APPRGAP.pgc
Normal file
38
app/src/ac/svc/ACQ_APPRGAP.pgc
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* ACQ_APPRGAP.pgc - ac 모듈 서비스 ACQ_APPRGAP (one service = one file).
|
||||
* 승인-매입 갭 점검: 승인 없는 매입(무승인 매입)과 매입 없는 승인(고아
|
||||
* 승인)을 양방향으로 세어 갭 규모를 보고한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_APPRGAP.h"
|
||||
|
||||
void ACQ_APPRGAP(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_noappr = 0, h_orphan = 0, h_amt = 0;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
/* 승인 없는 매입: 건수 + 금액 */
|
||||
EXEC SQL SELECT count(*), coalesce(sum(u.amount), 0)
|
||||
INTO :h_noappr, :h_amt
|
||||
FROM purchase u
|
||||
WHERE u.biz_date = :h_bizdate AND u.status NOT IN ('C', 'V', 'P')
|
||||
AND NOT EXISTS (SELECT 1 FROM approval a WHERE a.purchase_id = u.purchase_id AND a.approved = true);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
/* 매입 없는 고아 승인 */
|
||||
EXEC SQL SELECT count(*) INTO :h_orphan
|
||||
FROM approval a LEFT JOIN purchase u ON u.purchase_id = a.purchase_id
|
||||
WHERE u.purchase_id IS NULL;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_APPRGAP FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_ARG1, h_noappr); /* 무승인 매입 건수 */
|
||||
setl(b, T_AMT1, h_amt); /* 무승인 매입 금액 */
|
||||
setl(b, T_ARG2, h_orphan); /* 고아 승인 건수 */
|
||||
setl(b, T_RC, (h_noappr + h_orphan) > 0 ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_BULKVERIFY.h
Normal file
22
app/src/ac/svc/ACQ_BULKVERIFY.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_BULKVERIFY.h - ac 서비스 ACQ_BULKVERIFY 카피북 (copybook / record header).
|
||||
* 대량매입 검증 레코드.
|
||||
* Request fields: T_MERCHANT, T_BIZDATE
|
||||
* Response fields: T_COUNT, T_ARG1(수수료 오류), T_ARG2(정산금 오류), T_RC
|
||||
*/
|
||||
#ifndef ACQ_BULKVERIFY_H
|
||||
#define ACQ_BULKVERIFY_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char merchant_id[64];
|
||||
char biz_date[16];
|
||||
long total;
|
||||
long fee_bad; /* MDR 재계산 불일치 */
|
||||
long net_bad; /* amount-fee 불일치 */
|
||||
} ac_bulkverify_rec_t;
|
||||
|
||||
void ACQ_BULKVERIFY(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_BULKVERIFY_H */
|
||||
37
app/src/ac/svc/ACQ_BULKVERIFY.pgc
Normal file
37
app/src/ac/svc/ACQ_BULKVERIFY.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* ACQ_BULKVERIFY.pgc - ac 모듈 서비스 ACQ_BULKVERIFY (one service = one file).
|
||||
* 대량매입 검증: 가맹점·영업일 단위로 전 건의 수수료(MDR 재계산 대비)와
|
||||
* 정산금(amount-fee 대비) 정합을 일괄 점검해 오류 건수를 보고한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_BULKVERIFY.h"
|
||||
|
||||
void ACQ_BULKVERIFY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long bps = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_bps, h_total = 0, h_feebad = 0, h_netbad = 0;
|
||||
char h_merch[64], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_MERCHANT, h_merch, sizeof(h_merch));
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
if (acdb_merchant_mdr(h_merch, &bps) < 0) { setl(b, T_RC, 5); FAIL(b); }
|
||||
h_bps = bps;
|
||||
|
||||
EXEC SQL SELECT count(*),
|
||||
count(*) FILTER (WHERE fee <> amount * :h_bps / 10000),
|
||||
count(*) FILTER (WHERE net <> amount - fee)
|
||||
INTO :h_total, :h_feebad, :h_netbad
|
||||
FROM purchase
|
||||
WHERE merchant_id = :h_merch AND biz_date = :h_bizdate AND status NOT IN ('C', 'V');
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_BULKVERIFY FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_COUNT, h_total);
|
||||
setl(b, T_ARG1, h_feebad); /* 수수료 오류 건수 */
|
||||
setl(b, T_ARG2, h_netbad); /* 정산금 오류 건수 */
|
||||
setl(b, T_RC, (h_feebad + h_netbad) > 0 ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
21
app/src/ac/svc/ACQ_CB_DEFEND.h
Normal file
21
app/src/ac/svc/ACQ_CB_DEFEND.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* ACQ_CB_DEFEND.h - ac 서비스 ACQ_CB_DEFEND 카피북 (copybook / record header).
|
||||
* 지불거절 방어 레코드.
|
||||
* Request fields: T_CANCEL_ID, T_REASON(방어 증빙)
|
||||
* Response fields: T_PURCHASE_ID, T_RC(0=복원, 1=상태 유지, 4=CB 없음)
|
||||
*/
|
||||
#ifndef ACQ_CB_DEFEND_H
|
||||
#define ACQ_CB_DEFEND_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long cancel_id; /* CB 접수 ID */
|
||||
char evidence[96]; /* 방어 증빙 사유 */
|
||||
long purchase_id; /* 복원 대상 매입 */
|
||||
long rc;
|
||||
} ac_cb_defend_rec_t;
|
||||
|
||||
void ACQ_CB_DEFEND(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_CB_DEFEND_H */
|
||||
40
app/src/ac/svc/ACQ_CB_DEFEND.pgc
Normal file
40
app/src/ac/svc/ACQ_CB_DEFEND.pgc
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* ACQ_CB_DEFEND.pgc - ac 모듈 서비스 ACQ_CB_DEFEND (one service = one file).
|
||||
* 지불거절 방어: 접수된 CB 건에 방어 증빙 사유를 덧붙이고, 보류 중이던
|
||||
* 원매입을 대사완료(M) 상태로 복원한다. 방어 결과는 T_RC 로 응답.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_CB_DEFEND.h"
|
||||
|
||||
void ACQ_CB_DEFEND(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char evid[96];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_pid = 0, h_upd;
|
||||
char h_evid[110];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_cid = getl(b, T_CANCEL_ID);
|
||||
gets_(b, T_REASON, evid, sizeof(evid));
|
||||
if (evid[0] == 0) strcpy(evid, "EVIDENCE");
|
||||
snprintf(h_evid, sizeof(h_evid), "DEFEND:%s", evid);
|
||||
|
||||
EXEC SQL SELECT purchase_id INTO :h_pid FROM ac_cancel
|
||||
WHERE cancel_id = :h_cid AND cancel_type = 'CB';
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 4); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
EXEC SQL UPDATE ac_cancel SET reason = :h_evid WHERE cancel_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
/* 방어 접수 시 보류(H) 원매입을 대사완료로 복원 */
|
||||
EXEC SQL UPDATE purchase SET status = 'M', updated_at = now()
|
||||
WHERE purchase_id = :h_pid AND status = 'H';
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_CB_DEFEND FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
h_upd = sqlca.sqlerrd[2];
|
||||
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_RC, h_upd > 0 ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_CB_OPEN.h
Normal file
22
app/src/ac/svc/ACQ_CB_OPEN.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_CB_OPEN.h - ac 서비스 ACQ_CB_OPEN 카피북 (copybook / record header).
|
||||
* 지불거절 접수 레코드.
|
||||
* Request fields: T_PURCHASE_ID, T_AMOUNT, T_REASON, T_BIZDATE
|
||||
* Response fields: T_CANCEL_ID, T_RC
|
||||
*/
|
||||
#ifndef ACQ_CB_OPEN_H
|
||||
#define ACQ_CB_OPEN_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long purchase_id;
|
||||
long cb_amount; /* 지불거절 금액 */
|
||||
char reason[128]; /* 접수 사유 */
|
||||
char biz_date[16];
|
||||
long cancel_id; /* 생성된 CB 접수 ID */
|
||||
} ac_cb_open_rec_t;
|
||||
|
||||
void ACQ_CB_OPEN(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_CB_OPEN_H */
|
||||
43
app/src/ac/svc/ACQ_CB_OPEN.pgc
Normal file
43
app/src/ac/svc/ACQ_CB_OPEN.pgc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* ACQ_CB_OPEN.pgc - ac 모듈 서비스 ACQ_CB_OPEN (one service = one file).
|
||||
* 지불거절(chargeback) 접수: 대사완료/정산완료 매입만 접수 가능, ac_cancel 에
|
||||
* CB 유형 행을 생성하고 원매입을 보류(H) 상태로 전이한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_CB_OPEN.h"
|
||||
|
||||
void ACQ_CB_OPEN(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char reason[128];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id, h_pid, h_amt, h_orig;
|
||||
char h_st[4], h_bizdate[16], h_reason[140];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_pid = getl(b, T_PURCHASE_ID);
|
||||
h_amt = getl(b, T_AMOUNT);
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
gets_(b, T_REASON, reason, sizeof(reason));
|
||||
snprintf(h_reason, sizeof(h_reason), "CB:%s", reason[0] ? reason : "ISSUER");
|
||||
|
||||
/* 원매입 상태·금액 검증: 대사완료(M) 또는 정산완료(S)만 지불거절 대상 */
|
||||
EXEC SQL SELECT status, amount INTO :h_st, :h_orig FROM purchase WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
if (h_st[0] != 'M' && h_st[0] != 'S') { setl(b, T_RC, 2); FAIL(b); }
|
||||
if (h_amt <= 0 || h_amt > h_orig) { setl(b, T_RC, 3); FAIL(b); }
|
||||
|
||||
EXEC SQL SELECT nextval('ac_cancel_seq') INTO :h_id;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL INSERT INTO ac_cancel (cancel_id, purchase_id, cancel_type, amount, reason, biz_date)
|
||||
VALUES (:h_id, :h_pid, 'CB', :h_amt, :h_reason, :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
/* 분쟁 중 원매입은 보류 전이 */
|
||||
EXEC SQL UPDATE purchase SET status = 'H', updated_at = now() WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_CB_OPEN FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_CANCEL_ID, h_id);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_CB_QRY.h
Normal file
22
app/src/ac/svc/ACQ_CB_QRY.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_CB_QRY.h - ac 서비스 ACQ_CB_QRY 카피북 (copybook / record header).
|
||||
* 지불거절 목록조회 레코드.
|
||||
* Request fields: T_MERCHANT, T_BIZDATE
|
||||
* Response fields: T_COUNT, T_AMOUNT, T_ID1(occ 0..4 = 최근 접수 ID)
|
||||
*/
|
||||
#ifndef ACQ_CB_QRY_H
|
||||
#define ACQ_CB_QRY_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char merchant_id[64];
|
||||
char biz_date[16];
|
||||
long cb_count; /* CB 건수 */
|
||||
long cb_total; /* CB 금액 합계 */
|
||||
long recent_ids[5]; /* 최근 접수 ID */
|
||||
} ac_cb_qry_rec_t;
|
||||
|
||||
void ACQ_CB_QRY(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_CB_QRY_H */
|
||||
40
app/src/ac/svc/ACQ_CB_QRY.pgc
Normal file
40
app/src/ac/svc/ACQ_CB_QRY.pgc
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* ACQ_CB_QRY.pgc - ac 모듈 서비스 ACQ_CB_QRY (one service = one file).
|
||||
* 지불거절 목록조회: 가맹점·영업일 기준 CB 접수 건을 커서로 훑어 건수/합계를
|
||||
* 집계하고 최근 5건의 접수 ID 를 다중 occurrence 로 반환한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_CB_QRY.h"
|
||||
|
||||
void ACQ_CB_QRY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long cnt = 0, total = 0, shown = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_amt;
|
||||
char h_merch[64], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_MERCHANT, h_merch, sizeof(h_merch));
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL DECLARE cbq_cur CURSOR FOR
|
||||
SELECT c.cancel_id, c.amount
|
||||
FROM ac_cancel c JOIN purchase u ON u.purchase_id = c.purchase_id
|
||||
WHERE c.cancel_type = 'CB' AND c.biz_date = :h_bizdate AND u.merchant_id = :h_merch
|
||||
ORDER BY c.cancel_id DESC;
|
||||
EXEC SQL OPEN cbq_cur;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH cbq_cur INTO :h_cid, :h_amt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cbq_cur; FAIL(b); }
|
||||
cnt++; total += h_amt;
|
||||
if (shown < 5) { Badd(b, T_ID1, (char *)&h_cid, 0L); shown++; }
|
||||
}
|
||||
EXEC SQL CLOSE cbq_cur;
|
||||
|
||||
setl(b, T_COUNT, cnt);
|
||||
setl(b, T_AMOUNT, total);
|
||||
OK(b);
|
||||
}
|
||||
23
app/src/ac/svc/ACQ_CB_STAT.h
Normal file
23
app/src/ac/svc/ACQ_CB_STAT.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* ACQ_CB_STAT.h - ac 서비스 ACQ_CB_STAT 카피북 (copybook / record header).
|
||||
* 지불거절 일별 통계 레코드.
|
||||
* Request fields: T_BIZDATE
|
||||
* Response fields: T_COUNT, T_GROSS, T_AMT1(평균), T_AMT2(최대), T_ARG1(방어건수)
|
||||
*/
|
||||
#ifndef ACQ_CB_STAT_H
|
||||
#define ACQ_CB_STAT_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char biz_date[16];
|
||||
long cb_count;
|
||||
long cb_sum;
|
||||
long cb_avg;
|
||||
long cb_max;
|
||||
long defended; /* 방어 완료 건수 */
|
||||
} ac_cb_stat_rec_t;
|
||||
|
||||
void ACQ_CB_STAT(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_CB_STAT_H */
|
||||
34
app/src/ac/svc/ACQ_CB_STAT.pgc
Normal file
34
app/src/ac/svc/ACQ_CB_STAT.pgc
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* ACQ_CB_STAT.pgc - ac 모듈 서비스 ACQ_CB_STAT (one service = one file).
|
||||
* 지불거절 일별 통계: 영업일 기준 CB 건수·합계·평균·최대 금액과 방어 완료
|
||||
* (DEFEND 사유) 건수를 한 번의 FILTER 집계로 산출한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_CB_STAT.h"
|
||||
|
||||
void ACQ_CB_STAT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt = 0, h_sum = 0, h_avg = 0, h_max = 0, h_def = 0;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL SELECT count(*),
|
||||
coalesce(sum(amount), 0),
|
||||
coalesce(avg(amount)::bigint, 0),
|
||||
coalesce(max(amount), 0),
|
||||
count(*) FILTER (WHERE reason LIKE 'DEFEND:%')
|
||||
INTO :h_cnt, :h_sum, :h_avg, :h_max, :h_def
|
||||
FROM ac_cancel WHERE cancel_type = 'CB' AND biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_CB_STAT FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_sum);
|
||||
setl(b, T_AMT1, h_avg);
|
||||
setl(b, T_AMT2, h_max);
|
||||
setl(b, T_ARG1, h_def);
|
||||
OK(b);
|
||||
}
|
||||
23
app/src/ac/svc/ACQ_CCYSUM.h
Normal file
23
app/src/ac/svc/ACQ_CCYSUM.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* ACQ_CCYSUM.h - ac 서비스 ACQ_CCYSUM 카피북 (copybook / record header).
|
||||
* 통화별 매입 집계 레코드.
|
||||
* Request fields: T_CCY(선택), T_BIZDATE
|
||||
* Response fields: T_COUNT, T_FX_AMT, T_AMOUNT(원화), T_ARG1(통화 종수)
|
||||
*/
|
||||
#ifndef ACQ_CCYSUM_H
|
||||
#define ACQ_CCYSUM_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char ccy[8]; /* 통화코드(빈값=전체) */
|
||||
char biz_date[16];
|
||||
long fx_count;
|
||||
long fx_sum; /* 원통화 합계 */
|
||||
long krw_sum; /* 원화 환산 합계 */
|
||||
long ccy_kinds; /* 통화 종수 */
|
||||
} ac_ccysum_rec_t;
|
||||
|
||||
void ACQ_CCYSUM(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_CCYSUM_H */
|
||||
40
app/src/ac/svc/ACQ_CCYSUM.pgc
Normal file
40
app/src/ac/svc/ACQ_CCYSUM.pgc
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* ACQ_CCYSUM.pgc - ac 모듈 서비스 ACQ_CCYSUM (one service = one file).
|
||||
* 통화별 매입 집계: 통화코드를 지정하면 해당 통화의 원통화/원화 합계를,
|
||||
* 미지정 시 영업일 전체의 통화 종수와 원화 환산 총액을 집계한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_CCYSUM.h"
|
||||
|
||||
void ACQ_CCYSUM(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt = 0, h_fx = 0, h_krw = 0, h_nccy = 0;
|
||||
char h_ccy[8], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CCY, h_ccy, sizeof(h_ccy));
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
if (h_ccy[0]) {
|
||||
/* 단일 통화 집계 */
|
||||
EXEC SQL SELECT count(*), coalesce(sum(fx_amount),0), coalesce(sum(krw_amount),0)
|
||||
INTO :h_cnt, :h_fx, :h_krw
|
||||
FROM ac_fx WHERE ccy = :h_ccy AND biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
h_nccy = 1;
|
||||
} else {
|
||||
/* 전체 통화 요약: 통화 종수 + 원화 환산 총액 */
|
||||
EXEC SQL SELECT count(*), count(DISTINCT ccy), coalesce(sum(krw_amount),0)
|
||||
INTO :h_cnt, :h_nccy, :h_krw
|
||||
FROM ac_fx WHERE biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_CCYSUM FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
}
|
||||
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_FX_AMT, h_fx);
|
||||
setl(b, T_AMOUNT, h_krw);
|
||||
setl(b, T_ARG1, h_nccy);
|
||||
OK(b);
|
||||
}
|
||||
23
app/src/ac/svc/ACQ_CHANSTAT.h
Normal file
23
app/src/ac/svc/ACQ_CHANSTAT.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* ACQ_CHANSTAT.h - ac 서비스 ACQ_CHANSTAT 카피북 (copybook / record header).
|
||||
* 매입 채널별 통계 레코드.
|
||||
* Request fields: T_BIZDATE
|
||||
* Response fields: T_CHANNEL(최대 채널), T_AMT1, T_ARG1(종수), T_STR2/T_AMT3(occ)
|
||||
*/
|
||||
#ifndef ACQ_CHANSTAT_H
|
||||
#define ACQ_CHANSTAT_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char biz_date[16];
|
||||
char best_channel[16]; /* 최대 매출 채널 */
|
||||
long best_amount;
|
||||
long kinds; /* 채널 종수 */
|
||||
char channels[6][16];
|
||||
long amounts[6];
|
||||
} ac_chanstat_rec_t;
|
||||
|
||||
void ACQ_CHANSTAT(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_CHANSTAT_H */
|
||||
45
app/src/ac/svc/ACQ_CHANSTAT.pgc
Normal file
45
app/src/ac/svc/ACQ_CHANSTAT.pgc
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* ACQ_CHANSTAT.pgc - ac 모듈 서비스 ACQ_CHANSTAT (one service = one file).
|
||||
* 매입 채널별 통계: 영업일 채널 그룹 집계를 커서로 순회하며 채널 종수와
|
||||
* 최대 매출 채널을 찾고, 채널명/금액 쌍을 다중 occurrence 로 반환한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_CHANSTAT.h"
|
||||
|
||||
void ACQ_CHANSTAT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long kinds = 0, best = 0;
|
||||
char bestchan[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_sum, h_n;
|
||||
char h_chan[16], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
bestchan[0] = 0;
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL DECLARE chs_cur CURSOR FOR
|
||||
SELECT channel, count(*), sum(amount) FROM purchase
|
||||
WHERE biz_date = :h_bizdate AND status <> 'C'
|
||||
GROUP BY channel ORDER BY sum(amount) DESC;
|
||||
EXEC SQL OPEN chs_cur;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH chs_cur INTO :h_chan, :h_n, :h_sum;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE chs_cur; FAIL(b); }
|
||||
if (kinds == 0) { /* 정렬 첫 행 = 최대 매출 채널 */
|
||||
strncpy(bestchan, h_chan, sizeof(bestchan)-1); bestchan[sizeof(bestchan)-1] = 0;
|
||||
best = h_sum;
|
||||
}
|
||||
if (kinds < 6) { Badd(b, T_STR2, h_chan, 0L); Badd(b, T_AMT3, (char *)&h_sum, 0L); }
|
||||
kinds++;
|
||||
}
|
||||
EXEC SQL CLOSE chs_cur;
|
||||
|
||||
if (bestchan[0]) Bchg(b, T_CHANNEL, 0, bestchan, 0L);
|
||||
setl(b, T_AMT1, best);
|
||||
setl(b, T_ARG1, kinds); /* 채널 종수 */
|
||||
OK(b);
|
||||
}
|
||||
21
app/src/ac/svc/ACQ_CLAIMPROC.h
Normal file
21
app/src/ac/svc/ACQ_CLAIMPROC.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* ACQ_CLAIMPROC.h - ac 서비스 ACQ_CLAIMPROC 카피북 (copybook / record header).
|
||||
* 클레임 처리 종결 레코드.
|
||||
* Request fields: T_ID1(클레임 ID), T_STR1(처리결과), T_BIZDATE
|
||||
* Response fields: T_PURCHASE_ID, T_MSG, T_RC(4=클레임 아님)
|
||||
*/
|
||||
#ifndef ACQ_CLAIMPROC_H
|
||||
#define ACQ_CLAIMPROC_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long claim_id;
|
||||
char result[64]; /* 처리 결과 코드 */
|
||||
char biz_date[16];
|
||||
long purchase_id;
|
||||
} ac_claimproc_rec_t;
|
||||
|
||||
void ACQ_CLAIMPROC(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_CLAIMPROC_H */
|
||||
38
app/src/ac/svc/ACQ_CLAIMPROC.pgc
Normal file
38
app/src/ac/svc/ACQ_CLAIMPROC.pgc
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* ACQ_CLAIMPROC.pgc - ac 모듈 서비스 ACQ_CLAIMPROC (one service = one file).
|
||||
* 클레임 처리(종결): 등록된 클레임 행을 삭제하고 처리 결과를 원장에
|
||||
* CLAIMRES 분개(금액 0)로 남긴다. 클레임이 아니거나 없으면 T_RC=4.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_CLAIMPROC.h"
|
||||
|
||||
void ACQ_CLAIMPROC(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16], result[64];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_uid, h_pid = 0, h_del;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_uid = getl(b, T_ID1);
|
||||
gets_(b, T_STR1, result, sizeof(result));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
if (result[0] == 0) strcpy(result, "ACCEPTED");
|
||||
|
||||
EXEC SQL SELECT purchase_id INTO :h_pid FROM ac_unmatch
|
||||
WHERE unmatch_id = :h_uid AND reason LIKE 'CLAIM:%';
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 4); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
EXEC SQL DELETE FROM ac_unmatch WHERE unmatch_id = :h_uid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
h_del = sqlca.sqlerrd[2];
|
||||
|
||||
/* 처리 흔적을 원장에 남긴다 (금액 0, 유형 CLAIMRES) */
|
||||
if (h_del > 0 && acdb_insert_ledger(h_pid, "CLAIMRES", 0, bizdate) < 0) FAIL(b);
|
||||
|
||||
Bchg(b, T_MSG, 0, result, 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_RC, h_del > 0 ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
21
app/src/ac/svc/ACQ_CLAIMQRY.h
Normal file
21
app/src/ac/svc/ACQ_CLAIMQRY.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* ACQ_CLAIMQRY.h - ac 서비스 ACQ_CLAIMQRY 카피북 (copybook / record header).
|
||||
* 클레임 목록조회 레코드.
|
||||
* Request fields: T_BIZDATE
|
||||
* Response fields: T_COUNT, T_ARG1(수록 건수), T_ID1/T_STR1(occ 0..4)
|
||||
*/
|
||||
#ifndef ACQ_CLAIMQRY_H
|
||||
#define ACQ_CLAIMQRY_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char biz_date[16];
|
||||
long total; /* 미종결 클레임 총건수 */
|
||||
long claim_ids[5];
|
||||
char reasons[5][128];
|
||||
} ac_claimqry_rec_t;
|
||||
|
||||
void ACQ_CLAIMQRY(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_CLAIMQRY_H */
|
||||
42
app/src/ac/svc/ACQ_CLAIMQRY.pgc
Normal file
42
app/src/ac/svc/ACQ_CLAIMQRY.pgc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* ACQ_CLAIMQRY.pgc - ac 모듈 서비스 ACQ_CLAIMQRY (one service = one file).
|
||||
* 클레임 목록조회: 영업일의 미종결 클레임을 커서로 순회, 총건수와 함께
|
||||
* 상위 5건의 클레임 ID/사유를 다중 occurrence 로 내려준다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_CLAIMQRY.h"
|
||||
|
||||
void ACQ_CLAIMQRY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long total = 0, listed = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_uid;
|
||||
char h_reason[128], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL DECLARE clq_cur CURSOR FOR
|
||||
SELECT unmatch_id, reason FROM ac_unmatch
|
||||
WHERE reason LIKE 'CLAIM:%' AND biz_date = :h_bizdate
|
||||
ORDER BY unmatch_id;
|
||||
EXEC SQL OPEN clq_cur;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH clq_cur INTO :h_uid, :h_reason;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE clq_cur; FAIL(b); }
|
||||
total++;
|
||||
if (listed < 5) {
|
||||
Badd(b, T_ID1, (char *)&h_uid, 0L);
|
||||
Badd(b, T_STR1, h_reason, 0L);
|
||||
listed++;
|
||||
}
|
||||
}
|
||||
EXEC SQL CLOSE clq_cur;
|
||||
|
||||
setl(b, T_COUNT, total);
|
||||
setl(b, T_ARG1, listed);
|
||||
OK(b);
|
||||
}
|
||||
21
app/src/ac/svc/ACQ_CLAIMREG.h
Normal file
21
app/src/ac/svc/ACQ_CLAIMREG.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* ACQ_CLAIMREG.h - ac 서비스 ACQ_CLAIMREG 카피북 (copybook / record header).
|
||||
* 클레임 등록 레코드.
|
||||
* Request fields: T_PURCHASE_ID, T_REASON, T_BIZDATE
|
||||
* Response fields: T_ID1(클레임 ID), T_RC(2=중복, 5=매입 없음)
|
||||
*/
|
||||
#ifndef ACQ_CLAIMREG_H
|
||||
#define ACQ_CLAIMREG_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long purchase_id;
|
||||
char reason[100]; /* 이의신청 사유 */
|
||||
char biz_date[16];
|
||||
long claim_id; /* ac_unmatch 행 ID */
|
||||
} ac_claimreg_rec_t;
|
||||
|
||||
void ACQ_CLAIMREG(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_CLAIMREG_H */
|
||||
42
app/src/ac/svc/ACQ_CLAIMREG.pgc
Normal file
42
app/src/ac/svc/ACQ_CLAIMREG.pgc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* ACQ_CLAIMREG.pgc - ac 모듈 서비스 ACQ_CLAIMREG (one service = one file).
|
||||
* 클레임 등록: 가맹점 이의신청을 미매입 원장(ac_unmatch)에 CLAIM 사유로
|
||||
* 기록한다. 동일 매입에 미종결 클레임이 이미 있으면 중복 등록을 막는다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_CLAIMREG.h"
|
||||
|
||||
void ACQ_CLAIMREG(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char why[100];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id, h_pid, h_exist = 0, h_have = 0;
|
||||
char h_reason[120], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_pid = getl(b, T_PURCHASE_ID);
|
||||
gets_(b, T_REASON, why, sizeof(why));
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
snprintf(h_reason, sizeof(h_reason), "CLAIM:%s", why[0] ? why : "MERCHANT");
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :h_exist FROM purchase WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_exist == 0) { setl(b, T_RC, 5); FAIL(b); }
|
||||
|
||||
/* 미종결 클레임 중복 방지 */
|
||||
EXEC SQL SELECT count(*) INTO :h_have FROM ac_unmatch
|
||||
WHERE purchase_id = :h_pid AND reason LIKE 'CLAIM:%';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_have > 0) { setl(b, T_RC, 2); FAIL(b); }
|
||||
|
||||
EXEC SQL SELECT nextval('ac_unmatch_seq') INTO :h_id;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL INSERT INTO ac_unmatch (unmatch_id, purchase_id, reason, biz_date)
|
||||
VALUES (:h_id, :h_pid, :h_reason, :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_CLAIMREG FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_ID1, h_id);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_CORRHIST.h
Normal file
22
app/src/ac/svc/ACQ_CORRHIST.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_CORRHIST.h - ac 서비스 ACQ_CORRHIST 카피북 (copybook / record header).
|
||||
* 정정 이력조회 레코드.
|
||||
* Request fields: T_PURCHASE_ID
|
||||
* Response fields: T_COUNT, T_ARG1(취소류 건수), T_ADJ/T_DELTA(occ 0..9)
|
||||
*/
|
||||
#ifndef ACQ_CORRHIST_H
|
||||
#define ACQ_CORRHIST_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long purchase_id;
|
||||
long adj_rows; /* 수수료 정정 건수(최대 10) */
|
||||
long cancel_rows; /* 취소류 정정 건수 */
|
||||
long adj_ids[10];
|
||||
long deltas[10];
|
||||
} ac_corrhist_rec_t;
|
||||
|
||||
void ACQ_CORRHIST(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_CORRHIST_H */
|
||||
41
app/src/ac/svc/ACQ_CORRHIST.pgc
Normal file
41
app/src/ac/svc/ACQ_CORRHIST.pgc
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* ACQ_CORRHIST.pgc - ac 모듈 서비스 ACQ_CORRHIST (one service = one file).
|
||||
* 정정 이력조회: 매입 건에 붙은 수수료 조정 이력(최근 10건)을 역순 커서로
|
||||
* 내려주고, 취소계 정정(ac_cancel) 건수를 별도 카운트로 함께 응답한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_CORRHIST.h"
|
||||
|
||||
void ACQ_CORRHIST(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long rows = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pid, h_adj, h_delta, h_cxl = 0;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_pid = getl(b, T_PURCHASE_ID);
|
||||
|
||||
EXEC SQL DECLARE crh_cur CURSOR FOR
|
||||
SELECT adj_id, delta FROM ac_fee_adj
|
||||
WHERE purchase_id = :h_pid ORDER BY adj_id DESC LIMIT 10;
|
||||
EXEC SQL OPEN crh_cur;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH crh_cur INTO :h_adj, :h_delta;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE crh_cur; FAIL(b); }
|
||||
Badd(b, T_ADJ, (char *)&h_adj, 0L);
|
||||
Badd(b, T_DELTA, (char *)&h_delta, 0L);
|
||||
rows++;
|
||||
}
|
||||
EXEC SQL CLOSE crh_cur;
|
||||
|
||||
/* 취소·환불류 정정 건수 병기 */
|
||||
EXEC SQL SELECT count(*) INTO :h_cxl FROM ac_cancel WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_CORRHIST FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_COUNT, rows);
|
||||
setl(b, T_ARG1, h_cxl);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_CTRYSUM.h
Normal file
22
app/src/ac/svc/ACQ_CTRYSUM.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_CTRYSUM.h - ac 서비스 ACQ_CTRYSUM 카피북 (copybook / record header).
|
||||
* 국가권역별 매입 집계 레코드.
|
||||
* Request fields: T_BIZDATE
|
||||
* Response fields: T_ARG1(미주), T_ARG2(일본), T_ARG3(유럽), T_ARG4(기타), T_GROSS
|
||||
*/
|
||||
#ifndef ACQ_CTRYSUM_H
|
||||
#define ACQ_CTRYSUM_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char biz_date[16];
|
||||
long amer_krw; /* 미주권 원화 합계 */
|
||||
long japan_krw;
|
||||
long europe_krw;
|
||||
long etc_krw;
|
||||
} ac_ctrysum_rec_t;
|
||||
|
||||
void ACQ_CTRYSUM(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_CTRYSUM_H */
|
||||
48
app/src/ac/svc/ACQ_CTRYSUM.pgc
Normal file
48
app/src/ac/svc/ACQ_CTRYSUM.pgc
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* ACQ_CTRYSUM.pgc - ac 모듈 서비스 ACQ_CTRYSUM (one service = one file).
|
||||
* 국가별 매입 집계: 통화코드를 국가권역(미주/일본/유럽/기타)으로 매핑하는
|
||||
* C 분류기를 거쳐 해외매입 원화금액을 권역별 버킷에 누적한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_CTRYSUM.h"
|
||||
|
||||
/* 통화코드 → 권역 인덱스 (0=미주, 1=일본, 2=유럽, 3=기타) */
|
||||
static int ac_ccy_region(const char *ccy)
|
||||
{
|
||||
if (strcmp(ccy, "USD") == 0 || strcmp(ccy, "CAD") == 0) return 0;
|
||||
if (strcmp(ccy, "JPY") == 0) return 1;
|
||||
if (strcmp(ccy, "EUR") == 0 || strcmp(ccy, "GBP") == 0 || strcmp(ccy, "CHF") == 0) return 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
void ACQ_CTRYSUM(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long bucket[4] = {0, 0, 0, 0};
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_krw;
|
||||
char h_ccy[8], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL DECLARE ctr_cur CURSOR FOR
|
||||
SELECT ccy, sum(krw_amount) FROM ac_fx
|
||||
WHERE biz_date = :h_bizdate GROUP BY ccy;
|
||||
EXEC SQL OPEN ctr_cur;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH ctr_cur INTO :h_ccy, :h_krw;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE ctr_cur; FAIL(b); }
|
||||
bucket[ac_ccy_region(h_ccy)] += h_krw;
|
||||
}
|
||||
EXEC SQL CLOSE ctr_cur;
|
||||
|
||||
setl(b, T_ARG1, bucket[0]); /* 미주 */
|
||||
setl(b, T_ARG2, bucket[1]); /* 일본 */
|
||||
setl(b, T_ARG3, bucket[2]); /* 유럽 */
|
||||
setl(b, T_ARG4, bucket[3]); /* 기타 */
|
||||
setl(b, T_GROSS, bucket[0] + bucket[1] + bucket[2] + bucket[3]);
|
||||
OK(b);
|
||||
}
|
||||
26
app/src/ac/svc/ACQ_DAYSTAT.h
Normal file
26
app/src/ac/svc/ACQ_DAYSTAT.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* ACQ_DAYSTAT.h - ac 서비스 ACQ_DAYSTAT 카피북 (copybook / record header).
|
||||
* 매입 일별 상태 통계 레코드.
|
||||
* Request fields: T_BIZDATE
|
||||
* Response fields: T_ARG1..T_ARG6(상태별 건수), T_COUNT, T_GROSS
|
||||
*/
|
||||
#ifndef ACQ_DAYSTAT_H
|
||||
#define ACQ_DAYSTAT_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char biz_date[16];
|
||||
long cnt_accept; /* A */
|
||||
long cnt_matched; /* M */
|
||||
long cnt_settled; /* S */
|
||||
long cnt_cancel; /* C */
|
||||
long cnt_hold; /* H */
|
||||
long cnt_void; /* V */
|
||||
long total;
|
||||
long gross;
|
||||
} ac_daystat_rec_t;
|
||||
|
||||
void ACQ_DAYSTAT(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_DAYSTAT_H */
|
||||
40
app/src/ac/svc/ACQ_DAYSTAT.pgc
Normal file
40
app/src/ac/svc/ACQ_DAYSTAT.pgc
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* ACQ_DAYSTAT.pgc - ac 모듈 서비스 ACQ_DAYSTAT (one service = one file).
|
||||
* 매입 일별 상태 통계: 영업일 전 건을 상태별(접수/대사/정산/취소/보류/무효)
|
||||
* FILTER 집계 한 방으로 나눠 세고, 총건수·총액을 함께 내려준다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_DAYSTAT.h"
|
||||
|
||||
void ACQ_DAYSTAT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_a = 0, h_m = 0, h_s = 0, h_c = 0, h_h = 0, h_v = 0, h_tot = 0, h_sum = 0;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL SELECT count(*) FILTER (WHERE status = 'A'),
|
||||
count(*) FILTER (WHERE status = 'M'),
|
||||
count(*) FILTER (WHERE status = 'S'),
|
||||
count(*) FILTER (WHERE status = 'C'),
|
||||
count(*) FILTER (WHERE status = 'H'),
|
||||
count(*) FILTER (WHERE status = 'V'),
|
||||
count(*),
|
||||
coalesce(sum(amount), 0)
|
||||
INTO :h_a, :h_m, :h_s, :h_c, :h_h, :h_v, :h_tot, :h_sum
|
||||
FROM purchase WHERE biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_DAYSTAT FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_ARG1, h_a); /* 접수 */
|
||||
setl(b, T_ARG2, h_m); /* 대사완료 */
|
||||
setl(b, T_ARG3, h_s); /* 정산완료 */
|
||||
setl(b, T_ARG4, h_c); /* 취소 */
|
||||
setl(b, T_ARG5, h_h); /* 보류 */
|
||||
setl(b, T_ARG6, h_v); /* 무효 */
|
||||
setl(b, T_COUNT, h_tot);
|
||||
setl(b, T_GROSS, h_sum);
|
||||
OK(b);
|
||||
}
|
||||
21
app/src/ac/svc/ACQ_DUPSCAN.h
Normal file
21
app/src/ac/svc/ACQ_DUPSCAN.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* ACQ_DUPSCAN.h - ac 서비스 ACQ_DUPSCAN 카피북 (copybook / record header).
|
||||
* 중복매입 스캔 레코드.
|
||||
* Request fields: T_BIZDATE
|
||||
* Response fields: T_COUNT(의심 그룹), T_ARG1(연루 건수), T_AMT1(연루 총액), T_RC
|
||||
*/
|
||||
#ifndef ACQ_DUPSCAN_H
|
||||
#define ACQ_DUPSCAN_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char biz_date[16];
|
||||
long dup_groups; /* (가맹점,금액) 중복 그룹 수 */
|
||||
long dup_rows;
|
||||
long dup_amount;
|
||||
} ac_dupscan_rec_t;
|
||||
|
||||
void ACQ_DUPSCAN(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_DUPSCAN_H */
|
||||
33
app/src/ac/svc/ACQ_DUPSCAN.pgc
Normal file
33
app/src/ac/svc/ACQ_DUPSCAN.pgc
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* ACQ_DUPSCAN.pgc - ac 모듈 서비스 ACQ_DUPSCAN (one service = one file).
|
||||
* 중복매입 스캔: 영업일 내 (가맹점, 금액) 조합이 2건 이상인 그룹을 부질의로
|
||||
* 찾아 의심 그룹 수와 중복 연루 총액을 보고한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_DUPSCAN.h"
|
||||
|
||||
void ACQ_DUPSCAN(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_groups = 0, h_rows = 0, h_amt = 0;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL SELECT count(*), coalesce(sum(dup_n), 0), coalesce(sum(dup_amt), 0)
|
||||
INTO :h_groups, :h_rows, :h_amt
|
||||
FROM (SELECT count(*) AS dup_n, sum(amount) AS dup_amt
|
||||
FROM purchase
|
||||
WHERE biz_date = :h_bizdate AND status NOT IN ('C', 'V')
|
||||
GROUP BY merchant_id, amount
|
||||
HAVING count(*) > 1) g;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_DUPSCAN FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_COUNT, h_groups); /* 의심 그룹 수 */
|
||||
setl(b, T_ARG1, h_rows); /* 연루 매입 건수 */
|
||||
setl(b, T_AMT1, h_amt); /* 연루 총액 */
|
||||
setl(b, T_RC, h_groups > 0 ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
21
app/src/ac/svc/ACQ_EDIRESEND.h
Normal file
21
app/src/ac/svc/ACQ_EDIRESEND.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* ACQ_EDIRESEND.h - ac 서비스 ACQ_EDIRESEND 카피북 (copybook / record header).
|
||||
* EDI 재전송 레코드.
|
||||
* Request fields: T_DOCNO(원본 문서번호)
|
||||
* Response fields: T_ID1(재전송 EDI ID), T_DOCNO(-R 문서번호), T_AMOUNT, T_RC
|
||||
*/
|
||||
#ifndef ACQ_EDIRESEND_H
|
||||
#define ACQ_EDIRESEND_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char doc_no[64]; /* 원본 문서번호 */
|
||||
char resend_doc[72]; /* -R 접미 재전송 문서번호 */
|
||||
long new_edi_id;
|
||||
long amount;
|
||||
} ac_ediresend_rec_t;
|
||||
|
||||
void ACQ_EDIRESEND(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_EDIRESEND_H */
|
||||
46
app/src/ac/svc/ACQ_EDIRESEND.pgc
Normal file
46
app/src/ac/svc/ACQ_EDIRESEND.pgc
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* ACQ_EDIRESEND.pgc - ac 모듈 서비스 ACQ_EDIRESEND (one service = one file).
|
||||
* EDI 재전송: 문서번호의 최신 EDI 원장을 찾아 재전송 사본(-R 접미 문서번호)
|
||||
* 을 발행한다. 이미 재전송본이면 다시 만들지 않는다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_EDIRESEND.h"
|
||||
|
||||
void ACQ_EDIRESEND(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
size_t dlen;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_new, h_amt = 0;
|
||||
char h_doc[64], h_redoc[72], h_merch[64], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_DOCNO, h_doc, sizeof(h_doc));
|
||||
if (h_doc[0] == 0) { setl(b, T_RC, 8); FAIL(b); }
|
||||
|
||||
/* 재전송본(-R 접미) 자체는 재전송 금지 */
|
||||
dlen = strlen(h_doc);
|
||||
if (dlen >= 2 && strcmp(h_doc + dlen - 2, "-R") == 0) { setl(b, T_RC, 2); FAIL(b); }
|
||||
|
||||
/* 최신 원본 EDI 행 조회 */
|
||||
EXEC SQL SELECT merchant_id, amount, to_char(biz_date, 'YYYY-MM-DD')
|
||||
INTO :h_merch, :h_amt, :h_bizdate
|
||||
FROM ac_edi WHERE doc_no = :h_doc
|
||||
ORDER BY edi_id DESC LIMIT 1;
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 4); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
snprintf(h_redoc, sizeof(h_redoc), "%s-R", h_doc);
|
||||
|
||||
EXEC SQL SELECT nextval('ac_edi_seq') INTO :h_new;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL INSERT INTO ac_edi (edi_id, merchant_id, doc_no, amount, biz_date)
|
||||
VALUES (:h_new, :h_merch, :h_redoc, :h_amt, :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_EDIRESEND FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
Bchg(b, T_DOCNO, 0, h_redoc, 0L);
|
||||
setl(b, T_ID1, h_new);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_FEEHIST.h
Normal file
22
app/src/ac/svc/ACQ_FEEHIST.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_FEEHIST.h - ac 서비스 ACQ_FEEHIST 카피북 (copybook / record header).
|
||||
* 수수료 조정 이력 집계 레코드.
|
||||
* Request fields: T_PURCHASE_ID
|
||||
* Response fields: T_COUNT, T_DELTA(순증감), T_AMT1(증액), T_AMT2(감액), T_RC
|
||||
*/
|
||||
#ifndef ACQ_FEEHIST_H
|
||||
#define ACQ_FEEHIST_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long purchase_id;
|
||||
long adj_count;
|
||||
long net_delta; /* 순증감 합계 */
|
||||
long up_sum; /* 증액분 */
|
||||
long down_sum; /* 감액분 */
|
||||
} ac_feehist_rec_t;
|
||||
|
||||
void ACQ_FEEHIST(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_FEEHIST_H */
|
||||
32
app/src/ac/svc/ACQ_FEEHIST.pgc
Normal file
32
app/src/ac/svc/ACQ_FEEHIST.pgc
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* ACQ_FEEHIST.pgc - ac 모듈 서비스 ACQ_FEEHIST (one service = one file).
|
||||
* 수수료 조정 이력 집계: 매입 건의 조정 건수, 순증감 합계, 증액분/감액분을
|
||||
* FILTER 집계로 한 번에 산출한다. 순증감이 0 이 아니면 T_RC=1 로 표시.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_FEEHIST.h"
|
||||
|
||||
void ACQ_FEEHIST(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pid, h_n = 0, h_net = 0, h_up = 0, h_dn = 0;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_pid = getl(b, T_PURCHASE_ID);
|
||||
|
||||
EXEC SQL SELECT count(*),
|
||||
coalesce(sum(delta), 0),
|
||||
coalesce(sum(delta) FILTER (WHERE delta > 0), 0),
|
||||
coalesce(sum(delta) FILTER (WHERE delta < 0), 0)
|
||||
INTO :h_n, :h_net, :h_up, :h_dn
|
||||
FROM ac_fee_adj WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_FEEHIST FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_COUNT, h_n);
|
||||
setl(b, T_DELTA, h_net); /* 순증감 */
|
||||
setl(b, T_AMT1, h_up); /* 증액 합계 */
|
||||
setl(b, T_AMT2, h_dn); /* 감액 합계(음수) */
|
||||
setl(b, T_RC, h_net != 0 ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_FEERECALC.h
Normal file
22
app/src/ac/svc/ACQ_FEERECALC.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_FEERECALC.h - ac 서비스 ACQ_FEERECALC 카피북 (copybook / record header).
|
||||
* 수수료 재산정 레코드.
|
||||
* Request fields: T_PURCHASE_ID, T_BIZDATE
|
||||
* Response fields: T_FEE(재산정 수수료), T_DELTA(차액), T_ADJ, T_RC
|
||||
*/
|
||||
#ifndef ACQ_FEERECALC_H
|
||||
#define ACQ_FEERECALC_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long purchase_id;
|
||||
char biz_date[16];
|
||||
long new_fee; /* 현행 MDR 재산정 수수료 */
|
||||
long delta; /* 기존 대비 차액 */
|
||||
long adj_id;
|
||||
} ac_feerecalc_rec_t;
|
||||
|
||||
void ACQ_FEERECALC(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_FEERECALC_H */
|
||||
44
app/src/ac/svc/ACQ_FEERECALC.pgc
Normal file
44
app/src/ac/svc/ACQ_FEERECALC.pgc
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* ACQ_FEERECALC.pgc - ac 모듈 서비스 ACQ_FEERECALC (one service = one file).
|
||||
* 수수료 재산정: 가맹점의 현행 MDR 로 수수료를 다시 계산해 기존 수수료와의
|
||||
* 차액이 있으면 조정 이력을 남기고 purchase 의 fee/net 을 보정한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_FEERECALC.h"
|
||||
|
||||
void ACQ_FEERECALC(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long bps = 0, newfee, delta, adj;
|
||||
char bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pid, h_amt = 0, h_fee = 0, h_newfee;
|
||||
char h_merch[64];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_pid = getl(b, T_PURCHASE_ID);
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
|
||||
EXEC SQL SELECT merchant_id, amount, fee INTO :h_merch, :h_amt, :h_fee
|
||||
FROM purchase WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
|
||||
if (acdb_merchant_mdr(h_merch, &bps) < 0) FAIL(b);
|
||||
newfee = acq_fee(h_amt, bps);
|
||||
delta = newfee - h_fee;
|
||||
|
||||
if (delta != 0) {
|
||||
adj = acdb_insert_fee_adj(h_pid, delta, "RECALC", bizdate);
|
||||
if (adj < 0) FAIL(b);
|
||||
h_newfee = newfee;
|
||||
EXEC SQL UPDATE purchase SET fee = :h_newfee, net = amount - :h_newfee, updated_at = now()
|
||||
WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_FEERECALC FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
setl(b, T_ADJ, adj);
|
||||
}
|
||||
|
||||
setl(b, T_FEE, newfee);
|
||||
setl(b, T_DELTA, delta);
|
||||
setl(b, T_RC, delta == 0 ? 1 : 0); /* 1=차액 없음 */
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_FEEWAIVE.h
Normal file
22
app/src/ac/svc/ACQ_FEEWAIVE.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_FEEWAIVE.h - ac 서비스 ACQ_FEEWAIVE 카피북 (copybook / record header).
|
||||
* 수수료 감면 레코드.
|
||||
* Request fields: T_PURCHASE_ID, T_ARG1(감면율 bps), T_BIZDATE
|
||||
* Response fields: T_AMT1(감면액), T_ADJ, T_RC
|
||||
*/
|
||||
#ifndef ACQ_FEEWAIVE_H
|
||||
#define ACQ_FEEWAIVE_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long purchase_id;
|
||||
long waive_bps; /* 감면율 (basis points) */
|
||||
char biz_date[16];
|
||||
long waive_amount; /* 감면액 */
|
||||
long adj_id;
|
||||
} ac_feewaive_rec_t;
|
||||
|
||||
void ACQ_FEEWAIVE(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_FEEWAIVE_H */
|
||||
43
app/src/ac/svc/ACQ_FEEWAIVE.pgc
Normal file
43
app/src/ac/svc/ACQ_FEEWAIVE.pgc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* ACQ_FEEWAIVE.pgc - ac 모듈 서비스 ACQ_FEEWAIVE (one service = one file).
|
||||
* 수수료 감면: 요청 감면율(bps)만큼 수수료를 깎아 가맹점 정산금에 돌려준다.
|
||||
* 음수 delta 조정 이력을 남기고 purchase 의 fee 차감 / net 증액을 반영.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_FEEWAIVE.h"
|
||||
|
||||
void ACQ_FEEWAIVE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long rate, waive, adj;
|
||||
char bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pid, h_fee = 0, h_w;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_pid = getl(b, T_PURCHASE_ID);
|
||||
rate = getl(b, T_ARG1); /* 감면율 bps (1~10000) */
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
if (rate < 1 || rate > 10000) { setl(b, T_RC, 9); FAIL(b); }
|
||||
|
||||
EXEC SQL SELECT fee INTO :h_fee FROM purchase
|
||||
WHERE purchase_id = :h_pid AND status NOT IN ('C', 'V');
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 5); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
waive = acq_fee(h_fee, rate); /* fee * rate / 10000 */
|
||||
if (waive <= 0) { setl(b, T_RC, 1); setl(b, T_AMT1, 0); OK(b); }
|
||||
|
||||
adj = acdb_insert_fee_adj(h_pid, -waive, "WAIVE", bizdate);
|
||||
if (adj < 0) FAIL(b);
|
||||
|
||||
h_w = waive;
|
||||
EXEC SQL UPDATE purchase SET fee = fee - :h_w, net = net + :h_w, updated_at = now()
|
||||
WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_FEEWAIVE FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_AMT1, waive);
|
||||
setl(b, T_ADJ, adj);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
24
app/src/ac/svc/ACQ_FXCONVERT.h
Normal file
24
app/src/ac/svc/ACQ_FXCONVERT.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* ACQ_FXCONVERT.h - ac 서비스 ACQ_FXCONVERT 카피북 (copybook / record header).
|
||||
* 통화 환산 등록 레코드.
|
||||
* Request fields: T_PURCHASE_ID, T_CCY, T_FX_AMT, T_ARG1(환율 bps), T_BIZDATE
|
||||
* Response fields: T_ID1(fx 원장 ID), T_AMOUNT(원화 환산액), T_RC
|
||||
*/
|
||||
#ifndef ACQ_FXCONVERT_H
|
||||
#define ACQ_FXCONVERT_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long purchase_id;
|
||||
char ccy[8];
|
||||
long fx_amount; /* 원통화 금액 */
|
||||
long rate_bps; /* 적용환율 */
|
||||
char biz_date[16];
|
||||
long fx_id;
|
||||
long krw_amount; /* 원화 환산액 */
|
||||
} ac_fxconvert_rec_t;
|
||||
|
||||
void ACQ_FXCONVERT(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_FXCONVERT_H */
|
||||
43
app/src/ac/svc/ACQ_FXCONVERT.pgc
Normal file
43
app/src/ac/svc/ACQ_FXCONVERT.pgc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* ACQ_FXCONVERT.pgc - ac 모듈 서비스 ACQ_FXCONVERT (one service = one file).
|
||||
* 통화 환산 등록: 해외매입의 원통화 금액에 적용환율(bps)을 곱해 원화를
|
||||
* 산출하고 ac_fx 원장에 기록, 매입 채널을 FOREIGN 으로 표시한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_FXCONVERT.h"
|
||||
|
||||
void ACQ_FXCONVERT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long krw;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_fxid, h_pid, h_fx, h_rate, h_krw;
|
||||
char h_ccy[8], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_pid = getl(b, T_PURCHASE_ID);
|
||||
h_fx = getl(b, T_FX_AMT);
|
||||
h_rate = getl(b, T_ARG1); /* 환율 bps: KRW = fx * rate / 10000 */
|
||||
gets_(b, T_CCY, h_ccy, sizeof(h_ccy));
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
if (h_fx <= 0 || h_rate <= 0 || h_ccy[0] == 0) { setl(b, T_RC, 3); FAIL(b); }
|
||||
|
||||
krw = (h_fx * h_rate) / 10000L;
|
||||
h_krw = krw;
|
||||
|
||||
EXEC SQL SELECT nextval('ac_fx_seq') INTO :h_fxid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL INSERT INTO ac_fx (fx_id, purchase_id, ccy, fx_amount, krw_amount, rate_bps, biz_date)
|
||||
VALUES (:h_fxid, :h_pid, :h_ccy, :h_fx, :h_krw, :h_rate, :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
/* 해외매입 채널 표시 (존재하는 매입에만 반영) */
|
||||
EXEC SQL UPDATE purchase SET channel = 'FOREIGN', updated_at = now()
|
||||
WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_FXCONVERT FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_ID1, h_fxid);
|
||||
setl(b, T_AMOUNT, krw);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_FXRATE.h
Normal file
22
app/src/ac/svc/ACQ_FXRATE.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_FXRATE.h - ac 서비스 ACQ_FXRATE 카피북 (copybook / record header).
|
||||
* 통화 적용환율 조회 레코드.
|
||||
* Request fields: T_CCY, T_BIZDATE
|
||||
* Response fields: T_ARG1(평균 bps), T_ARG2(최저), T_ARG3(최고), T_COUNT, T_RC
|
||||
*/
|
||||
#ifndef ACQ_FXRATE_H
|
||||
#define ACQ_FXRATE_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char ccy[8];
|
||||
char biz_date[16];
|
||||
long avg_bps; /* 평균환율 bps */
|
||||
long min_bps;
|
||||
long max_bps;
|
||||
} ac_fxrate_rec_t;
|
||||
|
||||
void ACQ_FXRATE(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_FXRATE_H */
|
||||
35
app/src/ac/svc/ACQ_FXRATE.pgc
Normal file
35
app/src/ac/svc/ACQ_FXRATE.pgc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* ACQ_FXRATE.pgc - ac 모듈 서비스 ACQ_FXRATE (one service = one file).
|
||||
* 통화 적용환율 조회: 해외매입 원장(ac_fx)에서 특정 통화의 최근 영업일
|
||||
* 평균/최저/최고 환율(bps)을 조회한다. 건수가 없으면 T_RC=1.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_FXRATE.h"
|
||||
|
||||
void ACQ_FXRATE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_n = 0, h_avg = 0, h_min = 0, h_max = 0;
|
||||
char h_ccy[8], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_CCY, h_ccy, sizeof(h_ccy));
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
if (h_ccy[0] == 0) { setl(b, T_RC, 8); FAIL(b); }
|
||||
|
||||
EXEC SQL SELECT count(*),
|
||||
coalesce(avg(rate_bps)::bigint, 0),
|
||||
coalesce(min(rate_bps), 0),
|
||||
coalesce(max(rate_bps), 0)
|
||||
INTO :h_n, :h_avg, :h_min, :h_max
|
||||
FROM ac_fx WHERE ccy = :h_ccy AND biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_FXRATE FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_ARG1, h_avg);
|
||||
setl(b, T_ARG2, h_min);
|
||||
setl(b, T_ARG3, h_max);
|
||||
setl(b, T_COUNT, h_n);
|
||||
setl(b, T_RC, h_n > 0 ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_HOLDQRY.h
Normal file
22
app/src/ac/svc/ACQ_HOLDQRY.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_HOLDQRY.h - ac 서비스 ACQ_HOLDQRY 카피북 (copybook / record header).
|
||||
* 보류 매입 조회 레코드.
|
||||
* Request fields: T_MERCHANT
|
||||
* Response fields: T_COUNT, T_GROSS, T_ID2/T_AMT4(occ 0..4), T_RC(1=보류 존재)
|
||||
*/
|
||||
#ifndef ACQ_HOLDQRY_H
|
||||
#define ACQ_HOLDQRY_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char merchant_id[64];
|
||||
long hold_count;
|
||||
long hold_total;
|
||||
long top_pids[5];
|
||||
long top_amounts[5];
|
||||
} ac_holdqry_rec_t;
|
||||
|
||||
void ACQ_HOLDQRY(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_HOLDQRY_H */
|
||||
43
app/src/ac/svc/ACQ_HOLDQRY.pgc
Normal file
43
app/src/ac/svc/ACQ_HOLDQRY.pgc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* ACQ_HOLDQRY.pgc - ac 모듈 서비스 ACQ_HOLDQRY (one service = one file).
|
||||
* 보류 매입 조회: 가맹점의 보류(H) 건을 최근 갱신순 커서로 훑어 건수·총액을
|
||||
* 집계하고 상위 5건의 매입 ID/금액을 occurrence 로 내려준다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_HOLDQRY.h"
|
||||
|
||||
void ACQ_HOLDQRY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long cnt = 0, total = 0, top = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pid, h_amt;
|
||||
char h_merch[64];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_MERCHANT, h_merch, sizeof(h_merch));
|
||||
|
||||
EXEC SQL DECLARE hlq_cur CURSOR FOR
|
||||
SELECT purchase_id, amount FROM purchase
|
||||
WHERE merchant_id = :h_merch AND status = 'H'
|
||||
ORDER BY updated_at DESC;
|
||||
EXEC SQL OPEN hlq_cur;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH hlq_cur INTO :h_pid, :h_amt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE hlq_cur; FAIL(b); }
|
||||
cnt++; total += h_amt;
|
||||
if (top < 5) {
|
||||
Badd(b, T_ID2, (char *)&h_pid, 0L);
|
||||
Badd(b, T_AMT4, (char *)&h_amt, 0L);
|
||||
top++;
|
||||
}
|
||||
}
|
||||
EXEC SQL CLOSE hlq_cur;
|
||||
|
||||
setl(b, T_COUNT, cnt);
|
||||
setl(b, T_GROSS, total);
|
||||
setl(b, T_RC, cnt > 0 ? 1 : 0); /* 1=보류 존재 */
|
||||
OK(b);
|
||||
}
|
||||
23
app/src/ac/svc/ACQ_ISSSTAT.h
Normal file
23
app/src/ac/svc/ACQ_ISSSTAT.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* ACQ_ISSSTAT.h - ac 서비스 ACQ_ISSSTAT 카피북 (copybook / record header).
|
||||
* 매입 발급사별 통계 레코드.
|
||||
* Request fields: T_BIZDATE
|
||||
* Response fields: T_ISSUER(1위), T_COUNT, T_GROSS, T_ARG1(발급사 수), T_ARG2(점유율 bps)
|
||||
*/
|
||||
#ifndef ACQ_ISSSTAT_H
|
||||
#define ACQ_ISSSTAT_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char biz_date[16];
|
||||
char top_issuer[32];
|
||||
long top_count;
|
||||
long top_sum;
|
||||
long issuer_kinds;
|
||||
long share_bps; /* 1위 점유율 */
|
||||
} ac_issstat_rec_t;
|
||||
|
||||
void ACQ_ISSSTAT(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_ISSSTAT_H */
|
||||
44
app/src/ac/svc/ACQ_ISSSTAT.pgc
Normal file
44
app/src/ac/svc/ACQ_ISSSTAT.pgc
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* ACQ_ISSSTAT.pgc - ac 모듈 서비스 ACQ_ISSSTAT (one service = one file).
|
||||
* 매입 발급사별 통계: 영업일 발급사 그룹 집계에서 1위 발급사(건수·총액)와
|
||||
* 전체 발급사 수, 1위의 점유율(bps)을 계산해 응답한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_ISSSTAT.h"
|
||||
|
||||
void ACQ_ISSSTAT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long share_bps = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_topcnt = 0, h_topsum = 0, h_kinds = 0, h_total = 0;
|
||||
char h_top[32], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_top[0] = 0;
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
/* 전체 발급사 수 + 총액 */
|
||||
EXEC SQL SELECT count(DISTINCT issuer), coalesce(sum(amount), 0)
|
||||
INTO :h_kinds, :h_total
|
||||
FROM purchase WHERE biz_date = :h_bizdate AND status <> 'C';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
/* 1위 발급사 */
|
||||
EXEC SQL SELECT issuer, count(*), sum(amount)
|
||||
INTO :h_top, :h_topcnt, :h_topsum
|
||||
FROM purchase WHERE biz_date = :h_bizdate AND status <> 'C'
|
||||
GROUP BY issuer ORDER BY sum(amount) DESC, issuer LIMIT 1;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_ISSSTAT FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 1); OK(b); }
|
||||
|
||||
if (h_total > 0) share_bps = (h_topsum * 10000) / h_total;
|
||||
|
||||
Bchg(b, T_ISSUER, 0, h_top, 0L);
|
||||
setl(b, T_COUNT, h_topcnt);
|
||||
setl(b, T_GROSS, h_topsum);
|
||||
setl(b, T_ARG1, h_kinds);
|
||||
setl(b, T_ARG2, share_bps); /* 1위 점유율 bps */
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
23
app/src/ac/svc/ACQ_LIMITUSAGE.h
Normal file
23
app/src/ac/svc/ACQ_LIMITUSAGE.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* ACQ_LIMITUSAGE.h - ac 서비스 ACQ_LIMITUSAGE 카피북 (copybook / record header).
|
||||
* 가맹점 한도소진 조회 레코드.
|
||||
* Request fields: T_MERCHANT, T_BIZDATE
|
||||
* Response fields: T_AMT1(사용액), T_AMT2(한도), T_AMT3(잔여), T_ARG1(소진율 bps), T_RC
|
||||
*/
|
||||
#ifndef ACQ_LIMITUSAGE_H
|
||||
#define ACQ_LIMITUSAGE_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char merchant_id[64];
|
||||
char biz_date[16];
|
||||
long used; /* 당일 사용액 */
|
||||
long limit; /* 일한도 */
|
||||
long remain; /* 잔여 한도 */
|
||||
long usage_bps; /* 소진율 (basis points) */
|
||||
} ac_limitusage_rec_t;
|
||||
|
||||
void ACQ_LIMITUSAGE(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_LIMITUSAGE_H */
|
||||
37
app/src/ac/svc/ACQ_LIMITUSAGE.pgc
Normal file
37
app/src/ac/svc/ACQ_LIMITUSAGE.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* ACQ_LIMITUSAGE.pgc - ac 모듈 서비스 ACQ_LIMITUSAGE (one service = one file).
|
||||
* 가맹점 한도소진 조회: 영업일 유효 매입(취소/무효 제외) 합계를 일한도와
|
||||
* 비교해 사용액/잔여액/소진율(bps)을 산출한다. 90% 초과 시 경보 표시.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_LIMITUSAGE.h"
|
||||
|
||||
void ACQ_LIMITUSAGE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long pct_bps;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_limit = 0, h_used = 0;
|
||||
char h_merch[64], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_MERCHANT, h_merch, sizeof(h_merch));
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL SELECT daily_limit INTO :h_limit FROM merchant WHERE merchant_id = :h_merch;
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 5); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
EXEC SQL SELECT coalesce(sum(amount), 0) INTO :h_used FROM purchase
|
||||
WHERE merchant_id = :h_merch AND biz_date = :h_bizdate AND status NOT IN ('C', 'V');
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_LIMITUSAGE FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
pct_bps = (h_limit > 0) ? (h_used * 10000) / h_limit : 10000;
|
||||
|
||||
setl(b, T_AMT1, h_used);
|
||||
setl(b, T_AMT2, h_limit);
|
||||
setl(b, T_AMT3, h_limit > h_used ? h_limit - h_used : 0); /* 잔여 한도 */
|
||||
setl(b, T_ARG1, pct_bps);
|
||||
setl(b, T_RC, pct_bps > 9000 ? 1 : 0); /* 90% 초과 경보 */
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_MONSTAT.h
Normal file
22
app/src/ac/svc/ACQ_MONSTAT.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_MONSTAT.h - ac 서비스 ACQ_MONSTAT 카피북 (copybook / record header).
|
||||
* 매입 월간 통계 레코드.
|
||||
* Request fields: T_BIZDATE(월 기준일)
|
||||
* Response fields: T_COUNT, T_GROSS, T_AMT1(평균), T_ARG1(영업일수), T_RC
|
||||
*/
|
||||
#ifndef ACQ_MONSTAT_H
|
||||
#define ACQ_MONSTAT_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char base_date[16];
|
||||
long mon_count;
|
||||
long mon_gross;
|
||||
long mon_avg; /* 평균 거래액 */
|
||||
long biz_days; /* 거래 발생 영업일수 */
|
||||
} ac_monstat_rec_t;
|
||||
|
||||
void ACQ_MONSTAT(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_MONSTAT_H */
|
||||
35
app/src/ac/svc/ACQ_MONSTAT.pgc
Normal file
35
app/src/ac/svc/ACQ_MONSTAT.pgc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* ACQ_MONSTAT.pgc - ac 모듈 서비스 ACQ_MONSTAT (one service = one file).
|
||||
* 매입 월간 통계: 기준일이 속한 달 전체의 건수/총액/평균 거래액과 영업일수
|
||||
* (거래 발생일 기준)를 date_trunc 월 경계로 집계한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_MONSTAT.h"
|
||||
|
||||
void ACQ_MONSTAT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt = 0, h_amt = 0, h_avg = 0, h_days = 0;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL SELECT count(*),
|
||||
coalesce(sum(amount), 0),
|
||||
coalesce(avg(amount)::bigint, 0),
|
||||
count(DISTINCT biz_date)
|
||||
INTO :h_cnt, :h_amt, :h_avg, :h_days
|
||||
FROM purchase
|
||||
WHERE date_trunc('month', biz_date) = date_trunc('month', CAST(:h_bizdate AS date))
|
||||
AND status NOT IN ('C', 'V');
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_MONSTAT FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_amt);
|
||||
setl(b, T_AMT1, h_avg); /* 평균 거래액 */
|
||||
setl(b, T_ARG1, h_days); /* 거래 발생 영업일수 */
|
||||
setl(b, T_RC, h_cnt > 0 ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
21
app/src/ac/svc/ACQ_NETCALC.h
Normal file
21
app/src/ac/svc/ACQ_NETCALC.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* ACQ_NETCALC.h - ac 서비스 ACQ_NETCALC 카피북 (copybook / record header).
|
||||
* 정산금 재계산 레코드.
|
||||
* Request fields: T_PURCHASE_ID
|
||||
* Response fields: T_NET(재계산 정산금), T_TAX(원천세 누계), T_DELTA, T_RC
|
||||
*/
|
||||
#ifndef ACQ_NETCALC_H
|
||||
#define ACQ_NETCALC_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long purchase_id;
|
||||
long new_net; /* amount - fee - 원천세 */
|
||||
long wht_sum;
|
||||
long delta; /* 기존 net 대비 변경분 */
|
||||
} ac_netcalc_rec_t;
|
||||
|
||||
void ACQ_NETCALC(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_NETCALC_H */
|
||||
46
app/src/ac/svc/ACQ_NETCALC.pgc
Normal file
46
app/src/ac/svc/ACQ_NETCALC.pgc
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* ACQ_NETCALC.pgc - ac 모듈 서비스 ACQ_NETCALC (one service = one file).
|
||||
* 정산금 재계산: 매입금액에서 수수료와 원천세 누계를 차감한 실정산금을
|
||||
* 다시 구해 purchase.net 을 보정한다. 변경 없으면 T_RC=1.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_NETCALC.h"
|
||||
|
||||
void ACQ_NETCALC(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long newnet;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pid, h_amt = 0, h_fee = 0, h_oldnet = 0, h_wht = 0, h_newnet;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_pid = getl(b, T_PURCHASE_ID);
|
||||
|
||||
EXEC SQL SELECT amount, fee, net INTO :h_amt, :h_fee, :h_oldnet
|
||||
FROM purchase WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 5); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
/* 원천세 누계 반영 */
|
||||
EXEC SQL SELECT coalesce(sum(tax_amount), 0) INTO :h_wht
|
||||
FROM ac_wht WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
newnet = h_amt - h_fee - h_wht;
|
||||
if (newnet == h_oldnet) {
|
||||
setl(b, T_NET, newnet);
|
||||
setl(b, T_RC, 1); /* 이미 정합 */
|
||||
OK(b);
|
||||
}
|
||||
|
||||
h_newnet = newnet;
|
||||
EXEC SQL UPDATE purchase SET net = :h_newnet, updated_at = now()
|
||||
WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_NETCALC FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_NET, newnet);
|
||||
setl(b, T_TAX, h_wht);
|
||||
setl(b, T_DELTA, newnet - h_oldnet);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
23
app/src/ac/svc/ACQ_NOINTSHARE.h
Normal file
23
app/src/ac/svc/ACQ_NOINTSHARE.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* ACQ_NOINTSHARE.h - ac 서비스 ACQ_NOINTSHARE 카피북 (copybook / record header).
|
||||
* 무이자 할부 분담금 레코드.
|
||||
* Request fields: T_PURCHASE_ID, T_BIZDATE
|
||||
* Response fields: T_AMT1(분담금), T_INSTALL_N, T_ISSUER, T_ADJ, T_RC
|
||||
*/
|
||||
#ifndef ACQ_NOINTSHARE_H
|
||||
#define ACQ_NOINTSHARE_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long purchase_id;
|
||||
char biz_date[16];
|
||||
long share; /* 발급사 분담금 (months*15bps) */
|
||||
long months; /* 할부 개월수 */
|
||||
char issuer[32];
|
||||
long adj_id;
|
||||
} ac_nointshare_rec_t;
|
||||
|
||||
void ACQ_NOINTSHARE(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_NOINTSHARE_H */
|
||||
44
app/src/ac/svc/ACQ_NOINTSHARE.pgc
Normal file
44
app/src/ac/svc/ACQ_NOINTSHARE.pgc
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* ACQ_NOINTSHARE.pgc - ac 모듈 서비스 ACQ_NOINTSHARE (one service = one file).
|
||||
* 무이자 할부 분담금 산정: 할부 매입의 개월수에 월당 15bps 를 곱한 발급사
|
||||
* 분담률로 분담금을 계산해 수수료 조정(NOINT)으로 반영한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_NOINTSHARE.h"
|
||||
|
||||
#define AC_NOINT_BPS_PER_MONTH 15L /* 발급사 분담률: 월당 15bps */
|
||||
|
||||
void ACQ_NOINTSHARE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long share, adj;
|
||||
char bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pid, h_months = 0, h_amt = 0;
|
||||
char h_issuer[32];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_pid = getl(b, T_PURCHASE_ID);
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
|
||||
/* 할부 스케줄에서 개월수 확인 (스케줄 없으면 무이자 대상 아님) */
|
||||
EXEC SQL SELECT coalesce(max(months), 0) INTO :h_months
|
||||
FROM ac_install WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_months < 2) { setl(b, T_RC, 4); FAIL(b); }
|
||||
|
||||
EXEC SQL SELECT amount, issuer INTO :h_amt, :h_issuer
|
||||
FROM purchase WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
|
||||
share = acq_fee(h_amt, h_months * AC_NOINT_BPS_PER_MONTH);
|
||||
adj = acdb_insert_fee_adj(h_pid, -share, "NOINT", bizdate);
|
||||
if (adj < 0) { userlog("ACQ_NOINTSHARE adj FAIL pid=%ld", h_pid); FAIL(b); }
|
||||
|
||||
Bchg(b, T_ISSUER, 0, h_issuer, 0L);
|
||||
setl(b, T_AMT1, share); /* 발급사 분담금 */
|
||||
setl(b, T_INSTALL_N, h_months);
|
||||
setl(b, T_ADJ, adj);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
23
app/src/ac/svc/ACQ_PARTCXL.h
Normal file
23
app/src/ac/svc/ACQ_PARTCXL.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* ACQ_PARTCXL.h - ac 서비스 ACQ_PARTCXL 카피북 (copybook / record header).
|
||||
* 부분취소 레코드.
|
||||
* Request fields: T_PURCHASE_ID, T_AMOUNT(취소액), T_BIZDATE
|
||||
* Response fields: T_CANCEL_ID, T_AMT1(잔여금액), T_FEE(환급 수수료), T_RC
|
||||
*/
|
||||
#ifndef ACQ_PARTCXL_H
|
||||
#define ACQ_PARTCXL_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long purchase_id;
|
||||
long cancel_amount; /* 부분취소액 */
|
||||
char biz_date[16];
|
||||
long cancel_id;
|
||||
long remain_amount; /* 잔여 매입금액 */
|
||||
long fee_back; /* 비례 환급 수수료 */
|
||||
} ac_partcxl_rec_t;
|
||||
|
||||
void ACQ_PARTCXL(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_PARTCXL_H */
|
||||
51
app/src/ac/svc/ACQ_PARTCXL.pgc
Normal file
51
app/src/ac/svc/ACQ_PARTCXL.pgc
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* ACQ_PARTCXL.pgc - ac 모듈 서비스 ACQ_PARTCXL (one service = one file).
|
||||
* 부분취소: 취소액이 잔여 매입금액 미만인 경우에만 허용. 수수료를 비례
|
||||
* 배분해 환급하고 purchase 잔액(amount/fee/net)을 차감, PARTIAL 취소행 생성.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_PARTCXL.h"
|
||||
|
||||
void ACQ_PARTCXL(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long feeback;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_pid, h_cxl, h_amt = 0, h_fee = 0, h_fb;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_pid = getl(b, T_PURCHASE_ID);
|
||||
h_cxl = getl(b, T_AMOUNT);
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL SELECT amount, fee INTO :h_amt, :h_fee FROM purchase
|
||||
WHERE purchase_id = :h_pid AND status IN ('A', 'M');
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 5); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_cxl <= 0 || h_cxl >= h_amt) { setl(b, T_RC, 3); FAIL(b); }
|
||||
|
||||
/* 수수료 비례 환급분: fee * 취소액 / 원금액 */
|
||||
feeback = (h_fee * h_cxl) / h_amt;
|
||||
h_fb = feeback;
|
||||
|
||||
EXEC SQL SELECT nextval('ac_cancel_seq') INTO :h_cid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL INSERT INTO ac_cancel (cancel_id, purchase_id, cancel_type, amount, reason, biz_date)
|
||||
VALUES (:h_cid, :h_pid, 'PARTIAL', :h_cxl, 'PARTCXL', :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
EXEC SQL UPDATE purchase
|
||||
SET amount = amount - :h_cxl,
|
||||
fee = fee - :h_fb,
|
||||
net = net - (:h_cxl - :h_fb),
|
||||
updated_at = now()
|
||||
WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_PARTCXL FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_CANCEL_ID, h_cid);
|
||||
setl(b, T_AMT1, h_amt - h_cxl); /* 잔여 매입금액 */
|
||||
setl(b, T_FEE, feeback);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_PARTRFND.h
Normal file
22
app/src/ac/svc/ACQ_PARTRFND.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_PARTRFND.h - ac 서비스 ACQ_PARTRFND 카피북 (copybook / record header).
|
||||
* 부분환불 레코드.
|
||||
* Request fields: T_PURCHASE_ID, T_AMOUNT(환불 요청액), T_BIZDATE
|
||||
* Response fields: T_CANCEL_ID, T_AMT2(환불 누계), T_RC(6=한도초과)
|
||||
*/
|
||||
#ifndef ACQ_PARTRFND_H
|
||||
#define ACQ_PARTRFND_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long purchase_id;
|
||||
long refund_amount; /* 이번 환불 요청액 */
|
||||
char biz_date[16];
|
||||
long cancel_id;
|
||||
long refund_accum; /* 환불 누계 */
|
||||
} ac_partrfnd_rec_t;
|
||||
|
||||
void ACQ_PARTRFND(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_PARTRFND_H */
|
||||
44
app/src/ac/svc/ACQ_PARTRFND.pgc
Normal file
44
app/src/ac/svc/ACQ_PARTRFND.pgc
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* ACQ_PARTRFND.pgc - ac 모듈 서비스 ACQ_PARTRFND (one service = one file).
|
||||
* 부분환불: 기존 환불 누계 + 요청액이 매입금액을 넘지 않도록 검증하고
|
||||
* REFUND 취소행과 음수 원장 분개(PARTRFND)를 함께 기록한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_PARTRFND.h"
|
||||
|
||||
void ACQ_PARTRFND(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_pid, h_req, h_orig = 0, h_prev = 0;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_pid = getl(b, T_PURCHASE_ID);
|
||||
h_req = getl(b, T_AMOUNT);
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
EXEC SQL SELECT amount INTO :h_orig FROM purchase WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
|
||||
/* 환불 누계 검증: 이미 환불된 합계 + 이번 요청액 <= 매입금액 */
|
||||
EXEC SQL SELECT coalesce(sum(amount), 0) INTO :h_prev FROM ac_cancel
|
||||
WHERE purchase_id = :h_pid AND cancel_type = 'REFUND';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_req <= 0 || h_prev + h_req > h_orig) { setl(b, T_RC, 6); FAIL(b); }
|
||||
|
||||
EXEC SQL SELECT nextval('ac_cancel_seq') INTO :h_cid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL INSERT INTO ac_cancel (cancel_id, purchase_id, cancel_type, amount, reason, biz_date)
|
||||
VALUES (:h_cid, :h_pid, 'REFUND', :h_req, 'PARTRFND', :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
if (acdb_insert_ledger(h_pid, "PARTRFND", -h_req, bizdate) < 0) FAIL(b);
|
||||
|
||||
setl(b, T_CANCEL_ID, h_cid);
|
||||
setl(b, T_AMT2, h_prev + h_req); /* 환불 누계 */
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_PROMO.h
Normal file
22
app/src/ac/svc/ACQ_PROMO.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_PROMO.h - ac 서비스 ACQ_PROMO 카피북 (copybook / record header).
|
||||
* 프로모션 매입 등록 레코드.
|
||||
* Request fields: T_MERCHANT, T_AMOUNT, T_STR1(행사코드 PRM-*), T_BIZDATE
|
||||
* Response fields: T_PURCHASE_ID, T_NET(전액), T_RC(7=행사코드 오류)
|
||||
*/
|
||||
#ifndef ACQ_PROMO_H
|
||||
#define ACQ_PROMO_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char merchant_id[64];
|
||||
long amount;
|
||||
char promo_code[32]; /* PRM- 접두 행사코드 */
|
||||
char biz_date[16];
|
||||
long purchase_id;
|
||||
} ac_promo_rec_t;
|
||||
|
||||
void ACQ_PROMO(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_PROMO_H */
|
||||
42
app/src/ac/svc/ACQ_PROMO.pgc
Normal file
42
app/src/ac/svc/ACQ_PROMO.pgc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* ACQ_PROMO.pgc - ac 모듈 서비스 ACQ_PROMO (one service = one file).
|
||||
* 프로모션 매입 등록: 행사 코드가 유효하면 수수료 0 의 프로모션 매입을
|
||||
* 생성한다(분류 PROMO). 정산금 전액 지급, 원장에 행사 분개를 남긴다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_PROMO.h"
|
||||
|
||||
void ACQ_PROMO(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char promo[32], bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pid, h_amt;
|
||||
char h_merch[64], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_amt = getl(b, T_AMOUNT);
|
||||
gets_(b, T_MERCHANT, h_merch, sizeof(h_merch));
|
||||
gets_(b, T_STR1, promo, sizeof(promo));
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
/* 행사 코드 형식 검증: PRM- 접두 필수 */
|
||||
if (strncmp(promo, "PRM-", 4) != 0) { setl(b, T_RC, 7); FAIL(b); }
|
||||
if (h_amt <= 0) { setl(b, T_RC, 3); FAIL(b); }
|
||||
|
||||
EXEC SQL SELECT nextval('purchase_seq') INTO :h_pid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
/* 수수료 면제: fee 0, net 전액, 분류 PROMO */
|
||||
EXEC SQL INSERT INTO purchase (purchase_id, merchant_id, amount, fee, net, status, biz_date, channel, category)
|
||||
VALUES (:h_pid, :h_merch, :h_amt, 0, :h_amt, 'A', :h_bizdate, 'POS', 'PROMO');
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_PROMO FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
if (acdb_insert_ledger(h_pid, "PROMO", h_amt, bizdate) < 0) FAIL(b);
|
||||
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_NET, h_amt);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_REBUY.h
Normal file
22
app/src/ac/svc/ACQ_REBUY.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_REBUY.h - ac 서비스 ACQ_REBUY 카피북 (copybook / record header).
|
||||
* 재매입 생성 레코드.
|
||||
* Request fields: T_PURCHASE_ID(취소된 원매입), T_BIZDATE
|
||||
* Response fields: T_ID1(신규 매입 ID), T_FEE, T_NET
|
||||
*/
|
||||
#ifndef ACQ_REBUY_H
|
||||
#define ACQ_REBUY_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long orig_purchase_id; /* 취소 원매입 */
|
||||
char biz_date[16];
|
||||
long new_purchase_id; /* 재매입 신규 ID */
|
||||
long fee; /* 현행 MDR 재산출 수수료 */
|
||||
long net;
|
||||
} ac_rebuy_rec_t;
|
||||
|
||||
void ACQ_REBUY(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_REBUY_H */
|
||||
42
app/src/ac/svc/ACQ_REBUY.pgc
Normal file
42
app/src/ac/svc/ACQ_REBUY.pgc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* ACQ_REBUY.pgc - ac 모듈 서비스 ACQ_REBUY (one service = one file).
|
||||
* 재매입: 취소(C)된 원매입의 가맹점/금액/채널을 승계해 신규 매입을 생성하고
|
||||
* 현재 MDR 로 수수료를 재산출, 원장에 REBUY 연결 분개를 남긴다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_REBUY.h"
|
||||
|
||||
void ACQ_REBUY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long newpid, fee, net, bps = 0;
|
||||
char bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pid, h_amt = 0;
|
||||
char h_merch[64], h_chan[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_pid = getl(b, T_PURCHASE_ID);
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
|
||||
/* 취소 상태의 원매입만 재매입 대상 */
|
||||
EXEC SQL SELECT merchant_id, amount, channel INTO :h_merch, :h_amt, :h_chan
|
||||
FROM purchase WHERE purchase_id = :h_pid AND status = 'C';
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 5); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
if (acdb_merchant_mdr(h_merch, &bps) < 0) FAIL(b);
|
||||
fee = acq_fee(h_amt, bps);
|
||||
net = h_amt - fee;
|
||||
|
||||
newpid = acdb_next_purchase_id();
|
||||
if (newpid < 0) FAIL(b);
|
||||
if (acdb_insert_purchase(newpid, h_merch, h_amt, fee, net, "A", h_chan, bizdate) < 0) FAIL(b);
|
||||
/* 원매입 → 신매입 연결 분개 */
|
||||
if (acdb_insert_ledger(h_pid, "REBUY", h_amt, bizdate) < 0) FAIL(b);
|
||||
|
||||
setl(b, T_ID1, newpid);
|
||||
setl(b, T_FEE, fee);
|
||||
setl(b, T_NET, net);
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/ac/svc/ACQ_REMATCH.h
Normal file
20
app/src/ac/svc/ACQ_REMATCH.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* ACQ_REMATCH.h - ac 서비스 ACQ_REMATCH 카피북 (copybook / record header).
|
||||
* 승인미매칭 재처리 레코드.
|
||||
* Request fields: T_PURCHASE_ID
|
||||
* Response fields: T_ARG1(해소 미매입 수), T_ARG2(전이 건수), T_MSG, T_RC
|
||||
*/
|
||||
#ifndef ACQ_REMATCH_H
|
||||
#define ACQ_REMATCH_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long purchase_id;
|
||||
long resolved; /* 해소된 미매입 행 수 */
|
||||
long promoted; /* A→M 전이 건수 */
|
||||
} ac_rematch_rec_t;
|
||||
|
||||
void ACQ_REMATCH(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_REMATCH_H */
|
||||
43
app/src/ac/svc/ACQ_REMATCH.pgc
Normal file
43
app/src/ac/svc/ACQ_REMATCH.pgc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* ACQ_REMATCH.pgc - ac 모듈 서비스 ACQ_REMATCH (one service = one file).
|
||||
* 승인미매칭 재처리: 미매입 원장에 남은 건에 유효 승인이 도착했는지 다시
|
||||
* 확인하고, 승인이 있으면 미매입 행을 걷어내며 매입을 대사완료로 올린다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_REMATCH.h"
|
||||
|
||||
void ACQ_REMATCH(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pid, h_appr = 0, h_gone, h_up;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_pid = getl(b, T_PURCHASE_ID);
|
||||
|
||||
/* 유효 승인 존재 여부 재확인 */
|
||||
EXEC SQL SELECT count(*) INTO :h_appr FROM approval
|
||||
WHERE purchase_id = :h_pid AND approved = true;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
if (h_appr == 0) {
|
||||
Bchg(b, T_MSG, 0, "NO-APPROVAL", 0L);
|
||||
setl(b, T_RC, 1);
|
||||
OK(b); /* 승인 미도착: 미매입 유지 */
|
||||
}
|
||||
|
||||
EXEC SQL DELETE FROM ac_unmatch
|
||||
WHERE purchase_id = :h_pid AND reason NOT LIKE 'CLAIM:%';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
h_gone = sqlca.sqlerrd[2];
|
||||
|
||||
EXEC SQL UPDATE purchase SET status = 'M', updated_at = now()
|
||||
WHERE purchase_id = :h_pid AND status = 'A';
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_REMATCH FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
h_up = sqlca.sqlerrd[2];
|
||||
|
||||
setl(b, T_ARG1, h_gone); /* 해소된 미매입 행 수 */
|
||||
setl(b, T_ARG2, h_up); /* 상태 전이 건수 */
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_RESERVE.h
Normal file
22
app/src/ac/svc/ACQ_RESERVE.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_RESERVE.h - ac 서비스 ACQ_RESERVE 카피북 (copybook / record header).
|
||||
* 매입 예약 레코드.
|
||||
* Request fields: T_MERCHANT, T_AMOUNT, T_BIZDATE(예약일)
|
||||
* Response fields: T_PURCHASE_ID(예약 ID), T_FEE, T_RC(6=비활성 가맹점)
|
||||
*/
|
||||
#ifndef ACQ_RESERVE_H
|
||||
#define ACQ_RESERVE_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char merchant_id[64];
|
||||
long amount;
|
||||
char rsv_date[16]; /* 예약 영업일 */
|
||||
long purchase_id; /* 예약 매입 ID (status P) */
|
||||
long fee; /* 선산출 수수료 */
|
||||
} ac_reserve_rec_t;
|
||||
|
||||
void ACQ_RESERVE(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_RESERVE_H */
|
||||
41
app/src/ac/svc/ACQ_RESERVE.pgc
Normal file
41
app/src/ac/svc/ACQ_RESERVE.pgc
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* ACQ_RESERVE.pgc - ac 모듈 서비스 ACQ_RESERVE (one service = one file).
|
||||
* 매입 예약: 활성(ACTIVE) 가맹점에 대해 미래 영업일 예약 매입(status P)을
|
||||
* 만들어 둔다. 수수료는 현행 MDR 로 선산출하고 예약 채널(RSV)로 표시.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_RESERVE.h"
|
||||
|
||||
void ACQ_RESERVE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pid, h_amt, h_fee, h_net, h_bps = 0;
|
||||
char h_merch[64], h_mst[16], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_amt = getl(b, T_AMOUNT);
|
||||
gets_(b, T_MERCHANT, h_merch, sizeof(h_merch));
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
if (h_amt <= 0) { setl(b, T_RC, 3); FAIL(b); }
|
||||
|
||||
/* 활성 가맹점만 예약 허용 + MDR 동시 조회 */
|
||||
EXEC SQL SELECT status, mdr_bps INTO :h_mst, :h_bps FROM merchant WHERE merchant_id = :h_merch;
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 5); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (strcmp(h_mst, "ACTIVE") != 0) { setl(b, T_RC, 6); FAIL(b); }
|
||||
|
||||
h_fee = acq_fee(h_amt, h_bps);
|
||||
h_net = h_amt - h_fee;
|
||||
|
||||
EXEC SQL SELECT nextval('purchase_seq') INTO :h_pid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL INSERT INTO purchase (purchase_id, merchant_id, amount, fee, net, status, biz_date, channel)
|
||||
VALUES (:h_pid, :h_merch, :h_amt, :h_fee, :h_net, 'P', :h_bizdate, 'RSV');
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_RESERVE FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_FEE, h_fee);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
19
app/src/ac/svc/ACQ_RESERVECXL.h
Normal file
19
app/src/ac/svc/ACQ_RESERVECXL.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* ACQ_RESERVECXL.h - ac 서비스 ACQ_RESERVECXL 카피북 (copybook / record header).
|
||||
* 매입 예약취소 레코드.
|
||||
* Request fields: T_PURCHASE_ID(예약 ID)
|
||||
* Response fields: T_AMOUNT(취소된 예약 금액), T_RC(4=예약 아님)
|
||||
*/
|
||||
#ifndef ACQ_RESERVECXL_H
|
||||
#define ACQ_RESERVECXL_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long purchase_id; /* 예약(P) 매입 ID */
|
||||
long amount; /* 취소된 예약 금액 */
|
||||
} ac_reservecxl_rec_t;
|
||||
|
||||
void ACQ_RESERVECXL(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_RESERVECXL_H */
|
||||
31
app/src/ac/svc/ACQ_RESERVECXL.pgc
Normal file
31
app/src/ac/svc/ACQ_RESERVECXL.pgc
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* ACQ_RESERVECXL.pgc - ac 모듈 서비스 ACQ_RESERVECXL (one service = one file).
|
||||
* 매입 예약취소: 아직 접수 전환되지 않은 예약(P) 건만 물리 삭제한다.
|
||||
* 취소 전 예약 금액을 확보해 응답에 돌려주고 감사 로그를 남긴다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_RESERVECXL.h"
|
||||
|
||||
void ACQ_RESERVECXL(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pid, h_amt = 0, h_del;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_pid = getl(b, T_PURCHASE_ID);
|
||||
|
||||
EXEC SQL SELECT amount INTO :h_amt FROM purchase
|
||||
WHERE purchase_id = :h_pid AND status = 'P';
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 4); FAIL(b); } /* 예약 아님/전환됨 */
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
EXEC SQL DELETE FROM purchase WHERE purchase_id = :h_pid AND status = 'P';
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_RESERVECXL FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
h_del = sqlca.sqlerrd[2];
|
||||
|
||||
userlog("ACQ_RESERVECXL: pid=%ld amount=%ld deleted=%ld", h_pid, h_amt, h_del);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
setl(b, T_RC, h_del > 0 ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
21
app/src/ac/svc/ACQ_RESERVEQRY.h
Normal file
21
app/src/ac/svc/ACQ_RESERVEQRY.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* ACQ_RESERVEQRY.h - ac 서비스 ACQ_RESERVEQRY 카피북 (copybook / record header).
|
||||
* 매입 예약 조회 레코드.
|
||||
* Request fields: T_MERCHANT
|
||||
* Response fields: T_COUNT, T_GROSS, T_BIZDATE(최근접 예약일), T_RC
|
||||
*/
|
||||
#ifndef ACQ_RESERVEQRY_H
|
||||
#define ACQ_RESERVEQRY_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char merchant_id[64];
|
||||
long rsv_count;
|
||||
long rsv_total;
|
||||
char first_date[16]; /* 가장 빠른 예약일 */
|
||||
} ac_reserveqry_rec_t;
|
||||
|
||||
void ACQ_RESERVEQRY(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_RESERVEQRY_H */
|
||||
42
app/src/ac/svc/ACQ_RESERVEQRY.pgc
Normal file
42
app/src/ac/svc/ACQ_RESERVEQRY.pgc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* ACQ_RESERVEQRY.pgc - ac 모듈 서비스 ACQ_RESERVEQRY (one service = one file).
|
||||
* 매입 예약 조회: 가맹점의 대기 중 예약(P)을 예약일 순 커서로 훑어 건수와
|
||||
* 총액, 가장 빠른 예약일을 알려준다. 예약이 없으면 T_RC=1.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_RESERVEQRY.h"
|
||||
|
||||
void ACQ_RESERVEQRY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long cnt = 0, total = 0;
|
||||
char first_date[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_amt;
|
||||
char h_merch[64], h_date[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
first_date[0] = 0;
|
||||
gets_(b, T_MERCHANT, h_merch, sizeof(h_merch));
|
||||
|
||||
EXEC SQL DECLARE rvq_cur CURSOR FOR
|
||||
SELECT amount, to_char(biz_date, 'YYYY-MM-DD') FROM purchase
|
||||
WHERE merchant_id = :h_merch AND status = 'P'
|
||||
ORDER BY biz_date, purchase_id;
|
||||
EXEC SQL OPEN rvq_cur;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH rvq_cur INTO :h_amt, :h_date;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE rvq_cur; FAIL(b); }
|
||||
if (cnt == 0) { strncpy(first_date, h_date, sizeof(first_date)-1); first_date[sizeof(first_date)-1] = 0; }
|
||||
cnt++; total += h_amt;
|
||||
}
|
||||
EXEC SQL CLOSE rvq_cur;
|
||||
|
||||
if (first_date[0]) Bchg(b, T_BIZDATE, 0, first_date, 0L);
|
||||
setl(b, T_COUNT, cnt);
|
||||
setl(b, T_GROSS, total);
|
||||
setl(b, T_RC, cnt > 0 ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_RETURN.h
Normal file
22
app/src/ac/svc/ACQ_RETURN.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_RETURN.h - ac 서비스 ACQ_RETURN 카피북 (copybook / record header).
|
||||
* 매입 반송 레코드.
|
||||
* Request fields: T_PURCHASE_ID, T_REASON, T_BIZDATE
|
||||
* Response fields: T_CANCEL_ID, T_AMOUNT(반송액), T_RC
|
||||
*/
|
||||
#ifndef ACQ_RETURN_H
|
||||
#define ACQ_RETURN_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long purchase_id;
|
||||
char reason[110]; /* 반송 사유 */
|
||||
char biz_date[16];
|
||||
long cancel_id;
|
||||
long amount; /* 전액 반송 금액 */
|
||||
} ac_return_rec_t;
|
||||
|
||||
void ACQ_RETURN(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_RETURN_H */
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue