Phase 2b: 11개 모듈 전량 실동작 (333 서비스, 전서버 부팅)
- 10개 모듈 추가/확장(au py rc st lg cl mm vl mg cm), 각 30 서비스 = 330 + tmsrv - build.sh 자동발견으로 11 모듈서버 + dbio 라이브러리 23 + 배치 22 빌드 - schema.d 11파일 → 75 테이블, 모듈별 disjoint - 부팅 리소스 규명: fs.mqueue.queues_max=8192(330큐>256), NDRX_MSGSIZEMAX 16000· MSGMAX 50(큐당 5.6MB→0.8MB), msgqueue ulimit 2GB → 전 12서버 runok - 검증: xadmin psc 333 AVAIL, 매입체인 XA 커밋, prepared_xacts=0 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8219b85f14
commit
bec83c721e
73 changed files with 10705 additions and 35 deletions
71
app/src/cl/batch/cl_daily_batch.pgc
Normal file
71
app/src/cl/batch/cl_daily_batch.pgc
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* cl_daily_batch.pgc - cl 일 마감 배치 (미마감 점검 + 커서 M->S + XA).
|
||||
*
|
||||
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
|
||||
* transaction. 먼저 당일 대사완료(M) 미마감 매입 건수를 점검하고, 커서로 각 건을
|
||||
* 정산완료(S)로 마감 전환한 뒤, 당일 마감이력(close_log, DAILY)을 집계와 함께
|
||||
* 기록한다. tpcommit 이 XA 2PC 를 구동. Usage: cl_daily_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "cl_dbio.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
long closed = 0, cid;
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_pid, h_unclosed, h_cnt, h_amt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
/* 1) 미마감(대사완료 M) 점검 */
|
||||
EXEC SQL SELECT count(*) INTO :h_unclosed FROM purchase
|
||||
WHERE biz_date = :h_bizdate AND status = 'M';
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "COUNT FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
printf(">>> cl_daily_batch 미마감(M) 점검: bizdate=%s 대상=%ld건\n", bizdate, h_unclosed);
|
||||
|
||||
/* 2) 커서로 M -> S 마감 전환 */
|
||||
EXEC SQL DECLARE cdc CURSOR FOR
|
||||
SELECT purchase_id FROM purchase
|
||||
WHERE biz_date = :h_bizdate AND status = 'M'
|
||||
ORDER BY purchase_id;
|
||||
EXEC SQL OPEN cdc;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
for (;;) {
|
||||
EXEC SQL FETCH cdc INTO :h_pid;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE cdc; tpabort(0); return 1; }
|
||||
EXEC SQL UPDATE purchase SET status = 'S', updated_at = now() WHERE purchase_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cdc; tpabort(0); return 1; }
|
||||
closed++;
|
||||
}
|
||||
EXEC SQL CLOSE cdc;
|
||||
|
||||
/* 3) 당일 집계 + 마감이력(DAILY) 기록 (via dbio) */
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0) INTO :h_cnt, :h_amt
|
||||
FROM purchase WHERE biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
cid = cldb_next_close_id();
|
||||
if (cid < 0) { tpabort(0); return 1; }
|
||||
if (cldb_insert_close(cid, "DAILY", bizdate, bizdate, "C", h_cnt, h_amt, "일마감(배치)") < 0) {
|
||||
tpabort(0); return 1;
|
||||
}
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> cl_daily_batch COMMIT: bizdate=%s 마감전환=%ld cid=%ld 총건수=%ld\n",
|
||||
bizdate, closed, cid, h_cnt);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
66
app/src/cl/batch/cl_snapshot_batch.pgc
Normal file
66
app/src/cl/batch/cl_snapshot_batch.pgc
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* cl_snapshot_batch.pgc - cl 마감 스냅샷 배치 (커서 + XA).
|
||||
*
|
||||
* 당일 마감(close_log, DAILY)에 대해 merchant_summary 를 가맹점별로 커서 순회하여
|
||||
* cl_snapshot 에 고정 복사(스냅샷)한다. 마감 시점의 가맹점별 집계를 불변 기록으로
|
||||
* 남긴다. 모두 ONE global XA transaction 하에서 수행.
|
||||
* Usage: cl_snapshot_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include "cl_dbio.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
long rows = 0, sid;
|
||||
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16], h_merch[64];
|
||||
long h_cid, h_gross, h_fee, h_net, h_cnt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
/* 당일 최종 DAILY 마감 id 조회 (없으면 스냅샷 생략) */
|
||||
EXEC SQL SELECT coalesce(max(close_id), 0) INTO :h_cid FROM cl_close_log
|
||||
WHERE close_type = 'DAILY' AND biz_date = :h_bizdate AND status <> 'X';
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "CID FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
if (h_cid == 0) {
|
||||
printf(">>> cl_snapshot_batch: bizdate=%s DAILY 마감 없음 -> 스냅샷 생략\n", bizdate);
|
||||
tpabort(0); tpclose(); tpterm(); return 0;
|
||||
}
|
||||
|
||||
EXEC SQL DECLARE csc CURSOR FOR
|
||||
SELECT merchant_id, gross_amount, fee_amount, net_amount, txn_count
|
||||
FROM merchant_summary WHERE biz_date = :h_bizdate
|
||||
ORDER BY merchant_id;
|
||||
EXEC SQL OPEN csc;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
for (;;) {
|
||||
EXEC SQL FETCH csc INTO :h_merch, :h_gross, :h_fee, :h_net, :h_cnt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE csc; tpabort(0); return 1; }
|
||||
sid = cldb_next_snapshot_id();
|
||||
if (sid < 0) { EXEC SQL CLOSE csc; tpabort(0); return 1; }
|
||||
if (cldb_insert_snapshot(sid, h_cid, bizdate, bizdate, h_merch,
|
||||
h_gross, h_fee, h_net, h_cnt) < 0) {
|
||||
EXEC SQL CLOSE csc; tpabort(0); return 1;
|
||||
}
|
||||
rows++;
|
||||
}
|
||||
EXEC SQL CLOSE csc;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> cl_snapshot_batch COMMIT: bizdate=%s cid=%ld 스냅샷=%ld건\n", bizdate, h_cid, rows);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
650
app/src/cl/cl_svr.pgc
Normal file
650
app/src/cl/cl_svr.pgc
Normal file
|
|
@ -0,0 +1,650 @@
|
|||
/*
|
||||
* cl_svr.pgc - cl (마감/closing) MODULE SERVER.
|
||||
*
|
||||
* ONE binary that tpadvertise()s ALL ~30 online cl services (the real Tuxedo
|
||||
* "one module server, many services" pattern). Every service is a distinct 마감
|
||||
* operation with genuine EXEC SQL (directly, or via the linked libcldbio.a dbio
|
||||
* layer) and common helpers from libacqcommon.a.
|
||||
*
|
||||
* 마감 도메인: 일/월/분기/연 마감 이력(close_log), 가맹점별 마감 스냅샷(snapshot),
|
||||
* 기간 잠금(period_lock). 마감 상태 O=개시 -> C=마감완료 -> A=승인 -> L=잠금,
|
||||
* 취소 X / 재마감 R.
|
||||
*
|
||||
* XA: the connection is opened once by tpopen() (ECPG XA switch libndrxxaecpg.so);
|
||||
* there is NO EXEC SQL CONNECT. Each tpcall runs on this process's XA branch.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include <ubf.h>
|
||||
#include <userlog.h>
|
||||
#include <ndebug.h>
|
||||
#include "acq.fd.h"
|
||||
#include "cl_dbio.h"
|
||||
#include "acq_common.h"
|
||||
|
||||
/* ----- small UBF helpers ------------------------------------------------- */
|
||||
static long getl(UBFH *b, BFLDID f) { long v = 0; Bget(b, f, 0, (char *)&v, 0L); return v; }
|
||||
static void gets_(UBFH *b, BFLDID f, char *out, int cap)
|
||||
{ BFLDLEN l = cap; out[0] = 0; Bget(b, f, 0, out, &l); }
|
||||
static void setl(UBFH *b, BFLDID f, long v) { Bchg(b, f, 0, (char *)&v, 0L); }
|
||||
|
||||
#define FAIL(b) do { tpreturn(TPFAIL, 0, (char *)(b), 0L, 0L); return; } while (0)
|
||||
#define OK(b) do { tpreturn(TPSUCCESS, 0, (char *)(b), 0L, 0L); return; } while (0)
|
||||
|
||||
/* ----- service prototypes ------------------------------------------------ */
|
||||
void CL_DAILY(TPSVCINFO *p); void CL_MONTHLY(TPSVCINFO *p);
|
||||
void CL_QUARTER(TPSVCINFO *p); void CL_SNAPSHOT(TPSVCINFO *p);
|
||||
void CL_RECLOSE(TPSVCINFO *p); void CL_VERIFY(TPSVCINFO *p);
|
||||
void CL_CANCEL(TPSVCINFO *p); void CL_STATS(TPSVCINFO *p);
|
||||
void CL_BALVERIFY(TPSVCINFO *p); void CL_SEQ(TPSVCINFO *p);
|
||||
void CL_REPORT(TPSVCINFO *p); void CL_ALERT(TPSVCINFO *p);
|
||||
void CL_UNCLOSED(TPSVCINFO *p); void CL_APPROVE(TPSVCINFO *p);
|
||||
void CL_LOCK(TPSVCINFO *p); void CL_UNLOCK(TPSVCINFO *p);
|
||||
void CL_AGGREGATE(TPSVCINFO *p); void CL_DIFFCHK(TPSVCINFO *p);
|
||||
void CL_SUMMARY(TPSVCINFO *p); void CL_STATUS(TPSVCINFO *p);
|
||||
void CL_ROLLBACK(TPSVCINFO *p); void CL_CONFIRM(TPSVCINFO *p);
|
||||
void CL_PERIOD(TPSVCINFO *p); void CL_YEAREND(TPSVCINFO *p);
|
||||
void CL_MIDCLOSE(TPSVCINFO *p); void CL_RECON(TPSVCINFO *p);
|
||||
void CL_ARCHIVE(TPSVCINFO *p); void CL_PURGE(TPSVCINFO *p);
|
||||
void CL_RESTORE(TPSVCINFO *p); void CL_INQUIRY(TPSVCINFO *p);
|
||||
|
||||
/* ----- advertise table (this is what "scales to 30" cleanly) ------------- */
|
||||
static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
|
||||
{"CL_DAILY", CL_DAILY}, {"CL_MONTHLY", CL_MONTHLY},
|
||||
{"CL_QUARTER", CL_QUARTER}, {"CL_SNAPSHOT", CL_SNAPSHOT},
|
||||
{"CL_RECLOSE", CL_RECLOSE}, {"CL_VERIFY", CL_VERIFY},
|
||||
{"CL_CANCEL", CL_CANCEL}, {"CL_STATS", CL_STATS},
|
||||
{"CL_BALVERIFY", CL_BALVERIFY}, {"CL_SEQ", CL_SEQ},
|
||||
{"CL_REPORT", CL_REPORT}, {"CL_ALERT", CL_ALERT},
|
||||
{"CL_UNCLOSED", CL_UNCLOSED}, {"CL_APPROVE", CL_APPROVE},
|
||||
{"CL_LOCK", CL_LOCK}, {"CL_UNLOCK", CL_UNLOCK},
|
||||
{"CL_AGGREGATE", CL_AGGREGATE}, {"CL_DIFFCHK", CL_DIFFCHK},
|
||||
{"CL_SUMMARY", CL_SUMMARY}, {"CL_STATUS", CL_STATUS},
|
||||
{"CL_ROLLBACK", CL_ROLLBACK}, {"CL_CONFIRM", CL_CONFIRM},
|
||||
{"CL_PERIOD", CL_PERIOD}, {"CL_YEAREND", CL_YEAREND},
|
||||
{"CL_MIDCLOSE", CL_MIDCLOSE}, {"CL_RECON", CL_RECON},
|
||||
{"CL_ARCHIVE", CL_ARCHIVE}, {"CL_PURGE", CL_PURGE},
|
||||
{"CL_RESTORE", CL_RESTORE}, {"CL_INQUIRY", CL_INQUIRY},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
int tpsvrinit(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
if (tpopen() < 0) {
|
||||
userlog("cl_svr: tpopen FAIL: %s", tpstrerror(tperrno));
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; SVCS[i].name != NULL; i++) {
|
||||
if (tpadvertise((char *)SVCS[i].name, SVCS[i].fn) < 0) {
|
||||
userlog("cl_svr: tpadvertise(%s) FAIL: %s", SVCS[i].name, tpstrerror(tperrno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
userlog("cl_svr: %d cl 서비스 광고 완료, RM 개방", i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tpsvrdone(void)
|
||||
{
|
||||
tpclose();
|
||||
userlog("cl_svr: tpsvrdone");
|
||||
}
|
||||
|
||||
/* 공통: 매입 집계 후 마감 이력 생성 헬퍼 (일/월/분기/연 공용). */
|
||||
static int cl_open_close(UBFH *b, const char *ctype, const char *period,
|
||||
const char *bizdate, long *cid_out)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt, h_amt, h_cid;
|
||||
char h_bizdate[16], h_type[16], h_period[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
strncpy(h_type, ctype, sizeof(h_type)-1); h_type[sizeof(h_type)-1] = 0;
|
||||
|
||||
if (strcmp(ctype, "DAILY") == 0) {
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount), 0) INTO :h_cnt, :h_amt
|
||||
FROM purchase WHERE biz_date = :h_bizdate;
|
||||
} else {
|
||||
strncpy(h_period, period, sizeof(h_period)-1); h_period[sizeof(h_period)-1] = 0;
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount), 0) INTO :h_cnt, :h_amt
|
||||
FROM purchase WHERE to_char(biz_date, 'YYYY-MM') LIKE :h_period || '%';
|
||||
}
|
||||
if (sqlca.sqlcode < 0) return -1;
|
||||
|
||||
h_cid = cldb_next_close_id();
|
||||
if (h_cid < 0) return -1;
|
||||
if (cldb_insert_close(h_cid, ctype, period, bizdate, "C", h_cnt, h_amt, "마감") < 0) return -1;
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_amt);
|
||||
*cid_out = h_cid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
/* 1. CL_DAILY - 일 마감: 당일 매입 집계 후 마감이력(DAILY) 생성. */
|
||||
/* ========================================================================= */
|
||||
void CL_DAILY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16];
|
||||
long cid = 0;
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
if (cl_open_close(b, "DAILY", bizdate, bizdate, &cid) < 0) FAIL(b);
|
||||
setl(b, T_ID1, cid);
|
||||
Bchg(b, T_STATUS, 0, "C", 0L);
|
||||
userlog("CL_DAILY cid=%ld bizdate=%s 일마감 완료", cid, bizdate);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 2. CL_MONTHLY - 월 마감: 해당 월(YYYY-MM) 매입 집계 후 마감이력(MONTHLY). */
|
||||
void CL_MONTHLY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16], period[16];
|
||||
long cid = 0;
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
gets_(b, T_STR1, period, sizeof(period));
|
||||
if (period[0] == 0) { strncpy(period, bizdate, 7); period[7] = 0; }
|
||||
if (cl_open_close(b, "MONTHLY", period, bizdate, &cid) < 0) FAIL(b);
|
||||
setl(b, T_ID1, cid);
|
||||
Bchg(b, T_STATUS, 0, "C", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 3. CL_QUARTER - 분기 마감: 분기 프리픽스(YYYY-MM LIKE)로 집계. */
|
||||
void CL_QUARTER(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16], period[16];
|
||||
long cid = 0;
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
gets_(b, T_STR1, period, sizeof(period));
|
||||
if (period[0] == 0) { strncpy(period, bizdate, 4); period[4] = 0; }
|
||||
if (cl_open_close(b, "QUARTER", period, bizdate, &cid) < 0) FAIL(b);
|
||||
setl(b, T_ID1, cid);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 4. CL_SNAPSHOT - 마감 스냅샷: merchant_summary 를 close_id 로 고정 복사. */
|
||||
void CL_SNAPSHOT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16], period[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_cnt;
|
||||
char h_bizdate[16], h_period[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
h_cid = getl(b, T_ID1);
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
gets_(b, T_STR1, period, sizeof(period)); if (period[0] == 0) strcpy(period, bizdate);
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
strncpy(h_period, period, sizeof(h_period)-1); h_period[sizeof(h_period)-1] = 0;
|
||||
|
||||
EXEC SQL INSERT INTO cl_snapshot
|
||||
(snapshot_id, close_id, period_key, biz_date, merchant_id,
|
||||
gross_amount, fee_amount, net_amount, txn_count)
|
||||
SELECT nextval('cl_snapshot_seq'), :h_cid, :h_period, :h_bizdate,
|
||||
ms.merchant_id, ms.gross_amount, ms.fee_amount, ms.net_amount, ms.txn_count
|
||||
FROM merchant_summary ms WHERE ms.biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) { userlog("CL_SNAPSHOT FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
|
||||
h_cnt = sqlca.sqlerrd[2];
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
userlog("CL_SNAPSHOT cid=%ld 가맹점 %ld건 스냅샷", h_cid, h_cnt);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 5. CL_RECLOSE - 재마감: 상태 R 로 표시하고 총계 재집계. */
|
||||
void CL_RECLOSE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_cnt, h_amt;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
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 count(*), coalesce(sum(amount),0) INTO :h_cnt, :h_amt
|
||||
FROM purchase WHERE biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (cldb_update_close_totals(h_cid, h_cnt, h_amt) < 0) FAIL(b);
|
||||
if (cldb_update_close_status(h_cid, "R") < 0) FAIL(b);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
Bchg(b, T_STATUS, 0, "R", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 6. CL_VERIFY - 마감 검증: close_log 총건수 vs 실제 매입건수 비교. */
|
||||
void CL_VERIFY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_stored, h_actual;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
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 txn_count INTO :h_stored FROM cl_close_log WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
EXEC SQL SELECT count(*) INTO :h_actual FROM purchase WHERE biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, h_actual);
|
||||
setl(b, T_RC, (h_stored == h_actual) ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 7. CL_CANCEL - 마감 취소: 상태 X. */
|
||||
void CL_CANCEL(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long cid = getl(b, T_ID1);
|
||||
if (cldb_update_close_status(cid, "X") < 0) FAIL(b);
|
||||
Bchg(b, T_STATUS, 0, "X", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 8. CL_STATS - 마감 통계: close_type 별 마감 건수/총액. */
|
||||
void CL_STATS(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char ctype[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt, h_amt;
|
||||
char h_type[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_STR2, ctype, sizeof(ctype)); if (ctype[0] == 0) strcpy(ctype, "DAILY");
|
||||
strncpy(h_type, ctype, sizeof(h_type)-1); h_type[sizeof(h_type)-1] = 0;
|
||||
EXEC SQL SELECT count(*), coalesce(sum(total_amount),0) INTO :h_cnt, :h_amt
|
||||
FROM cl_close_log WHERE close_type = :h_type AND status <> 'X';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_amt);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 9. CL_BALVERIFY - 잔액 검증: 스냅샷 net 합 vs close_log total 비교. */
|
||||
void CL_BALVERIFY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_snap_net, h_total;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
EXEC SQL SELECT coalesce(sum(net_amount),0) INTO :h_snap_net
|
||||
FROM cl_snapshot WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL SELECT total_amount INTO :h_total FROM cl_close_log WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
setl(b, T_AMT2, h_snap_net);
|
||||
setl(b, T_AMT3, h_total);
|
||||
setl(b, T_DELTA, h_total - h_snap_net);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 10. CL_SEQ - 마감 순번 발번(dbio upsert). */
|
||||
void CL_SEQ(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char ctype[16];
|
||||
long seq;
|
||||
gets_(b, T_STR2, ctype, sizeof(ctype)); if (ctype[0] == 0) strcpy(ctype, "DAILY");
|
||||
seq = cldb_bump_seq(ctype);
|
||||
if (seq < 0) FAIL(b);
|
||||
setl(b, T_ID2, seq);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 11. CL_REPORT - 마감 리포트: 특정 마감의 스냅샷 건수/총매출. */
|
||||
void CL_REPORT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_cnt, h_gross;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
EXEC SQL SELECT count(*), coalesce(sum(gross_amount),0) INTO :h_cnt, :h_gross
|
||||
FROM cl_snapshot WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_gross);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 12. CL_ALERT - 미마감 경보: 당일 대사완료(M) 미전기 매입 건수. */
|
||||
void CL_ALERT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
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 count(*) INTO :h_cnt FROM purchase
|
||||
WHERE biz_date = :h_bizdate AND status = 'M';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_RC, (h_cnt > 0) ? 1 : 0);
|
||||
if (h_cnt > 0) userlog("CL_ALERT %s 미마감 %ld건 감지", bizdate, h_cnt);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 13. CL_UNCLOSED - 미마감일 점검: close_log 없는 매입 영업일 건수. */
|
||||
void CL_UNCLOSED(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
EXEC SQL SELECT count(DISTINCT p.biz_date) INTO :h_cnt
|
||||
FROM purchase p
|
||||
WHERE NOT EXISTS (SELECT 1 FROM cl_close_log c
|
||||
WHERE c.close_type = 'DAILY' AND c.biz_date = p.biz_date
|
||||
AND c.status <> 'X');
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 14. CL_APPROVE - 마감 승인: 상태 A. */
|
||||
void CL_APPROVE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long cid = getl(b, T_ID1);
|
||||
if (cldb_update_close_status(cid, "A") < 0) FAIL(b);
|
||||
Bchg(b, T_STATUS, 0, "A", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 15. CL_LOCK - 기간 잠금: cl_period_lock upsert(locked=true) + 마감 L. */
|
||||
void CL_LOCK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char period[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid;
|
||||
char h_period[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
gets_(b, T_STR1, period, sizeof(period)); if (period[0] == 0) gets_(b, T_BIZDATE, period, sizeof(period));
|
||||
strncpy(h_period, period, sizeof(h_period)-1); h_period[sizeof(h_period)-1] = 0;
|
||||
EXEC SQL INSERT INTO cl_period_lock (period_key, locked) VALUES (:h_period, true)
|
||||
ON CONFLICT (period_key) DO UPDATE SET locked = true, locked_at = now();
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_cid > 0 && cldb_update_close_status(h_cid, "L") < 0) FAIL(b);
|
||||
Bchg(b, T_STATUS, 0, "L", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 16. CL_UNLOCK - 기간 잠금 해제. */
|
||||
void CL_UNLOCK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char period[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_period[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_STR1, period, sizeof(period)); if (period[0] == 0) gets_(b, T_BIZDATE, period, sizeof(period));
|
||||
strncpy(h_period, period, sizeof(h_period)-1); h_period[sizeof(h_period)-1] = 0;
|
||||
EXEC SQL UPDATE cl_period_lock SET locked = false, locked_at = now()
|
||||
WHERE period_key = :h_period;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, sqlca.sqlerrd[2]);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 17. CL_AGGREGATE - 마감 총계 재집계 후 close_log 반영. */
|
||||
void CL_AGGREGATE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_cnt, h_amt;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
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 count(*), coalesce(sum(amount),0) INTO :h_cnt, :h_amt
|
||||
FROM purchase WHERE biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (cldb_update_close_totals(h_cid, h_cnt, h_amt) < 0) FAIL(b);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_amt);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 18. CL_DIFFCHK - 차액 점검: close_log total vs 스냅샷 gross 합. */
|
||||
void CL_DIFFCHK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_total, h_snap;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
EXEC SQL SELECT total_amount INTO :h_total FROM cl_close_log WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
EXEC SQL SELECT coalesce(sum(gross_amount),0) INTO :h_snap
|
||||
FROM cl_snapshot WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_DELTA, h_total - h_snap);
|
||||
setl(b, T_RC, (h_total == h_snap) ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 19. CL_SUMMARY - 마감 요약: 스냅샷 gross/fee/net 합계 반환. */
|
||||
void CL_SUMMARY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_gross, h_fee, h_net;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
EXEC SQL SELECT coalesce(sum(gross_amount),0), coalesce(sum(fee_amount),0),
|
||||
coalesce(sum(net_amount),0)
|
||||
INTO :h_gross, :h_fee, :h_net FROM cl_snapshot WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_GROSS, h_gross);
|
||||
setl(b, T_FEE, h_fee);
|
||||
setl(b, T_NET, h_net);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 20. CL_STATUS - 마감 상태 조회(dbio getter). */
|
||||
void CL_STATUS(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long cid = getl(b, T_ID1);
|
||||
char st[4];
|
||||
if (cldb_get_close_status(cid, st) < 0) FAIL(b);
|
||||
Bchg(b, T_STATUS, 0, st, 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 21. CL_ROLLBACK - 마감 롤백: 스냅샷 삭제 + 상태 O 로 복귀. */
|
||||
void CL_ROLLBACK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
EXEC SQL DELETE FROM cl_snapshot WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, sqlca.sqlerrd[2]);
|
||||
if (cldb_update_close_status(h_cid, "O") < 0) FAIL(b);
|
||||
Bchg(b, T_STATUS, 0, "O", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 22. CL_CONFIRM - 마감 확정: 상태 C. */
|
||||
void CL_CONFIRM(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long cid = getl(b, T_ID1);
|
||||
if (cldb_update_close_status(cid, "C") < 0) FAIL(b);
|
||||
Bchg(b, T_STATUS, 0, "C", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 23. CL_PERIOD - 기간 마감 개시(open): close_log 를 O 상태로 등록. */
|
||||
void CL_PERIOD(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16], period[16], ctype[16];
|
||||
long cid;
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
gets_(b, T_STR1, period, sizeof(period)); if (period[0] == 0) strcpy(period, bizdate);
|
||||
gets_(b, T_STR2, ctype, sizeof(ctype)); if (ctype[0] == 0) strcpy(ctype, "DAILY");
|
||||
cid = cldb_next_close_id();
|
||||
if (cid < 0) FAIL(b);
|
||||
if (cldb_insert_close(cid, ctype, period, bizdate, "O", 0, 0, "기간개시") < 0) FAIL(b);
|
||||
setl(b, T_ID1, cid);
|
||||
Bchg(b, T_STATUS, 0, "O", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 24. CL_YEAREND - 연말 마감: 연도(YYYY) 프리픽스로 집계. */
|
||||
void CL_YEAREND(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16], period[16];
|
||||
long cid = 0;
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
strncpy(period, bizdate, 4); period[4] = 0;
|
||||
if (cl_open_close(b, "YEAREND", period, bizdate, &cid) < 0) FAIL(b);
|
||||
setl(b, T_ID1, cid);
|
||||
Bchg(b, T_STATUS, 0, "C", 0L);
|
||||
userlog("CL_YEAREND cid=%ld 연도=%s 연마감 완료", cid, period);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 25. CL_MIDCLOSE - 중간 마감: 당일 중간 스냅 마감이력(MID) 생성. */
|
||||
void CL_MIDCLOSE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt, h_amt, h_cid;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
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 count(*), coalesce(sum(amount),0) INTO :h_cnt, :h_amt
|
||||
FROM purchase WHERE biz_date = :h_bizdate AND status IN ('A', 'M');
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
h_cid = cldb_next_close_id();
|
||||
if (h_cid < 0) FAIL(b);
|
||||
if (cldb_insert_close(h_cid, "MID", bizdate, bizdate, "O", h_cnt, h_amt, "중간마감") < 0) FAIL(b);
|
||||
setl(b, T_ID1, h_cid);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 26. CL_RECON - 마감 대사: 실제 매입건수 vs close_log txn_count 대사. */
|
||||
void CL_RECON(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_stored, h_actual, h_asum, h_tsum;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
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 txn_count, total_amount INTO :h_stored, :h_tsum
|
||||
FROM cl_close_log WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0) INTO :h_actual, :h_asum
|
||||
FROM purchase WHERE biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, h_actual);
|
||||
setl(b, T_DELTA, h_tsum - h_asum);
|
||||
setl(b, T_RC, (h_stored == h_actual && h_tsum == h_asum) ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 27. CL_ARCHIVE - 마감 아카이브: 승인/완료 마감을 보관 상태로(memo 표시). */
|
||||
void CL_ARCHIVE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET memo = 'ARCHIVED', updated_at = now()
|
||||
WHERE close_id = :h_cid AND status IN ('C', 'A', 'L');
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
setl(b, T_COUNT, sqlca.sqlerrd[2]);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 28. CL_PURGE - 취소 마감 정리: 오래된 X 상태 마감과 그 스냅샷 삭제. */
|
||||
void CL_PURGE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char bizdate[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_bizdate[16];
|
||||
long h_cnt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
EXEC SQL DELETE FROM cl_snapshot WHERE close_id IN
|
||||
(SELECT close_id FROM cl_close_log WHERE status = 'X' AND biz_date < :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL DELETE FROM cl_close_log WHERE status = 'X' AND biz_date < :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
h_cnt = sqlca.sqlerrd[2];
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
userlog("CL_PURGE %s 이전 취소마감 %ld건 삭제", bizdate, h_cnt);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 29. CL_RESTORE - 마감 복원: 취소(X) 마감을 개시(O) 상태로 되돌림. */
|
||||
void CL_RESTORE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
EXEC SQL UPDATE cl_close_log SET status = 'O', memo = 'RESTORED', updated_at = now()
|
||||
WHERE close_id = :h_cid AND status = 'X';
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
Bchg(b, T_STATUS, 0, "O", 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* 30. CL_INQUIRY - 마감 조회: close_type/기간/상태/총건수 반환. */
|
||||
void CL_INQUIRY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_cnt, h_amt;
|
||||
char h_type[16], h_status[8];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
EXEC SQL SELECT close_type, status, txn_count, total_amount
|
||||
INTO :h_type, :h_status, :h_cnt, :h_amt
|
||||
FROM cl_close_log WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
Bchg(b, T_STR2, 0, h_type, 0L);
|
||||
Bchg(b, T_STATUS, 0, h_status, 0L);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_amt);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
120
app/src/cl/dbio/cl_close_dbio.pgc
Normal file
120
app/src/cl/dbio/cl_close_dbio.pgc
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* cl_close_dbio.pgc - 마감이력(close_log) + 순번관리 DB 접근 (part of libcldbio.a).
|
||||
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <userlog.h>
|
||||
#include "cl_dbio.h"
|
||||
|
||||
long cldb_next_close_id(void)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
EXEC SQL SELECT nextval('cl_close_seq') INTO :h_id;
|
||||
if (sqlca.sqlcode < 0) {
|
||||
userlog("cldb_next_close_id FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
return h_id;
|
||||
}
|
||||
|
||||
int cldb_insert_close(long cid, const char *ctype, const char *period,
|
||||
const char *bizdate, const char *status,
|
||||
long txn_count, long total_amount, const char *memo)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid = cid, h_cnt = txn_count, h_amt = total_amount;
|
||||
char h_type[16], h_period[16], h_bizdate[16], h_status[8], h_memo[128];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_type, ctype, sizeof(h_type) - 1); h_type[sizeof(h_type)-1] = 0;
|
||||
strncpy(h_period, period, sizeof(h_period) - 1); h_period[sizeof(h_period)-1] = 0;
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
strncpy(h_status, status, sizeof(h_status) - 1); h_status[sizeof(h_status)-1] = 0;
|
||||
strncpy(h_memo, memo, sizeof(h_memo) - 1); h_memo[sizeof(h_memo)-1] = 0;
|
||||
|
||||
EXEC SQL INSERT INTO cl_close_log
|
||||
(close_id, close_type, period_key, biz_date, status, txn_count, total_amount, memo)
|
||||
VALUES (:h_cid, :h_type, :h_period, :h_bizdate, :h_status, :h_cnt, :h_amt, :h_memo);
|
||||
if (sqlca.sqlcode < 0) {
|
||||
userlog("cldb_insert_close FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cldb_update_close_status(long cid, const char *status)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid = cid;
|
||||
char h_status[8];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_status, status, sizeof(h_status) - 1); h_status[sizeof(h_status)-1] = 0;
|
||||
|
||||
EXEC SQL UPDATE cl_close_log SET status = :h_status, updated_at = now()
|
||||
WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) {
|
||||
userlog("cldb_update_close_status FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cldb_get_close_status(long cid, char *out)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid = cid;
|
||||
char h_status[8];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
EXEC SQL SELECT status INTO :h_status FROM cl_close_log WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) {
|
||||
userlog("cldb_get_close_status FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
out[0] = h_status[0];
|
||||
out[1] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cldb_update_close_totals(long cid, long txn_count, long total_amount)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid = cid, h_cnt = txn_count, h_amt = total_amount;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET txn_count = :h_cnt, total_amount = :h_amt, updated_at = now()
|
||||
WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) {
|
||||
userlog("cldb_update_close_totals FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* close_type 별 마지막 순번을 1 증가시켜 반환 (upsert). */
|
||||
long cldb_bump_seq(const char *ctype)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_seq;
|
||||
char h_type[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_type, ctype, sizeof(h_type) - 1); h_type[sizeof(h_type)-1] = 0;
|
||||
|
||||
EXEC SQL INSERT INTO cl_seq_reg (close_type, last_seq)
|
||||
VALUES (:h_type, 1)
|
||||
ON CONFLICT (close_type) DO UPDATE
|
||||
SET last_seq = cl_seq_reg.last_seq + 1, updated_at = now();
|
||||
if (sqlca.sqlcode < 0) {
|
||||
userlog("cldb_bump_seq FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
EXEC SQL SELECT last_seq INTO :h_seq FROM cl_seq_reg WHERE close_type = :h_type;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) return -1;
|
||||
return h_seq;
|
||||
}
|
||||
28
app/src/cl/dbio/cl_dbio.h
Normal file
28
app/src/cl/dbio/cl_dbio.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* cl_dbio.h - cl 모듈 (마감/closing) DB 접근 계층 (libcldbio.a).
|
||||
* ECPG (EXEC SQL) functions compiled into a static library and linked into
|
||||
* cl_svr and the cl batches. They run on the caller's XA branch/connection
|
||||
* (no EXEC SQL CONNECT); sqlca is the shared per-thread ECPG SQLCA.
|
||||
* Return convention: 0 = ok, -1 = SQL error (caller may also inspect sqlca).
|
||||
*/
|
||||
#ifndef CL_DBIO_H
|
||||
#define CL_DBIO_H
|
||||
|
||||
/* 마감 이력 (close_log) */
|
||||
long cldb_next_close_id(void);
|
||||
int cldb_insert_close(long cid, const char *ctype, const char *period,
|
||||
const char *bizdate, const char *status,
|
||||
long txn_count, long total_amount, const char *memo);
|
||||
int cldb_update_close_status(long cid, const char *status);
|
||||
int cldb_get_close_status(long cid, char *out /* >= 2 bytes */);
|
||||
int cldb_update_close_totals(long cid, long txn_count, long total_amount);
|
||||
|
||||
/* 마감 스냅샷 (snapshot) */
|
||||
long cldb_next_snapshot_id(void);
|
||||
int cldb_insert_snapshot(long sid, long cid, const char *period, const char *bizdate,
|
||||
const char *merch, long gross, long fee, long net, long cnt);
|
||||
|
||||
/* 마감 순번 관리 (seq registry) */
|
||||
long cldb_bump_seq(const char *ctype);
|
||||
|
||||
#endif /* CL_DBIO_H */
|
||||
45
app/src/cl/dbio/cl_snapshot_dbio.pgc
Normal file
45
app/src/cl/dbio/cl_snapshot_dbio.pgc
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* cl_snapshot_dbio.pgc - 마감 스냅샷(snapshot) DB 접근 (part of libcldbio.a).
|
||||
* ECPG functions; run on the caller's XA branch. No EXEC SQL CONNECT.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <userlog.h>
|
||||
#include "cl_dbio.h"
|
||||
|
||||
long cldb_next_snapshot_id(void)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_id;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
EXEC SQL SELECT nextval('cl_snapshot_seq') INTO :h_id;
|
||||
if (sqlca.sqlcode < 0) {
|
||||
userlog("cldb_next_snapshot_id FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
return h_id;
|
||||
}
|
||||
|
||||
int cldb_insert_snapshot(long sid, long cid, const char *period, const char *bizdate,
|
||||
const char *merch, long gross, long fee, long net, long cnt)
|
||||
{
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_sid = sid, h_cid = cid, h_gross = gross, h_fee = fee, h_net = net, h_cnt = cnt;
|
||||
char h_period[16], h_bizdate[16], h_merch[64];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
strncpy(h_period, period, sizeof(h_period) - 1); h_period[sizeof(h_period)-1] = 0;
|
||||
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
|
||||
strncpy(h_merch, merch, sizeof(h_merch) - 1); h_merch[sizeof(h_merch)-1] = 0;
|
||||
|
||||
EXEC SQL INSERT INTO cl_snapshot
|
||||
(snapshot_id, close_id, period_key, biz_date, merchant_id,
|
||||
gross_amount, fee_amount, net_amount, txn_count)
|
||||
VALUES (:h_sid, :h_cid, :h_period, :h_bizdate, :h_merch,
|
||||
:h_gross, :h_fee, :h_net, :h_cnt);
|
||||
if (sqlca.sqlcode < 0) {
|
||||
userlog("cldb_insert_snapshot FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue