Phase 2a: 모듈서버 패턴 + 재사용 빌드시스템 (ac 모듈 38서비스 실동작)

- ac_svr(30 매입서비스 advertise) + rc_svr/st_svr, dbio 정적라이브러리, common 라이브러리
- app/build.sh: 모듈 자동발견(app/src/<mod>/<mod>_svr.pgc) → ecpg+buildserver+ndrxconfig 생성
- ac 배치 2종, 스키마 9테이블, 검증: 41서비스 AVAIL, 체인·배치 psql 커밋, prepared_xacts=0

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
forge-bot 2026-07-19 09:37:17 +00:00
parent e6e29e6b5d
commit 05a0ff3e56
28 changed files with 1964 additions and 410 deletions

139
app/src/st/st_svr.pgc Normal file
View file

@ -0,0 +1,139 @@
/*
* st_svr.pgc - st (정산/수수료) MODULE SERVER.
*
* Advertises the settlement services. SETTLE keeps the proven behavior: its own
* XA branch writes the settlement + settle ledger rows (the purchase status
* transition is owned by the ACQUIRE branch). Terminal service of the 매입 chain.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include <ubf.h>
#include <userlog.h>
#include <ndebug.h>
#include "acq.fd.h"
static long getl(UBFH *b, BFLDID f) { long v = 0; Bget(b, f, 0, (char *)&v, 0L); return v; }
static void gets_(UBFH *b, BFLDID f, char *out, int cap)
{ BFLDLEN l = cap; out[0] = 0; Bget(b, f, 0, out, &l); }
static void setl(UBFH *b, BFLDID f, long v) { Bchg(b, f, 0, (char *)&v, 0L); }
#define FAIL(b) do { tpreturn(TPFAIL, 0, (char *)(b), 0L, 0L); return; } while (0)
#define OK(b) do { tpreturn(TPSUCCESS, 0, (char *)(b), 0L, 0L); return; } while (0)
void SETTLE(TPSVCINFO *p);
void ST_MDR(TPSVCINFO *p);
void ST_NETTING(TPSVCINFO *p);
void ST_VAT(TPSVCINFO *p);
static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
{"SETTLE", SETTLE}, {"ST_MDR", ST_MDR},
{"ST_NETTING", ST_NETTING}, {"ST_VAT", ST_VAT},
{NULL, NULL}
};
int tpsvrinit(int argc, char **argv)
{
int i;
if (tpopen() < 0) { userlog("st_svr: tpopen FAIL: %s", tpstrerror(tperrno)); return -1; }
for (i = 0; SVCS[i].name; i++)
if (tpadvertise((char *)SVCS[i].name, SVCS[i].fn) < 0) {
userlog("st_svr: tpadvertise(%s) FAIL: %s", SVCS[i].name, tpstrerror(tperrno));
return -1;
}
userlog("st_svr: %d st services advertised, RM opened", i);
return 0;
}
void tpsvrdone(void) { tpclose(); userlog("st_svr: tpsvrdone"); }
void SETTLE(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], bizdate[16];
EXEC SQL BEGIN DECLARE SECTION;
long h_pid, h_sid, h_net;
char h_merch[64], h_bizdate[16];
EXEC SQL END DECLARE SECTION;
h_pid = getl(b, T_PURCHASE_ID);
h_net = getl(b, T_NET);
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL SELECT nextval('settlement_seq') INTO :h_sid;
if (sqlca.sqlcode < 0) FAIL(b);
EXEC SQL INSERT INTO settlement (settlement_id, purchase_id, merchant_id, net, biz_date, status)
VALUES (:h_sid, :h_pid, :h_merch, :h_net, :h_bizdate, 'SETTLED');
if (sqlca.sqlcode < 0) { userlog("SETTLE INSERT settlement FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
EXEC SQL INSERT INTO ledger (ledger_id, purchase_id, entry_type, amount, biz_date)
VALUES (nextval('ledger_seq'), :h_pid, 'SETTLE', :h_net, :h_bizdate);
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_SETTLE_ID, h_sid);
Bchg(b, T_STATUS, 0, "S", 0L);
userlog("SETTLE pid=%ld settlement_id=%ld net=%ld", h_pid, h_sid, h_net);
OK(b);
}
/* ST_MDR - MDR 수수료 원장 기록. */
void ST_MDR(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char bizdate[16];
EXEC SQL BEGIN DECLARE SECTION;
long h_pid, h_fee;
char h_bizdate[16];
EXEC SQL END DECLARE SECTION;
h_pid = getl(b, T_PURCHASE_ID); h_fee = getl(b, T_FEE);
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL INSERT INTO ledger (ledger_id, purchase_id, entry_type, amount, biz_date)
VALUES (nextval('ledger_seq'), :h_pid, 'MDR', :h_fee, :h_bizdate);
if (sqlca.sqlcode < 0) FAIL(b);
OK(b);
}
/* ST_NETTING - 당일 net 합계 조회. */
void ST_NETTING(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char merch[64], bizdate[16];
EXEC SQL BEGIN DECLARE SECTION;
long h_sum;
char h_merch[64], h_bizdate[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_MERCHANT, merch, sizeof(merch));
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL SELECT coalesce(sum(net),0) INTO :h_sum FROM settlement
WHERE merchant_id = :h_merch AND biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_GROSS, h_sum);
OK(b);
}
/* ST_VAT - 정산 부가세 원장 기록. */
void ST_VAT(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char bizdate[16];
EXEC SQL BEGIN DECLARE SECTION;
long h_pid, h_vat;
char h_bizdate[16];
EXEC SQL END DECLARE SECTION;
h_pid = getl(b, T_PURCHASE_ID); h_vat = getl(b, T_FEE) / 10;
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL INSERT INTO ledger (ledger_id, purchase_id, entry_type, amount, biz_date)
VALUES (nextval('ledger_seq'), :h_pid, 'VAT', :h_vat, :h_bizdate);
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_TAX, h_vat);
OK(b);
}
/* vim: set ts=4 sw=4 et smartindent: */