chore: acquire-core migration monorepo (legacy C + Spring Boot target skeleton)
Some checks failed
ci / build (push) Failing after 2s
Some checks failed
ci / build (push) Failing after 2s
TxCore/ECPG legacy 매입·정산 C 슬라이스(빌드검증) + Spring Boot 멀티모듈 골격(mvn test green) + MIGRATION.md 전환룰 + CI(boot 빌드).
This commit is contained in:
commit
ff0b0b60a2
31 changed files with 2208 additions and 0 deletions
136
legacy/app/online/ac_intake_svc.pgc
Normal file
136
legacy/app/online/ac_intake_svc.pgc
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* ac_intake_svc.pgc - 매입접수 서비스 (AC_INTAKE)
|
||||
*
|
||||
* MG_RECV 가 적재한 TXBUF 필드를 검증하고, 트랜잭션 하에서
|
||||
* purchase 테이블에 접수 INSERT 한 뒤 정산집계 서비스를 tx_call 한다.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "txcore.h"
|
||||
#include "acq_util.h"
|
||||
#include "purchase_dbio.h"
|
||||
|
||||
EXEC SQL INCLUDE sqlca;
|
||||
|
||||
TX_SERVICE(AC_INTAKE, ctx)
|
||||
{
|
||||
purchase_rec_t rec;
|
||||
char merch[16];
|
||||
char card[20];
|
||||
char appr[16];
|
||||
char txndate[16];
|
||||
long amount = 0;
|
||||
int rc;
|
||||
TXBUF *sub_in;
|
||||
TXBUF *sub_out;
|
||||
|
||||
tx_log(TX_LOG_INFO, "[AC_INTAKE] 매입접수 서비스 진입");
|
||||
|
||||
/* 입력 필드 추출 */
|
||||
if (tx_buf_get(ctx->in, "MERCHID", merch, sizeof(merch)) != TX_OK ||
|
||||
tx_buf_get(ctx->in, "CARDNO", card, sizeof(card)) != TX_OK ||
|
||||
tx_buf_get(ctx->in, "APPRNO", appr, sizeof(appr)) != TX_OK ||
|
||||
tx_buf_get(ctx->in, "TXNDATE", txndate, sizeof(txndate)) != TX_OK) {
|
||||
tx_log(TX_LOG_ERROR, "[AC_INTAKE] 입력 필드 누락");
|
||||
tx_return(ctx, TX_EINVAL, ctx->out);
|
||||
return;
|
||||
}
|
||||
tx_buf_getlong(ctx->in, "AMOUNT", &amount);
|
||||
|
||||
/* 업무 검증: 가맹점/금액/일자 */
|
||||
if (merch[0] == '\0') {
|
||||
tx_log(TX_LOG_WARN, "[AC_INTAKE] 가맹점번호 없음");
|
||||
tx_return(ctx, TX_EINVAL, ctx->out);
|
||||
return;
|
||||
}
|
||||
if (!amount_is_valid(amount)) {
|
||||
tx_log(TX_LOG_WARN, "[AC_INTAKE] 금액 범위 오류 amount=%ld", amount);
|
||||
tx_return(ctx, TX_EINVAL, ctx->out);
|
||||
return;
|
||||
}
|
||||
if (!date_is_valid(txndate)) {
|
||||
tx_log(TX_LOG_WARN, "[AC_INTAKE] 거래일자 오류 date=%s", txndate);
|
||||
tx_return(ctx, TX_EINVAL, ctx->out);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 레코드 구성 */
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
strncpy(rec.appr_no, appr, sizeof(rec.appr_no) - 1);
|
||||
strncpy(rec.merch_id, merch, sizeof(rec.merch_id) - 1);
|
||||
strncpy(rec.card_no, card, sizeof(rec.card_no) - 1);
|
||||
strncpy(rec.txn_date, txndate, sizeof(rec.txn_date) - 1);
|
||||
strncpy(rec.status, PUR_ST_RECV, sizeof(rec.status) - 1);
|
||||
rec.amount = amount;
|
||||
|
||||
/* 트랜잭션 시작 → 접수 INSERT */
|
||||
if (tx_begin() != TX_OK) {
|
||||
tx_return(ctx, TX_FAIL, ctx->out);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = purchase_insert(&rec);
|
||||
if (rc != TX_OK) {
|
||||
tx_log(TX_LOG_ERROR, "[AC_INTAKE] 접수 INSERT 실패 rc=%d(%s)",
|
||||
rc, tx_strerror(rc));
|
||||
tx_abort();
|
||||
tx_return(ctx, rc, ctx->out);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 정산집계 서비스 호출 (동일 트랜잭션 컨텍스트) */
|
||||
sub_in = tx_buf_alloc();
|
||||
sub_out = tx_buf_alloc();
|
||||
if (sub_in && sub_out) {
|
||||
tx_buf_sets(sub_in, "MERCHID", merch);
|
||||
tx_buf_sets(sub_in, "TXNDATE", txndate);
|
||||
tx_buf_setlong(sub_in, "AMOUNT", amount);
|
||||
rc = tx_call("AC_SETTLE", sub_in, sub_out);
|
||||
if (rc != TX_OK)
|
||||
tx_log(TX_LOG_WARN, "[AC_INTAKE] 정산집계 경고 rc=%d", rc);
|
||||
}
|
||||
tx_buf_free(sub_in);
|
||||
tx_buf_free(sub_out);
|
||||
|
||||
tx_commit();
|
||||
|
||||
tx_buf_reset(ctx->out);
|
||||
tx_buf_sets(ctx->out, "RESPCODE", RESP_OK);
|
||||
tx_buf_sets(ctx->out, "APPRNO", appr);
|
||||
tx_log(TX_LOG_INFO, "[AC_INTAKE] 접수완료 appr=%s amount=%ld", appr, amount);
|
||||
|
||||
tx_return(ctx, TX_OK, ctx->out);
|
||||
}
|
||||
|
||||
/*
|
||||
* AC_SETTLE - 정산집계 서비스 (동일 모듈에 배치)
|
||||
* purchase 접수 건을 가맹점/영업일 단위 정산집계에 누적한다.
|
||||
*/
|
||||
TX_SERVICE(AC_SETTLE, ctx)
|
||||
{
|
||||
char merch[16];
|
||||
char txndate[16];
|
||||
char bizdate[9];
|
||||
long amount = 0;
|
||||
int rc;
|
||||
|
||||
if (tx_buf_get(ctx->in, "MERCHID", merch, sizeof(merch)) != TX_OK ||
|
||||
tx_buf_get(ctx->in, "TXNDATE", txndate, sizeof(txndate)) != TX_OK) {
|
||||
tx_return(ctx, TX_EINVAL, ctx->out);
|
||||
return;
|
||||
}
|
||||
tx_buf_getlong(ctx->in, "AMOUNT", &amount);
|
||||
|
||||
/* 정산 영업일 = 거래일의 다음 영업일 */
|
||||
if (date_next_business(txndate, bizdate) != 0) {
|
||||
memcpy(bizdate, txndate, 8);
|
||||
bizdate[8] = '\0';
|
||||
}
|
||||
|
||||
rc = settlement_accumulate(merch, bizdate, amount);
|
||||
tx_log(TX_LOG_INFO, "[AC_SETTLE] 집계 merch=%s biz=%s amount=%ld rc=%d",
|
||||
merch, bizdate, amount, rc);
|
||||
|
||||
tx_return(ctx, rc, ctx->out);
|
||||
}
|
||||
71
legacy/app/online/mg_recv_svc.pgc
Normal file
71
legacy/app/online/mg_recv_svc.pgc
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* mg_recv_svc.pgc - 전문수신 서비스 (MG_RECV)
|
||||
*
|
||||
* 대외 매입요청 전문(고정길이 100바이트)을 수신하여 unpack 하고,
|
||||
* 필드를 TXBUF 로 적재한 뒤 후속 서비스가 소비하도록 응답한다.
|
||||
* (ATMI 의 void SVC(TPSVCINFO*) 대응)
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "txcore.h"
|
||||
#include "acq_util.h"
|
||||
#include "purchase_dbio.h"
|
||||
|
||||
EXEC SQL INCLUDE sqlca;
|
||||
|
||||
TX_SERVICE(MG_RECV, ctx)
|
||||
{
|
||||
char raw[MSG_ACQ_LEN + 1];
|
||||
acq_msg_t msg;
|
||||
char fld[64];
|
||||
long amount;
|
||||
int rc;
|
||||
TXBUF *out;
|
||||
|
||||
tx_log(TX_LOG_INFO, "[MG_RECV] 전문수신 서비스 진입");
|
||||
|
||||
/* 요청 버퍼에서 원시 전문 획득 */
|
||||
memset(raw, 0, sizeof(raw));
|
||||
rc = tx_buf_get(ctx->in, "RAWMSG", raw, sizeof(raw));
|
||||
if (rc != TX_OK) {
|
||||
tx_log(TX_LOG_ERROR, "[MG_RECV] RAWMSG 누락 rc=%d", rc);
|
||||
tx_return(ctx, TX_EINVAL, ctx->out);
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg_unpack(&msg, raw, (int)strlen(raw)) != 0) {
|
||||
tx_log(TX_LOG_ERROR, "[MG_RECV] 전문 언팩 실패 len=%zu", strlen(raw));
|
||||
tx_return(ctx, TX_EINVAL, ctx->out);
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg_validate(&msg) != 0) {
|
||||
tx_log(TX_LOG_WARN, "[MG_RECV] 필수항목 검증 실패");
|
||||
tx_return(ctx, TX_EINVAL, ctx->out);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 필드를 응답 TXBUF 로 적재 (후속 매입접수 서비스가 소비) */
|
||||
out = ctx->out;
|
||||
tx_buf_reset(out);
|
||||
|
||||
msg_field_copy(fld, msg.msg_type, FLD_MSG_TYPE_LEN);
|
||||
tx_buf_sets(out, "MSGTYPE", fld);
|
||||
msg_field_copy(fld, msg.merch_id, FLD_MERCH_ID_LEN);
|
||||
tx_buf_sets(out, "MERCHID", fld);
|
||||
msg_field_copy(fld, msg.card_no, FLD_CARD_NO_LEN);
|
||||
tx_buf_sets(out, "CARDNO", fld);
|
||||
msg_field_copy(fld, msg.approval_no, FLD_APPROVAL_LEN);
|
||||
tx_buf_sets(out, "APPRNO", fld);
|
||||
msg_field_copy(fld, msg.txn_date, FLD_TXN_DATE_LEN);
|
||||
tx_buf_sets(out, "TXNDATE", fld);
|
||||
|
||||
amount = amount_parse(msg.amount, FLD_AMOUNT_LEN);
|
||||
tx_buf_setlong(out, "AMOUNT", amount);
|
||||
|
||||
tx_log(TX_LOG_INFO, "[MG_RECV] 언팩완료 merch=%.15s appr=%.9s amount=%ld",
|
||||
msg.merch_id, msg.approval_no, amount);
|
||||
|
||||
tx_return(ctx, TX_OK, out);
|
||||
}
|
||||
36
legacy/app/online/server_main.c
Normal file
36
legacy/app/online/server_main.c
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* server_main.c - acquire-core 온라인 서버 데모 부트스트랩
|
||||
*
|
||||
* Tuxedo 의 tmboot/서버 메인처럼, 온라인 서비스들을 TxCore 레지스트리에
|
||||
* 등록한다. 실제 TP 모니터에서는 tpsvrinit() 에 해당한다. 여기서는
|
||||
* 등록/디스패치 링크 경로를 검증하기 위한 최소 데모 엔트리다.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
#include "txcore.h"
|
||||
|
||||
/* 각 .pgc 서비스의 외부 선언 (TX_SERVICE 매크로가 생성한 함수) */
|
||||
void MG_RECV(TXSVCINFO *ctx);
|
||||
void AC_INTAKE(TXSVCINFO *ctx);
|
||||
void AC_SETTLE(TXSVCINFO *ctx);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
tx_set_loglevel(TX_LOG_INFO);
|
||||
tx_log(TX_LOG_INFO, "acquire-core 온라인 서버 기동 (TxCore)");
|
||||
|
||||
/* 서비스 등록 (tpsvrinit 상당) */
|
||||
tx_register("MG_RECV", MG_RECV);
|
||||
tx_register("AC_INTAKE", AC_INTAKE);
|
||||
tx_register("AC_SETTLE", AC_SETTLE);
|
||||
|
||||
tx_log(TX_LOG_INFO, "등록 서비스 수 = %d", tx_service_count());
|
||||
printf("acquire-core-server 준비완료: 서비스 %d개 등록\n",
|
||||
tx_service_count());
|
||||
|
||||
/*
|
||||
* 실환경에서는 여기서 TP 모니터 이벤트 루프(advertise/serve)로 진입한다.
|
||||
* 데모에서는 DB 접속 없이 링크 경로만 검증하고 종료한다.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
Reference in a new issue