규모확장 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
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 */
|
||||
45
app/src/ac/svc/ACQ_RETURN.pgc
Normal file
45
app/src/ac/svc/ACQ_RETURN.pgc
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* ACQ_RETURN.pgc - ac 모듈 서비스 ACQ_RETURN (one service = one file).
|
||||
* 매입 반송: 접수(A) 상태의 매입을 전액 반송 처리한다. 상태를 취소(C)로
|
||||
* 전이하고 RETURN 유형의 취소행에 반송 사유를 기록한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_RETURN.h"
|
||||
|
||||
void ACQ_RETURN(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char why[110];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pid, h_cid, h_amt = 0, h_aff;
|
||||
char h_why[128], 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_why, sizeof(h_why), "RETURN:%s", why[0] ? why : "FORMAT");
|
||||
|
||||
EXEC SQL SELECT amount INTO :h_amt FROM purchase
|
||||
WHERE purchase_id = :h_pid AND status = 'A';
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 5); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
/* 접수 상태에서만 반송 전이 허용 */
|
||||
EXEC SQL UPDATE purchase SET status = 'C', updated_at = now()
|
||||
WHERE purchase_id = :h_pid AND status = 'A';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
h_aff = sqlca.sqlerrd[2];
|
||||
if (h_aff == 0) { setl(b, T_RC, 1); 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, 'RETURN', :h_amt, :h_why, :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_RETURN FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_CANCEL_ID, h_cid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_SETTLEDUE.h
Normal file
22
app/src/ac/svc/ACQ_SETTLEDUE.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_SETTLEDUE.h - ac 서비스 ACQ_SETTLEDUE 카피북 (copybook / record header).
|
||||
* 정산예정 조회 레코드.
|
||||
* Request fields: T_MERCHANT, T_BIZDATE
|
||||
* Response fields: T_COUNT, T_NET(정산예정액), T_STR1(정산예정일), T_RC
|
||||
*/
|
||||
#ifndef ACQ_SETTLEDUE_H
|
||||
#define ACQ_SETTLEDUE_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char merchant_id[64];
|
||||
char biz_date[16];
|
||||
long due_count;
|
||||
long due_net; /* 정산예정액 */
|
||||
char due_date[16]; /* 다음 영업일 */
|
||||
} ac_settledue_rec_t;
|
||||
|
||||
void ACQ_SETTLEDUE(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_SETTLEDUE_H */
|
||||
36
app/src/ac/svc/ACQ_SETTLEDUE.pgc
Normal file
36
app/src/ac/svc/ACQ_SETTLEDUE.pgc
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* ACQ_SETTLEDUE.pgc - ac 모듈 서비스 ACQ_SETTLEDUE (one service = one file).
|
||||
* 정산예정 조회: 대사완료(M) 상태이면서 아직 정산행이 만들어지지 않은
|
||||
* 매입의 건수와 정산예정액을 NOT EXISTS 부질의로 집계한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_SETTLEDUE.h"
|
||||
|
||||
void ACQ_SETTLEDUE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char nextday[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt = 0, h_due = 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 count(*), coalesce(sum(u.net), 0)
|
||||
INTO :h_cnt, :h_due
|
||||
FROM purchase u
|
||||
WHERE u.merchant_id = :h_merch AND u.biz_date = :h_bizdate AND u.status = 'M'
|
||||
AND NOT EXISTS (SELECT 1 FROM settlement s WHERE s.purchase_id = u.purchase_id);
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_SETTLEDUE FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
/* 정산예정일 = 다음 영업일 (주말 건너뜀) */
|
||||
if (acq_next_bizday(h_bizdate, nextday) == 0)
|
||||
Bchg(b, T_STR1, 0, nextday, 0L);
|
||||
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_NET, h_due);
|
||||
setl(b, T_RC, h_cnt > 0 ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_SPLITPAY.h
Normal file
22
app/src/ac/svc/ACQ_SPLITPAY.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_SPLITPAY.h - ac 서비스 ACQ_SPLITPAY 카피북 (copybook / record header).
|
||||
* 분할납부 등록 레코드.
|
||||
* Request fields: T_PURCHASE_ID, T_INSTALL_N(회차수 2..24), T_BIZDATE
|
||||
* Response fields: T_COUNT, T_AMT1(회차금액), T_AMT2(마지막 회차), T_RC
|
||||
*/
|
||||
#ifndef ACQ_SPLITPAY_H
|
||||
#define ACQ_SPLITPAY_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long purchase_id;
|
||||
long split_n; /* 분할 회차수 */
|
||||
char biz_date[16];
|
||||
long per_amount; /* 회차 균등금액 */
|
||||
long last_amount; /* 잔액 가산된 마지막 회차 */
|
||||
} ac_splitpay_rec_t;
|
||||
|
||||
void ACQ_SPLITPAY(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_SPLITPAY_H */
|
||||
43
app/src/ac/svc/ACQ_SPLITPAY.pgc
Normal file
43
app/src/ac/svc/ACQ_SPLITPAY.pgc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* ACQ_SPLITPAY.pgc - ac 모듈 서비스 ACQ_SPLITPAY (one service = one file).
|
||||
* 매입 분할납부 등록: 매입금액을 요청 회차수로 균등 분할(잔액은 마지막
|
||||
* 회차에 가산)해 ac_install 에 회차별 스케줄 행을 루프 삽입한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_SPLITPAY.h"
|
||||
|
||||
void ACQ_SPLITPAY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long n, per, rest, i;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pid, h_amt = 0, h_seq, h_n, h_m;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_pid = getl(b, T_PURCHASE_ID);
|
||||
n = getl(b, T_INSTALL_N);
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
if (n < 2 || n > 24) { setl(b, T_RC, 7); FAIL(b); }
|
||||
|
||||
EXEC SQL SELECT amount INTO :h_amt FROM purchase WHERE purchase_id = :h_pid AND status <> 'C';
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
|
||||
per = h_amt / n;
|
||||
rest = h_amt - per * n; /* 마지막 회차 가산 잔액 */
|
||||
h_n = n;
|
||||
|
||||
for (i = 1; i <= n; i++) {
|
||||
h_seq = i;
|
||||
h_m = (i == n) ? per + rest : per;
|
||||
EXEC SQL INSERT INTO ac_install (install_id, purchase_id, seq_no, months, month_amount, biz_date)
|
||||
VALUES (nextval('ac_install_seq'), :h_pid, :h_seq, :h_n, :h_m, :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_SPLITPAY FAIL seq=%ld [%d]", i, sqlca.sqlcode); FAIL(b); }
|
||||
}
|
||||
|
||||
setl(b, T_COUNT, n);
|
||||
setl(b, T_AMT1, per);
|
||||
setl(b, T_AMT2, per + rest); /* 마지막 회차 금액 */
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
22
app/src/ac/svc/ACQ_SPLITQRY.h
Normal file
22
app/src/ac/svc/ACQ_SPLITQRY.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* ACQ_SPLITQRY.h - ac 서비스 ACQ_SPLITQRY 카피북 (copybook / record header).
|
||||
* 분할납부 회차 조회 레코드.
|
||||
* Request fields: T_PURCHASE_ID
|
||||
* Response fields: T_COUNT, T_GROSS, T_AMT1(최소), T_AMT2(최대), T_RC(일치=0)
|
||||
*/
|
||||
#ifndef ACQ_SPLITQRY_H
|
||||
#define ACQ_SPLITQRY_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long purchase_id;
|
||||
long sched_count; /* 회차수 */
|
||||
long sched_sum; /* 스케줄 합계 */
|
||||
long min_amount;
|
||||
long max_amount;
|
||||
} ac_splitqry_rec_t;
|
||||
|
||||
void ACQ_SPLITQRY(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_SPLITQRY_H */
|
||||
43
app/src/ac/svc/ACQ_SPLITQRY.pgc
Normal file
43
app/src/ac/svc/ACQ_SPLITQRY.pgc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* ACQ_SPLITQRY.pgc - ac 모듈 서비스 ACQ_SPLITQRY (one service = one file).
|
||||
* 분할납부 회차 조회: 매입 건의 회차 스케줄을 커서로 순회하며 회차수·합계와
|
||||
* 최소/최대 회차금액을 산출하고, 원금 대비 스케줄 합계 일치 여부를 점검한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_SPLITQRY.h"
|
||||
|
||||
void ACQ_SPLITQRY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long cnt = 0, sum = 0, mn = 0, mx = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pid, h_seq, h_m, h_orig = 0;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_pid = getl(b, T_PURCHASE_ID);
|
||||
|
||||
EXEC SQL DECLARE spq_cur CURSOR FOR
|
||||
SELECT seq_no, month_amount FROM ac_install
|
||||
WHERE purchase_id = :h_pid ORDER BY seq_no;
|
||||
EXEC SQL OPEN spq_cur;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH spq_cur INTO :h_seq, :h_m;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE spq_cur; FAIL(b); }
|
||||
cnt++; sum += h_m;
|
||||
if (mn == 0 || h_m < mn) mn = h_m;
|
||||
if (h_m > mx) mx = h_m;
|
||||
}
|
||||
EXEC SQL CLOSE spq_cur;
|
||||
|
||||
EXEC SQL SELECT amount INTO :h_orig FROM purchase WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
setl(b, T_COUNT, cnt);
|
||||
setl(b, T_GROSS, sum);
|
||||
setl(b, T_AMT1, mn);
|
||||
setl(b, T_AMT2, mx);
|
||||
setl(b, T_RC, (cnt > 0 && sum == h_orig) ? 0 : 1); /* 스케줄-원금 일치 여부 */
|
||||
OK(b);
|
||||
}
|
||||
20
app/src/ac/svc/ACQ_TAXCXL.h
Normal file
20
app/src/ac/svc/ACQ_TAXCXL.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* ACQ_TAXCXL.h - ac 서비스 ACQ_TAXCXL 카피북 (copybook / record header).
|
||||
* 세금계산서 취소(음수 발행) 레코드.
|
||||
* Request fields: T_ID1(원본 계산서 ID)
|
||||
* Response fields: T_ID2(음수 계산서 ID), T_TAX(-부가세), T_RC
|
||||
*/
|
||||
#ifndef ACQ_TAXCXL_H
|
||||
#define ACQ_TAXCXL_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long orig_inv_id;
|
||||
long neg_inv_id; /* 상쇄용 음수 계산서 */
|
||||
long neg_vat;
|
||||
} ac_taxcxl_rec_t;
|
||||
|
||||
void ACQ_TAXCXL(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_TAXCXL_H */
|
||||
42
app/src/ac/svc/ACQ_TAXCXL.pgc
Normal file
42
app/src/ac/svc/ACQ_TAXCXL.pgc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* ACQ_TAXCXL.pgc - ac 모듈 서비스 ACQ_TAXCXL (one service = one file).
|
||||
* 세금계산서 취소: 원본 계산서를 상쇄하는 음수(공급가/부가세 부호 반전)
|
||||
* 계산서를 발행한다. 이미 상쇄된 계산서(합계 0)는 재취소를 거부한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_TAXCXL.h"
|
||||
|
||||
void ACQ_TAXCXL(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_inv, h_neg, h_pid = 0, h_supply = 0, h_vat = 0, h_bal = 0;
|
||||
char h_merch[64], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_inv = getl(b, T_ID1);
|
||||
|
||||
EXEC SQL SELECT purchase_id, merchant_id, supply, vat, to_char(biz_date, 'YYYY-MM-DD')
|
||||
INTO :h_pid, :h_merch, :h_supply, :h_vat, :h_bizdate
|
||||
FROM ac_tax_invoice WHERE inv_id = :h_inv;
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 4); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_supply < 0) { setl(b, T_RC, 3); FAIL(b); } /* 음수 계산서는 취소 불가 */
|
||||
|
||||
/* 동일 매입의 계산서 잔액이 이미 0 이면 상쇄 완료 상태 */
|
||||
EXEC SQL SELECT coalesce(sum(supply), 0) INTO :h_bal
|
||||
FROM ac_tax_invoice WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_bal == 0) { setl(b, T_RC, 2); FAIL(b); }
|
||||
|
||||
EXEC SQL SELECT nextval('ac_taxinv_seq') INTO :h_neg;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL INSERT INTO ac_tax_invoice (inv_id, purchase_id, merchant_id, supply, vat, biz_date)
|
||||
VALUES (:h_neg, :h_pid, :h_merch, -:h_supply, -:h_vat, :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_TAXCXL FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_ID2, h_neg);
|
||||
setl(b, T_TAX, -h_vat);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
21
app/src/ac/svc/ACQ_TAXREISSUE.h
Normal file
21
app/src/ac/svc/ACQ_TAXREISSUE.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* ACQ_TAXREISSUE.h - ac 서비스 ACQ_TAXREISSUE 카피북 (copybook / record header).
|
||||
* 세금계산서 재발행 레코드.
|
||||
* Request fields: T_ID1(원본 계산서 ID), T_BIZDATE(재발행일)
|
||||
* Response fields: T_ID2(신규 계산서 ID), T_TAX, T_RC(2=부가세 불일치)
|
||||
*/
|
||||
#ifndef ACQ_TAXREISSUE_H
|
||||
#define ACQ_TAXREISSUE_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long orig_inv_id;
|
||||
char biz_date[16];
|
||||
long new_inv_id;
|
||||
long vat; /* 승계 부가세 */
|
||||
} ac_taxreissue_rec_t;
|
||||
|
||||
void ACQ_TAXREISSUE(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_TAXREISSUE_H */
|
||||
39
app/src/ac/svc/ACQ_TAXREISSUE.pgc
Normal file
39
app/src/ac/svc/ACQ_TAXREISSUE.pgc
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* ACQ_TAXREISSUE.pgc - ac 모듈 서비스 ACQ_TAXREISSUE (one service = one file).
|
||||
* 세금계산서 재발행: 원본 계산서의 공급가/부가세를 승계한 신규 계산서를
|
||||
* 지정 영업일로 다시 발행한다. 부가세는 공급가 기준으로 재검증한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_TAXREISSUE.h"
|
||||
|
||||
void ACQ_TAXREISSUE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_old, h_new, h_pid = 0, h_supply = 0, h_vat = 0;
|
||||
char h_merch[64], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_old = getl(b, T_ID1);
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL SELECT purchase_id, merchant_id, supply, vat
|
||||
INTO :h_pid, :h_merch, :h_supply, :h_vat
|
||||
FROM ac_tax_invoice WHERE inv_id = :h_old;
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 4); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
/* 부가세 정합 재검증: 공급가의 10% 와 다르면 재발행 거부 */
|
||||
if (h_vat != acq_vat(h_supply)) { setl(b, T_RC, 2); FAIL(b); }
|
||||
|
||||
EXEC SQL SELECT nextval('ac_taxinv_seq') INTO :h_new;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL INSERT INTO ac_tax_invoice (inv_id, purchase_id, merchant_id, supply, vat, biz_date)
|
||||
VALUES (:h_new, :h_pid, :h_merch, :h_supply, :h_vat, :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_TAXREISSUE FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_ID2, h_new);
|
||||
setl(b, T_TAX, h_vat);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
23
app/src/ac/svc/ACQ_TOPMERCH.h
Normal file
23
app/src/ac/svc/ACQ_TOPMERCH.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* ACQ_TOPMERCH.h - ac 서비스 ACQ_TOPMERCH 카피북 (copybook / record header).
|
||||
* 상위 가맹점 조회 레코드.
|
||||
* Request fields: T_BIZDATE, T_ARG1(상위 N; 1..10, 기본 5)
|
||||
* Response fields: T_COUNT, T_GROSS, T_KEY1/T_AMT2(occ 0..N-1)
|
||||
*/
|
||||
#ifndef ACQ_TOPMERCH_H
|
||||
#define ACQ_TOPMERCH_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char biz_date[16];
|
||||
long topn;
|
||||
long got;
|
||||
long top_sum; /* 상위권 매출 합계 */
|
||||
char merchants[10][64];
|
||||
long amounts[10];
|
||||
} ac_topmerch_rec_t;
|
||||
|
||||
void ACQ_TOPMERCH(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_TOPMERCH_H */
|
||||
44
app/src/ac/svc/ACQ_TOPMERCH.pgc
Normal file
44
app/src/ac/svc/ACQ_TOPMERCH.pgc
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* ACQ_TOPMERCH.pgc - ac 모듈 서비스 ACQ_TOPMERCH (one service = one file).
|
||||
* 상위 가맹점 조회: 영업일 매출 상위 N개 가맹점을 커서로 뽑아 가맹점 ID와
|
||||
* 매출액 쌍을 occurrence 로 내려주고 상위권 합계를 계산한다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_TOPMERCH.h"
|
||||
|
||||
void ACQ_TOPMERCH(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long want, got = 0, topsum = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_want, h_sum;
|
||||
char h_merch[64], h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
want = getl(b, T_ARG1);
|
||||
if (want < 1 || want > 10) want = 5L;
|
||||
h_want = want;
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
|
||||
EXEC SQL DECLARE tpm_cur CURSOR FOR
|
||||
SELECT merchant_id, sum(amount) FROM purchase
|
||||
WHERE biz_date = :h_bizdate AND status NOT IN ('C', 'V')
|
||||
GROUP BY merchant_id ORDER BY sum(amount) DESC, merchant_id
|
||||
LIMIT :h_want;
|
||||
EXEC SQL OPEN tpm_cur;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH tpm_cur INTO :h_merch, :h_sum;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE tpm_cur; FAIL(b); }
|
||||
Badd(b, T_KEY1, h_merch, 0L);
|
||||
Badd(b, T_AMT2, (char *)&h_sum, 0L);
|
||||
got++; topsum += h_sum;
|
||||
}
|
||||
EXEC SQL CLOSE tpm_cur;
|
||||
|
||||
setl(b, T_COUNT, got);
|
||||
setl(b, T_GROSS, topsum); /* 상위권 매출 합계 */
|
||||
setl(b, T_RC, got > 0 ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
21
app/src/ac/svc/ACQ_VELOCITY.h
Normal file
21
app/src/ac/svc/ACQ_VELOCITY.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* ACQ_VELOCITY.h - ac 서비스 ACQ_VELOCITY 카피북 (copybook / record header).
|
||||
* 매입 유입속도 점검 레코드.
|
||||
* Request fields: T_MERCHANT, T_ARG2(10분 허용 건수; 0=기본 100)
|
||||
* Response fields: T_ARG1(10분 건수), T_ARG3(1시간 건수), T_RC(1=초과)
|
||||
*/
|
||||
#ifndef ACQ_VELOCITY_H
|
||||
#define ACQ_VELOCITY_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char merchant_id[64];
|
||||
long allow_10m; /* 10분 허용 건수 */
|
||||
long cnt_10m;
|
||||
long cnt_1h;
|
||||
} ac_velocity_rec_t;
|
||||
|
||||
void ACQ_VELOCITY(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_VELOCITY_H */
|
||||
32
app/src/ac/svc/ACQ_VELOCITY.pgc
Normal file
32
app/src/ac/svc/ACQ_VELOCITY.pgc
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* ACQ_VELOCITY.pgc - ac 모듈 서비스 ACQ_VELOCITY (one service = one file).
|
||||
* 매입 유입속도 점검: 가맹점의 최근 10분간 접수 건수를 재어 허용치 초과
|
||||
* 여부를 판정한다. 초과 시 경보와 함께 직전 1시간 건수도 참고로 준다.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_VELOCITY.h"
|
||||
|
||||
void ACQ_VELOCITY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long allow;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_10m = 0, h_1h = 0;
|
||||
char h_merch[64];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
allow = getl(b, T_ARG2); /* 10분 허용 건수 */
|
||||
if (allow <= 0) allow = 100L;
|
||||
gets_(b, T_MERCHANT, h_merch, sizeof(h_merch));
|
||||
|
||||
EXEC SQL SELECT count(*) FILTER (WHERE created_at >= now() - interval '10 minutes'),
|
||||
count(*) FILTER (WHERE created_at >= now() - interval '1 hour')
|
||||
INTO :h_10m, :h_1h
|
||||
FROM purchase WHERE merchant_id = :h_merch;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_VELOCITY FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
setl(b, T_ARG1, h_10m); /* 최근 10분 건수 */
|
||||
setl(b, T_ARG3, h_1h); /* 최근 1시간 건수 */
|
||||
setl(b, T_RC, h_10m > allow ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
23
app/src/ac/svc/ACQ_WEEKSTAT.h
Normal file
23
app/src/ac/svc/ACQ_WEEKSTAT.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* ACQ_WEEKSTAT.h - ac 서비스 ACQ_WEEKSTAT 카피북 (copybook / record header).
|
||||
* 매입 주간 통계 레코드.
|
||||
* Request fields: T_BIZDATE(기준일)
|
||||
* Response fields: T_COUNT, T_GROSS, T_FEE, T_STR1(최대 거래일), T_AMT1
|
||||
*/
|
||||
#ifndef ACQ_WEEKSTAT_H
|
||||
#define ACQ_WEEKSTAT_H
|
||||
|
||||
#include "ac_svc.h"
|
||||
|
||||
typedef struct {
|
||||
char base_date[16]; /* 기준 영업일 */
|
||||
long week_count;
|
||||
long week_gross;
|
||||
long week_fee;
|
||||
char peak_day[16]; /* 최대 거래일 */
|
||||
long peak_amount;
|
||||
} ac_weekstat_rec_t;
|
||||
|
||||
void ACQ_WEEKSTAT(TPSVCINFO *p);
|
||||
|
||||
#endif /* ACQ_WEEKSTAT_H */
|
||||
44
app/src/ac/svc/ACQ_WEEKSTAT.pgc
Normal file
44
app/src/ac/svc/ACQ_WEEKSTAT.pgc
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* ACQ_WEEKSTAT.pgc - ac 모듈 서비스 ACQ_WEEKSTAT (one service = one file).
|
||||
* 매입 주간 통계: 기준일 포함 직전 7일 구간의 건수/총액/수수료 합계와
|
||||
* 최대 거래일(거래액 기준)을 산출한다. 구간 경계는 date 연산으로 계산.
|
||||
* Runs on the caller's XA branch (no EXEC SQL CONNECT). Advertised by ac_svr.
|
||||
*/
|
||||
#include "ACQ_WEEKSTAT.h"
|
||||
|
||||
void ACQ_WEEKSTAT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt = 0, h_amt = 0, h_fee = 0, h_peak = 0;
|
||||
char h_bizdate[16], h_peakday[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
h_peakday[0] = 0;
|
||||
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount), 0), coalesce(sum(fee), 0)
|
||||
INTO :h_cnt, :h_amt, :h_fee
|
||||
FROM purchase
|
||||
WHERE biz_date > CAST(:h_bizdate AS date) - 7
|
||||
AND biz_date <= CAST(:h_bizdate AS date)
|
||||
AND status <> 'C';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
|
||||
/* 주간 최대 거래일 */
|
||||
EXEC SQL SELECT to_char(biz_date, 'YYYY-MM-DD'), sum(amount)
|
||||
INTO :h_peakday, :h_peak
|
||||
FROM purchase
|
||||
WHERE biz_date > CAST(:h_bizdate AS date) - 7
|
||||
AND biz_date <= CAST(:h_bizdate AS date)
|
||||
AND status <> 'C'
|
||||
GROUP BY biz_date ORDER BY sum(amount) DESC LIMIT 1;
|
||||
if (sqlca.sqlcode < 0) { userlog("ACQ_WEEKSTAT FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
|
||||
if (h_peakday[0]) Bchg(b, T_STR1, 0, h_peakday, 0L);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_amt);
|
||||
setl(b, T_FEE, h_fee);
|
||||
setl(b, T_AMT1, h_peak);
|
||||
OK(b);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue