규모확장 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
62
app/src/cl/batch/cl_apprflow_batch.pgc
Normal file
62
app/src/cl/batch/cl_apprflow_batch.pgc
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* cl_apprflow_batch.pgc - cl 마감 승인 워크플로 일괄 배치 (검증부 승인 + XA).
|
||||
*
|
||||
* 승인요청(APPR_REQ)된 완료(C) 마감을 커서로 순회, 저장 건수와 실매입 건수가
|
||||
* 일치하는 건만 승인(A)으로 전환하고 불일치 건은 HOLD 표시 후 건너뛴다.
|
||||
* 승인 게이트가 검증을 겸하는 워크플로. 전 구간 ONE global XA.
|
||||
* host 변수는 전용 카피북 cl_apprflow_cpy.h 를 EXEC SQL INCLUDE 로 가져온다.
|
||||
* Usage: cl_apprflow_batch [YYYY-MM]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *prefix = (argc > 1) ? argv[1] : "2026-07";
|
||||
long ok = 0, held = 0;
|
||||
|
||||
EXEC SQL INCLUDE cl_apprflow_cpy;
|
||||
|
||||
strncpy(af_prefix, prefix, sizeof(af_prefix)-1); af_prefix[sizeof(af_prefix)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(90, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE bapf CURSOR FOR
|
||||
SELECT close_id, to_char(biz_date,'YYYY-MM-DD'), txn_count FROM cl_close_log
|
||||
WHERE status = 'C' AND memo LIKE '%APPR_REQ%'
|
||||
AND period_key LIKE :af_prefix || '%'
|
||||
ORDER BY close_id;
|
||||
EXEC SQL OPEN bapf;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
for (;;) {
|
||||
EXEC SQL FETCH bapf INTO :af_cid, :af_day, :af_stored;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bapf; tpabort(0); return 1; }
|
||||
EXEC SQL SELECT count(*) INTO :af_actual FROM purchase WHERE biz_date = :af_day;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bapf; tpabort(0); return 1; }
|
||||
if (af_stored == af_actual) {
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET status = 'A', updated_at = now() WHERE close_id = :af_cid;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bapf; tpabort(0); return 1; }
|
||||
ok++;
|
||||
} else {
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET memo = memo || '|HOLD', updated_at = now() WHERE close_id = :af_cid;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bapf; tpabort(0); return 1; }
|
||||
printf(" 승인보류 cid=%ld (%ld != %ld)\n", af_cid, af_stored, af_actual);
|
||||
held++;
|
||||
}
|
||||
}
|
||||
EXEC SQL CLOSE bapf;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> cl_apprflow_batch COMMIT: prefix=%s 승인=%ld 보류=%ld\n", prefix, ok, held);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
8
app/src/cl/batch/cl_apprflow_cpy.h
Normal file
8
app/src/cl/batch/cl_apprflow_cpy.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/* cl_apprflow_cpy.h - cl_apprflow_batch 전용 카피북 (host 변수 선언, EXEC SQL INCLUDE 대상). */
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char af_prefix[16];
|
||||
char af_day[16];
|
||||
long af_cid;
|
||||
long af_stored;
|
||||
long af_actual;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
64
app/src/cl/batch/cl_audit_batch.pgc
Normal file
64
app/src/cl/batch/cl_audit_batch.pgc
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* cl_audit_batch.pgc - cl 마감 이력 감사 배치 (4개 감사항목 집계 + XA).
|
||||
*
|
||||
* 기간 프리픽스에 대해 (1)재개시 흔적(REOPEN memo) (2)승인/잠금인데 잠금행
|
||||
* 없음 (3)잠금시각 이후 수정 흔적 (4)사유 없는 취소(X) 4개 감사항목을
|
||||
* 각각 단건 집계 SELECT 로 산출해 감사 리포트를 출력한다 (조회 전용).
|
||||
* host 변수는 전용 카피북 cl_audit_cpy.h 를 EXEC SQL INCLUDE 로 가져온다.
|
||||
* Usage: cl_audit_batch [YYYY-MM]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *prefix = (argc > 1) ? argv[1] : "2026-07";
|
||||
long findings = 0;
|
||||
|
||||
EXEC SQL INCLUDE cl_audit_cpy;
|
||||
|
||||
strncpy(au_prefix, prefix, sizeof(au_prefix)-1); au_prefix[sizeof(au_prefix)-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; }
|
||||
|
||||
printf(">>> cl_audit_batch %s 마감 이력 감사\n", prefix);
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :au_reopened FROM cl_close_log
|
||||
WHERE period_key LIKE :au_prefix || '%' AND memo LIKE 'REOPEN:%';
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
printf(" [감사1] 재개시 이력 : %ld건\n", au_reopened);
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :au_nolockrow FROM cl_close_log c
|
||||
WHERE c.period_key LIKE :au_prefix || '%' AND c.status IN ('A','L')
|
||||
AND NOT EXISTS (SELECT 1 FROM cl_period_lock l
|
||||
WHERE l.period_key = c.period_key AND l.locked = true);
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
printf(" [감사2] 승인/잠금인데 잠금행 없음: %ld건\n", au_nolockrow);
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :au_tampered
|
||||
FROM cl_close_log c, cl_period_lock l
|
||||
WHERE c.period_key LIKE :au_prefix || '%'
|
||||
AND l.period_key = c.period_key AND l.locked = true
|
||||
AND c.updated_at > l.locked_at;
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
printf(" [감사3] 잠금 후 수정 흔적 : %ld건\n", au_tampered);
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :au_emptycxl FROM cl_close_log
|
||||
WHERE period_key LIKE :au_prefix || '%' AND status = 'X'
|
||||
AND (memo = '' OR memo IS NULL);
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
printf(" [감사4] 사유 없는 취소 : %ld건\n", au_emptycxl);
|
||||
|
||||
findings = au_nolockrow + au_tampered + au_emptycxl;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> cl_audit_batch 결과: 이상항목 합계 %ld건 -> %s\n",
|
||||
findings, findings ? "감사 소명 필요" : "적합");
|
||||
|
||||
tpclose(); tpterm();
|
||||
return findings ? 2 : 0;
|
||||
}
|
||||
8
app/src/cl/batch/cl_audit_cpy.h
Normal file
8
app/src/cl/batch/cl_audit_cpy.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/* cl_audit_cpy.h - cl_audit_batch 전용 카피북 (host 변수 선언, EXEC SQL INCLUDE 대상). */
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char au_prefix[16];
|
||||
long au_reopened;
|
||||
long au_nolockrow;
|
||||
long au_tampered;
|
||||
long au_emptycxl;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
54
app/src/cl/batch/cl_chnclose_batch.pgc
Normal file
54
app/src/cl/batch/cl_chnclose_batch.pgc
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* cl_chnclose_batch.pgc - cl 채널별 일괄 마감 배치 (그룹 커서 + XA).
|
||||
*
|
||||
* 영업일의 매입을 채널(POS/EDC/EDI/FOREIGN) 그룹 커서로 순회하며 채널마다
|
||||
* CHN 마감이력을 한 건씩 생성한다. 전 구간 ONE global XA (tpcommit = 2PC).
|
||||
* host 변수는 전용 카피북 cl_chnclose_cpy.h 를 EXEC SQL INCLUDE 로 가져온다.
|
||||
* Usage: cl_chnclose_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
long made = 0;
|
||||
|
||||
EXEC SQL INCLUDE cl_chnclose_cpy;
|
||||
|
||||
strncpy(cc_bizdate, bizdate, sizeof(cc_bizdate)-1); cc_bizdate[sizeof(cc_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE bchn CURSOR FOR
|
||||
SELECT channel, count(*), coalesce(sum(amount),0) FROM purchase
|
||||
WHERE biz_date = :cc_bizdate GROUP BY channel ORDER BY channel;
|
||||
EXEC SQL OPEN bchn;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
for (;;) {
|
||||
EXEC SQL FETCH bchn INTO :cc_chn, :cc_cnt, :cc_amt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE bchn; tpabort(0); return 1; }
|
||||
EXEC SQL SELECT nextval('cl_close_seq') INTO :cc_cid;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bchn; tpabort(0); return 1; }
|
||||
snprintf(cc_memo, sizeof(cc_memo), "채널마감:%s", cc_chn);
|
||||
EXEC SQL INSERT INTO cl_close_log
|
||||
(close_id, close_type, period_key, biz_date, status, txn_count, total_amount, memo)
|
||||
VALUES (:cc_cid, 'CHN', :cc_bizdate, :cc_bizdate, 'C', :cc_cnt, :cc_amt, :cc_memo);
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bchn; tpabort(0); return 1; }
|
||||
printf(" 채널 %-8s cid=%ld cnt=%ld amt=%ld\n", cc_chn, cc_cid, cc_cnt, cc_amt);
|
||||
made++;
|
||||
}
|
||||
EXEC SQL CLOSE bchn;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> cl_chnclose_batch COMMIT: bizdate=%s 채널마감 %ld건 생성\n", bizdate, made);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
9
app/src/cl/batch/cl_chnclose_cpy.h
Normal file
9
app/src/cl/batch/cl_chnclose_cpy.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/* cl_chnclose_cpy.h - cl_chnclose_batch 전용 카피북 (host 변수 선언, EXEC SQL INCLUDE 대상). */
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char cc_bizdate[16];
|
||||
char cc_chn[16];
|
||||
char cc_memo[48];
|
||||
long cc_cid;
|
||||
long cc_cnt;
|
||||
long cc_amt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
57
app/src/cl/batch/cl_dupchk_batch.pgc
Normal file
57
app/src/cl/batch/cl_dupchk_batch.pgc
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* cl_dupchk_batch.pgc - cl 중복 마감 정리 배치 (HAVING 그룹 커서 + 정리 + XA).
|
||||
*
|
||||
* 취소(X) 제외 동일 (close_type, period_key) 마감이 2건 이상인 그룹을 찾아
|
||||
* 최소 close_id 한 건만 남기고 나머지를 취소(X, memo 'DUP') 처리한다.
|
||||
* 그룹별 잔존/정리 건수를 리포트. 전 구간 ONE global XA.
|
||||
* host 변수는 전용 카피북 cl_dupchk_cpy.h 를 EXEC SQL INCLUDE 로 가져온다.
|
||||
* Usage: cl_dupchk_batch
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
long groups = 0, cleaned = 0;
|
||||
|
||||
EXEC SQL INCLUDE cl_dupchk_cpy;
|
||||
|
||||
(void)argc; (void)argv;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(90, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE bdup CURSOR FOR
|
||||
SELECT close_type, period_key, count(*), min(close_id) FROM cl_close_log
|
||||
WHERE status <> 'X'
|
||||
GROUP BY close_type, period_key HAVING count(*) > 1
|
||||
ORDER BY close_type, period_key;
|
||||
EXEC SQL OPEN bdup;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
for (;;) {
|
||||
EXEC SQL FETCH bdup INTO :dp_type, :dp_period, :dp_n, :dp_keep;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bdup; tpabort(0); return 1; }
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET status = 'X', memo = 'DUP', updated_at = now()
|
||||
WHERE close_type = :dp_type AND period_key = :dp_period
|
||||
AND status <> 'X' AND close_id <> :dp_keep;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bdup; tpabort(0); return 1; }
|
||||
dp_gone = sqlca.sqlerrd[2];
|
||||
printf(" 중복그룹 %s/%s %ld건 -> keep cid=%ld, 취소 %ld건\n",
|
||||
dp_type, dp_period, dp_n, dp_keep, dp_gone);
|
||||
cleaned += dp_gone;
|
||||
groups++;
|
||||
}
|
||||
EXEC SQL CLOSE bdup;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> cl_dupchk_batch COMMIT: 중복그룹=%ld 정리=%ld건\n", groups, cleaned);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
8
app/src/cl/batch/cl_dupchk_cpy.h
Normal file
8
app/src/cl/batch/cl_dupchk_cpy.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/* cl_dupchk_cpy.h - cl_dupchk_batch 전용 카피북 (host 변수 선언, EXEC SQL INCLUDE 대상). */
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char dp_type[16];
|
||||
char dp_period[24];
|
||||
long dp_n;
|
||||
long dp_keep;
|
||||
long dp_gone;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
60
app/src/cl/batch/cl_finalize_batch.pgc
Normal file
60
app/src/cl/batch/cl_finalize_batch.pgc
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* cl_finalize_batch.pgc - cl 가마감 -> 본마감 일괄 확정 배치 (커서 + 재집계 + XA).
|
||||
*
|
||||
* 월 내 가마감(PROV, status O)을 커서로 순회하며 각 일자의 매입을 재집계해
|
||||
* 본마감(C, memo FINAL)으로 확정한다. 가마감 대비 건수 변동은 리포트로 출력.
|
||||
* 전 구간 ONE global XA. host 변수는 전용 카피북 cl_finalize_cpy.h 사용.
|
||||
* Usage: cl_finalize_batch [YYYY-MM]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *month = (argc > 1) ? argv[1] : "2026-07";
|
||||
long fixed = 0, drift = 0;
|
||||
|
||||
EXEC SQL INCLUDE cl_finalize_cpy;
|
||||
|
||||
strncpy(fz_month, month, sizeof(fz_month)-1); fz_month[sizeof(fz_month)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(90, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE bfin CURSOR FOR
|
||||
SELECT close_id, period_key, txn_count FROM cl_close_log
|
||||
WHERE close_type = 'DAILY' AND status = 'O' AND memo = 'PROV'
|
||||
AND period_key LIKE :fz_month || '%'
|
||||
ORDER BY period_key;
|
||||
EXEC SQL OPEN bfin;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
for (;;) {
|
||||
EXEC SQL FETCH bfin INTO :fz_cid, :fz_day, :fz_oldcnt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bfin; tpabort(0); return 1; }
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0) INTO :fz_cnt, :fz_amt
|
||||
FROM purchase WHERE biz_date = :fz_day AND status IN ('M','S');
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bfin; tpabort(0); return 1; }
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET status = 'C', txn_count = :fz_cnt, total_amount = :fz_amt,
|
||||
memo = 'FINAL', updated_at = now()
|
||||
WHERE close_id = :fz_cid AND status = 'O';
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bfin; tpabort(0); return 1; }
|
||||
if (fz_cnt != fz_oldcnt) {
|
||||
printf(" 본마감 %s cid=%ld 건수변동 %ld -> %ld\n", fz_day, fz_cid, fz_oldcnt, fz_cnt);
|
||||
drift++;
|
||||
}
|
||||
fixed++;
|
||||
}
|
||||
EXEC SQL CLOSE bfin;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> cl_finalize_batch COMMIT: %s 본마감 확정=%ld건 (변동 %ld건)\n", month, fixed, drift);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
9
app/src/cl/batch/cl_finalize_cpy.h
Normal file
9
app/src/cl/batch/cl_finalize_cpy.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/* cl_finalize_cpy.h - cl_finalize_batch 전용 카피북 (host 변수 선언, EXEC SQL INCLUDE 대상). */
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char fz_month[16];
|
||||
char fz_day[16];
|
||||
long fz_cid;
|
||||
long fz_oldcnt;
|
||||
long fz_cnt;
|
||||
long fz_amt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
58
app/src/cl/batch/cl_gapdays_batch.pgc
Normal file
58
app/src/cl/batch/cl_gapdays_batch.pgc
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* cl_gapdays_batch.pgc - cl 마감 누락일 탐지/보정 배치 (NOT EXISTS 커서 + XA).
|
||||
*
|
||||
* 월 내 매입은 있으나 일마감이 전혀 없는 누락일을 커서로 찾아 리포트하고,
|
||||
* 각 누락일에 개시(O) placeholder 마감(memo 'GAP')을 만들어 마감 담당자의
|
||||
* 후속 처리 대기열에 올린다. 전 구간 ONE global XA.
|
||||
* host 변수는 전용 카피북 cl_gapdays_cpy.h 를 EXEC SQL INCLUDE 로 가져온다.
|
||||
* Usage: cl_gapdays_batch [YYYY-MM]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *month = (argc > 1) ? argv[1] : "2026-07";
|
||||
long gaps = 0;
|
||||
|
||||
EXEC SQL INCLUDE cl_gapdays_cpy;
|
||||
|
||||
strncpy(gd_month, month, sizeof(gd_month)-1); gd_month[sizeof(gd_month)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE bgapd CURSOR FOR
|
||||
SELECT to_char(p.biz_date,'YYYY-MM-DD'), count(*) FROM purchase p
|
||||
WHERE to_char(p.biz_date,'YYYY-MM') = :gd_month
|
||||
AND NOT EXISTS (SELECT 1 FROM cl_close_log c
|
||||
WHERE c.close_type = 'DAILY'
|
||||
AND c.period_key = to_char(p.biz_date,'YYYY-MM-DD'))
|
||||
GROUP BY p.biz_date ORDER BY p.biz_date;
|
||||
EXEC SQL OPEN bgapd;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
for (;;) {
|
||||
EXEC SQL FETCH bgapd INTO :gd_day, :gd_txn;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bgapd; tpabort(0); return 1; }
|
||||
EXEC SQL SELECT nextval('cl_close_seq') INTO :gd_cid;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bgapd; tpabort(0); return 1; }
|
||||
EXEC SQL INSERT INTO cl_close_log
|
||||
(close_id, close_type, period_key, biz_date, status, txn_count, total_amount, memo)
|
||||
VALUES (:gd_cid, 'DAILY', :gd_day, :gd_day, 'O', 0, 0, 'GAP');
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bgapd; tpabort(0); return 1; }
|
||||
printf(" 누락일 %s (매입 %ld건) -> placeholder cid=%ld 개시\n", gd_day, gd_txn, gd_cid);
|
||||
gaps++;
|
||||
}
|
||||
EXEC SQL CLOSE bgapd;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> cl_gapdays_batch COMMIT: %s 누락일 %ld건 등록\n", month, gaps);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
7
app/src/cl/batch/cl_gapdays_cpy.h
Normal file
7
app/src/cl/batch/cl_gapdays_cpy.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
/* cl_gapdays_cpy.h - cl_gapdays_batch 전용 카피북 (host 변수 선언, EXEC SQL INCLUDE 대상). */
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char gd_month[16];
|
||||
char gd_day[16];
|
||||
long gd_cid;
|
||||
long gd_txn;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
77
app/src/cl/batch/cl_halfclose_batch.pgc
Normal file
77
app/src/cl/batch/cl_halfclose_batch.pgc
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* cl_halfclose_batch.pgc - cl 반기 결산 마감 배치 (월별 소계 + 반기 마감 + XA).
|
||||
*
|
||||
* 연도/반기(1|2)를 받아 반기 구간의 월별 소계를 커서로 출력한 뒤 반기 전체를
|
||||
* BETWEEN 집계해 HALF 마감이력(YYYY-Hn, status C)을 생성한다.
|
||||
* 동일 반기 기존 마감이 있으면 거절. 전 구간 ONE global XA.
|
||||
* host 변수는 전용 카피북 cl_halfclose_cpy.h 를 EXEC SQL INCLUDE 로 가져온다.
|
||||
* Usage: cl_halfclose_batch [YYYY] [1|2]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *year = (argc > 1) ? argv[1] : "2026";
|
||||
int half = (argc > 2) ? atoi(argv[2]) : 1;
|
||||
long months = 0;
|
||||
|
||||
EXEC SQL INCLUDE cl_halfclose_cpy;
|
||||
|
||||
if (half != 1 && half != 2) { fprintf(stderr, "반기는 1|2 만 허용\n"); return 1; }
|
||||
if (half == 1) {
|
||||
snprintf(hf_from, sizeof(hf_from), "%s-01-01", year);
|
||||
snprintf(hf_to, sizeof(hf_to), "%s-06-30", year);
|
||||
} else {
|
||||
snprintf(hf_from, sizeof(hf_from), "%s-07-01", year);
|
||||
snprintf(hf_to, sizeof(hf_to), "%s-12-31", year);
|
||||
}
|
||||
snprintf(hf_period, sizeof(hf_period), "%s-H%d", year, half);
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(90, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :hf_cnt FROM cl_close_log
|
||||
WHERE close_type = 'HALF' AND period_key = :hf_period AND status <> 'X';
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
if (hf_cnt > 0) {
|
||||
fprintf(stderr, "cl_halfclose_batch: %s 반기마감 기존재 - 중복 불가\n", hf_period);
|
||||
tpabort(0); tpclose(); tpterm();
|
||||
return 2;
|
||||
}
|
||||
|
||||
EXEC SQL DECLARE bhalf CURSOR FOR
|
||||
SELECT to_char(biz_date,'YYYY-MM'), count(*), coalesce(sum(amount),0)
|
||||
FROM purchase WHERE biz_date BETWEEN :hf_from AND :hf_to
|
||||
GROUP BY 1 ORDER BY 1;
|
||||
EXEC SQL OPEN bhalf;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
for (;;) {
|
||||
EXEC SQL FETCH bhalf INTO :hf_mon, :hf_mcnt, :hf_mamt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bhalf; tpabort(0); return 1; }
|
||||
printf(" 월소계 %s cnt=%ld amt=%ld\n", hf_mon, hf_mcnt, hf_mamt);
|
||||
months++;
|
||||
}
|
||||
EXEC SQL CLOSE bhalf;
|
||||
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0) INTO :hf_cnt, :hf_amt
|
||||
FROM purchase WHERE biz_date BETWEEN :hf_from AND :hf_to;
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
EXEC SQL SELECT nextval('cl_close_seq') INTO :hf_cid;
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
EXEC SQL INSERT INTO cl_close_log
|
||||
(close_id, close_type, period_key, biz_date, status, txn_count, total_amount, memo)
|
||||
VALUES (:hf_cid, 'HALF', :hf_period, :hf_to, 'C', :hf_cnt, :hf_amt, '반기결산');
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> cl_halfclose_batch COMMIT: %s cid=%ld 월=%ld개 cnt=%ld amt=%ld\n",
|
||||
hf_period, hf_cid, months, hf_cnt, hf_amt);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
12
app/src/cl/batch/cl_halfclose_cpy.h
Normal file
12
app/src/cl/batch/cl_halfclose_cpy.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/* cl_halfclose_cpy.h - cl_halfclose_batch 전용 카피북 (host 변수 선언, EXEC SQL INCLUDE 대상). */
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char hf_from[16];
|
||||
char hf_to[16];
|
||||
char hf_period[16];
|
||||
char hf_mon[16];
|
||||
long hf_cid;
|
||||
long hf_cnt;
|
||||
long hf_amt;
|
||||
long hf_mcnt;
|
||||
long hf_mamt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
60
app/src/cl/batch/cl_holiday_batch.pgc
Normal file
60
app/src/cl/batch/cl_holiday_batch.pgc
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* cl_holiday_batch.pgc - cl 휴일 마감 정책 배치 (주말 판정 + 태깅 + XA).
|
||||
*
|
||||
* 월 내 매입 발생 일자를 커서로 순회하며 요일을 판정, 주말(토/일) 거래일을
|
||||
* 리포트하고 해당 일자의 일마감에는 memo '|HOL' 태그를 남긴다.
|
||||
* 휴일 마감은 익영업일 이월 대상이라는 정책 표시. 전 구간 ONE global XA.
|
||||
* host 변수는 전용 카피북 cl_holiday_cpy.h 를 EXEC SQL INCLUDE 로 가져온다.
|
||||
* Usage: cl_holiday_batch [YYYY-MM]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *month = (argc > 1) ? argv[1] : "2026-07";
|
||||
long weekend = 0, tagged = 0;
|
||||
|
||||
EXEC SQL INCLUDE cl_holiday_cpy;
|
||||
|
||||
strncpy(hd_month, month, sizeof(hd_month)-1); hd_month[sizeof(hd_month)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE bhol CURSOR FOR
|
||||
SELECT to_char(biz_date,'YYYY-MM-DD'), to_char(biz_date,'D'), count(*)
|
||||
FROM purchase
|
||||
WHERE to_char(biz_date,'YYYY-MM') = :hd_month
|
||||
GROUP BY biz_date ORDER BY biz_date;
|
||||
EXEC SQL OPEN bhol;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
for (;;) {
|
||||
EXEC SQL FETCH bhol INTO :hd_day, :hd_dow, :hd_txn;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bhol; tpabort(0); return 1; }
|
||||
if (hd_dow[0] != '1' && hd_dow[0] != '7') continue; /* 평일은 정책 대상 아님 */
|
||||
weekend++;
|
||||
printf(" 휴일거래 %s (요일코드 %s) %ld건 -> 익영업일 이월 대상\n", hd_day, hd_dow, hd_txn);
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET memo = memo || '|HOL', updated_at = now()
|
||||
WHERE close_type = 'DAILY' AND period_key = :hd_day
|
||||
AND status <> 'X' AND memo NOT LIKE '%|HOL%';
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bhol; tpabort(0); return 1; }
|
||||
EXEC SQL SELECT count(*) INTO :hd_marked FROM cl_close_log
|
||||
WHERE close_type = 'DAILY' AND period_key = :hd_day AND memo LIKE '%|HOL%';
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bhol; tpabort(0); return 1; }
|
||||
tagged += hd_marked;
|
||||
}
|
||||
EXEC SQL CLOSE bhol;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> cl_holiday_batch COMMIT: %s 휴일거래일=%ld HOL태그 마감=%ld\n", month, weekend, tagged);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
8
app/src/cl/batch/cl_holiday_cpy.h
Normal file
8
app/src/cl/batch/cl_holiday_cpy.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/* cl_holiday_cpy.h - cl_holiday_batch 전용 카피북 (host 변수 선언, EXEC SQL INCLUDE 대상). */
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char hd_month[16];
|
||||
char hd_day[16];
|
||||
char hd_dow[4];
|
||||
long hd_txn;
|
||||
long hd_marked;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
57
app/src/cl/batch/cl_posttrig_batch.pgc
Normal file
57
app/src/cl/batch/cl_posttrig_batch.pgc
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* cl_posttrig_batch.pgc - cl 마감 후속작업 트리거 배치 (INSERT..SELECT + XA).
|
||||
*
|
||||
* 마감 완료(C/A/L)된 영업일의 정산건 중 아직 ledger 에 XFER 전기가 없는
|
||||
* 건을 NOT EXISTS 조건 INSERT..SELECT 한 방으로 일괄 전기하고, 전기 전/후
|
||||
* 건수를 리포트한다. 마감 없는 일자는 거절. 전 구간 ONE global XA.
|
||||
* host 변수는 전용 카피북 cl_posttrig_cpy.h 를 EXEC SQL INCLUDE 로 가져온다.
|
||||
* Usage: cl_posttrig_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
long closed = 0;
|
||||
|
||||
EXEC SQL INCLUDE cl_posttrig_cpy;
|
||||
|
||||
strncpy(pt_bizdate, bizdate, sizeof(pt_bizdate)-1); pt_bizdate[sizeof(pt_bizdate)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :pt_ready FROM cl_close_log
|
||||
WHERE close_type = 'DAILY' AND period_key = :pt_bizdate AND status IN ('C','A','L');
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
if (pt_ready == 0) {
|
||||
fprintf(stderr, "cl_posttrig_batch: %s 완료된 일마감 없음 - 후속작업 불가\n", bizdate);
|
||||
tpabort(0); tpclose(); tpterm();
|
||||
return 2;
|
||||
}
|
||||
closed = pt_ready;
|
||||
|
||||
EXEC SQL INSERT INTO ledger (ledger_id, purchase_id, entry_type, amount, biz_date)
|
||||
SELECT nextval('ledger_seq'), s.purchase_id, 'XFER', s.net, s.biz_date
|
||||
FROM settlement s
|
||||
WHERE s.biz_date = :pt_bizdate
|
||||
AND NOT EXISTS (SELECT 1 FROM ledger l
|
||||
WHERE l.purchase_id = s.purchase_id AND l.entry_type = 'XFER');
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "INSERT FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
pt_ins = sqlca.sqlerrd[2];
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :pt_total FROM ledger
|
||||
WHERE biz_date = :pt_bizdate AND entry_type = 'XFER';
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> cl_posttrig_batch COMMIT: %s (마감 %ld건 확인) 신규 XFER=%ld 누적=%ld\n",
|
||||
bizdate, closed, pt_ins, pt_total);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
7
app/src/cl/batch/cl_posttrig_cpy.h
Normal file
7
app/src/cl/batch/cl_posttrig_cpy.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
/* cl_posttrig_cpy.h - cl_posttrig_batch 전용 카피북 (host 변수 선언, EXEC SQL INCLUDE 대상). */
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char pt_bizdate[16];
|
||||
long pt_ready;
|
||||
long pt_ins;
|
||||
long pt_total;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
64
app/src/cl/batch/cl_precheck_batch.pgc
Normal file
64
app/src/cl/batch/cl_precheck_batch.pgc
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* cl_precheck_batch.pgc - cl 마감 전 체크리스트 일괄 검증 배치 (5항목 + XA).
|
||||
*
|
||||
* 일마감 직전에 돌려 (1)미마감 M 매입 (2)미매칭 (3)기간잠금 (4)기존 마감
|
||||
* (5)보류(H) 매입 5개 항목을 점검하고 체크리스트 리포트를 출력한다.
|
||||
* 하나라도 실패면 rc=2 로 종료해 후속 마감 잡을 차단한다 (조회 전용, XA 조회 브랜치).
|
||||
* host 변수는 전용 카피북 cl_precheck_cpy.h 를 EXEC SQL INCLUDE 로 가져온다.
|
||||
* Usage: cl_precheck_batch [YYYY-MM-DD]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
|
||||
int fails = 0;
|
||||
|
||||
EXEC SQL INCLUDE cl_precheck_cpy;
|
||||
|
||||
strncpy(pc_bizdate, bizdate, sizeof(pc_bizdate)-1); pc_bizdate[sizeof(pc_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(30, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
printf(">>> cl_precheck_batch %s 마감 전 체크리스트\n", bizdate);
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :pc_unclosed FROM purchase
|
||||
WHERE biz_date = :pc_bizdate AND status = 'M';
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
printf(" [1] 미마감(M) 매입 : %ld건 %s\n", pc_unclosed, pc_unclosed ? "FAIL" : "ok");
|
||||
if (pc_unclosed) fails++;
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :pc_unmatch FROM ac_unmatch WHERE biz_date = :pc_bizdate;
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
printf(" [2] 미매칭 건 : %ld건 %s\n", pc_unmatch, pc_unmatch ? "FAIL" : "ok");
|
||||
if (pc_unmatch) fails++;
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :pc_locked FROM cl_period_lock
|
||||
WHERE period_key = :pc_bizdate AND locked = true;
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
printf(" [3] 기간 잠금 : %s\n", pc_locked ? "잠금됨 FAIL" : "ok");
|
||||
if (pc_locked) fails++;
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :pc_already FROM cl_close_log
|
||||
WHERE close_type = 'DAILY' AND period_key = :pc_bizdate AND status <> 'X';
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
printf(" [4] 기존 일마감 : %ld건 %s\n", pc_already, pc_already ? "FAIL" : "ok");
|
||||
if (pc_already) fails++;
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :pc_hold FROM purchase
|
||||
WHERE biz_date = :pc_bizdate AND status = 'H';
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
printf(" [5] 보류(H) 매입 : %ld건 %s\n", pc_hold, pc_hold ? "FAIL" : "ok");
|
||||
if (pc_hold) fails++;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> cl_precheck_batch 결과: %d항목 실패 -> %s\n", fails, fails ? "마감 차단" : "마감 진행 가능");
|
||||
|
||||
tpclose(); tpterm();
|
||||
return fails ? 2 : 0;
|
||||
}
|
||||
9
app/src/cl/batch/cl_precheck_cpy.h
Normal file
9
app/src/cl/batch/cl_precheck_cpy.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/* cl_precheck_cpy.h - cl_precheck_batch 전용 카피북 (host 변수 선언, EXEC SQL INCLUDE 대상). */
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char pc_bizdate[16];
|
||||
long pc_unclosed;
|
||||
long pc_unmatch;
|
||||
long pc_locked;
|
||||
long pc_already;
|
||||
long pc_hold;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
62
app/src/cl/batch/cl_provclose_batch.pgc
Normal file
62
app/src/cl/batch/cl_provclose_batch.pgc
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* cl_provclose_batch.pgc - cl 가마감 일괄 생성 배치 (누락일 커서 + XA).
|
||||
*
|
||||
* 월(YYYY-MM) 내 매입은 있으나 어떤 일마감도 없는 일자를 커서로 찾아
|
||||
* 일자마다 status O + memo 'PROV' 가마감을 집계와 함께 생성한다.
|
||||
* 본마감 전 임시 스냅샷 성격. 전 구간 ONE global XA.
|
||||
* host 변수는 전용 카피북 cl_provclose_cpy.h 를 EXEC SQL INCLUDE 로 가져온다.
|
||||
* Usage: cl_provclose_batch [YYYY-MM]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *month = (argc > 1) ? argv[1] : "2026-07";
|
||||
long made = 0;
|
||||
|
||||
EXEC SQL INCLUDE cl_provclose_cpy;
|
||||
|
||||
strncpy(pv_month, month, sizeof(pv_month)-1); pv_month[sizeof(pv_month)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(90, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE bprov CURSOR FOR
|
||||
SELECT DISTINCT to_char(p.biz_date,'YYYY-MM-DD') FROM purchase p
|
||||
WHERE to_char(p.biz_date,'YYYY-MM') = :pv_month
|
||||
AND NOT EXISTS (SELECT 1 FROM cl_close_log c
|
||||
WHERE c.close_type = 'DAILY'
|
||||
AND c.period_key = to_char(p.biz_date,'YYYY-MM-DD')
|
||||
AND c.status <> 'X')
|
||||
ORDER BY 1;
|
||||
EXEC SQL OPEN bprov;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
for (;;) {
|
||||
EXEC SQL FETCH bprov INTO :pv_day;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bprov; tpabort(0); return 1; }
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0) INTO :pv_cnt, :pv_amt
|
||||
FROM purchase WHERE biz_date = :pv_day AND status IN ('M','S');
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bprov; tpabort(0); return 1; }
|
||||
EXEC SQL SELECT nextval('cl_close_seq') INTO :pv_cid;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bprov; tpabort(0); return 1; }
|
||||
EXEC SQL INSERT INTO cl_close_log
|
||||
(close_id, close_type, period_key, biz_date, status, txn_count, total_amount, memo)
|
||||
VALUES (:pv_cid, 'DAILY', :pv_day, :pv_day, 'O', :pv_cnt, :pv_amt, 'PROV');
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bprov; tpabort(0); return 1; }
|
||||
printf(" 가마감 %s cid=%ld cnt=%ld\n", pv_day, pv_cid, pv_cnt);
|
||||
made++;
|
||||
}
|
||||
EXEC SQL CLOSE bprov;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> cl_provclose_batch COMMIT: %s 가마감 %ld건 생성\n", month, made);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
8
app/src/cl/batch/cl_provclose_cpy.h
Normal file
8
app/src/cl/batch/cl_provclose_cpy.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
/* cl_provclose_cpy.h - cl_provclose_batch 전용 카피북 (host 변수 선언, EXEC SQL INCLUDE 대상). */
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char pv_month[16];
|
||||
char pv_day[16];
|
||||
long pv_cid;
|
||||
long pv_cnt;
|
||||
long pv_amt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
62
app/src/cl/batch/cl_slamon_batch.pgc
Normal file
62
app/src/cl/batch/cl_slamon_batch.pgc
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* cl_slamon_batch.pgc - cl 마감 SLA 모니터 배치 (지연 마감 태깅 + XA).
|
||||
*
|
||||
* 기간 내 일마감 중 생성시각이 기준시각(HHMI, 기본 1000)을 넘긴 지연 마감을
|
||||
* 커서로 찾아 memo 에 '|SLA' 태그를 남기고 지연 목록을 출력한다.
|
||||
* 이미 태깅된 건은 제외. 전 구간 ONE global XA.
|
||||
* host 변수는 전용 카피북 cl_slamon_cpy.h 를 EXEC SQL INCLUDE 로 가져온다.
|
||||
* Usage: cl_slamon_batch [YYYY-MM] [HHMI]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *prefix = (argc > 1) ? argv[1] : "2026-07";
|
||||
const char *cutoff = (argc > 2) ? argv[2] : "1000";
|
||||
long tagged = 0;
|
||||
|
||||
EXEC SQL INCLUDE cl_slamon_cpy;
|
||||
|
||||
strncpy(sl_prefix, prefix, sizeof(sl_prefix)-1); sl_prefix[sizeof(sl_prefix)-1] = 0;
|
||||
strncpy(sl_cut, cutoff, sizeof(sl_cut)-1); sl_cut[sizeof(sl_cut)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE bsla CURSOR FOR
|
||||
SELECT close_id, period_key, to_char(created_at,'HH24MI') FROM cl_close_log
|
||||
WHERE close_type = 'DAILY' AND status <> 'X'
|
||||
AND period_key LIKE :sl_prefix || '%'
|
||||
AND to_char(created_at,'HH24MI') > :sl_cut
|
||||
AND memo NOT LIKE '%|SLA%'
|
||||
ORDER BY created_at;
|
||||
EXEC SQL OPEN bsla;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
for (;;) {
|
||||
EXEC SQL FETCH bsla INTO :sl_cid, :sl_period, :sl_hhmi;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bsla; tpabort(0); return 1; }
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET memo = memo || '|SLA', updated_at = now() WHERE close_id = :sl_cid;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bsla; tpabort(0); return 1; }
|
||||
printf(" SLA위반 %s cid=%ld 생성 %s (기준 %s)\n", sl_period, sl_cid, sl_hhmi, sl_cut);
|
||||
tagged++;
|
||||
}
|
||||
EXEC SQL CLOSE bsla;
|
||||
|
||||
EXEC SQL SELECT count(*) INTO :sl_late FROM cl_close_log
|
||||
WHERE close_type = 'DAILY' AND period_key LIKE :sl_prefix || '%'
|
||||
AND memo LIKE '%|SLA%';
|
||||
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> cl_slamon_batch COMMIT: prefix=%s 신규태깅=%ld 누적 SLA위반=%ld\n", prefix, tagged, sl_late);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return 0;
|
||||
}
|
||||
9
app/src/cl/batch/cl_slamon_cpy.h
Normal file
9
app/src/cl/batch/cl_slamon_cpy.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/* cl_slamon_cpy.h - cl_slamon_batch 전용 카피북 (host 변수 선언, EXEC SQL INCLUDE 대상). */
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char sl_prefix[16];
|
||||
char sl_cut[8];
|
||||
char sl_hhmi[8];
|
||||
char sl_period[24];
|
||||
long sl_cid;
|
||||
long sl_late;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
62
app/src/cl/batch/cl_xcheck_batch.pgc
Normal file
62
app/src/cl/batch/cl_xcheck_batch.pgc
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* cl_xcheck_batch.pgc - cl 마감 데이터 건수/금액 크로스체크 배치 (이중 대사 + XA).
|
||||
*
|
||||
* 기간 내 일마감을 커서로 순회하며 마감이력의 (txn_count, total_amount) 와
|
||||
* 실매입의 (count, sum) 을 동시에 대사해 건수/금액 불일치를 각각 집계,
|
||||
* 불일치 상세를 표로 출력한다 (조회 전용). host 변수는 cl_xcheck_cpy.h 사용.
|
||||
* Usage: cl_xcheck_batch [YYYY-MM]
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *prefix = (argc > 1) ? argv[1] : "2026-07";
|
||||
long seen = 0, cntbad = 0, amtbad = 0;
|
||||
|
||||
EXEC SQL INCLUDE cl_xcheck_cpy;
|
||||
|
||||
strncpy(xc_prefix, prefix, sizeof(xc_prefix)-1); xc_prefix[sizeof(xc_prefix)-1] = 0;
|
||||
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
EXEC SQL DECLARE bxch CURSOR FOR
|
||||
SELECT close_id, to_char(biz_date,'YYYY-MM-DD'), txn_count, total_amount
|
||||
FROM cl_close_log
|
||||
WHERE close_type = 'DAILY' AND status IN ('C','A','L')
|
||||
AND period_key LIKE :xc_prefix || '%'
|
||||
ORDER BY biz_date;
|
||||
EXEC SQL OPEN bxch;
|
||||
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
|
||||
|
||||
for (;;) {
|
||||
EXEC SQL FETCH bxch INTO :xc_cid, :xc_day, :xc_logcnt, :xc_logamt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bxch; tpabort(0); return 1; }
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0) INTO :xc_realcnt, :xc_realamt
|
||||
FROM purchase WHERE biz_date = :xc_day;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bxch; tpabort(0); return 1; }
|
||||
seen++;
|
||||
if (xc_logcnt != xc_realcnt) {
|
||||
printf(" [건수] %s cid=%ld 이력=%ld 실제=%ld\n", xc_day, xc_cid, xc_logcnt, xc_realcnt);
|
||||
cntbad++;
|
||||
}
|
||||
if (xc_logamt != xc_realamt) {
|
||||
printf(" [금액] %s cid=%ld 이력=%ld 실제=%ld (편차 %+ld)\n",
|
||||
xc_day, xc_cid, xc_logamt, xc_realamt, xc_logamt - xc_realamt);
|
||||
amtbad++;
|
||||
}
|
||||
}
|
||||
EXEC SQL CLOSE bxch;
|
||||
|
||||
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
|
||||
printf(">>> cl_xcheck_batch COMMIT: prefix=%s 대사=%ld 건수불일치=%ld 금액불일치=%ld\n",
|
||||
prefix, seen, cntbad, amtbad);
|
||||
|
||||
tpclose(); tpterm();
|
||||
return (cntbad + amtbad) ? 2 : 0;
|
||||
}
|
||||
10
app/src/cl/batch/cl_xcheck_cpy.h
Normal file
10
app/src/cl/batch/cl_xcheck_cpy.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/* cl_xcheck_cpy.h - cl_xcheck_batch 전용 카피북 (host 변수 선언, EXEC SQL INCLUDE 대상). */
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char xc_prefix[16];
|
||||
char xc_day[16];
|
||||
long xc_cid;
|
||||
long xc_logcnt;
|
||||
long xc_logamt;
|
||||
long xc_realcnt;
|
||||
long xc_realamt;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
* cl_svr.pgc - cl (마감/closing) MODULE SERVER (thin dispatcher).
|
||||
*
|
||||
* The legacy "one module server, many services" pattern: this binary owns NO
|
||||
* business logic. Each of cl's 30 online services now lives in its own file
|
||||
* business logic. Each of cl's 75 online services now lives in its own file
|
||||
* (app/src/cl/svc/<SVCNAME>.pgc) with its own copybook header
|
||||
* (app/src/cl/svc/<SVCNAME>.h); those objects are archived into libclsvc.a and
|
||||
* linked into this server. Here we only:
|
||||
|
|
@ -53,6 +53,51 @@
|
|||
#include "CL_PURGE.h"
|
||||
#include "CL_RESTORE.h"
|
||||
#include "CL_INQUIRY.h"
|
||||
#include "CL_CHNCLOSE.h"
|
||||
#include "CL_DIVCLOSE.h"
|
||||
#include "CL_CORPCLOSE.h"
|
||||
#include "CL_PRECHECK.h"
|
||||
#include "CL_DELAYREG.h"
|
||||
#include "CL_PROVCLOSE.h"
|
||||
#include "CL_FINALIZE.h"
|
||||
#include "CL_APPRREQ.h"
|
||||
#include "CL_APPRREJECT.h"
|
||||
#include "CL_APPRHIST.h"
|
||||
#include "CL_CXLREASON.h"
|
||||
#include "CL_CNTXCHECK.h"
|
||||
#include "CL_AMTXCHECK.h"
|
||||
#include "CL_SNAPXCHECK.h"
|
||||
#include "CL_RPTCHN.h"
|
||||
#include "CL_RPTISSUER.h"
|
||||
#include "CL_RPTCAT.h"
|
||||
#include "CL_RPTTOPMER.h"
|
||||
#include "CL_SCHEDULE.h"
|
||||
#include "CL_HOLIDAY.h"
|
||||
#include "CL_POSTTRIG.h"
|
||||
#include "CL_AUDITTRAIL.h"
|
||||
#include "CL_HALFCLOSE.h"
|
||||
#include "CL_YEARPREP.h"
|
||||
#include "CL_SLAMON.h"
|
||||
#include "CL_DELAYLIST.h"
|
||||
#include "CL_LOCKSWEEP.h"
|
||||
#include "CL_LOCKAUDIT.h"
|
||||
#include "CL_SEQAUDIT.h"
|
||||
#include "CL_MEMOSEARCH.h"
|
||||
#include "CL_REOPENREQ.h"
|
||||
#include "CL_CLOSERATE.h"
|
||||
#include "CL_GAPDAYS.h"
|
||||
#include "CL_DUPCHK.h"
|
||||
#include "CL_TREND.h"
|
||||
#include "CL_CHNVERIFY.h"
|
||||
#include "CL_MERCLOSE.h"
|
||||
#include "CL_FEEVERIFY.h"
|
||||
#include "CL_NETVERIFY.h"
|
||||
#include "CL_PENDLIST.h"
|
||||
#include "CL_ESCALATE.h"
|
||||
#include "CL_CALENDAR.h"
|
||||
#include "CL_TRIGSTAT.h"
|
||||
#include "CL_FORCECLOSE.h"
|
||||
#include "CL_SNAPDIFF.h"
|
||||
|
||||
/* ----- advertise table: {service name, function} (fn is extern from its file) */
|
||||
static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
|
||||
|
|
@ -71,6 +116,29 @@ static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
|
|||
{"CL_MIDCLOSE", CL_MIDCLOSE}, {"CL_RECON", CL_RECON},
|
||||
{"CL_ARCHIVE", CL_ARCHIVE}, {"CL_PURGE", CL_PURGE},
|
||||
{"CL_RESTORE", CL_RESTORE}, {"CL_INQUIRY", CL_INQUIRY},
|
||||
{"CL_CHNCLOSE", CL_CHNCLOSE}, {"CL_DIVCLOSE", CL_DIVCLOSE},
|
||||
{"CL_CORPCLOSE", CL_CORPCLOSE}, {"CL_PRECHECK", CL_PRECHECK},
|
||||
{"CL_DELAYREG", CL_DELAYREG}, {"CL_PROVCLOSE", CL_PROVCLOSE},
|
||||
{"CL_FINALIZE", CL_FINALIZE}, {"CL_APPRREQ", CL_APPRREQ},
|
||||
{"CL_APPRREJECT", CL_APPRREJECT}, {"CL_APPRHIST", CL_APPRHIST},
|
||||
{"CL_CXLREASON", CL_CXLREASON}, {"CL_CNTXCHECK", CL_CNTXCHECK},
|
||||
{"CL_AMTXCHECK", CL_AMTXCHECK}, {"CL_SNAPXCHECK", CL_SNAPXCHECK},
|
||||
{"CL_RPTCHN", CL_RPTCHN}, {"CL_RPTISSUER", CL_RPTISSUER},
|
||||
{"CL_RPTCAT", CL_RPTCAT}, {"CL_RPTTOPMER", CL_RPTTOPMER},
|
||||
{"CL_SCHEDULE", CL_SCHEDULE}, {"CL_HOLIDAY", CL_HOLIDAY},
|
||||
{"CL_POSTTRIG", CL_POSTTRIG}, {"CL_AUDITTRAIL", CL_AUDITTRAIL},
|
||||
{"CL_HALFCLOSE", CL_HALFCLOSE}, {"CL_YEARPREP", CL_YEARPREP},
|
||||
{"CL_SLAMON", CL_SLAMON}, {"CL_DELAYLIST", CL_DELAYLIST},
|
||||
{"CL_LOCKSWEEP", CL_LOCKSWEEP}, {"CL_LOCKAUDIT", CL_LOCKAUDIT},
|
||||
{"CL_SEQAUDIT", CL_SEQAUDIT}, {"CL_MEMOSEARCH", CL_MEMOSEARCH},
|
||||
{"CL_REOPENREQ", CL_REOPENREQ}, {"CL_CLOSERATE", CL_CLOSERATE},
|
||||
{"CL_GAPDAYS", CL_GAPDAYS}, {"CL_DUPCHK", CL_DUPCHK},
|
||||
{"CL_TREND", CL_TREND}, {"CL_CHNVERIFY", CL_CHNVERIFY},
|
||||
{"CL_MERCLOSE", CL_MERCLOSE}, {"CL_FEEVERIFY", CL_FEEVERIFY},
|
||||
{"CL_NETVERIFY", CL_NETVERIFY}, {"CL_PENDLIST", CL_PENDLIST},
|
||||
{"CL_ESCALATE", CL_ESCALATE}, {"CL_CALENDAR", CL_CALENDAR},
|
||||
{"CL_TRIGSTAT", CL_TRIGSTAT}, {"CL_FORCECLOSE", CL_FORCECLOSE},
|
||||
{"CL_SNAPDIFF", CL_SNAPDIFF},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
|||
21
app/src/cl/svc/CL_AMTXCHECK.h
Normal file
21
app/src/cl/svc/CL_AMTXCHECK.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_AMTXCHECK.h - cl 서비스 CL_AMTXCHECK 카피북 (copybook / record header).
|
||||
* 마감 금액 크로스체크: 마감총액 vs 매입합계 vs 스냅샷 gross 편차 산출.
|
||||
*/
|
||||
#ifndef CL_AMTXCHECK_H
|
||||
#define CL_AMTXCHECK_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_amtxcheck_rec_t;
|
||||
|
||||
void CL_AMTXCHECK(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_AMTXCHECK_H */
|
||||
39
app/src/cl/svc/CL_AMTXCHECK.pgc
Normal file
39
app/src/cl/svc/CL_AMTXCHECK.pgc
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* CL_AMTXCHECK.pgc - cl 모듈 서비스 CL_AMTXCHECK (one service = one file).
|
||||
* 마감 금액 크로스체크: 마감이력 total_amount vs 매입 amount 합계 vs 스냅샷
|
||||
* gross 합계를 대사하고 최대 절대 편차(T_DELTA)를 산출한다.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_AMTXCHECK.h"
|
||||
|
||||
void CL_AMTXCHECK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long d1, d2, worst;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_log, h_real, h_snap;
|
||||
char h_date[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
EXEC SQL SELECT total_amount, to_char(biz_date,'YYYY-MM-DD')
|
||||
INTO :h_log, :h_date FROM cl_close_log WHERE close_id = :h_cid AND status <> 'X';
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
EXEC SQL SELECT coalesce(sum(amount),0) INTO :h_real
|
||||
FROM purchase WHERE biz_date = :h_date;
|
||||
if (sqlca.sqlcode < 0) 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);
|
||||
d1 = h_log - h_real; if (d1 < 0) d1 = -d1;
|
||||
d2 = (h_snap == 0) ? 0 : (h_log - h_snap);
|
||||
if (d2 < 0) d2 = -d2;
|
||||
worst = (d1 > d2) ? d1 : d2;
|
||||
setl(b, T_AMT1, h_log);
|
||||
setl(b, T_AMT2, h_real);
|
||||
setl(b, T_AMT3, h_snap);
|
||||
setl(b, T_DELTA, worst);
|
||||
setl(b, T_RC, (worst == 0) ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_APPRHIST.h
Normal file
21
app/src/cl/svc/CL_APPRHIST.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_APPRHIST.h - cl 서비스 CL_APPRHIST 카피북 (copybook / record header).
|
||||
* 마감 승인 이력: 기간 프리픽스의 승인/완료/취소 건수 CASE 집계.
|
||||
*/
|
||||
#ifndef CL_APPRHIST_H
|
||||
#define CL_APPRHIST_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_apprhist_rec_t;
|
||||
|
||||
void CL_APPRHIST(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_APPRHIST_H */
|
||||
32
app/src/cl/svc/CL_APPRHIST.pgc
Normal file
32
app/src/cl/svc/CL_APPRHIST.pgc
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* CL_APPRHIST.pgc - cl 모듈 서비스 CL_APPRHIST (one service = one file).
|
||||
* 마감 승인 이력: 기간 프리픽스(YYYY-MM 등)의 마감을 승인(A/L)/완료(C)/취소(X)
|
||||
* 로 CASE 집계하여 승인 진행률 현황을 한 번의 SELECT 로 반환한다.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_APPRHIST.h"
|
||||
|
||||
void CL_APPRHIST(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_appr, h_done, h_cxl;
|
||||
char h_prefix[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_STR1, h_prefix, sizeof(h_prefix));
|
||||
if (h_prefix[0] == 0) { Bchg(b, T_MSG, 0, "기간 프리픽스 필요", 0L); FAIL(b); }
|
||||
EXEC SQL SELECT
|
||||
coalesce(sum(CASE WHEN status IN ('A','L') THEN 1 ELSE 0 END),0),
|
||||
coalesce(sum(CASE WHEN status = 'C' THEN 1 ELSE 0 END),0),
|
||||
coalesce(sum(CASE WHEN status = 'X' THEN 1 ELSE 0 END),0)
|
||||
INTO :h_appr, :h_done, :h_cxl
|
||||
FROM cl_close_log WHERE period_key LIKE :h_prefix || '%';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_ARG1, h_appr);
|
||||
setl(b, T_ARG2, h_done);
|
||||
setl(b, T_ARG3, h_cxl);
|
||||
setl(b, T_COUNT, h_appr + h_done + h_cxl);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_APPRREJECT.h
Normal file
21
app/src/cl/svc/CL_APPRREJECT.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_APPRREJECT.h - cl 서비스 CL_APPRREJECT 카피북 (copybook / record header).
|
||||
* 마감 승인 반려: 잠금기간 아닌 A 상태 마감을 C 로 반려하고 사유 기록.
|
||||
*/
|
||||
#ifndef CL_APPRREJECT_H
|
||||
#define CL_APPRREJECT_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_apprreject_rec_t;
|
||||
|
||||
void CL_APPRREJECT(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_APPRREJECT_H */
|
||||
38
app/src/cl/svc/CL_APPRREJECT.pgc
Normal file
38
app/src/cl/svc/CL_APPRREJECT.pgc
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* CL_APPRREJECT.pgc - cl 모듈 서비스 CL_APPRREJECT (one service = one file).
|
||||
* 마감 승인 반려: 승인(A) 상태 마감을 완료(C)로 되돌리며 반려 사유를 기록.
|
||||
* 해당 기간이 이미 잠금(cl_period_lock)되어 있으면 반려 불가.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_APPRREJECT.h"
|
||||
|
||||
void CL_APPRREJECT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char reason[64];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid;
|
||||
char h_memo[80];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
gets_(b, T_REASON, reason, sizeof(reason));
|
||||
if (reason[0] == 0) strcpy(reason, "사유미기재");
|
||||
snprintf(h_memo, sizeof(h_memo), "REJ:%s", reason);
|
||||
EXEC SQL UPDATE cl_close_log c
|
||||
SET status = 'C', memo = :h_memo, updated_at = now()
|
||||
WHERE c.close_id = :h_cid AND c.status = 'A'
|
||||
AND NOT EXISTS (SELECT 1 FROM cl_period_lock l
|
||||
WHERE l.period_key = c.period_key AND l.locked = true);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (sqlca.sqlerrd[2] == 0) {
|
||||
setl(b, T_RC, 2);
|
||||
Bchg(b, T_MSG, 0, "반려 불가(비승인 상태 또는 잠금 기간)", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
setl(b, T_RC, 0);
|
||||
Bchg(b, T_STATUS, 0, "C", 0L);
|
||||
userlog("CL_APPRREJECT cid=%ld 승인 반려: %s", h_cid, reason);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_APPRREQ.h
Normal file
21
app/src/cl/svc/CL_APPRREQ.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_APPRREQ.h - cl 서비스 CL_APPRREQ 카피북 (copybook / record header).
|
||||
* 마감 승인 요청: C 상태 검증 후 승인요청 표시, 승인 대기 순번 반환.
|
||||
*/
|
||||
#ifndef CL_APPRREQ_H
|
||||
#define CL_APPRREQ_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_apprreq_rec_t;
|
||||
|
||||
void CL_APPRREQ(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_APPRREQ_H */
|
||||
35
app/src/cl/svc/CL_APPRREQ.pgc
Normal file
35
app/src/cl/svc/CL_APPRREQ.pgc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* CL_APPRREQ.pgc - cl 모듈 서비스 CL_APPRREQ (one service = one file).
|
||||
* 마감 승인 요청: C 상태이며 집계건수>0 인 마감에 승인요청(APPR_REQ) 표시를
|
||||
* 남기고, 자기보다 먼저 요청된 승인 대기(C) 건수 기준 대기 순번을 반환.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_APPRREQ.h"
|
||||
|
||||
void CL_APPRREQ(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_txn, h_ahead;
|
||||
char h_st[4];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
EXEC SQL SELECT status, txn_count INTO :h_st, :h_txn
|
||||
FROM cl_close_log WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
if (h_st[0] != 'C') { Bchg(b, T_MSG, 0, "완료(C) 상태만 승인 요청 가능", 0L); FAIL(b); }
|
||||
if (h_txn <= 0) { Bchg(b, T_MSG, 0, "집계 0건 마감은 승인 불가", 0L); FAIL(b); }
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET memo = memo || '|APPR_REQ', updated_at = now()
|
||||
WHERE close_id = :h_cid AND memo NOT LIKE '%APPR_REQ%';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL SELECT count(*) INTO :h_ahead FROM cl_close_log
|
||||
WHERE status = 'C' AND memo LIKE '%APPR_REQ%' AND close_id < :h_cid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_ARG1, h_ahead + 1);
|
||||
setl(b, T_RC, 0);
|
||||
userlog("CL_APPRREQ cid=%ld 승인요청 대기순번=%ld", h_cid, h_ahead + 1);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_AUDITTRAIL.h
Normal file
21
app/src/cl/svc/CL_AUDITTRAIL.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_AUDITTRAIL.h - cl 서비스 CL_AUDITTRAIL 카피북 (copybook / record header).
|
||||
* 마감 이력 감사: 생성/수정 시각 차이와 잠금 후 수정 여부 감사.
|
||||
*/
|
||||
#ifndef CL_AUDITTRAIL_H
|
||||
#define CL_AUDITTRAIL_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_audittrail_rec_t;
|
||||
|
||||
void CL_AUDITTRAIL(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_AUDITTRAIL_H */
|
||||
37
app/src/cl/svc/CL_AUDITTRAIL.pgc
Normal file
37
app/src/cl/svc/CL_AUDITTRAIL.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* CL_AUDITTRAIL.pgc - cl 모듈 서비스 CL_AUDITTRAIL (one service = one file).
|
||||
* 마감 이력 감사: 마감건의 생성-수정 시각 간격(초)을 산출하고, 잠금(L)
|
||||
* 상태인데 잠금 후에도 수정된 흔적(수정시각>잠금기록시각)을 감사 플래그로 반환.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_AUDITTRAIL.h"
|
||||
|
||||
void CL_AUDITTRAIL(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long flag = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_gap, h_tampered;
|
||||
char h_st[4];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
EXEC SQL SELECT status,
|
||||
cast(extract(epoch from (updated_at - created_at)) as bigint)
|
||||
INTO :h_st, :h_gap FROM cl_close_log WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
if (h_st[0] == 'L') {
|
||||
EXEC SQL SELECT count(*) INTO :h_tampered
|
||||
FROM cl_close_log c, cl_period_lock l
|
||||
WHERE c.close_id = :h_cid AND l.period_key = c.period_key
|
||||
AND c.updated_at > l.locked_at;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_tampered > 0) flag = 1;
|
||||
}
|
||||
Bchg(b, T_STATUS, 0, h_st, 0L);
|
||||
setl(b, T_ARG1, h_gap);
|
||||
setl(b, T_RC, flag);
|
||||
if (flag) userlog("CL_AUDITTRAIL cid=%ld 잠금 후 수정 흔적 감지", h_cid);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_CALENDAR.h
Normal file
21
app/src/cl/svc/CL_CALENDAR.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_CALENDAR.h - cl 서비스 CL_CALENDAR 카피북 (copybook / record header).
|
||||
* 마감 캘린더: 월 일자별 마감 상태 비트맵 문자열 생성.
|
||||
*/
|
||||
#ifndef CL_CALENDAR_H
|
||||
#define CL_CALENDAR_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_calendar_rec_t;
|
||||
|
||||
void CL_CALENDAR(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_CALENDAR_H */
|
||||
45
app/src/cl/svc/CL_CALENDAR.pgc
Normal file
45
app/src/cl/svc/CL_CALENDAR.pgc
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* CL_CALENDAR.pgc - cl 모듈 서비스 CL_CALENDAR (one service = one file).
|
||||
* 마감 캘린더: 월(YYYY-MM)의 1~31일 각 일자 마감 상태를 한 글자씩 표현한
|
||||
* 비트맵 문자열을 만들어 반환한다. '.'=마감없음, 그 외 상태문자(O/C/A/L/R/X).
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_CALENDAR.h"
|
||||
|
||||
void CL_CALENDAR(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char map[33];
|
||||
int i;
|
||||
long done = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_day;
|
||||
char h_month[16], h_st[4];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_STR1, h_month, sizeof(h_month));
|
||||
if (h_month[0] == 0) { Bchg(b, T_MSG, 0, "월(YYYY-MM) 입력 필요", 0L); FAIL(b); }
|
||||
for (i = 0; i < 31; i++) map[i] = '.';
|
||||
map[31] = 0;
|
||||
EXEC SQL DECLARE ccal CURSOR FOR
|
||||
SELECT cast(substr(period_key, 9, 2) as int), max(status)
|
||||
FROM cl_close_log
|
||||
WHERE close_type = 'DAILY' AND period_key LIKE :h_month || '-%'
|
||||
GROUP BY 1 ORDER BY 1;
|
||||
EXEC SQL OPEN ccal;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH ccal INTO :h_day, :h_st;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE ccal; FAIL(b); }
|
||||
if (h_day >= 1 && h_day <= 31) {
|
||||
map[h_day - 1] = h_st[0];
|
||||
if (h_st[0] != 'O' && h_st[0] != 'X') done++;
|
||||
}
|
||||
}
|
||||
EXEC SQL CLOSE ccal;
|
||||
Bchg(b, T_STR1, 0, map, 0L);
|
||||
setl(b, T_COUNT, done);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_CHNCLOSE.h
Normal file
21
app/src/cl/svc/CL_CHNCLOSE.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_CHNCLOSE.h - cl 서비스 CL_CHNCLOSE 카피북 (copybook / record header).
|
||||
* 채널별 마감: 채널(POS/EDC/EDI/FOREIGN) 단위 매입 집계 후 CHN 마감이력 생성.
|
||||
*/
|
||||
#ifndef CL_CHNCLOSE_H
|
||||
#define CL_CHNCLOSE_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_chnclose_rec_t;
|
||||
|
||||
void CL_CHNCLOSE(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_CHNCLOSE_H */
|
||||
35
app/src/cl/svc/CL_CHNCLOSE.pgc
Normal file
35
app/src/cl/svc/CL_CHNCLOSE.pgc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* CL_CHNCLOSE.pgc - cl 모듈 서비스 CL_CHNCLOSE (one service = one file).
|
||||
* 채널별 마감: 채널(POS/EDC/EDI/FOREIGN) 단위로 당일 매입을 집계하고
|
||||
* CHN 마감이력을 생성한다. memo 에 채널명을 남긴다.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_CHNCLOSE.h"
|
||||
|
||||
void CL_CHNCLOSE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char memo[48];
|
||||
long cid;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt, h_amt;
|
||||
char h_bizdate[16], h_chn[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
gets_(b, T_CHANNEL, h_chn, sizeof(h_chn));
|
||||
if (h_chn[0] == 0) strcpy(h_chn, "POS");
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0) INTO :h_cnt, :h_amt
|
||||
FROM purchase WHERE biz_date = :h_bizdate AND channel = :h_chn;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
cid = cldb_next_close_id();
|
||||
if (cid < 0) FAIL(b);
|
||||
snprintf(memo, sizeof(memo), "채널마감:%s", h_chn);
|
||||
if (cldb_insert_close(cid, "CHN", h_bizdate, h_bizdate, "C", h_cnt, h_amt, memo) < 0) FAIL(b);
|
||||
setl(b, T_ID1, cid);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_amt);
|
||||
userlog("CL_CHNCLOSE cid=%ld chn=%s cnt=%ld 채널마감", cid, h_chn, h_cnt);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_CHNVERIFY.h
Normal file
21
app/src/cl/svc/CL_CHNVERIFY.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_CHNVERIFY.h - cl 서비스 CL_CHNVERIFY 카피북 (copybook / record header).
|
||||
* 채널별 마감 검증: 채널 매입건수 vs ledger RECON 조인 대사.
|
||||
*/
|
||||
#ifndef CL_CHNVERIFY_H
|
||||
#define CL_CHNVERIFY_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_chnverify_rec_t;
|
||||
|
||||
void CL_CHNVERIFY(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_CHNVERIFY_H */
|
||||
34
app/src/cl/svc/CL_CHNVERIFY.pgc
Normal file
34
app/src/cl/svc/CL_CHNVERIFY.pgc
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* CL_CHNVERIFY.pgc - cl 모듈 서비스 CL_CHNVERIFY (one service = one file).
|
||||
* 채널별 마감 검증: 영업일+채널의 매입건수와 해당 매입에 연결된 ledger
|
||||
* RECON 전기건수를 조인 대사한다. 미전기 잔여건수를 반환.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_CHNVERIFY.h"
|
||||
|
||||
void CL_CHNVERIFY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pur, h_led;
|
||||
char h_bizdate[16], h_chn[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
gets_(b, T_CHANNEL, h_chn, sizeof(h_chn));
|
||||
if (h_chn[0] == 0) strcpy(h_chn, "POS");
|
||||
EXEC SQL SELECT count(*) INTO :h_pur FROM purchase
|
||||
WHERE biz_date = :h_bizdate AND channel = :h_chn AND status <> 'C';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL SELECT count(DISTINCT l.purchase_id) INTO :h_led
|
||||
FROM ledger l JOIN purchase pu ON pu.purchase_id = l.purchase_id
|
||||
WHERE l.entry_type = 'RECON' AND pu.biz_date = :h_bizdate
|
||||
AND pu.channel = :h_chn;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_ARG1, h_pur);
|
||||
setl(b, T_ARG2, h_led);
|
||||
setl(b, T_DELTA, h_pur - h_led);
|
||||
setl(b, T_RC, (h_pur == h_led) ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_CLOSERATE.h
Normal file
21
app/src/cl/svc/CL_CLOSERATE.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_CLOSERATE.h - cl 서비스 CL_CLOSERATE 카피북 (copybook / record header).
|
||||
* 마감율 산출: 월 영업일 대비 일마감 완료율(bps) 계산.
|
||||
*/
|
||||
#ifndef CL_CLOSERATE_H
|
||||
#define CL_CLOSERATE_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_closerate_rec_t;
|
||||
|
||||
void CL_CLOSERATE(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_CLOSERATE_H */
|
||||
36
app/src/cl/svc/CL_CLOSERATE.pgc
Normal file
36
app/src/cl/svc/CL_CLOSERATE.pgc
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* CL_CLOSERATE.pgc - cl 모듈 서비스 CL_CLOSERATE (one service = one file).
|
||||
* 마감율 산출: 월 프리픽스(YYYY-MM)에 대해 매입이 발생한 영업일수 대비
|
||||
* 일마감 완료(C/A/L)된 일수의 비율을 bps(만분율)로 계산해 반환한다.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_CLOSERATE.h"
|
||||
|
||||
void CL_CLOSERATE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long rate;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_bizdays, h_closed;
|
||||
char h_month[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_STR1, h_month, sizeof(h_month));
|
||||
if (h_month[0] == 0) { Bchg(b, T_MSG, 0, "월(YYYY-MM) 입력 필요", 0L); FAIL(b); }
|
||||
EXEC SQL SELECT count(DISTINCT biz_date) INTO :h_bizdays
|
||||
FROM purchase WHERE to_char(biz_date,'YYYY-MM') = :h_month;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL SELECT count(DISTINCT period_key) INTO :h_closed
|
||||
FROM cl_close_log
|
||||
WHERE close_type = 'DAILY' AND status IN ('C','A','L')
|
||||
AND period_key LIKE :h_month || '%';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
rate = (h_bizdays > 0) ? (h_closed * 10000) / h_bizdays : 0;
|
||||
if (rate > 10000) rate = 10000;
|
||||
setl(b, T_ARG1, h_bizdays);
|
||||
setl(b, T_ARG2, h_closed);
|
||||
setl(b, T_ARG3, rate);
|
||||
setl(b, T_RC, (rate >= 10000) ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_CNTXCHECK.h
Normal file
21
app/src/cl/svc/CL_CNTXCHECK.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_CNTXCHECK.h - cl 서비스 CL_CNTXCHECK 카피북 (copybook / record header).
|
||||
* 마감 건수 크로스체크: 마감이력 vs 실매입 vs 스냅샷 3원 건수 대사.
|
||||
*/
|
||||
#ifndef CL_CNTXCHECK_H
|
||||
#define CL_CNTXCHECK_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_cntxcheck_rec_t;
|
||||
|
||||
void CL_CNTXCHECK(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_CNTXCHECK_H */
|
||||
37
app/src/cl/svc/CL_CNTXCHECK.pgc
Normal file
37
app/src/cl/svc/CL_CNTXCHECK.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* CL_CNTXCHECK.pgc - cl 모듈 서비스 CL_CNTXCHECK (one service = one file).
|
||||
* 마감 건수 크로스체크: 마감이력 txn_count vs 실매입 count vs 스냅샷
|
||||
* txn_count 합계의 3원 대사. RC 비트: 1=이력/실매입 불일치, 2=이력/스냅샷 불일치.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_CNTXCHECK.h"
|
||||
|
||||
void CL_CNTXCHECK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long rc = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_log, h_real, h_snap;
|
||||
char h_date[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
EXEC SQL SELECT txn_count, to_char(biz_date,'YYYY-MM-DD') INTO :h_log, :h_date
|
||||
FROM cl_close_log WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
EXEC SQL SELECT count(*) INTO :h_real FROM purchase WHERE biz_date = :h_date;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL SELECT coalesce(sum(txn_count),0) INTO :h_snap
|
||||
FROM cl_snapshot WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_log != h_real) rc |= 1;
|
||||
if (h_snap != 0 && h_log != h_snap) rc |= 2;
|
||||
setl(b, T_ARG1, h_log);
|
||||
setl(b, T_ARG2, h_real);
|
||||
setl(b, T_ARG3, h_snap);
|
||||
setl(b, T_RC, rc);
|
||||
if (rc) userlog("CL_CNTXCHECK cid=%ld 건수 불일치 rc=%ld (%ld/%ld/%ld)",
|
||||
h_cid, rc, h_log, h_real, h_snap);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_CORPCLOSE.h
Normal file
21
app/src/cl/svc/CL_CORPCLOSE.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_CORPCLOSE.h - cl 서비스 CL_CORPCLOSE 카피북 (copybook / record header).
|
||||
* 법인별 마감: 발급사(issuer) 법인 단위 커서 순회로 CORP 마감이력 일괄 생성.
|
||||
*/
|
||||
#ifndef CL_CORPCLOSE_H
|
||||
#define CL_CORPCLOSE_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_corpclose_rec_t;
|
||||
|
||||
void CL_CORPCLOSE(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_CORPCLOSE_H */
|
||||
43
app/src/cl/svc/CL_CORPCLOSE.pgc
Normal file
43
app/src/cl/svc/CL_CORPCLOSE.pgc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* CL_CORPCLOSE.pgc - cl 모듈 서비스 CL_CORPCLOSE (one service = one file).
|
||||
* 법인별 마감: 당일 매입을 발급사(issuer) 법인 단위로 그룹 커서 순회하며
|
||||
* 법인마다 CORP 마감이력을 한 건씩 생성한다. 생성 건수를 반환.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_CORPCLOSE.h"
|
||||
|
||||
void CL_CORPCLOSE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long made = 0, lastcid = 0, cid;
|
||||
char memo[64];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt, h_amt;
|
||||
char h_bizdate[16], h_issuer[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
EXEC SQL DECLARE ccorp CURSOR FOR
|
||||
SELECT issuer, count(*), coalesce(sum(amount),0) FROM purchase
|
||||
WHERE biz_date = :h_bizdate GROUP BY issuer ORDER BY issuer;
|
||||
EXEC SQL OPEN ccorp;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH ccorp INTO :h_issuer, :h_cnt, :h_amt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE ccorp; FAIL(b); }
|
||||
cid = cldb_next_close_id();
|
||||
if (cid < 0) { EXEC SQL CLOSE ccorp; FAIL(b); }
|
||||
snprintf(memo, sizeof(memo), "법인마감:%s", h_issuer);
|
||||
if (cldb_insert_close(cid, "CORP", h_bizdate, h_bizdate, "C",
|
||||
h_cnt, h_amt, memo) < 0) { EXEC SQL CLOSE ccorp; FAIL(b); }
|
||||
lastcid = cid;
|
||||
made++;
|
||||
}
|
||||
EXEC SQL CLOSE ccorp;
|
||||
setl(b, T_COUNT, made);
|
||||
setl(b, T_ID1, lastcid);
|
||||
userlog("CL_CORPCLOSE %s 법인마감 %ld건 생성", h_bizdate, made);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_CXLREASON.h
Normal file
21
app/src/cl/svc/CL_CXLREASON.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_CXLREASON.h - cl 서비스 CL_CXLREASON 카피북 (copybook / record header).
|
||||
* 마감 취소 사유별 집계: X 상태 memo 그룹 커서 → occurrence 반환.
|
||||
*/
|
||||
#ifndef CL_CXLREASON_H
|
||||
#define CL_CXLREASON_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_cxlreason_rec_t;
|
||||
|
||||
void CL_CXLREASON(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_CXLREASON_H */
|
||||
39
app/src/cl/svc/CL_CXLREASON.pgc
Normal file
39
app/src/cl/svc/CL_CXLREASON.pgc
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* CL_CXLREASON.pgc - cl 모듈 서비스 CL_CXLREASON (one service = one file).
|
||||
* 마감 취소 사유별 집계: 기간 프리픽스의 취소(X) 마감을 memo(사유)별로 그룹
|
||||
* 커서 순회하여 UBF occurrence (T_STR1[i]=사유, T_ARG1[i]=건수) 로 반환.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_CXLREASON.h"
|
||||
|
||||
void CL_CXLREASON(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long occ = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_n;
|
||||
char h_prefix[16], h_memo[80];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_STR1, h_prefix, sizeof(h_prefix));
|
||||
if (h_prefix[0] == 0) strcpy(h_prefix, "2026");
|
||||
EXEC SQL DECLARE ccxl CURSOR FOR
|
||||
SELECT memo, count(*) FROM cl_close_log
|
||||
WHERE status = 'X' AND period_key LIKE :h_prefix || '%'
|
||||
GROUP BY memo ORDER BY count(*) DESC, memo;
|
||||
EXEC SQL OPEN ccxl;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH ccxl INTO :h_memo, :h_n;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE ccxl; FAIL(b); }
|
||||
if (occ >= 20) break; /* occurrence 상한 */
|
||||
Bchg(b, T_STR1, (BFLDOCC)occ, h_memo, 0L);
|
||||
Bchg(b, T_ARG1, (BFLDOCC)occ, (char *)&h_n, 0L);
|
||||
occ++;
|
||||
}
|
||||
EXEC SQL CLOSE ccxl;
|
||||
setl(b, T_COUNT, occ);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_DELAYLIST.h
Normal file
21
app/src/cl/svc/CL_DELAYLIST.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_DELAYLIST.h - cl 서비스 CL_DELAYLIST 카피북 (copybook / record header).
|
||||
* 지연 마감 목록: 24시간 경과 미완료(O) 마감 커서 목록 반환.
|
||||
*/
|
||||
#ifndef CL_DELAYLIST_H
|
||||
#define CL_DELAYLIST_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_delaylist_rec_t;
|
||||
|
||||
void CL_DELAYLIST(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_DELAYLIST_H */
|
||||
38
app/src/cl/svc/CL_DELAYLIST.pgc
Normal file
38
app/src/cl/svc/CL_DELAYLIST.pgc
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* CL_DELAYLIST.pgc - cl 모듈 서비스 CL_DELAYLIST (one service = one file).
|
||||
* 지연 마감 목록: 생성 후 24시간이 지나도록 개시(O) 상태로 남은 마감을
|
||||
* 커서로 수집해 occurrence (T_ID1[i], T_STR1[i]=기간) 목록으로 반환한다.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_DELAYLIST.h"
|
||||
|
||||
void CL_DELAYLIST(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long occ = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid;
|
||||
char h_period[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
EXEC SQL DECLARE cdly CURSOR FOR
|
||||
SELECT close_id, period_key FROM cl_close_log
|
||||
WHERE status = 'O' AND created_at < now() - interval '24 hours'
|
||||
ORDER BY created_at;
|
||||
EXEC SQL OPEN cdly;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH cdly INTO :h_cid, :h_period;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cdly; FAIL(b); }
|
||||
if (occ >= 40) break;
|
||||
Bchg(b, T_ID1, (BFLDOCC)occ, (char *)&h_cid, 0L);
|
||||
Bchg(b, T_STR1, (BFLDOCC)occ, h_period, 0L);
|
||||
occ++;
|
||||
}
|
||||
EXEC SQL CLOSE cdly;
|
||||
setl(b, T_COUNT, occ);
|
||||
setl(b, T_RC, (occ > 0) ? 1 : 0);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_DELAYREG.h
Normal file
21
app/src/cl/svc/CL_DELAYREG.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_DELAYREG.h - cl 서비스 CL_DELAYREG 카피북 (copybook / record header).
|
||||
* 마감 지연 사유 등록: 개시(O) 상태 마감건 memo 에 지연 사유 기록.
|
||||
*/
|
||||
#ifndef CL_DELAYREG_H
|
||||
#define CL_DELAYREG_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_delayreg_rec_t;
|
||||
|
||||
void CL_DELAYREG(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_DELAYREG_H */
|
||||
36
app/src/cl/svc/CL_DELAYREG.pgc
Normal file
36
app/src/cl/svc/CL_DELAYREG.pgc
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* CL_DELAYREG.pgc - cl 모듈 서비스 CL_DELAYREG (one service = one file).
|
||||
* 마감 지연 사유 등록: 개시(O) 상태의 마감건에만 지연 사유를 memo 로
|
||||
* 기록한다 (기존 memo 에 '지연:' 프리픽스로 덧붙임). 상태가 O 가 아니면 거절.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_DELAYREG.h"
|
||||
|
||||
void CL_DELAYREG(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char st[4], reason[64];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid;
|
||||
char h_reason[80];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
gets_(b, T_REASON, reason, sizeof(reason));
|
||||
if (reason[0] == 0) { Bchg(b, T_MSG, 0, "지연 사유 누락", 0L); FAIL(b); }
|
||||
if (cldb_get_close_status(h_cid, st) < 0) FAIL(b);
|
||||
if (st[0] != 'O') {
|
||||
setl(b, T_RC, 9);
|
||||
Bchg(b, T_MSG, 0, "개시(O) 상태만 지연 등록 가능", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
snprintf(h_reason, sizeof(h_reason), "지연:%s", reason);
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET memo = :h_reason, updated_at = now()
|
||||
WHERE close_id = :h_cid AND status = 'O';
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] == 0) FAIL(b);
|
||||
setl(b, T_RC, 0);
|
||||
userlog("CL_DELAYREG cid=%ld 지연사유 등록: %s", h_cid, reason);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_DIVCLOSE.h
Normal file
21
app/src/cl/svc/CL_DIVCLOSE.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_DIVCLOSE.h - cl 서비스 CL_DIVCLOSE 카피북 (copybook / record header).
|
||||
* 부문별 마감: 업종(category) 부문 단위 정산액 집계 후 DIV 마감이력 직접 생성.
|
||||
*/
|
||||
#ifndef CL_DIVCLOSE_H
|
||||
#define CL_DIVCLOSE_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_divclose_rec_t;
|
||||
|
||||
void CL_DIVCLOSE(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_DIVCLOSE_H */
|
||||
36
app/src/cl/svc/CL_DIVCLOSE.pgc
Normal file
36
app/src/cl/svc/CL_DIVCLOSE.pgc
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* CL_DIVCLOSE.pgc - cl 모듈 서비스 CL_DIVCLOSE (one service = one file).
|
||||
* 부문별 마감: 업종(category) 부문 단위로 당일 매입 건수/정산액(net)을 집계하고
|
||||
* 마감이력을 nextval 로 직접 INSERT (DIV, status C, memo=부문코드).
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_DIVCLOSE.h"
|
||||
|
||||
void CL_DIVCLOSE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_cnt, h_net;
|
||||
char h_bizdate[16], h_cat[16], h_memo[48];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
gets_(b, T_CATEGORY, h_cat, sizeof(h_cat));
|
||||
if (h_cat[0] == 0) strcpy(h_cat, "GEN");
|
||||
EXEC SQL SELECT count(*), coalesce(sum(net),0) INTO :h_cnt, :h_net
|
||||
FROM purchase
|
||||
WHERE biz_date = :h_bizdate AND category = :h_cat AND status <> 'C';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
snprintf(h_memo, sizeof(h_memo), "부문마감:%s", h_cat);
|
||||
EXEC SQL SELECT nextval('cl_close_seq') INTO :h_cid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL INSERT INTO cl_close_log
|
||||
(close_id, close_type, period_key, biz_date, status, txn_count, total_amount, memo)
|
||||
VALUES (:h_cid, 'DIV', :h_bizdate, :h_bizdate, 'C', :h_cnt, :h_net, :h_memo);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_ID1, h_cid);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_NET, h_net);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_DUPCHK.h
Normal file
21
app/src/cl/svc/CL_DUPCHK.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_DUPCHK.h - cl 서비스 CL_DUPCHK 카피북 (copybook / record header).
|
||||
* 중복 마감 탐지: (유형,기간) 중복 마감 그룹 탐지 집계.
|
||||
*/
|
||||
#ifndef CL_DUPCHK_H
|
||||
#define CL_DUPCHK_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_dupchk_rec_t;
|
||||
|
||||
void CL_DUPCHK(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_DUPCHK_H */
|
||||
43
app/src/cl/svc/CL_DUPCHK.pgc
Normal file
43
app/src/cl/svc/CL_DUPCHK.pgc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* CL_DUPCHK.pgc - cl 모듈 서비스 CL_DUPCHK (one service = one file).
|
||||
* 중복 마감 탐지: 취소(X) 제외 동일 (close_type, period_key) 에 마감이 2건
|
||||
* 이상인 그룹을 HAVING 으로 찾아 그룹 수와 잉여 건수 합계를 반환한다.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_DUPCHK.h"
|
||||
|
||||
void CL_DUPCHK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long groups = 0, extras = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_n;
|
||||
char h_type[16], h_period[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
EXEC SQL DECLARE cdup CURSOR FOR
|
||||
SELECT close_type, period_key, count(*) FROM cl_close_log
|
||||
WHERE status <> 'X'
|
||||
GROUP BY close_type, period_key HAVING count(*) > 1
|
||||
ORDER BY count(*) DESC;
|
||||
EXEC SQL OPEN cdup;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH cdup INTO :h_type, :h_period, :h_n;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cdup; FAIL(b); }
|
||||
if (groups < 20) {
|
||||
Bchg(b, T_STR2, (BFLDOCC)groups, h_type, 0L);
|
||||
Bchg(b, T_KEY2, (BFLDOCC)groups, h_period, 0L);
|
||||
}
|
||||
extras += h_n - 1;
|
||||
groups++;
|
||||
}
|
||||
EXEC SQL CLOSE cdup;
|
||||
setl(b, T_COUNT, groups);
|
||||
setl(b, T_ARG1, extras);
|
||||
setl(b, T_RC, (groups == 0) ? 0 : 1);
|
||||
if (groups) userlog("CL_DUPCHK 중복그룹 %ld개 잉여 %ld건", groups, extras);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_ESCALATE.h
Normal file
21
app/src/cl/svc/CL_ESCALATE.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_ESCALATE.h - cl 서비스 CL_ESCALATE 카피북 (copybook / record header).
|
||||
* 승인 지연 에스컬레이션: 기준일 초과 대기 마감 ESC 표시.
|
||||
*/
|
||||
#ifndef CL_ESCALATE_H
|
||||
#define CL_ESCALATE_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_escalate_rec_t;
|
||||
|
||||
void CL_ESCALATE(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_ESCALATE_H */
|
||||
35
app/src/cl/svc/CL_ESCALATE.pgc
Normal file
35
app/src/cl/svc/CL_ESCALATE.pgc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* CL_ESCALATE.pgc - cl 모듈 서비스 CL_ESCALATE (one service = one file).
|
||||
* 승인 지연 에스컬레이션: 기준일수(T_ARG1, 기본 3일) 초과 승인 대기(C)
|
||||
* 마감에 ESC 표시를 일괄 갱신하고 대상 건수를 반환한다.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_ESCALATE.h"
|
||||
|
||||
void CL_ESCALATE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long marked;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_days, h_left;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_days = getl(b, T_ARG1);
|
||||
if (h_days <= 0) h_days = 3;
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET memo = memo || '|ESC', updated_at = now()
|
||||
WHERE status = 'C' AND memo LIKE '%APPR_REQ%'
|
||||
AND memo NOT LIKE '%|ESC%'
|
||||
AND created_at < now() - make_interval(days => cast(:h_days as int));
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
marked = sqlca.sqlerrd[2];
|
||||
EXEC SQL SELECT count(*) INTO :h_left FROM cl_close_log
|
||||
WHERE status = 'C' AND memo LIKE '%APPR_REQ%' AND memo NOT LIKE '%|ESC%';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, marked);
|
||||
setl(b, T_ARG2, h_left);
|
||||
setl(b, T_RC, (marked > 0) ? 1 : 0);
|
||||
if (marked) userlog("CL_ESCALATE %ld일 초과 %ld건 에스컬레이션", h_days, marked);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_FEEVERIFY.h
Normal file
21
app/src/cl/svc/CL_FEEVERIFY.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_FEEVERIFY.h - cl 서비스 CL_FEEVERIFY 카피북 (copybook / record header).
|
||||
* 수수료 검증: 스냅샷 fee 합계 vs 매입 fee 합계 대사.
|
||||
*/
|
||||
#ifndef CL_FEEVERIFY_H
|
||||
#define CL_FEEVERIFY_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_feeverify_rec_t;
|
||||
|
||||
void CL_FEEVERIFY(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_FEEVERIFY_H */
|
||||
39
app/src/cl/svc/CL_FEEVERIFY.pgc
Normal file
39
app/src/cl/svc/CL_FEEVERIFY.pgc
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* CL_FEEVERIFY.pgc - cl 모듈 서비스 CL_FEEVERIFY (one service = one file).
|
||||
* 수수료 검증: 마감 스냅샷의 fee 합계와 해당 영업일 매입 fee 합계에
|
||||
* 수수료 조정(ac_fee_adj delta)을 가산한 기대치를 대사한다.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_FEEVERIFY.h"
|
||||
|
||||
void CL_FEEVERIFY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long expect;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_snapfee, h_purfee, h_adj;
|
||||
char h_date[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
EXEC SQL SELECT to_char(biz_date,'YYYY-MM-DD') INTO :h_date
|
||||
FROM cl_close_log WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
EXEC SQL SELECT coalesce(sum(fee_amount),0) INTO :h_snapfee
|
||||
FROM cl_snapshot WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL SELECT coalesce(sum(fee),0) INTO :h_purfee
|
||||
FROM purchase WHERE biz_date = :h_date;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL SELECT coalesce(sum(delta),0) INTO :h_adj
|
||||
FROM ac_fee_adj WHERE biz_date = :h_date;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
expect = h_purfee + h_adj;
|
||||
setl(b, T_AMT1, h_snapfee);
|
||||
setl(b, T_AMT2, h_purfee);
|
||||
setl(b, T_AMT3, h_adj);
|
||||
setl(b, T_DELTA, h_snapfee - expect);
|
||||
setl(b, T_RC, (h_snapfee == expect) ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_FINALIZE.h
Normal file
21
app/src/cl/svc/CL_FINALIZE.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_FINALIZE.h - cl 서비스 CL_FINALIZE 카피북 (copybook / record header).
|
||||
* 본마감: 가마감(PROV) 대상 재집계 후 본마감(C) 확정 전환.
|
||||
*/
|
||||
#ifndef CL_FINALIZE_H
|
||||
#define CL_FINALIZE_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_finalize_rec_t;
|
||||
|
||||
void CL_FINALIZE(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_FINALIZE_H */
|
||||
39
app/src/cl/svc/CL_FINALIZE.pgc
Normal file
39
app/src/cl/svc/CL_FINALIZE.pgc
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* CL_FINALIZE.pgc - cl 모듈 서비스 CL_FINALIZE (one service = one file).
|
||||
* 본마감: 해당 영업일의 가마감(PROV, status O)을 찾아 매입을 재집계한 뒤
|
||||
* 본마감(C)으로 확정 전환한다. 가마감 시점과 건수가 달라졌으면 새 집계로 갱신.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_FINALIZE.h"
|
||||
|
||||
void CL_FINALIZE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_oldcnt, h_cnt, h_amt;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
EXEC SQL SELECT close_id, txn_count INTO :h_cid, :h_oldcnt FROM cl_close_log
|
||||
WHERE close_type = 'DAILY' AND period_key = :h_bizdate
|
||||
AND status = 'O' AND memo = 'PROV'
|
||||
ORDER BY close_id DESC LIMIT 1;
|
||||
if (sqlca.sqlcode == 100) { Bchg(b, T_MSG, 0, "확정할 가마감 없음", 0L); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0) INTO :h_cnt, :h_amt
|
||||
FROM purchase WHERE biz_date = :h_bizdate AND status IN ('M','S');
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET status = 'C', txn_count = :h_cnt, total_amount = :h_amt,
|
||||
memo = 'FINAL', updated_at = now()
|
||||
WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] == 0) FAIL(b);
|
||||
setl(b, T_ID1, h_cid);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_DELTA, h_cnt - h_oldcnt);
|
||||
Bchg(b, T_STATUS, 0, "C", 0L);
|
||||
userlog("CL_FINALIZE cid=%ld 본마감 확정 (가마감 대비 %+ld건)", h_cid, h_cnt - h_oldcnt);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_FORCECLOSE.h
Normal file
21
app/src/cl/svc/CL_FORCECLOSE.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_FORCECLOSE.h - cl 서비스 CL_FORCECLOSE 카피북 (copybook / record header).
|
||||
* 강제 마감: 기존 개시(O)건 제거 후 FORCE 마감 생성.
|
||||
*/
|
||||
#ifndef CL_FORCECLOSE_H
|
||||
#define CL_FORCECLOSE_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_forceclose_rec_t;
|
||||
|
||||
void CL_FORCECLOSE(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_FORCECLOSE_H */
|
||||
37
app/src/cl/svc/CL_FORCECLOSE.pgc
Normal file
37
app/src/cl/svc/CL_FORCECLOSE.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* CL_FORCECLOSE.pgc - cl 모듈 서비스 CL_FORCECLOSE (one service = one file).
|
||||
* 강제 마감: 체크리스트를 우회해 해당 영업일의 미확정 개시(O) 마감을 제거한
|
||||
* 뒤 FORCE memo 로 즉시 완료(C) 마감을 생성한다. 운영 비상용.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_FORCECLOSE.h"
|
||||
|
||||
void CL_FORCECLOSE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long cid, wiped;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt, h_amt;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
EXEC SQL DELETE FROM cl_close_log
|
||||
WHERE close_type = 'DAILY' AND period_key = :h_bizdate AND status = 'O';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
wiped = sqlca.sqlerrd[2];
|
||||
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);
|
||||
cid = cldb_next_close_id();
|
||||
if (cid < 0) FAIL(b);
|
||||
if (cldb_insert_close(cid, "DAILY", h_bizdate, h_bizdate, "C",
|
||||
h_cnt, h_amt, "FORCE") < 0) FAIL(b);
|
||||
setl(b, T_ID1, cid);
|
||||
setl(b, T_ARG1, wiped);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
Bchg(b, T_STATUS, 0, "C", 0L);
|
||||
userlog("CL_FORCECLOSE %s 강제마감 cid=%ld (개시건 %ld건 제거)", h_bizdate, cid, wiped);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_GAPDAYS.h
Normal file
21
app/src/cl/svc/CL_GAPDAYS.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_GAPDAYS.h - cl 서비스 CL_GAPDAYS 카피북 (copybook / record header).
|
||||
* 마감 누락일 탐지: 매입 존재하나 일마감 없는 일자 커서 수집.
|
||||
*/
|
||||
#ifndef CL_GAPDAYS_H
|
||||
#define CL_GAPDAYS_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_gapdays_rec_t;
|
||||
|
||||
void CL_GAPDAYS(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_GAPDAYS_H */
|
||||
42
app/src/cl/svc/CL_GAPDAYS.pgc
Normal file
42
app/src/cl/svc/CL_GAPDAYS.pgc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* CL_GAPDAYS.pgc - cl 모듈 서비스 CL_GAPDAYS (one service = one file).
|
||||
* 마감 누락일 탐지: 월 프리픽스 내 매입은 존재하나 일마감이 없는 일자를
|
||||
* NOT EXISTS 커서로 수집해 occurrence (T_STR4[i]=일자) 로 반환한다.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_GAPDAYS.h"
|
||||
|
||||
void CL_GAPDAYS(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long occ = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_month[16], h_day[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_STR1, h_month, sizeof(h_month));
|
||||
if (h_month[0] == 0) { Bchg(b, T_MSG, 0, "월(YYYY-MM) 입력 필요", 0L); FAIL(b); }
|
||||
EXEC SQL DECLARE cgapd CURSOR FOR
|
||||
SELECT DISTINCT to_char(p.biz_date,'YYYY-MM-DD') FROM purchase p
|
||||
WHERE to_char(p.biz_date,'YYYY-MM') = :h_month
|
||||
AND NOT EXISTS (SELECT 1 FROM cl_close_log c
|
||||
WHERE c.close_type = 'DAILY'
|
||||
AND c.period_key = to_char(p.biz_date,'YYYY-MM-DD')
|
||||
AND c.status <> 'X')
|
||||
ORDER BY 1;
|
||||
EXEC SQL OPEN cgapd;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH cgapd INTO :h_day;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cgapd; FAIL(b); }
|
||||
if (occ >= 31) break;
|
||||
Bchg(b, T_STR4, (BFLDOCC)occ, h_day, 0L);
|
||||
occ++;
|
||||
}
|
||||
EXEC SQL CLOSE cgapd;
|
||||
setl(b, T_COUNT, occ);
|
||||
setl(b, T_RC, (occ == 0) ? 0 : 1);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_HALFCLOSE.h
Normal file
21
app/src/cl/svc/CL_HALFCLOSE.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_HALFCLOSE.h - cl 서비스 CL_HALFCLOSE 카피북 (copybook / record header).
|
||||
* 반기 결산 마감: 상/하반기 기간 집계 후 HALF 마감이력 생성.
|
||||
*/
|
||||
#ifndef CL_HALFCLOSE_H
|
||||
#define CL_HALFCLOSE_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_halfclose_rec_t;
|
||||
|
||||
void CL_HALFCLOSE(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_HALFCLOSE_H */
|
||||
45
app/src/cl/svc/CL_HALFCLOSE.pgc
Normal file
45
app/src/cl/svc/CL_HALFCLOSE.pgc
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* CL_HALFCLOSE.pgc - cl 모듈 서비스 CL_HALFCLOSE (one service = one file).
|
||||
* 반기 결산 마감: 연도(T_STR1=YYYY)와 반기(T_ARG1=1|2)를 받아 상/하반기
|
||||
* 날짜구간을 만들어 매입을 BETWEEN 집계하고 HALF 마감이력(YYYY-Hn)을 생성.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_HALFCLOSE.h"
|
||||
|
||||
void CL_HALFCLOSE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long half, cid;
|
||||
char year[8], period[16];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt, h_amt;
|
||||
char h_from[16], h_to[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_STR1, year, sizeof(year));
|
||||
half = getl(b, T_ARG1);
|
||||
if (year[0] == 0 || (half != 1 && half != 2)) {
|
||||
Bchg(b, T_MSG, 0, "연도(YYYY)/반기(1|2) 입력 필요", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
if (half == 1) {
|
||||
snprintf(h_from, sizeof(h_from), "%s-01-01", year);
|
||||
snprintf(h_to, sizeof(h_to), "%s-06-30", year);
|
||||
} else {
|
||||
snprintf(h_from, sizeof(h_from), "%s-07-01", year);
|
||||
snprintf(h_to, sizeof(h_to), "%s-12-31", year);
|
||||
}
|
||||
snprintf(period, sizeof(period), "%s-H%ld", year, half);
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0) INTO :h_cnt, :h_amt
|
||||
FROM purchase WHERE biz_date BETWEEN :h_from AND :h_to;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
cid = cldb_next_close_id();
|
||||
if (cid < 0) FAIL(b);
|
||||
if (cldb_insert_close(cid, "HALF", period, h_to, "C", h_cnt, h_amt, "반기결산") < 0) FAIL(b);
|
||||
setl(b, T_ID1, cid);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_amt);
|
||||
userlog("CL_HALFCLOSE %s 반기결산 cid=%ld cnt=%ld", period, cid, h_cnt);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_HOLIDAY.h
Normal file
21
app/src/cl/svc/CL_HOLIDAY.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_HOLIDAY.h - cl 서비스 CL_HOLIDAY 카피북 (copybook / record header).
|
||||
* 휴일 마감 정책: 요일 판정으로 휴일이면 마감 SKIP 정책 응답.
|
||||
*/
|
||||
#ifndef CL_HOLIDAY_H
|
||||
#define CL_HOLIDAY_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_holiday_rec_t;
|
||||
|
||||
void CL_HOLIDAY(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_HOLIDAY_H */
|
||||
38
app/src/cl/svc/CL_HOLIDAY.pgc
Normal file
38
app/src/cl/svc/CL_HOLIDAY.pgc
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* CL_HOLIDAY.pgc - cl 모듈 서비스 CL_HOLIDAY (one service = one file).
|
||||
* 휴일 마감 정책: 영업일의 요일을 판정해 주말이면 마감 SKIP(RC=1) 정책을,
|
||||
* 평일이면 매입 유무에 따라 진행(0)/무거래(2) 를 응답한다.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_HOLIDAY.h"
|
||||
|
||||
void CL_HOLIDAY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_txn;
|
||||
char h_bizdate[16], h_dow[4];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
EXEC SQL SELECT to_char(to_date(:h_bizdate,'YYYY-MM-DD'),'D') INTO :h_dow;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
Bchg(b, T_STR3, 0, h_dow, 0L);
|
||||
if (h_dow[0] == '1' || h_dow[0] == '7') {
|
||||
setl(b, T_RC, 1);
|
||||
Bchg(b, T_MSG, 0, "휴일 정책: 주말 마감 SKIP, 익영업일로 이월", 0L);
|
||||
OK(b);
|
||||
}
|
||||
EXEC SQL SELECT count(*) INTO :h_txn FROM purchase WHERE biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, h_txn);
|
||||
if (h_txn == 0) {
|
||||
setl(b, T_RC, 2);
|
||||
Bchg(b, T_MSG, 0, "평일 무거래: 0건 마감 여부 운영 판단", 0L);
|
||||
} else {
|
||||
setl(b, T_RC, 0);
|
||||
Bchg(b, T_MSG, 0, "평일 정상: 마감 진행 가능", 0L);
|
||||
}
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_LOCKAUDIT.h
Normal file
21
app/src/cl/svc/CL_LOCKAUDIT.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_LOCKAUDIT.h - cl 서비스 CL_LOCKAUDIT 카피북 (copybook / record header).
|
||||
* 잠금 감사: 승인(A/L) 마감 없는 잠금 기간 탐지.
|
||||
*/
|
||||
#ifndef CL_LOCKAUDIT_H
|
||||
#define CL_LOCKAUDIT_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_lockaudit_rec_t;
|
||||
|
||||
void CL_LOCKAUDIT(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_LOCKAUDIT_H */
|
||||
33
app/src/cl/svc/CL_LOCKAUDIT.pgc
Normal file
33
app/src/cl/svc/CL_LOCKAUDIT.pgc
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* CL_LOCKAUDIT.pgc - cl 모듈 서비스 CL_LOCKAUDIT (one service = one file).
|
||||
* 잠금 감사: 잠금(locked=true) 기간 중 승인(A) 또는 잠금(L) 마감이 하나도
|
||||
* 없는 비정상 잠금을 탐지해 건수와 첫 위반 기간키를 반환한다.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_LOCKAUDIT.h"
|
||||
|
||||
void CL_LOCKAUDIT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_bad;
|
||||
char h_first[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
EXEC SQL SELECT count(*), coalesce(min(l.period_key),'')
|
||||
INTO :h_bad, :h_first
|
||||
FROM cl_period_lock l
|
||||
WHERE l.locked = true
|
||||
AND NOT EXISTS (SELECT 1 FROM cl_close_log c
|
||||
WHERE c.period_key = l.period_key
|
||||
AND c.status IN ('A','L'));
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, h_bad);
|
||||
setl(b, T_RC, (h_bad == 0) ? 0 : 1);
|
||||
if (h_bad > 0) {
|
||||
Bchg(b, T_KEY1, 0, h_first, 0L);
|
||||
userlog("CL_LOCKAUDIT 승인없는 잠금 %ld건 (최초 %s)", h_bad, h_first);
|
||||
}
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_LOCKSWEEP.h
Normal file
21
app/src/cl/svc/CL_LOCKSWEEP.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_LOCKSWEEP.h - cl 서비스 CL_LOCKSWEEP 카피북 (copybook / record header).
|
||||
* 기간 잠금 일괄: 프리픽스 잠금 갱신 + 누락 잠금 보충 삽입.
|
||||
*/
|
||||
#ifndef CL_LOCKSWEEP_H
|
||||
#define CL_LOCKSWEEP_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_locksweep_rec_t;
|
||||
|
||||
void CL_LOCKSWEEP(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_LOCKSWEEP_H */
|
||||
37
app/src/cl/svc/CL_LOCKSWEEP.pgc
Normal file
37
app/src/cl/svc/CL_LOCKSWEEP.pgc
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* CL_LOCKSWEEP.pgc - cl 모듈 서비스 CL_LOCKSWEEP (one service = one file).
|
||||
* 기간 잠금 일괄: 프리픽스 구간의 기존 잠금 레코드를 locked=true 로 재잠금하고
|
||||
* 승인(A/L) 마감이 있으나 잠금 레코드가 없는 기간은 보충 INSERT 한다.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_LOCKSWEEP.h"
|
||||
|
||||
void CL_LOCKSWEEP(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long relocked, added;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
char h_prefix[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_STR1, h_prefix, sizeof(h_prefix));
|
||||
if (h_prefix[0] == 0) { Bchg(b, T_MSG, 0, "잠금 프리픽스 필요", 0L); FAIL(b); }
|
||||
EXEC SQL UPDATE cl_period_lock
|
||||
SET locked = true, locked_at = now()
|
||||
WHERE period_key LIKE :h_prefix || '%' AND locked = false;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
relocked = sqlca.sqlerrd[2];
|
||||
EXEC SQL INSERT INTO cl_period_lock (period_key, locked)
|
||||
SELECT DISTINCT c.period_key, true FROM cl_close_log c
|
||||
WHERE c.period_key LIKE :h_prefix || '%' AND c.status IN ('A','L')
|
||||
AND NOT EXISTS (SELECT 1 FROM cl_period_lock l
|
||||
WHERE l.period_key = c.period_key);
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
added = sqlca.sqlerrd[2];
|
||||
setl(b, T_ARG1, relocked);
|
||||
setl(b, T_ARG2, added);
|
||||
setl(b, T_COUNT, relocked + added);
|
||||
userlog("CL_LOCKSWEEP %s 재잠금=%ld 보충=%ld", h_prefix, relocked, added);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_MEMOSEARCH.h
Normal file
21
app/src/cl/svc/CL_MEMOSEARCH.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_MEMOSEARCH.h - cl 서비스 CL_MEMOSEARCH 카피북 (copybook / record header).
|
||||
* 마감 사유 검색: memo 키워드 검색으로 최신 마감 반환.
|
||||
*/
|
||||
#ifndef CL_MEMOSEARCH_H
|
||||
#define CL_MEMOSEARCH_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_memosearch_rec_t;
|
||||
|
||||
void CL_MEMOSEARCH(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_MEMOSEARCH_H */
|
||||
35
app/src/cl/svc/CL_MEMOSEARCH.pgc
Normal file
35
app/src/cl/svc/CL_MEMOSEARCH.pgc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* CL_MEMOSEARCH.pgc - cl 모듈 서비스 CL_MEMOSEARCH (one service = one file).
|
||||
* 마감 사유 검색: memo 에 키워드(T_STR1)가 포함된 마감을 검색해 총 건수와
|
||||
* 가장 최근 마감의 id/상태/기간을 반환한다. 키워드 없으면 거절.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_MEMOSEARCH.h"
|
||||
|
||||
void CL_MEMOSEARCH(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_hits, h_cid;
|
||||
char h_kw[40], h_st[4], h_period[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_STR1, h_kw, sizeof(h_kw));
|
||||
if (h_kw[0] == 0) { Bchg(b, T_MSG, 0, "검색 키워드 필요", 0L); FAIL(b); }
|
||||
EXEC SQL SELECT count(*) INTO :h_hits FROM cl_close_log
|
||||
WHERE memo LIKE '%' || :h_kw || '%';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, h_hits);
|
||||
if (h_hits == 0) { setl(b, T_RC, 1); OK(b); }
|
||||
EXEC SQL SELECT close_id, status, period_key INTO :h_cid, :h_st, :h_period
|
||||
FROM cl_close_log
|
||||
WHERE memo LIKE '%' || :h_kw || '%'
|
||||
ORDER BY created_at DESC, close_id DESC LIMIT 1;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_ID1, h_cid);
|
||||
Bchg(b, T_STATUS, 0, h_st, 0L);
|
||||
Bchg(b, T_KEY1, 0, h_period, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_MERCLOSE.h
Normal file
21
app/src/cl/svc/CL_MERCLOSE.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_MERCLOSE.h - cl 서비스 CL_MERCLOSE 카피북 (copybook / record header).
|
||||
* 가맹점별 마감: 단일 가맹점 당일 집계 스냅샷 확정.
|
||||
*/
|
||||
#ifndef CL_MERCLOSE_H
|
||||
#define CL_MERCLOSE_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_merclose_rec_t;
|
||||
|
||||
void CL_MERCLOSE(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_MERCLOSE_H */
|
||||
43
app/src/cl/svc/CL_MERCLOSE.pgc
Normal file
43
app/src/cl/svc/CL_MERCLOSE.pgc
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* CL_MERCLOSE.pgc - cl 모듈 서비스 CL_MERCLOSE (one service = one file).
|
||||
* 가맹점별 마감: 단일 가맹점의 당일 매입(gross/fee/net/건수)을 집계해 해당
|
||||
* 영업일 최신 DAILY 마감에 연결된 스냅샷으로 확정 기록한다.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_MERCLOSE.h"
|
||||
|
||||
void CL_MERCLOSE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long sid;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_gross, h_fee, h_net, h_cnt;
|
||||
char h_bizdate[16], h_merch[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
gets_(b, T_MERCHANT, h_merch, sizeof(h_merch));
|
||||
if (h_merch[0] == 0) { Bchg(b, T_MSG, 0, "가맹점 ID 필요", 0L); FAIL(b); }
|
||||
EXEC SQL SELECT close_id INTO :h_cid FROM cl_close_log
|
||||
WHERE close_type = 'DAILY' AND period_key = :h_bizdate AND status <> 'X'
|
||||
ORDER BY close_id DESC LIMIT 1;
|
||||
if (sqlca.sqlcode == 100) { Bchg(b, T_MSG, 0, "당일 일마감 선행 필요", 0L); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
EXEC SQL SELECT coalesce(sum(amount),0), coalesce(sum(fee),0),
|
||||
coalesce(sum(net),0), count(*)
|
||||
INTO :h_gross, :h_fee, :h_net, :h_cnt
|
||||
FROM purchase WHERE biz_date = :h_bizdate AND merchant_id = :h_merch;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
sid = cldb_next_snapshot_id();
|
||||
if (sid < 0) FAIL(b);
|
||||
if (cldb_insert_snapshot(sid, h_cid, h_bizdate, h_bizdate, h_merch,
|
||||
h_gross, h_fee, h_net, h_cnt) < 0) FAIL(b);
|
||||
setl(b, T_ID1, h_cid);
|
||||
setl(b, T_ID2, sid);
|
||||
setl(b, T_GROSS, h_gross);
|
||||
setl(b, T_NET, h_net);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
userlog("CL_MERCLOSE %s/%s sid=%ld 가맹점 마감", h_merch, h_bizdate, sid);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_NETVERIFY.h
Normal file
21
app/src/cl/svc/CL_NETVERIFY.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_NETVERIFY.h - cl 서비스 CL_NETVERIFY 카피북 (copybook / record header).
|
||||
* 정산액 검증: 스냅샷 gross-fee=net 위반행 탐지.
|
||||
*/
|
||||
#ifndef CL_NETVERIFY_H
|
||||
#define CL_NETVERIFY_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_netverify_rec_t;
|
||||
|
||||
void CL_NETVERIFY(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_NETVERIFY_H */
|
||||
35
app/src/cl/svc/CL_NETVERIFY.pgc
Normal file
35
app/src/cl/svc/CL_NETVERIFY.pgc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* CL_NETVERIFY.pgc - cl 모듈 서비스 CL_NETVERIFY (one service = one file).
|
||||
* 정산액 검증: 마감 스냅샷에서 gross - fee <> net 인 내부 모순 행을 찾아
|
||||
* 위반 행수와 첫 위반 가맹점/편차를 반환한다.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_NETVERIFY.h"
|
||||
|
||||
void CL_NETVERIFY(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_bad, h_gap;
|
||||
char h_merch[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
EXEC SQL SELECT count(*) INTO :h_bad FROM cl_snapshot
|
||||
WHERE close_id = :h_cid AND gross_amount - fee_amount <> net_amount;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, h_bad);
|
||||
if (h_bad == 0) { setl(b, T_RC, 0); OK(b); }
|
||||
EXEC SQL SELECT merchant_id, gross_amount - fee_amount - net_amount
|
||||
INTO :h_merch, :h_gap
|
||||
FROM cl_snapshot
|
||||
WHERE close_id = :h_cid AND gross_amount - fee_amount <> net_amount
|
||||
ORDER BY abs(gross_amount - fee_amount - net_amount) DESC LIMIT 1;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
setl(b, T_DELTA, h_gap);
|
||||
setl(b, T_RC, 1);
|
||||
userlog("CL_NETVERIFY cid=%ld net 모순 %ld행 (최대 %s %+ld)", h_cid, h_bad, h_merch, h_gap);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_PENDLIST.h
Normal file
21
app/src/cl/svc/CL_PENDLIST.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_PENDLIST.h - cl 서비스 CL_PENDLIST 카피북 (copybook / record header).
|
||||
* 승인 대기 목록: 승인 대기(C) 건수와 최장 대기 마감 조회.
|
||||
*/
|
||||
#ifndef CL_PENDLIST_H
|
||||
#define CL_PENDLIST_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_pendlist_rec_t;
|
||||
|
||||
void CL_PENDLIST(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_PENDLIST_H */
|
||||
36
app/src/cl/svc/CL_PENDLIST.pgc
Normal file
36
app/src/cl/svc/CL_PENDLIST.pgc
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* CL_PENDLIST.pgc - cl 모듈 서비스 CL_PENDLIST (one service = one file).
|
||||
* 승인 대기 목록: 승인요청(memo APPR_REQ) 상태로 대기 중인 완료(C) 마감의
|
||||
* 건수, 최장 대기 건의 id 와 대기 일수를 반환한다.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_PENDLIST.h"
|
||||
|
||||
void CL_PENDLIST(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_pend, h_oldest, h_waitdays;
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
EXEC SQL SELECT count(*) INTO :h_pend FROM cl_close_log
|
||||
WHERE status = 'C' AND memo LIKE '%APPR_REQ%';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, h_pend);
|
||||
if (h_pend == 0) {
|
||||
setl(b, T_RC, 0);
|
||||
Bchg(b, T_MSG, 0, "승인 대기 없음", 0L);
|
||||
OK(b);
|
||||
}
|
||||
EXEC SQL SELECT close_id, current_date - cast(updated_at as date)
|
||||
INTO :h_oldest, :h_waitdays
|
||||
FROM cl_close_log
|
||||
WHERE status = 'C' AND memo LIKE '%APPR_REQ%'
|
||||
ORDER BY updated_at ASC LIMIT 1;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_ID1, h_oldest);
|
||||
setl(b, T_ARG1, h_waitdays);
|
||||
setl(b, T_RC, (h_waitdays >= 3) ? 2 : 1);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_POSTTRIG.h
Normal file
21
app/src/cl/svc/CL_POSTTRIG.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_POSTTRIG.h - cl 서비스 CL_POSTTRIG 카피북 (copybook / record header).
|
||||
* 마감 후속작업 트리거: 마감 완료 후 정산건을 ledger XFER 로 전기.
|
||||
*/
|
||||
#ifndef CL_POSTTRIG_H
|
||||
#define CL_POSTTRIG_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_posttrig_rec_t;
|
||||
|
||||
void CL_POSTTRIG(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_POSTTRIG_H */
|
||||
38
app/src/cl/svc/CL_POSTTRIG.pgc
Normal file
38
app/src/cl/svc/CL_POSTTRIG.pgc
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* CL_POSTTRIG.pgc - cl 모듈 서비스 CL_POSTTRIG (one service = one file).
|
||||
* 마감 후속작업 트리거: 마감(C/A) 확인 후 해당 영업일의 정산건을 ledger 에
|
||||
* XFER 로 일괄 전기한다(이미 전기된 건은 NOT EXISTS 로 제외). INSERT..SELECT.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_POSTTRIG.h"
|
||||
|
||||
void CL_POSTTRIG(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char st[4];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid;
|
||||
char h_date[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
if (cldb_get_close_status(h_cid, st) < 0) FAIL(b);
|
||||
if (st[0] != 'C' && st[0] != 'A') {
|
||||
Bchg(b, T_MSG, 0, "마감완료(C)/승인(A) 후에만 후속작업 가능", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
EXEC SQL SELECT to_char(biz_date,'YYYY-MM-DD') INTO :h_date
|
||||
FROM cl_close_log WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
|
||||
EXEC SQL INSERT INTO ledger (ledger_id, purchase_id, entry_type, amount, biz_date)
|
||||
SELECT nextval('ledger_seq'), s.purchase_id, 'XFER', s.net, s.biz_date
|
||||
FROM settlement s
|
||||
WHERE s.biz_date = :h_date
|
||||
AND NOT EXISTS (SELECT 1 FROM ledger l
|
||||
WHERE l.purchase_id = s.purchase_id AND l.entry_type = 'XFER');
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
setl(b, T_COUNT, sqlca.sqlerrd[2]);
|
||||
userlog("CL_POSTTRIG cid=%ld XFER %ld건 전기", h_cid, (long)sqlca.sqlerrd[2]);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_PRECHECK.h
Normal file
21
app/src/cl/svc/CL_PRECHECK.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_PRECHECK.h - cl 서비스 CL_PRECHECK 카피북 (copybook / record header).
|
||||
* 마감 전 체크리스트 검증: 미마감/미매칭/기잠금/기마감 4항목 비트마스크 점검.
|
||||
*/
|
||||
#ifndef CL_PRECHECK_H
|
||||
#define CL_PRECHECK_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_precheck_rec_t;
|
||||
|
||||
void CL_PRECHECK(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_PRECHECK_H */
|
||||
47
app/src/cl/svc/CL_PRECHECK.pgc
Normal file
47
app/src/cl/svc/CL_PRECHECK.pgc
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* CL_PRECHECK.pgc - cl 모듈 서비스 CL_PRECHECK (one service = one file).
|
||||
* 마감 전 체크리스트 검증: (1)미마감 M 매입 (2)미매칭 ac_unmatch (3)기간 기잠금
|
||||
* (4)당일 DAILY 기마감 존재 - 4개 항목을 비트마스크(T_RC)로 반환.
|
||||
* 0 이면 마감 진행 가능. T_MSG 에 실패 항목 요약.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_PRECHECK.h"
|
||||
|
||||
void CL_PRECHECK(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long mask = 0;
|
||||
char msg[128];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_m, h_um, h_lk, h_dc;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
EXEC SQL SELECT count(*) INTO :h_m FROM purchase
|
||||
WHERE biz_date = :h_bizdate AND status = 'M';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_m > 0) mask |= 1;
|
||||
EXEC SQL SELECT count(*) INTO :h_um FROM ac_unmatch WHERE biz_date = :h_bizdate;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_um > 0) mask |= 2;
|
||||
EXEC SQL SELECT count(*) INTO :h_lk FROM cl_period_lock
|
||||
WHERE period_key = :h_bizdate AND locked = true;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_lk > 0) mask |= 4;
|
||||
EXEC SQL SELECT count(*) INTO :h_dc FROM cl_close_log
|
||||
WHERE close_type = 'DAILY' AND period_key = :h_bizdate AND status <> 'X';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_dc > 0) mask |= 8;
|
||||
msg[0] = 0;
|
||||
if (mask & 1) strcat(msg, "[미마감M]");
|
||||
if (mask & 2) strcat(msg, "[미매칭]");
|
||||
if (mask & 4) strcat(msg, "[기간잠금]");
|
||||
if (mask & 8) strcat(msg, "[기마감]");
|
||||
if (mask == 0) strcpy(msg, "체크리스트 전항목 통과");
|
||||
setl(b, T_RC, mask);
|
||||
setl(b, T_COUNT, h_m + h_um);
|
||||
Bchg(b, T_MSG, 0, msg, 0L);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_PROVCLOSE.h
Normal file
21
app/src/cl/svc/CL_PROVCLOSE.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_PROVCLOSE.h - cl 서비스 CL_PROVCLOSE 카피북 (copybook / record header).
|
||||
* 가마감: 기존 가마감 중복 확인 후 status O + memo PROV 가마감 생성.
|
||||
*/
|
||||
#ifndef CL_PROVCLOSE_H
|
||||
#define CL_PROVCLOSE_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_provclose_rec_t;
|
||||
|
||||
void CL_PROVCLOSE(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_PROVCLOSE_H */
|
||||
42
app/src/cl/svc/CL_PROVCLOSE.pgc
Normal file
42
app/src/cl/svc/CL_PROVCLOSE.pgc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* CL_PROVCLOSE.pgc - cl 모듈 서비스 CL_PROVCLOSE (one service = one file).
|
||||
* 가마감: 당일 매입 집계 후 status O + memo 'PROV' 가마감을 생성한다.
|
||||
* 동일 영업일에 미확정 가마감이 이미 있으면 중복 생성하지 않고 거절.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_PROVCLOSE.h"
|
||||
|
||||
void CL_PROVCLOSE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long cid;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_dup, h_cnt, h_amt;
|
||||
char h_bizdate[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
EXEC SQL SELECT count(*) INTO :h_dup FROM cl_close_log
|
||||
WHERE close_type = 'DAILY' AND period_key = :h_bizdate
|
||||
AND status = 'O' AND memo = 'PROV';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_dup > 0) {
|
||||
setl(b, T_RC, 1);
|
||||
Bchg(b, T_MSG, 0, "가마감 중복: 미확정 가마감 존재", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
EXEC SQL SELECT count(*), coalesce(sum(amount),0) INTO :h_cnt, :h_amt
|
||||
FROM purchase WHERE biz_date = :h_bizdate AND status IN ('M','S');
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
cid = cldb_next_close_id();
|
||||
if (cid < 0) FAIL(b);
|
||||
if (cldb_insert_close(cid, "DAILY", h_bizdate, h_bizdate, "O",
|
||||
h_cnt, h_amt, "PROV") < 0) FAIL(b);
|
||||
setl(b, T_ID1, cid);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_amt);
|
||||
Bchg(b, T_STATUS, 0, "O", 0L);
|
||||
userlog("CL_PROVCLOSE cid=%ld %s 가마감 생성", cid, h_bizdate);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_REOPENREQ.h
Normal file
21
app/src/cl/svc/CL_REOPENREQ.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_REOPENREQ.h - cl 서비스 CL_REOPENREQ 카피북 (copybook / record header).
|
||||
* 마감 재개시: 잠금 아닌 완료(C) 마감을 O 로 재개시.
|
||||
*/
|
||||
#ifndef CL_REOPENREQ_H
|
||||
#define CL_REOPENREQ_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_reopenreq_rec_t;
|
||||
|
||||
void CL_REOPENREQ(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_REOPENREQ_H */
|
||||
44
app/src/cl/svc/CL_REOPENREQ.pgc
Normal file
44
app/src/cl/svc/CL_REOPENREQ.pgc
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* CL_REOPENREQ.pgc - cl 모듈 서비스 CL_REOPENREQ (one service = one file).
|
||||
* 마감 재개시: 완료(C) 상태이고 기간이 잠금되지 않은 마감을 개시(O)로
|
||||
* 되돌린다. memo 에 REOPEN 사유를 남기며, 잠금 기간이면 RC=3 거절.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_REOPENREQ.h"
|
||||
|
||||
void CL_REOPENREQ(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
char reason[48];
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cid, h_locked;
|
||||
char h_memo[64];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
h_cid = getl(b, T_ID1);
|
||||
gets_(b, T_REASON, reason, sizeof(reason));
|
||||
EXEC SQL SELECT count(*) INTO :h_locked
|
||||
FROM cl_period_lock l, cl_close_log c
|
||||
WHERE c.close_id = :h_cid AND l.period_key = c.period_key AND l.locked = true;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (h_locked > 0) {
|
||||
setl(b, T_RC, 3);
|
||||
Bchg(b, T_MSG, 0, "잠금 기간: 재개시 불가 (선 잠금해제 필요)", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
snprintf(h_memo, sizeof(h_memo), "REOPEN:%s", reason[0] ? reason : "무사유");
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET status = 'O', memo = :h_memo, updated_at = now()
|
||||
WHERE close_id = :h_cid AND status = 'C';
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
if (sqlca.sqlerrd[2] != 1) {
|
||||
setl(b, T_RC, 4);
|
||||
Bchg(b, T_MSG, 0, "완료(C) 상태가 아니어서 재개시 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
setl(b, T_RC, 0);
|
||||
Bchg(b, T_STATUS, 0, "O", 0L);
|
||||
userlog("CL_REOPENREQ cid=%ld 재개시", h_cid);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_RPTCAT.h
Normal file
21
app/src/cl/svc/CL_RPTCAT.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_RPTCAT.h - cl 서비스 CL_RPTCAT 카피북 (copybook / record header).
|
||||
* 업종별 마감 리포트: 업종별 수수료율(bps) 산출 리포트.
|
||||
*/
|
||||
#ifndef CL_RPTCAT_H
|
||||
#define CL_RPTCAT_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_rptcat_rec_t;
|
||||
|
||||
void CL_RPTCAT(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_RPTCAT_H */
|
||||
41
app/src/cl/svc/CL_RPTCAT.pgc
Normal file
41
app/src/cl/svc/CL_RPTCAT.pgc
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* CL_RPTCAT.pgc - cl 모듈 서비스 CL_RPTCAT (one service = one file).
|
||||
* 업종별 마감 리포트: 영업일 매입을 업종(category) 그룹으로 집계하며 업종별
|
||||
* 실효 수수료율(bps = fee 합계 * 10000 / amount 합계)을 SQL 에서 산출해 반환.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_RPTCAT.h"
|
||||
|
||||
void CL_RPTCAT(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long occ = 0, maxbps = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_amt, h_bps;
|
||||
char h_bizdate[16], h_cat[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
EXEC SQL DECLARE crcat CURSOR FOR
|
||||
SELECT category, coalesce(sum(amount),0),
|
||||
coalesce(sum(fee) * 10000 / nullif(sum(amount),0), 0)
|
||||
FROM purchase WHERE biz_date = :h_bizdate
|
||||
GROUP BY category ORDER BY category;
|
||||
EXEC SQL OPEN crcat;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH crcat INTO :h_cat, :h_amt, :h_bps;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE crcat; FAIL(b); }
|
||||
Bchg(b, T_CATEGORY, (BFLDOCC)occ, h_cat, 0L);
|
||||
Bchg(b, T_AMT3, (BFLDOCC)occ, (char *)&h_amt, 0L);
|
||||
Bchg(b, T_ARG3, (BFLDOCC)occ, (char *)&h_bps, 0L);
|
||||
if (h_bps > maxbps) maxbps = h_bps;
|
||||
occ++;
|
||||
}
|
||||
EXEC SQL CLOSE crcat;
|
||||
setl(b, T_COUNT, occ);
|
||||
setl(b, T_ARG4, maxbps);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_RPTCHN.h
Normal file
21
app/src/cl/svc/CL_RPTCHN.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_RPTCHN.h - cl 서비스 CL_RPTCHN 카피북 (copybook / record header).
|
||||
* 채널별 마감 리포트: 영업일 채널 그룹 집계 occurrence 리포트.
|
||||
*/
|
||||
#ifndef CL_RPTCHN_H
|
||||
#define CL_RPTCHN_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_rptchn_rec_t;
|
||||
|
||||
void CL_RPTCHN(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_RPTCHN_H */
|
||||
40
app/src/cl/svc/CL_RPTCHN.pgc
Normal file
40
app/src/cl/svc/CL_RPTCHN.pgc
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* CL_RPTCHN.pgc - cl 모듈 서비스 CL_RPTCHN (one service = one file).
|
||||
* 채널별 마감 리포트: 영업일의 매입을 채널 그룹으로 집계해 occurrence
|
||||
* (T_CHANNEL[i], T_ARG1[i]=건수, T_AMT1[i]=금액) 리포트로 반환한다.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_RPTCHN.h"
|
||||
|
||||
void CL_RPTCHN(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long occ = 0, totamt = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_cnt, h_amt;
|
||||
char h_bizdate[16], h_chn[16];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
EXEC SQL DECLARE crchn CURSOR FOR
|
||||
SELECT channel, count(*), coalesce(sum(amount),0)
|
||||
FROM purchase WHERE biz_date = :h_bizdate AND status <> 'C'
|
||||
GROUP BY channel ORDER BY 3 DESC;
|
||||
EXEC SQL OPEN crchn;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
for (;;) {
|
||||
EXEC SQL FETCH crchn INTO :h_chn, :h_cnt, :h_amt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE crchn; FAIL(b); }
|
||||
Bchg(b, T_CHANNEL, (BFLDOCC)occ, h_chn, 0L);
|
||||
Bchg(b, T_ARG1, (BFLDOCC)occ, (char *)&h_cnt, 0L);
|
||||
Bchg(b, T_AMT1, (BFLDOCC)occ, (char *)&h_amt, 0L);
|
||||
totamt += h_amt;
|
||||
occ++;
|
||||
}
|
||||
EXEC SQL CLOSE crchn;
|
||||
setl(b, T_COUNT, occ);
|
||||
setl(b, T_GROSS, totamt);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_RPTISSUER.h
Normal file
21
app/src/cl/svc/CL_RPTISSUER.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_RPTISSUER.h - cl 서비스 CL_RPTISSUER 카피북 (copybook / record header).
|
||||
* 발급사별 마감 리포트: 임계금액 이상 발급사 HAVING 리포트.
|
||||
*/
|
||||
#ifndef CL_RPTISSUER_H
|
||||
#define CL_RPTISSUER_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_rptissuer_rec_t;
|
||||
|
||||
void CL_RPTISSUER(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_RPTISSUER_H */
|
||||
41
app/src/cl/svc/CL_RPTISSUER.pgc
Normal file
41
app/src/cl/svc/CL_RPTISSUER.pgc
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* CL_RPTISSUER.pgc - cl 모듈 서비스 CL_RPTISSUER (one service = one file).
|
||||
* 발급사별 마감 리포트: 영업일 매입을 발급사 그룹으로 집계하되 임계금액
|
||||
* (T_AMT1 입력, 기본 0) 이상인 발급사만 HAVING 으로 걸러 occurrence 반환.
|
||||
* 호출자의 XA 브랜치에서 수행(EXEC SQL CONNECT 없음); cl_svr 가 광고한다.
|
||||
*/
|
||||
#include "CL_RPTISSUER.h"
|
||||
|
||||
void CL_RPTISSUER(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long occ = 0;
|
||||
EXEC SQL BEGIN DECLARE SECTION;
|
||||
long h_min, h_cnt, h_amt;
|
||||
char h_bizdate[16], h_iss[24];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate));
|
||||
h_min = getl(b, T_AMT1);
|
||||
if (h_min < 0) h_min = 0;
|
||||
EXEC SQL DECLARE criss CURSOR FOR
|
||||
SELECT issuer, count(*), sum(amount) FROM purchase
|
||||
WHERE biz_date = :h_bizdate
|
||||
GROUP BY issuer HAVING sum(amount) >= :h_min
|
||||
ORDER BY sum(amount) DESC;
|
||||
EXEC SQL OPEN criss;
|
||||
if (sqlca.sqlcode < 0) FAIL(b);
|
||||
while (occ < 30) {
|
||||
EXEC SQL FETCH criss INTO :h_iss, :h_cnt, :h_amt;
|
||||
if (sqlca.sqlcode == 100) break;
|
||||
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE criss; FAIL(b); }
|
||||
Bchg(b, T_ISSUER, (BFLDOCC)occ, h_iss, 0L);
|
||||
Bchg(b, T_ARG2, (BFLDOCC)occ, (char *)&h_cnt, 0L);
|
||||
Bchg(b, T_AMT2, (BFLDOCC)occ, (char *)&h_amt, 0L);
|
||||
occ++;
|
||||
}
|
||||
EXEC SQL CLOSE criss;
|
||||
setl(b, T_COUNT, occ);
|
||||
OK(b);
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4 et smartindent: */
|
||||
21
app/src/cl/svc/CL_RPTTOPMER.h
Normal file
21
app/src/cl/svc/CL_RPTTOPMER.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* CL_RPTTOPMER.h - cl 서비스 CL_RPTTOPMER 카피북 (copybook / record header).
|
||||
* 상위 가맹점 마감 리포트: 스냅샷 net 상위 N 가맹점 리포트.
|
||||
*/
|
||||
#ifndef CL_RPTTOPMER_H
|
||||
#define CL_RPTTOPMER_H
|
||||
|
||||
#include "cl_svc.h"
|
||||
|
||||
typedef struct {
|
||||
long id1;
|
||||
long id2;
|
||||
long amount;
|
||||
char status[8];
|
||||
char key1[32];
|
||||
char biz_date[16];
|
||||
} cl_cl_rpttopmer_rec_t;
|
||||
|
||||
void CL_RPTTOPMER(TPSVCINFO *p);
|
||||
|
||||
#endif /* CL_RPTTOPMER_H */
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue