Wave E/F: 업무흐름 tpcall 오케스트레이션 + 크로스브랜치 교착 제거
477개 서비스를 tpcall 체인으로 연결하고(2 → 477), 그 과정에서 드러난
런타임 결함들을 실행 검증으로 잡아냈다.
체인 오케스트레이션 (Wave E)
- 매입/승인/정산/지급/대사/원장/마감/마스터/전문 흐름을 모듈 간 tpcall 로 연결
- 호출그래프 553노드 494엣지, 순환 0, SELFCALL 0
- 핵심 경로: ACQUIRE→RECONCILE→SETTLE→ST_MDR→LG_SETTLEPOST (6단, XA 2PC)
런타임 결함 수정 (Wave F) — 정적 게이트로는 잡히지 않던 것들
1. 모듈내 체인 자기교착: 모듈 서버 카피가 1이면 SETTLE→ST_MDR 처럼 같은
서버로 되돌아오는 호출이 자기 요청을 못 꺼내 TPETIME. 카피 4로 상향.
2. 크로스브랜치 핫로우 교착: 한 글로벌 트랜잭션의 형제 XA 브랜치가 같은 행을
UPDATE 하면 같은 트랜잭션이라 락이 안 풀려 타임아웃까지 블록된다.
- mg_channel: 비소유자 96개 서비스의 UPDATE 제거, STAN 은 시퀀스 채번으로
(실제 전문 스위치 방식). 생애주기 소유자 7개만 UPDATE 유지.
- lg_merch_bal: ACQ_SETTLELINK 의 LG_SETTLEPOST 다이아몬드 호출 제거.
교착일 뿐 아니라 같은 정산건이 원장에 이중 전기되는 회계 오류였다.
- cl_close_log / py_payout / lg_account_bal: CHAIN 마커로 쓰기 소유자 일원화.
py_payout 건은 피호출자가 호출자의 미커밋 승인을 볼 수 없어 기능적으로도
동작 불능이었다.
3. cm_log PK 충돌: st 131개 파일이 max(log_id)+1 로 채번해 nextval 을 쓰는
피호출자와 동일 PK 를 INSERT, 미커밋 인덱스 엔트리에 걸려 블록. 전부
nextval('cm_log_seq') 로 전환.
4. strncpy 스택 파괴: cmdb_get_param 이 strncpy(out, h_val, 127) 로 항상 128
바이트를 써서, bizdate[16] 을 넘기는 호출부 133곳이 매번 호출자 스택 112
바이트를 훼손했다. 인접 ecpg 호스트 변수가 오염돼 서버 카피가 세그폴트.
DB 락 대기가 0인데 60초 블록되는 증상의 원인. cm_code/py_payout_reject 동일.
5. ACQ_CANCEL→LIMIT_RST 입력계약 불일치: 카드번호를 안 실어 보내 항상 거절.
승인원장에서 카드를 끌어오고, 무승인 매입은 한도원복을 생략하도록 수정.
6. mgdb_channel_bump_stan: 활동 채널 전체를 한 번에 잠그는 다중행 UPDATE
(호출자 0인 잠복 지뢰). 시퀀스 채번 + 집계 조회로 교체.
화면
- 기본값을 실존 시드 키로 부팅 시 조회해 덮어쓴다. 기존 플레이스홀더
(card_limit 에 없는 카드, 8자리 영업일)로는 처리성 화면이 전부 거절당했다.
- 게이트웨이가 단일 스레드 직렬 루프라 기본값 조회도 순차로 수행.
검증 (실측)
- 통합 빌드: modules=11 servers=11 batches=506, error 0
- 도메인: 45 프로세스, 1,466 서비스 AVAIL
- 체인 전수 스모크 477/477 응답, TPETIME/TPEABORT 0건, 최대 530ms
- AUTH: 수정 전 60초 블록→TPEABORT, 수정 후 0.215초 ok:true
- 6단 매입 체인 COMMIT OK, 미결 2PC 0
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4cede852a0
commit
074d244bba
654 changed files with 36008 additions and 2805 deletions
|
|
@ -170,8 +170,11 @@ gen_servers() {
|
|||
cat <<EOF
|
||||
<server name="${m}_svr">
|
||||
<srvid>${srvid}</srvid>
|
||||
<min>1</min>
|
||||
<max>1</max>
|
||||
<!-- 모듈 내부 tpcall 체인(예: SETTLE→ST_MDR)이 같은 서버로 되돌아오므로
|
||||
복수 카피 필수. 카피가 1이면 호출자가 블록된 채 자기 요청을 못 꺼내
|
||||
자기교착(TPETIME)이 난다. 모듈내 최대 체인 깊이 3 + 동시성 여유 = 4. -->
|
||||
<min>4</min>
|
||||
<max>4</max>
|
||||
<sysopt>-e \${NDRX_APPHOME}/log/${m}_svr.log -r</sysopt>
|
||||
</server>
|
||||
EOF
|
||||
|
|
@ -208,7 +211,7 @@ cat > "$CONF/ndrxconfig.xml" <<EOF
|
|||
<srvid>40</srvid>
|
||||
<min>1</min>
|
||||
<max>1</max>
|
||||
<sysopt>-e \${NDRX_APPHOME}/log/tmsrv-rm1.log -r -- -t1 -l\${NDRX_APPHOME}/tmlogs/rm1 -m10</sysopt>
|
||||
<sysopt>-e \${NDRX_APPHOME}/log/tmsrv-rm1.log -r -- -t3 -l\${NDRX_APPHOME}/tmlogs/rm1 -m20</sysopt>
|
||||
</server>
|
||||
$(gen_servers)
|
||||
</servers>
|
||||
|
|
|
|||
|
|
@ -27,72 +27,105 @@
|
|||
<srvid>40</srvid>
|
||||
<min>1</min>
|
||||
<max>1</max>
|
||||
<sysopt>-e ${NDRX_APPHOME}/log/tmsrv-rm1.log -r -- -t1 -l${NDRX_APPHOME}/tmlogs/rm1 -m10</sysopt>
|
||||
<sysopt>-e ${NDRX_APPHOME}/log/tmsrv-rm1.log -r -- -t3 -l${NDRX_APPHOME}/tmlogs/rm1 -m20</sysopt>
|
||||
</server>
|
||||
<server name="ac_svr">
|
||||
<srvid>100</srvid>
|
||||
<min>1</min>
|
||||
<max>1</max>
|
||||
<!-- 모듈 내부 tpcall 체인(예: SETTLE→ST_MDR)이 같은 서버로 되돌아오므로
|
||||
복수 카피 필수. 카피가 1이면 호출자가 블록된 채 자기 요청을 못 꺼내
|
||||
자기교착(TPETIME)이 난다. 모듈내 최대 체인 깊이 3 + 동시성 여유 = 4. -->
|
||||
<min>4</min>
|
||||
<max>4</max>
|
||||
<sysopt>-e ${NDRX_APPHOME}/log/ac_svr.log -r</sysopt>
|
||||
</server>
|
||||
<server name="au_svr">
|
||||
<srvid>110</srvid>
|
||||
<min>1</min>
|
||||
<max>1</max>
|
||||
<!-- 모듈 내부 tpcall 체인(예: SETTLE→ST_MDR)이 같은 서버로 되돌아오므로
|
||||
복수 카피 필수. 카피가 1이면 호출자가 블록된 채 자기 요청을 못 꺼내
|
||||
자기교착(TPETIME)이 난다. 모듈내 최대 체인 깊이 3 + 동시성 여유 = 4. -->
|
||||
<min>4</min>
|
||||
<max>4</max>
|
||||
<sysopt>-e ${NDRX_APPHOME}/log/au_svr.log -r</sysopt>
|
||||
</server>
|
||||
<server name="cl_svr">
|
||||
<srvid>120</srvid>
|
||||
<min>1</min>
|
||||
<max>1</max>
|
||||
<!-- 모듈 내부 tpcall 체인(예: SETTLE→ST_MDR)이 같은 서버로 되돌아오므로
|
||||
복수 카피 필수. 카피가 1이면 호출자가 블록된 채 자기 요청을 못 꺼내
|
||||
자기교착(TPETIME)이 난다. 모듈내 최대 체인 깊이 3 + 동시성 여유 = 4. -->
|
||||
<min>4</min>
|
||||
<max>4</max>
|
||||
<sysopt>-e ${NDRX_APPHOME}/log/cl_svr.log -r</sysopt>
|
||||
</server>
|
||||
<server name="cm_svr">
|
||||
<srvid>130</srvid>
|
||||
<min>1</min>
|
||||
<max>1</max>
|
||||
<!-- 모듈 내부 tpcall 체인(예: SETTLE→ST_MDR)이 같은 서버로 되돌아오므로
|
||||
복수 카피 필수. 카피가 1이면 호출자가 블록된 채 자기 요청을 못 꺼내
|
||||
자기교착(TPETIME)이 난다. 모듈내 최대 체인 깊이 3 + 동시성 여유 = 4. -->
|
||||
<min>4</min>
|
||||
<max>4</max>
|
||||
<sysopt>-e ${NDRX_APPHOME}/log/cm_svr.log -r</sysopt>
|
||||
</server>
|
||||
<server name="lg_svr">
|
||||
<srvid>140</srvid>
|
||||
<min>1</min>
|
||||
<max>1</max>
|
||||
<!-- 모듈 내부 tpcall 체인(예: SETTLE→ST_MDR)이 같은 서버로 되돌아오므로
|
||||
복수 카피 필수. 카피가 1이면 호출자가 블록된 채 자기 요청을 못 꺼내
|
||||
자기교착(TPETIME)이 난다. 모듈내 최대 체인 깊이 3 + 동시성 여유 = 4. -->
|
||||
<min>4</min>
|
||||
<max>4</max>
|
||||
<sysopt>-e ${NDRX_APPHOME}/log/lg_svr.log -r</sysopt>
|
||||
</server>
|
||||
<server name="mg_svr">
|
||||
<srvid>150</srvid>
|
||||
<min>1</min>
|
||||
<max>1</max>
|
||||
<!-- 모듈 내부 tpcall 체인(예: SETTLE→ST_MDR)이 같은 서버로 되돌아오므로
|
||||
복수 카피 필수. 카피가 1이면 호출자가 블록된 채 자기 요청을 못 꺼내
|
||||
자기교착(TPETIME)이 난다. 모듈내 최대 체인 깊이 3 + 동시성 여유 = 4. -->
|
||||
<min>4</min>
|
||||
<max>4</max>
|
||||
<sysopt>-e ${NDRX_APPHOME}/log/mg_svr.log -r</sysopt>
|
||||
</server>
|
||||
<server name="mm_svr">
|
||||
<srvid>160</srvid>
|
||||
<min>1</min>
|
||||
<max>1</max>
|
||||
<!-- 모듈 내부 tpcall 체인(예: SETTLE→ST_MDR)이 같은 서버로 되돌아오므로
|
||||
복수 카피 필수. 카피가 1이면 호출자가 블록된 채 자기 요청을 못 꺼내
|
||||
자기교착(TPETIME)이 난다. 모듈내 최대 체인 깊이 3 + 동시성 여유 = 4. -->
|
||||
<min>4</min>
|
||||
<max>4</max>
|
||||
<sysopt>-e ${NDRX_APPHOME}/log/mm_svr.log -r</sysopt>
|
||||
</server>
|
||||
<server name="py_svr">
|
||||
<srvid>170</srvid>
|
||||
<min>1</min>
|
||||
<max>1</max>
|
||||
<!-- 모듈 내부 tpcall 체인(예: SETTLE→ST_MDR)이 같은 서버로 되돌아오므로
|
||||
복수 카피 필수. 카피가 1이면 호출자가 블록된 채 자기 요청을 못 꺼내
|
||||
자기교착(TPETIME)이 난다. 모듈내 최대 체인 깊이 3 + 동시성 여유 = 4. -->
|
||||
<min>4</min>
|
||||
<max>4</max>
|
||||
<sysopt>-e ${NDRX_APPHOME}/log/py_svr.log -r</sysopt>
|
||||
</server>
|
||||
<server name="rc_svr">
|
||||
<srvid>180</srvid>
|
||||
<min>1</min>
|
||||
<max>1</max>
|
||||
<!-- 모듈 내부 tpcall 체인(예: SETTLE→ST_MDR)이 같은 서버로 되돌아오므로
|
||||
복수 카피 필수. 카피가 1이면 호출자가 블록된 채 자기 요청을 못 꺼내
|
||||
자기교착(TPETIME)이 난다. 모듈내 최대 체인 깊이 3 + 동시성 여유 = 4. -->
|
||||
<min>4</min>
|
||||
<max>4</max>
|
||||
<sysopt>-e ${NDRX_APPHOME}/log/rc_svr.log -r</sysopt>
|
||||
</server>
|
||||
<server name="st_svr">
|
||||
<srvid>190</srvid>
|
||||
<min>1</min>
|
||||
<max>1</max>
|
||||
<!-- 모듈 내부 tpcall 체인(예: SETTLE→ST_MDR)이 같은 서버로 되돌아오므로
|
||||
복수 카피 필수. 카피가 1이면 호출자가 블록된 채 자기 요청을 못 꺼내
|
||||
자기교착(TPETIME)이 난다. 모듈내 최대 체인 깊이 3 + 동시성 여유 = 4. -->
|
||||
<min>4</min>
|
||||
<max>4</max>
|
||||
<sysopt>-e ${NDRX_APPHOME}/log/st_svr.log -r</sysopt>
|
||||
</server>
|
||||
<server name="vl_svr">
|
||||
<srvid>200</srvid>
|
||||
<min>1</min>
|
||||
<max>1</max>
|
||||
<!-- 모듈 내부 tpcall 체인(예: SETTLE→ST_MDR)이 같은 서버로 되돌아오므로
|
||||
복수 카피 필수. 카피가 1이면 호출자가 블록된 채 자기 요청을 못 꺼내
|
||||
자기교착(TPETIME)이 난다. 모듈내 최대 체인 깊이 3 + 동시성 여유 = 4. -->
|
||||
<min>4</min>
|
||||
<max>4</max>
|
||||
<sysopt>-e ${NDRX_APPHOME}/log/vl_svr.log -r</sysopt>
|
||||
</server>
|
||||
</servers>
|
||||
|
|
|
|||
|
|
@ -143,6 +143,39 @@ void ACQ_ALERTDUP(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 중복 경보 -> 매입 중복 검증(VL_DUPPURCH) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_ALERTDUP", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 경보로 잡힌 후보를 검증계 매입중복 규칙으로 확정한다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
if (tpcall("VL_DUPPURCH", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(VL_DUPPURCH) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "매입 중복 검증 실패", 0L); setl(b, T_RC, 491);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: VL_DUPPURCH 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 결과 필드 채움 */
|
||||
setl(b, T_COUNT, h_a);
|
||||
setl(b, T_ARG1, h_b);
|
||||
|
|
|
|||
|
|
@ -140,6 +140,39 @@ void ACQ_AMTFIX(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 금액 보정 -> 금액 검증(VL_AMOUNT) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_AMTFIX", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 보정 후 금액이 허용 오차 안인지 검증계에서 확인한다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
setl(b, T_DELTA, h_delta);
|
||||
if (tpcall("VL_AMOUNT", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(VL_AMOUNT) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "보정 금액 검증 실패", 0L); setl(b, T_RC, 531);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: VL_AMOUNT 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
setl(b, T_DELTA, h_delta);
|
||||
|
|
|
|||
|
|
@ -148,6 +148,39 @@ void ACQ_APPRLINK(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 승인 연계 -> 한도 차감(LIMIT_DEC) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_APPRLINK", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 매입에 연결된 승인건만큼 한도를 확정 차감한다 */
|
||||
Bchg(b, T_ISSUER, 0, h_issuer, 0L);
|
||||
setl(b, T_ARG3, h_id);
|
||||
if (tpcall("LIMIT_DEC", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(LIMIT_DEC) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "승인 한도 차감 실패", 0L); setl(b, T_RC, 341);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: LIMIT_DEC 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_COUNT, h_b);
|
||||
setl(b, T_ID1, h_id);
|
||||
|
|
|
|||
|
|
@ -134,6 +134,40 @@ void ACQ_APPRMAP(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 승인 매핑 -> 미매핑 승인 취소(AUTH_CANCEL) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_APPRMAP", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 매입에 붙지 못한 승인건을 승인계에서 정리한다 */
|
||||
Bchg(b, T_ISSUER, 0, h_issuer, 0L);
|
||||
setl(b, T_ARG3, h_id);
|
||||
Bchg(b, T_REASON, 0, "ACQ_UNMAPPED", 0L);
|
||||
if (tpcall("AUTH_CANCEL", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(AUTH_CANCEL) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "승인 취소 연동 실패", 0L); setl(b, T_RC, 351);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: AUTH_CANCEL 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 결과 필드 채움 */
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_ARG1, h_a);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ void ACQ_CANCEL(TPSVCINFO *p)
|
|||
long h_id, h_pid, h_amt;
|
||||
long h_orig = 0, h_fee = 0, h_prior = 0, h_cnt = 0, h_sum = 0, h_logid = 0;
|
||||
char h_bizdate[16], h_reason[128], h_prev[8], h_merch[64], h_logmsg[256];
|
||||
char h_cardno[32];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
|
||||
userlog("%s 진입: 매입 전액 취소 요청", SVC);
|
||||
|
|
@ -105,6 +106,76 @@ void ACQ_CANCEL(TPSVCINFO *p)
|
|||
VALUES (:h_logid, 'ACQ_CANCEL', 'I', :h_logmsg, :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) { setl(b, T_RC, 90); FAIL(b); }
|
||||
|
||||
/* --- 업무 체인: 매입취소 -> 한도원복(LIMIT_RST) -> 원장역분개(LG_REVERSE) -> 정산취소(ST_CANCEL) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_CANCEL", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_CANCEL_ID, h_id);
|
||||
|
||||
/* 1단계: 취소금액만큼 가맹점/카드 한도를 되돌린다.
|
||||
* LIMIT_RST 는 카드번호(T_KEY1)를 필수로 요구하지만 매입원장에는 카드가 없다.
|
||||
* 승인원장(au_authorization.auth_id = purchase_id)에서 카드를 끌어와 전문에 싣는다.
|
||||
* 승인 없이 접수된 매입(무승인 매입 등)은 원복할 카드 컨텍스트 자체가 없으므로
|
||||
* 한도원복 단계를 건너뛴다 — 실패가 아니라 해당 없음이다. */
|
||||
h_cardno[0] = 0;
|
||||
EXEC SQL SELECT card_no INTO :h_cardno FROM au_authorization WHERE auth_id = :h_pid;
|
||||
if (sqlca.sqlcode < 0) {
|
||||
userlog("%s: 승인원장 카드 조회 실패 [%d]", SVC, sqlca.sqlcode);
|
||||
setl(b, T_RC, 90); FAIL(b);
|
||||
}
|
||||
if (h_cardno[0] != 0) {
|
||||
Bchg(b, T_KEY1, 0, h_cardno, 0L);
|
||||
setl(b, T_ARG3, h_orig);
|
||||
Bchg(b, T_REASON, 0, h_reason, 0L);
|
||||
if (tpcall("LIMIT_RST", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(LIMIT_RST) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "한도 원복 실패", 0L); setl(b, T_RC, 141);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: LIMIT_RST 응답 rc=%ld card=%s", SVC, chain_rc, h_cardno);
|
||||
} else {
|
||||
userlog("%s 체인: pid=%ld 승인원장 카드 없음 — 한도원복 생략", SVC, h_pid);
|
||||
}
|
||||
|
||||
/* 2단계: 원 매입 전표를 역분개해 회계 잔액을 맞춘다 */
|
||||
setl(b, T_ARG4, h_id);
|
||||
setl(b, T_ARG5, ratio);
|
||||
if (tpcall("LG_REVERSE", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(LG_REVERSE) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "원장 역분개 실패", 0L); setl(b, T_RC, 142);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: LG_REVERSE 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 3단계: 정산 예정분을 취소해 지급 대상에서 제외한다 */
|
||||
setl(b, T_ARG6, h_fee);
|
||||
if (tpcall("ST_CANCEL", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(ST_CANCEL) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "정산 취소 실패", 0L); setl(b, T_RC, 143);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: ST_CANCEL 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 (계약 보존: T_CANCEL_ID / T_STATUS='C') */
|
||||
setl(b, T_CANCEL_ID, h_id);
|
||||
Bchg(b, T_STATUS, 0, "C", 0L);
|
||||
|
|
|
|||
|
|
@ -156,6 +156,39 @@ void ACQ_CB_OPEN(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 차지백 접수 -> 정산 차지백 반영(ST_CHARGEBACK) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_CB_OPEN", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 접수된 차지백 금액을 정산 지급에서 차감 예약한다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
Bchg(b, T_REASON, 0, h_reason, 0L);
|
||||
if (tpcall("ST_CHARGEBACK", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(ST_CHARGEBACK) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "차지백 정산 반영 실패", 0L); setl(b, T_RC, 561);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: ST_CHARGEBACK 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_CANCEL_ID, h_canid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
|
|
|
|||
|
|
@ -165,6 +165,39 @@ void ACQ_CB_REVERSE(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 차지백 역전 -> 원장 역분개(LG_REVERSE) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_CB_REVERSE", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 가맹점 승소로 되돌아온 차지백을 원장에서 역분개한다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
setl(b, T_ARG3, h_val);
|
||||
if (tpcall("LG_REVERSE", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(LG_REVERSE) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "차지백 역전 원장 반영 실패", 0L); setl(b, T_RC, 571);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: LG_REVERSE 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_ARG1, h_rem);
|
||||
|
|
|
|||
|
|
@ -156,6 +156,39 @@ void ACQ_CLAIMREG(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 클레임 등록 -> 분쟁 등록(ST_DISPUTE) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_CLAIMREG", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 접수된 클레임을 정산 분쟁건으로 등록해 지급을 묶는다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
Bchg(b, T_REASON, 0, h_reason, 0L);
|
||||
if (tpcall("ST_DISPUTE", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(ST_DISPUTE) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "정산 분쟁 등록 실패", 0L); setl(b, T_RC, 581);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: ST_DISPUTE 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_ID1, h_id);
|
||||
setl(b, T_ARG1, h_val);
|
||||
|
|
|
|||
|
|
@ -144,6 +144,39 @@ void ACQ_CORRECT(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 매입정정 -> 원장 정정분개(LG_CORRECT) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_CORRECT", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 정정 전/후 금액 차액을 원장에 정정분개로 반영한다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
setl(b, T_DELTA, h_amt - h_gross);
|
||||
if (tpcall("LG_CORRECT", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(LG_CORRECT) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "원장 정정 분개 실패", 0L); setl(b, T_RC, 191);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: LG_CORRECT 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_ADJ, h_adjid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
|
|
|
|||
|
|
@ -156,6 +156,40 @@ void ACQ_DDC(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: DDC 매입 -> 전문 로깅(MG_LOG) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_DDC", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: DDC 수신 전문을 게이트웨이 로그에 남겨 추적 가능하게 한다 */
|
||||
Bchg(b, T_CHANNEL, 0, h_chan, 0L);
|
||||
Bchg(b, T_KEY1, 0, "DDC", 0L);
|
||||
setl(b, T_AMT1, h_gross);
|
||||
if (tpcall("MG_LOG", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(MG_LOG) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "DDC 전문 로깅 실패", 0L); setl(b, T_RC, 401);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: MG_LOG 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_ID1, h_id);
|
||||
setl(b, T_AMOUNT, h_krw);
|
||||
|
|
|
|||
|
|
@ -152,6 +152,39 @@ void ACQ_DUPCHK(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 중복 매입 점검 -> 중복 검증(VL_DUP) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_DUPCHK", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 검증계 중복 규칙으로 동일 매입 재접수를 걸러낸다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
if (tpcall("VL_DUP", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(VL_DUP) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "중복 검증 실패", 0L); setl(b, T_RC, 481);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: VL_DUP 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 결과 필드 채움 */
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_ARG1, h_c);
|
||||
|
|
|
|||
|
|
@ -146,6 +146,40 @@ void ACQ_EDC(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: EDC 매입 -> 전문 로깅(MG_LOG) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_EDC", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: EDC 단말 매입 전문을 게이트웨이 로그로 적재한다 */
|
||||
Bchg(b, T_CHANNEL, 0, h_chan, 0L);
|
||||
Bchg(b, T_KEY1, 0, "EDC", 0L);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
if (tpcall("MG_LOG", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(MG_LOG) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "EDC 전문 로깅 실패", 0L); setl(b, T_RC, 411);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: MG_LOG 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_PURCHASE_ID, h_new);
|
||||
setl(b, T_FEE, h_fee);
|
||||
|
|
|
|||
|
|
@ -154,6 +154,40 @@ void ACQ_EDI(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: EDI 매입 -> 전문 송신(MG_SEND) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_EDI", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 확정된 EDI 매입 전문을 상대 기관으로 송신한다 */
|
||||
Bchg(b, T_CHANNEL, 0, h_chan, 0L);
|
||||
Bchg(b, T_KEY1, 0, "EDI", 0L);
|
||||
setl(b, T_AMT1, h_gross);
|
||||
if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(MG_SEND) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "EDI 전문 송신 실패", 0L); setl(b, T_RC, 421);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: MG_SEND 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_PURCHASE_ID, h_new);
|
||||
setl(b, T_ID1, h_id);
|
||||
|
|
|
|||
|
|
@ -158,6 +158,40 @@ void ACQ_EDIRESEND(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: EDI 재전송 -> 전문 재송신(MG_RESEND) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_EDIRESEND", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 미응답 EDI 전문을 게이트웨이에서 재송신시킨다 */
|
||||
Bchg(b, T_CHANNEL, 0, h_chan, 0L);
|
||||
setl(b, T_ARG3, h_n);
|
||||
Bchg(b, T_KEY1, 0, "EDI_RESEND", 0L);
|
||||
if (tpcall("MG_RESEND", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(MG_RESEND) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "EDI 전문 재송신 실패", 0L); setl(b, T_RC, 431);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: MG_RESEND 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_ID1, h_id);
|
||||
Bchg(b, T_DOCNO, 0, h_str1, 0L);
|
||||
|
|
|
|||
|
|
@ -148,6 +148,39 @@ void ACQ_ESCROW(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 에스크로 예치 -> 지급보류(PAY_HOLD) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_ESCROW", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 예치 기간 동안 지급이 나가지 않도록 잠근다 */
|
||||
setl(b, T_AMT1, h_net);
|
||||
Bchg(b, T_KEY1, 0, "ESCROW", 0L);
|
||||
if (tpcall("PAY_HOLD", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(PAY_HOLD) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "에스크로 지급보류 실패", 0L); setl(b, T_RC, 221);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: PAY_HOLD 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_ID1, h_ledid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
|
|
|
|||
|
|
@ -149,6 +149,39 @@ void ACQ_ESCROWREL(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 에스크로 해지 -> 지급보류해제(PAY_RELEASE) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_ESCROWREL", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 예치 해지 후 지급 가능 상태로 되돌린다 */
|
||||
setl(b, T_AMT1, h_net);
|
||||
Bchg(b, T_KEY1, 0, "ESCROW_REL", 0L);
|
||||
if (tpcall("PAY_RELEASE", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(PAY_RELEASE) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "에스크로 해지 지급 재개 실패", 0L); setl(b, T_RC, 231);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: PAY_RELEASE 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_ID1, h_ledid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
|
|
|
|||
|
|
@ -165,6 +165,39 @@ void ACQ_EXCHANGE(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 환전 매입 -> 교차환율 조회(CM_FX_CROSS) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_EXCHANGE", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 원통화-정산통화 간 교차환율을 공통계에서 구한다 */
|
||||
Bchg(b, T_CCY, 0, h_ccy, 0L);
|
||||
setl(b, T_FX_AMT, h_fx);
|
||||
if (tpcall("CM_FX_CROSS", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(CM_FX_CROSS) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "교차환율 조회 실패", 0L); setl(b, T_RC, 471);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: CM_FX_CROSS 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_CANCEL_ID, h_canid);
|
||||
setl(b, T_DELTA, h_delta);
|
||||
|
|
|
|||
|
|
@ -143,6 +143,39 @@ void ACQ_FEEADJ(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 수수료 조정 -> 원장 조정분개(LG_ADJUST) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_FEEADJ", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 조정된 수수료 증감분을 원장 조정분개로 남긴다 */
|
||||
setl(b, T_DELTA, h_delta);
|
||||
setl(b, T_AMT1, h_fee);
|
||||
if (tpcall("LG_ADJUST", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(LG_ADJUST) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "수수료 조정 원장 반영 실패", 0L); setl(b, T_RC, 281);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: LG_ADJUST 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_ADJ, h_adjid);
|
||||
setl(b, T_DELTA, h_delta);
|
||||
|
|
|
|||
|
|
@ -138,6 +138,39 @@ void ACQ_FEERECALC(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 수수료 재산출 -> 정산 재계산(ST_RECALC) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_FEERECALC", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 재산출된 요율로 정산 지급액을 다시 만든다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
setl(b, T_ARG3, h_rate);
|
||||
if (tpcall("ST_RECALC", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(ST_RECALC) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "정산 재계산 실패", 0L); setl(b, T_RC, 291);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: ST_RECALC 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_ADJ, h_adjid);
|
||||
setl(b, T_FEE, h_fee);
|
||||
|
|
|
|||
|
|
@ -158,6 +158,40 @@ void ACQ_FOREIGN(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 해외 매입 -> 환산(CM_FX_CONV) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_FOREIGN", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 원통화 금액을 공통 환율로 원화 환산한다 */
|
||||
Bchg(b, T_CCY, 0, h_ccy, 0L);
|
||||
setl(b, T_FX_AMT, h_fx);
|
||||
setl(b, T_AMT1, h_krw);
|
||||
if (tpcall("CM_FX_CONV", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(CM_FX_CONV) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "해외매입 환산 실패", 0L); setl(b, T_RC, 441);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: CM_FX_CONV 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_PURCHASE_ID, h_new);
|
||||
setl(b, T_AMOUNT, h_krw);
|
||||
|
|
|
|||
|
|
@ -162,6 +162,39 @@ void ACQ_FXCONVERT(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 통화 환산 -> 환율 조회(CM_FX) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_FXCONVERT", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 영업일 기준 고시환율을 공통계에서 받아온다 */
|
||||
Bchg(b, T_CCY, 0, h_ccy, 0L);
|
||||
setl(b, T_FX_AMT, h_fx);
|
||||
if (tpcall("CM_FX", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(CM_FX) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "환율 조회 실패", 0L); setl(b, T_RC, 451);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: CM_FX 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_ID1, h_id);
|
||||
setl(b, T_AMOUNT, h_krw);
|
||||
|
|
|
|||
|
|
@ -145,6 +145,39 @@ void ACQ_FXRATE(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 환율 적용 -> 환율 유효성 검증(CM_FX_VALID) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_FXRATE", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 적용하려는 환율이 고시 범위 안인지 확인한다 */
|
||||
Bchg(b, T_CCY, 0, h_ccy, 0L);
|
||||
setl(b, T_ARG3, h_rate);
|
||||
if (tpcall("CM_FX_VALID", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(CM_FX_VALID) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "환율 유효성 검증 실패", 0L); setl(b, T_RC, 461);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: CM_FX_VALID 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 결과 필드 채움 */
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_ARG1, h_rate);
|
||||
|
|
|
|||
|
|
@ -149,6 +149,39 @@ void ACQ_GUARANTEE(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 매입 보증 -> 정산 담보 확인(ST_COLLATERAL) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_GUARANTEE", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 보증 한도가 담보 범위 안인지 정산계에서 확인한다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
setl(b, T_AMT2, h_net);
|
||||
if (tpcall("ST_COLLATERAL", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(ST_COLLATERAL) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "정산 담보 확인 실패", 0L); setl(b, T_RC, 631);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: ST_COLLATERAL 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_ID1, h_ledid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
|
|
|
|||
|
|
@ -122,6 +122,39 @@ void ACQ_HOLD(TPSVCINFO *p)
|
|||
if (h_ctx > 1000)
|
||||
userlog("%s 경보: 당일 보류 처리 %ld 회로 과다", SVC, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 매입보류 -> 지급보류(PAY_HOLD) 연동 ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_HOLD", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 보류된 매입의 정산 지급을 지급계에서 함께 잠근다 */
|
||||
Bchg(b, T_REASON, 0, h_reason, 0L);
|
||||
setl(b, T_ARG3, h_id);
|
||||
if (tpcall("PAY_HOLD", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(PAY_HOLD) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "지급 보류 연동 실패", 0L); setl(b, T_RC, 201);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: PAY_HOLD 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 (계약 보존: 반영 시 T_STATUS='H', T_RC 는 0/1) */
|
||||
if (h_aff > 0) Bchg(b, T_STATUS, 0, "H", 0L);
|
||||
else Bchg(b, T_STATUS, 0, h_prev, 0L);
|
||||
|
|
|
|||
|
|
@ -158,6 +158,39 @@ void ACQ_INSTALL(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 할부 등록 -> 할부 조건 검증(VL_INSTCHK) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_INSTALL", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 개월수/금액 하한 등 할부 규칙을 검증계에서 확인한다 */
|
||||
setl(b, T_INSTALL_N, h_months);
|
||||
setl(b, T_AMT1, h_gross);
|
||||
if (tpcall("VL_INSTCHK", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(VL_INSTCHK) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "할부 조건 검증 실패", 0L); setl(b, T_RC, 321);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: VL_INSTCHK 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_COUNT, h_months);
|
||||
setl(b, T_INSTALL_N, h_months);
|
||||
|
|
|
|||
|
|
@ -160,6 +160,39 @@ void ACQ_INSTCXL(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 할부 취소 -> 한도원복(LIMIT_RST) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_INSTCXL", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 할부 잔여 회차분의 점유 한도를 되돌린다 */
|
||||
setl(b, T_INSTALL_N, h_months);
|
||||
setl(b, T_AMT1, h_gross);
|
||||
if (tpcall("LIMIT_RST", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(LIMIT_RST) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "할부취소 한도 원복 실패", 0L); setl(b, T_RC, 331);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: LIMIT_RST 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_COUNT, h_rem);
|
||||
setl(b, T_INSTALL_N, h_months);
|
||||
|
|
|
|||
|
|
@ -152,6 +152,39 @@ void ACQ_LIMITCHK(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 매입 한도 점검 -> 한도 검증(VL_LIMIT) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_LIMITCHK", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 가맹점 한도 소진 여부를 검증계 규칙으로 재확인한다 */
|
||||
setl(b, T_AMT1, h_lim);
|
||||
setl(b, T_AMT2, h_sum);
|
||||
if (tpcall("VL_LIMIT", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(VL_LIMIT) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "한도 검증 실패", 0L); setl(b, T_RC, 501);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: VL_LIMIT 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 결과 필드 채움 */
|
||||
setl(b, T_GROSS, h_b);
|
||||
setl(b, T_ARG1, h_lim);
|
||||
|
|
|
|||
|
|
@ -156,6 +156,39 @@ void ACQ_LIMITEXC(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 한도 초과 처리 -> 한도초과 검증(VL_OVERLIMIT) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_LIMITEXC", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 초과분이 예외 승인 범위인지 검증계에서 판정한다 */
|
||||
setl(b, T_AMT1, h_lim);
|
||||
setl(b, T_AMT2, h_sum);
|
||||
if (tpcall("VL_OVERLIMIT", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(VL_OVERLIMIT) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "한도초과 검증 실패", 0L); setl(b, T_RC, 511);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: VL_OVERLIMIT 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_GROSS, h_sum);
|
||||
setl(b, T_ARG1, h_lim);
|
||||
|
|
|
|||
|
|
@ -103,6 +103,37 @@ void ACQ_MERCHSUM(TPSVCINFO *p)
|
|||
VALUES (:h_logid, 'ACQ_MERCHSUM', 'I', :h_logmsg, :h_bizdate);
|
||||
if (sqlca.sqlcode < 0) { setl(b, T_RC, 90); FAIL(b); }
|
||||
|
||||
/* --- 업무 체인: 가맹점 실적 요약 -> 가맹점 마스터 조회(MM_MERCH_INQ) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_MERCHSUM", 0L);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 요약에 붙일 가맹점 등급/상태를 마스터계에서 받아온다 */
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_AMT1, h_gross);
|
||||
if (tpcall("MM_MERCH_INQ", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(MM_MERCH_INQ) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "가맹점 마스터 조회 실패", 0L); setl(b, T_RC, 621);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: MM_MERCH_INQ 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 (계약 보존: T_COUNT / T_GROSS) */
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_gross);
|
||||
|
|
|
|||
|
|
@ -146,6 +146,39 @@ void ACQ_NETCALC(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 순액 산출 -> 원장 순포지션 확인(LG_NETPOS) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_NETCALC", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 산출한 순액이 원장 순포지션과 맞는지 대조한다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
setl(b, T_AMT2, h_fee);
|
||||
if (tpcall("LG_NETPOS", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(LG_NETPOS) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "원장 순포지션 조회 실패", 0L); setl(b, T_RC, 611);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: LG_NETPOS 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_NET, computed);
|
||||
setl(b, T_DELTA, h_delta);
|
||||
|
|
|
|||
|
|
@ -163,6 +163,50 @@ void ACQ_PARTCXL(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 부분취소 -> 한도원복(LIMIT_RST) -> 부분역분개(LG_PARTREVERSE) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_PARTCXL", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 부분취소 금액만큼만 한도를 되돌린다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
setl(b, T_ARG3, h_val);
|
||||
if (tpcall("LIMIT_RST", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(LIMIT_RST) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "부분취소 한도 원복 실패", 0L); setl(b, T_RC, 161);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: LIMIT_RST 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 2단계: 원 전표를 남긴 채 취소분만 부분 역분개한다 */
|
||||
setl(b, T_AMT2, h_fee);
|
||||
setl(b, T_AMT3, h_net);
|
||||
if (tpcall("LG_PARTREVERSE", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(LG_PARTREVERSE) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "부분 역분개 실패", 0L); setl(b, T_RC, 162);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: LG_PARTREVERSE 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_CANCEL_ID, h_canid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
|
|
|
|||
|
|
@ -168,6 +168,39 @@ void ACQ_PARTRFND(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 부분환불 -> 정산 환불액 재산출(ST_REFUNDCALC) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_PARTRFND", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 부분환불 후 남는 정산 지급액을 정산계에서 재산출한다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
setl(b, T_AMT2, h_fee);
|
||||
if (tpcall("ST_REFUNDCALC", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(ST_REFUNDCALC) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "환불 정산액 산출 실패", 0L); setl(b, T_RC, 171);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: ST_REFUNDCALC 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_CANCEL_ID, h_canid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
|
|
|
|||
|
|
@ -149,6 +149,39 @@ void ACQ_PROMO(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 프로모션 적용 -> 정산 프로모 반영(ST_PROMOAPPLY) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_PROMO", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 프로모션 우대요율을 정산 수수료에 반영한다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
Bchg(b, T_KEY1, 0, h_str1, 0L);
|
||||
if (tpcall("ST_PROMOAPPLY", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(ST_PROMOAPPLY) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "프로모션 정산 반영 실패", 0L); setl(b, T_RC, 311);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: ST_PROMOAPPLY 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_PURCHASE_ID, h_new);
|
||||
setl(b, T_FEE, h_fee);
|
||||
|
|
|
|||
|
|
@ -165,6 +165,50 @@ void ACQ_REFUND(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 매입환불 -> 한도원복(LIMIT_RST) -> 원장역분개(LG_REVERSE) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_REFUND", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 환불액만큼 소진한도를 복구한다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
Bchg(b, T_ISSUER, 0, h_issuer, 0L);
|
||||
if (tpcall("LIMIT_RST", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(LIMIT_RST) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "환불 한도 원복 실패", 0L); setl(b, T_RC, 151);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: LIMIT_RST 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 2단계: 환불분에 해당하는 매입 전표를 역분개한다 */
|
||||
setl(b, T_AMT2, h_fee);
|
||||
setl(b, T_ARG5, h_rem);
|
||||
if (tpcall("LG_REVERSE", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(LG_REVERSE) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "환불 원장 역분개 실패", 0L); setl(b, T_RC, 152);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: LG_REVERSE 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_CANCEL_ID, h_canid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
|
|
|
|||
|
|
@ -153,6 +153,39 @@ void ACQ_RELEASE(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 보류해제 -> 지급보류해제(PAY_RELEASE) 연동 ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_RELEASE", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 매입 보류 해제와 동시에 지급 잠금도 해제한다 */
|
||||
setl(b, T_AMT1, h_net);
|
||||
Bchg(b, T_REASON, 0, h_reason, 0L);
|
||||
if (tpcall("PAY_RELEASE", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(PAY_RELEASE) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "지급 보류 해제 실패", 0L); setl(b, T_RC, 211);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: PAY_RELEASE 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
Bchg(b, T_STR1, 0, h_prev, 0L);
|
||||
setl(b, T_ARG1, h_val);
|
||||
|
|
|
|||
|
|
@ -159,6 +159,39 @@ void ACQ_REMATCH(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 재매칭 -> 대사 재매칭(RC_REMATCH) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_REMATCH", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 보정된 키로 대사계에 재매칭을 요청한다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
if (tpcall("RC_REMATCH", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(RC_REMATCH) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "대사 재매칭 실패", 0L); setl(b, T_RC, 551);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: RC_REMATCH 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_ARG1, h_a);
|
||||
|
|
|
|||
|
|
@ -150,6 +150,39 @@ void ACQ_REPROC(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 매입 재처리 -> 대사 재처리(RC_REPROC) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_REPROC", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 재처리된 매입을 대사계에서 다시 태운다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
if (tpcall("RC_REPROC", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(RC_REPROC) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "대사 재처리 실패", 0L); setl(b, T_RC, 601);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: RC_REPROC 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_ARG1, h_val);
|
||||
|
|
|
|||
|
|
@ -148,6 +148,39 @@ void ACQ_RESERVE(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 유보금 설정 -> 정산 보류(ST_HOLD) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_RESERVE", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 유보율만큼 정산 지급을 정산계에서 붙잡아 둔다 */
|
||||
setl(b, T_AMT1, h_net);
|
||||
setl(b, T_ARG3, h_rate);
|
||||
if (tpcall("ST_HOLD", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(ST_HOLD) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "정산 유보 설정 실패", 0L); setl(b, T_RC, 241);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: ST_HOLD 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_PURCHASE_ID, h_new);
|
||||
Bchg(b, T_BIZDATE, 0, h_d1, 0L);
|
||||
|
|
|
|||
|
|
@ -157,6 +157,39 @@ void ACQ_RESERVECXL(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 유보금 해제 -> 정산 보류해제(ST_RELEASE) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_RESERVECXL", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 해제된 유보금을 다음 정산 회차에 태운다 */
|
||||
setl(b, T_AMT1, h_net);
|
||||
setl(b, T_ARG3, h_val);
|
||||
if (tpcall("ST_RELEASE", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(ST_RELEASE) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "정산 유보 해제 실패", 0L); setl(b, T_RC, 251);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: ST_RELEASE 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
setl(b, T_ARG1, h_rem);
|
||||
|
|
|
|||
|
|
@ -153,6 +153,39 @@ void ACQ_RETURN(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 반품 매입 -> 대사 환불건 등록(RC_REFUNDREC) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_RETURN", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 반품으로 발생한 환불건을 대사계에 등록한다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
Bchg(b, T_REASON, 0, h_reason, 0L);
|
||||
if (tpcall("RC_REFUNDREC", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(RC_REFUNDREC) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "대사 환불건 등록 실패", 0L); setl(b, T_RC, 591);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: RC_REFUNDREC 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_CANCEL_ID, h_canid);
|
||||
setl(b, T_AMOUNT, h_gross);
|
||||
|
|
|
|||
|
|
@ -151,6 +151,95 @@ void ACQ_SETTLELINK(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 정산연계 -> 수수료 산출/원장반영(ST_MDR) -> 대차검증(LG_BALCHK) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다.
|
||||
*
|
||||
* XA 핫로우 규율: 원장 전기(LG_SETTLEPOST)는 ST_MDR 브랜치가 이미 수행한다
|
||||
* (ST_MDR -> LG_SETTLEPOST). 여기서 LG_SETTLEPOST 를 다시 직접 호출하면
|
||||
* 같은 글로벌 트랜잭션의 '형제 브랜치'가 lg_merch_bal 의 동일행
|
||||
* (merchant_id, biz_date) 을 ON CONFLICT DO UPDATE 로 두 번 잠가
|
||||
* 서로의 미커밋 락을 기다리며 트랜잭션 타임아웃까지 교착된다. 게다가
|
||||
* 같은 정산건이 원장에 두 번 전기되어 잔액이 이중계상되는 회계 오류도 된다.
|
||||
* 따라서 원장 쓰기 소유자는 ST_MDR 브랜치 하나로 일원화하고, 이 브랜치는
|
||||
* 전기 결과를 읽기전용 서비스 LG_BALCHK 로 대차검증만 한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
long chain_fee = 0, bal_dr = 0, bal_cr = 0, bal_diff = 0, bal_cnt = 0;
|
||||
long keep_amt2 = 0, keep_amt3 = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_SETTLELINK", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 정산계 요율표로 MDR 수수료를 확정한다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
setl(b, T_ARG3, h_rate);
|
||||
Bchg(b, T_CATEGORY, 0, h_category, 0L);
|
||||
if (tpcall("ST_MDR", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(ST_MDR) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "정산 수수료 산출 실패", 0L); setl(b, T_RC, 271);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
chain_fee = getl(b, T_ARG1);
|
||||
if (chain_fee > 0) setl(b, T_AMT2, chain_fee); /* 하위 산출 수수료를 다음 단계로 */
|
||||
userlog("%s 체인: ST_MDR 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 2단계: ST_MDR 브랜치가 전기한 정산 원장의 대차일치를 검증한다.
|
||||
* LG_BALCHK 는 조회 전용(원장/잔액에 쓰기 없음)이라 형제 브랜치와
|
||||
* 같은 행을 잠그지 않는다. 따라서 이 체인은 핫로우 교착을 만들지 않는다. */
|
||||
keep_amt2 = getl(b, T_AMT2); /* 하위가 덮어쓰기 전 수수료 보존 */
|
||||
keep_amt3 = getl(b, T_AMT3);
|
||||
setl(b, T_AMT3, h_net);
|
||||
setl(b, T_AMOUNT, (h_net < 0 ? 0 : h_net));
|
||||
setl(b, T_ID1, h_setid);
|
||||
setl(b, T_DELTA, 0L);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
Bchg(b, T_REASON, 0, "정산전기-대차검증", 0L);
|
||||
if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(LG_BALCHK) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "정산 원장 대차검증 실패", 0L); setl(b, T_RC, 272);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
bal_dr = getl(b, T_ARG7);
|
||||
bal_cr = getl(b, T_ARG8);
|
||||
bal_cnt = getl(b, T_ARG5);
|
||||
bal_diff = getl(b, T_ARG6);
|
||||
if (bal_diff < 0) bal_diff = -bal_diff;
|
||||
userlog("%s 체인: LG_BALCHK 응답 rc=%ld 차변=%ld 대변=%ld 건수=%ld 차이=%ld",
|
||||
SVC, chain_rc, bal_dr, bal_cr, bal_cnt, bal_diff);
|
||||
|
||||
/* 대차 불일치는 정산 연계를 되돌릴 사유는 아니지만(원장 전기 자체는
|
||||
* ST_MDR 브랜치에서 성공), 감사 추적이 남도록 사유/경보를 기록한다. */
|
||||
if (chain_rc != 0 || bal_diff != 0) {
|
||||
snprintf(h_logmsg, sizeof(h_logmsg),
|
||||
"%s 정산원장 대차불일치 merch=%s biz=%s 차변=%ld 대변=%ld 차이=%ld",
|
||||
SVC, h_merch, h_bizdate, bal_dr, bal_cr, bal_diff);
|
||||
userlog("%s 경보: %s", SVC, h_logmsg);
|
||||
Bchg(b, T_MSG, 0, "정산 원장 대차 불일치(감사대상)", 0L);
|
||||
} else {
|
||||
userlog("%s 체인: 정산원장 대차일치 확인 merch=%s biz=%s 계상=%ld",
|
||||
SVC, h_merch, h_bizdate, bal_dr);
|
||||
}
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태/금액 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
if (keep_amt2 > 0) setl(b, T_AMT2, keep_amt2);
|
||||
if (keep_amt3 > 0) setl(b, T_AMT3, keep_amt3);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_SETTLE_ID, h_setid);
|
||||
setl(b, T_NET, h_net);
|
||||
|
|
|
|||
|
|
@ -161,6 +161,39 @@ void ACQ_SPLITPAY(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 분할지급 -> 정산 분할(ST_SPLIT) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_SPLITPAY", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 분할 회차 수만큼 정산 지급 계획을 쪼갠다 */
|
||||
setl(b, T_AMT1, h_net);
|
||||
setl(b, T_ARG3, h_n);
|
||||
if (tpcall("ST_SPLIT", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(ST_SPLIT) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "정산 분할 처리 실패", 0L); setl(b, T_RC, 301);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: ST_SPLIT 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_COUNT, h_n);
|
||||
setl(b, T_AMT1, h_mamt);
|
||||
|
|
|
|||
|
|
@ -155,6 +155,39 @@ void ACQ_TAXCXL(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 세금계산서 취소 -> 정산 조정 반영(ST_ADJUST) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_TAXCXL", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 취소된 세액을 정산 조정에서 되돌린다 */
|
||||
setl(b, T_TAX, -h_vat);
|
||||
Bchg(b, T_DOCNO, 0, h_docno, 0L);
|
||||
if (tpcall("ST_ADJUST", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(ST_ADJUST) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "세금계산서 취소 정산 반영 실패", 0L); setl(b, T_RC, 371);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: ST_ADJUST 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_ID1, h_invid);
|
||||
setl(b, T_GROSS, h_delta);
|
||||
|
|
|
|||
|
|
@ -142,6 +142,40 @@ void ACQ_TAXINV(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 세금계산서 발행 -> 정산 조정 반영(ST_ADJUST) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_TAXINV", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 발행된 세액/공급가액을 정산 조정으로 넘긴다 */
|
||||
setl(b, T_TAX, h_vat);
|
||||
setl(b, T_AMT1, h_supply);
|
||||
Bchg(b, T_DOCNO, 0, h_docno, 0L);
|
||||
if (tpcall("ST_ADJUST", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(ST_ADJUST) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "세금계산서 정산 조정 실패", 0L); setl(b, T_RC, 361);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: ST_ADJUST 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_ID1, h_invid);
|
||||
setl(b, T_TAX, h_vat);
|
||||
|
|
|
|||
|
|
@ -160,6 +160,39 @@ void ACQ_TAXREVERSE(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 세금계산서 역발행 -> 원장 역분개(LG_REVERSE) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_TAXREVERSE", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 역발행분의 부가세 전표를 원장에서 역분개한다 */
|
||||
setl(b, T_TAX, h_vat);
|
||||
Bchg(b, T_DOCNO, 0, h_docno, 0L);
|
||||
if (tpcall("LG_REVERSE", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(LG_REVERSE) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "세무 원장 역분개 실패", 0L); setl(b, T_RC, 381);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: LG_REVERSE 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_ID1, h_invid);
|
||||
setl(b, T_ID2, h_id);
|
||||
|
|
|
|||
|
|
@ -160,6 +160,39 @@ void ACQ_UNMATCH(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 미매칭 매입 -> 대사 미매칭 등록(RC_UNMATCH) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_UNMATCH", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 매입측에서 잡은 미매칭 건을 대사계 원장에 올린다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
if (tpcall("RC_UNMATCH", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(RC_UNMATCH) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "대사 미매칭 등록 실패", 0L); setl(b, T_RC, 541);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: RC_UNMATCH 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_ID1, h_id);
|
||||
setl(b, T_COUNT, h_cnt + 1);
|
||||
|
|
|
|||
|
|
@ -157,6 +157,39 @@ void ACQ_VELOCITY(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 속도 점검 -> 속도 검증(VL_VELOCITY) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_VELOCITY", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 단위시간 건수/금액이 임계치를 넘는지 검증계에 묻는다 */
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_AMT1, h_gross);
|
||||
if (tpcall("VL_VELOCITY", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(VL_VELOCITY) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "속도 검증 실패", 0L); setl(b, T_RC, 521);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: VL_VELOCITY 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 결과 필드 채움 */
|
||||
setl(b, T_COUNT, h_a);
|
||||
setl(b, T_ARG2, h_b);
|
||||
|
|
|
|||
|
|
@ -154,6 +154,39 @@ void ACQ_VOID(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 매입무효 -> 전표무효(LG_VOIDVOUCHER) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_VOID", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 무효 처리된 매입의 회계 전표를 무효화한다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
Bchg(b, T_REASON, 0, h_reason, 0L);
|
||||
if (tpcall("LG_VOIDVOUCHER", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(LG_VOIDVOUCHER) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "전표 무효화 실패", 0L); setl(b, T_RC, 181);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: LG_VOIDVOUCHER 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_AMOUNT, h_gross);
|
||||
setl(b, T_DELTA, h_delta);
|
||||
|
|
|
|||
|
|
@ -155,6 +155,52 @@ void ACQ_WHT(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 원천징수 -> 원천세 산출(ST_WHT) -> 정산 조정 반영(ST_ADJUST) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
long chain_wht = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_WHT", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 정산계 원천징수 요율로 원천세를 산출한다 */
|
||||
setl(b, T_AMT1, h_gross);
|
||||
setl(b, T_ARG3, h_rate);
|
||||
if (tpcall("ST_WHT", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(ST_WHT) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "원천세 산출 실패", 0L); setl(b, T_RC, 391);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
chain_wht = getl(b, T_TAX);
|
||||
if (chain_wht > 0) setl(b, T_AMT2, chain_wht); /* 산출 원천세를 조정단계로 전달 */
|
||||
userlog("%s 체인: ST_WHT 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 2단계: 원천세 차감분을 정산 지급액에 조정 반영한다 */
|
||||
setl(b, T_AMT3, h_net);
|
||||
if (tpcall("ST_ADJUST", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(ST_ADJUST) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "원천세 정산 조정 실패", 0L); setl(b, T_RC, 392);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: ST_ADJUST 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_TAX, h_tax);
|
||||
setl(b, T_ID1, h_id);
|
||||
|
|
|
|||
|
|
@ -153,6 +153,39 @@ void ACQ_XFERLINK(TPSVCINFO *p)
|
|||
userlog("%s 경보: 당일 호출 %ld 회로 과다", SVC, h_ctx);
|
||||
setl(b, T_ARG6, h_ctx);
|
||||
|
||||
/* --- 업무 체인: 이체 연계 -> 지급 이체건 연결(PAY_XFERLINK) ---
|
||||
* 하위 서비스는 별도 XA 브랜치라 이 서비스가 방금 INSERT/UPDATE 한
|
||||
* 미커밋 행을 볼 수 없다. 판정에 필요한 값은 전부 UBF 전문으로 실어 보낸다.
|
||||
* 하위 실패 시 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요).
|
||||
* 자기 응답 계약은 이 블록 뒤 응답부에서 다시 확정한다. */
|
||||
{
|
||||
long rlen = 0, chain_rc = 0;
|
||||
char keep_status[16];
|
||||
|
||||
keep_status[0] = 0;
|
||||
gets_(b, T_STATUS, keep_status, sizeof(keep_status));
|
||||
Bchg(b, T_SVCNAME, 0, "ACQ_XFERLINK", 0L);
|
||||
setl(b, T_PURCHASE_ID, h_pid);
|
||||
setl(b, T_AMOUNT, h_amt);
|
||||
Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
|
||||
/* 1단계: 매입건과 실제 이체건을 지급계에서 짝지어 둔다 */
|
||||
setl(b, T_AMT1, h_net);
|
||||
Bchg(b, T_CHANNEL, 0, h_chan, 0L);
|
||||
if (tpcall("PAY_XFERLINK", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
userlog("%s: tpcall(PAY_XFERLINK) 실패: %s", SVC, tpstrerror(tperrno));
|
||||
Bchg(b, T_MSG, 0, "지급 이체 연계 실패", 0L); setl(b, T_RC, 261);
|
||||
FAIL(b);
|
||||
}
|
||||
chain_rc = getl(b, T_RC);
|
||||
userlog("%s 체인: PAY_XFERLINK 응답 rc=%ld", SVC, chain_rc);
|
||||
|
||||
/* 하위가 덮어쓴 자기 상태 계약값 복원 */
|
||||
if (keep_status[0] != 0) Bchg(b, T_STATUS, 0, keep_status, 0L);
|
||||
setl(b, T_RC, 0);
|
||||
}
|
||||
|
||||
/* 8) 응답부 */
|
||||
setl(b, T_ID1, h_ledid);
|
||||
setl(b, T_NET, h_net);
|
||||
|
|
|
|||
|
|
@ -87,9 +87,12 @@ void AUTH(TPSVCINFO *p)
|
|||
"AUTH", res_status, h_bizdate) < 0) {
|
||||
setl(b, T_RC, 24L); Bchg(b, T_MSG, 0, "승인원장 적재 실패", 0L); FAIL(b); }
|
||||
if (res_status[0] == 'A') {
|
||||
if (audb_limit_dec(h_card, h_amount) < 0) {
|
||||
setl(b, T_RC, 25L); Bchg(b, T_MSG, 0, "한도 차감 실패", 0L); FAIL(b); }
|
||||
/* 한도 차감은 아래 업무체인의 LIMIT_DEC 가 수행한다(한도원장 단일 소유자).
|
||||
* 같은 글로벌 트랜잭션이라도 XA 브랜치가 다르므로, 여기서 card_limit 을
|
||||
* 직접 갱신하면 하위 브랜치가 이 미커밋 행 락을 기다려 교착된다.
|
||||
* 따라서 이 브랜치는 승인원장만 쓰고 한도 반영치는 예상값으로만 계산한다. */
|
||||
h_used += h_amount; avail = h_limit - h_used;
|
||||
userlog("[%s] 한도차감 위임 → LIMIT_DEC 체인 (예상 사용=%ld)", svcname, h_used);
|
||||
}
|
||||
|
||||
/* 5) 이력/재집계부: 당일 카드 승인 실적 재집계(감사 요약) */
|
||||
|
|
@ -212,6 +215,69 @@ void AUTH(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH → LIMIT_DEC (승인 확정분 한도차감)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && res_status[0] == 'A' && h_amount > 0) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_DEC card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_DEC", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_DEC) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7101L);
|
||||
Bchg(b, T_MSG, 0, "한도차감 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7151L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "승인/한도차감 정상" : "한도차감 하위경고"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_DEC rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH → FRAUD_DETECT (승인건 이상거래 스코어링)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && h_auth > 0 && strlen(h_bizdate) >= 8) {
|
||||
long ch_len = 0, ch_rc = 0, ch_score = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
setl(b, T_ID1, h_auth);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → FRAUD_DETECT card=%s auth=%ld", svcname, h_card, (long)(h_auth));
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("FRAUD_DETECT", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(FRAUD_DETECT) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7102L);
|
||||
Bchg(b, T_MSG, 0, "이상거래 판정 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 판정코드 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
ch_score = getl(b, T_ARG1);
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
if (ch_rc != 0) {
|
||||
if (rc == 0) rc = 7152L;
|
||||
Bchg(b, T_MSG, 0, "이상거래 판정 경보", 0L);
|
||||
}
|
||||
userlog("[%s] 체인 완료 FRAUD_DETECT rc=%ld 지표=%ld", svcname, ch_rc, ch_score);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_ID1, h_auth);
|
||||
setl(b, T_RC, rc);
|
||||
|
|
|
|||
|
|
@ -204,6 +204,36 @@ respond:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH_AMT_ADJUST → LIMIT_DEC (승인금액 증액분 한도차감)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && h_delta > 0) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_delta;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_DEC card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_DEC", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_DEC) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7105L);
|
||||
Bchg(b, T_MSG, 0, "증액 한도차감 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7155L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "증액분 한도차감 완료" : "증액분 한도차감 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_DEC rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
setl(b, T_RC, rc);
|
||||
|
|
|
|||
|
|
@ -202,6 +202,36 @@ respond:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH_APPROVE → LIMIT_DEC (승인확정 한도차감)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && h_amount > 0) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_DEC card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_DEC", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_DEC) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7103L);
|
||||
Bchg(b, T_MSG, 0, "승인확정 한도차감 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7153L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "승인확정 한도차감 완료" : "승인확정 한도차감 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_DEC rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
Bchg(b, T_STATUS, 0, res_status, 0L);
|
||||
setl(b, T_RC, rc);
|
||||
|
|
|
|||
|
|
@ -84,9 +84,12 @@ void AUTH_CANCEL(TPSVCINFO *p)
|
|||
strcpy(res_status, "C"); rc = 0;
|
||||
/* 취소/역전/무효: 승인금액 한도 원복 */
|
||||
if (h_card[0] && h_amount > 0) {
|
||||
EXEC SQL UPDATE card_limit SET used_amount = GREATEST(used_amount - :h_amount, 0),
|
||||
updated_at = now() WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0) { setl(b, T_RC, 36L); FAIL(b); }
|
||||
/* 한도 원복은 아래 업무체인의 LIMIT_RST 가 수행한다(한도원장 단일 소유자).
|
||||
* 동일 card_limit 행을 상위/하위 두 XA 브랜치가 함께 쓰면 서로의 미커밋
|
||||
* 락을 기다려 교착되므로, 이 브랜치는 취소원장만 쓰고 원복은 위임한다. */
|
||||
h_used = (h_used > h_amount) ? (h_used - h_amount) : 0;
|
||||
avail = h_limit - h_used;
|
||||
userlog("[%s] 한도원복 위임 → LIMIT_RST 체인 (예상 사용=%ld)", svcname, h_used);
|
||||
}
|
||||
EXEC SQL SELECT nextval('au_cancel_seq') INTO :h_id;
|
||||
if (sqlca.sqlcode >= 0)
|
||||
|
|
@ -210,6 +213,36 @@ respond:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH_CANCEL → LIMIT_RST (승인취소 한도원복)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0]) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_RST card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_RST", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_RST) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7108L);
|
||||
Bchg(b, T_MSG, 0, "취소 한도원복 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7158L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "취소분 한도원복 완료" : "취소분 한도원복 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_RST rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_CANCEL_ID, h_id);
|
||||
Bchg(b, T_STATUS, 0, res_status, 0L);
|
||||
|
|
|
|||
|
|
@ -201,6 +201,36 @@ respond:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH_CAPTURE → ACQ_APPRGAP (매입확정 후 승인-매입 갭 연계점검)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
/* 매입 접수 연계 대상 확보: 전문에 실려온 매입 ID 우선, 없으면 스킵 */
|
||||
h_v3 = getl(b, T_PURCHASE_ID);
|
||||
if (h_v3 <= 0) userlog("[%s] 매입 ID 미지정 - 매입 연계 스킵", svcname);
|
||||
if (h_v3 > 0 && strlen(h_bizdate) == 10) {
|
||||
long ch_len = 0, ch_rc = 0, ch_pid = h_v3;
|
||||
setl(b, T_PURCHASE_ID, ch_pid);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → ACQ_APPRGAP pid=%ld merch=%s", svcname, ch_pid, h_merch);
|
||||
if (tpcall("ACQ_APPRGAP", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(ACQ_APPRGAP) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7114L);
|
||||
Bchg(b, T_MSG, 0, "매입 갭점검 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 매입 접수 결과 반영 */
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
if (ch_rc != 0 && rc == 0) rc = 7164L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "매입 접수 연동 완료" : "매입 접수 연동 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 ACQ_APPRGAP rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_RC, rc);
|
||||
Bchg(b, T_STATUS, 0, res_status, 0L);
|
||||
|
|
|
|||
|
|
@ -203,6 +203,38 @@ respond:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH_DECLINE → CM_LOG (승인거절 사유 공통로그 적재)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && strlen(h_bizdate) == 10 && h_bizdate[4] == '-') {
|
||||
long ch_len = 0, ch_rc = 0;
|
||||
char ch_str1[64], ch_line[200];
|
||||
ch_str1[0] = 0;
|
||||
gets_(b, T_STR1, ch_str1, sizeof(ch_str1)); /* 원 전문값 보존 */
|
||||
snprintf(ch_line, sizeof(ch_line), "승인거절 card=%s 사유=%s 금액=%ld", h_card, h_reason, h_amount);
|
||||
Bchg(b, T_SVCNAME, 0, (char *)svcname, 0L);
|
||||
Bchg(b, T_MSG, 0, ch_line, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
Bchg(b, T_STR1, 0, "AU_ALERT", 0L);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → CM_LOG [%s]", svcname, ch_line);
|
||||
if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(CM_LOG) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7134L);
|
||||
Bchg(b, T_MSG, 0, "승인거절 공통로그 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 공통로그 결과 반영 */
|
||||
Bchg(b, T_STR1, 0, ch_str1, 0L);
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
Bchg(b, T_MSG, 0, ch_line, 0L);
|
||||
userlog("[%s] 체인 완료 CM_LOG rc=%ld id=%ld", svcname, ch_rc, getl(b, T_ID1));
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
Bchg(b, T_STATUS, 0, res_status, 0L);
|
||||
setl(b, T_RC, rc);
|
||||
|
|
|
|||
|
|
@ -198,6 +198,46 @@ void AUTH_DUP_CHK(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH_DUP_CHK → FRAUD_DETECT (중복승인 의심건 이상거래 판정)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
/* 이상거래 스코어링 대상 승인건 확보: 없으면 판정 대상이 아니므로 스킵 */
|
||||
h_prev = 0;
|
||||
if (h_card[0]) {
|
||||
EXEC SQL SELECT coalesce(max(auth_id), 0) INTO :h_prev
|
||||
FROM au_authorization WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0) h_prev = 0;
|
||||
}
|
||||
if (h_prev > 0 && strlen(h_bizdate) >= 8) {
|
||||
long ch_len = 0, ch_rc = 0, ch_score = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
setl(b, T_ID1, h_prev);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → FRAUD_DETECT card=%s auth=%ld", svcname, h_card, (long)(h_prev));
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("FRAUD_DETECT", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(FRAUD_DETECT) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7128L);
|
||||
Bchg(b, T_MSG, 0, "중복승인 이상거래 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 판정코드 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
ch_score = getl(b, T_ARG1);
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
if (ch_rc != 0) {
|
||||
if (rc == 0) rc = 7178L;
|
||||
Bchg(b, T_MSG, 0, "이상거래 판정 경보", 0L);
|
||||
}
|
||||
userlog("[%s] 체인 완료 FRAUD_DETECT rc=%ld 지표=%ld", svcname, ch_rc, ch_score);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_ARG1, h_v1);
|
||||
setl(b, T_ID1, h_auth);
|
||||
|
|
|
|||
|
|
@ -197,6 +197,36 @@ void AUTH_EXPIRE_CHK(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH_EXPIRE_CHK → LIMIT_RST (승인만료건 한도원복)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0]) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_RST card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_RST", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_RST) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7113L);
|
||||
Bchg(b, T_MSG, 0, "만료 한도원복 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7163L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "만료분 한도원복 완료" : "만료분 한도원복 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_RST rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_sum);
|
||||
|
|
|
|||
|
|
@ -202,6 +202,36 @@ respond:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH_HOLD → LIMIT_CHK (승인보류 전 가용한도 재점검)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0]) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_CHK card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_CHK", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_CHK) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7107L);
|
||||
Bchg(b, T_MSG, 0, "보류 한도점검 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7157L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "보류건 한도 가용" : "보류건 한도 부족"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_CHK rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_RC, rc);
|
||||
Bchg(b, T_STATUS, 0, res_status, 0L);
|
||||
|
|
|
|||
|
|
@ -87,9 +87,12 @@ void AUTH_PARTAPPR(TPSVCINFO *p)
|
|||
"AUTH", res_status, h_bizdate) < 0) {
|
||||
setl(b, T_RC, 24L); Bchg(b, T_MSG, 0, "승인원장 적재 실패", 0L); FAIL(b); }
|
||||
if (res_status[0] == 'A') {
|
||||
if (audb_limit_dec(h_card, h_amount) < 0) {
|
||||
setl(b, T_RC, 25L); Bchg(b, T_MSG, 0, "한도 차감 실패", 0L); FAIL(b); }
|
||||
/* 한도 차감은 아래 업무체인의 LIMIT_DEC 가 수행한다(한도원장 단일 소유자).
|
||||
* 같은 글로벌 트랜잭션이라도 XA 브랜치가 다르므로, 여기서 card_limit 을
|
||||
* 직접 갱신하면 하위 브랜치가 이 미커밋 행 락을 기다려 교착된다.
|
||||
* 따라서 이 브랜치는 승인원장만 쓰고 한도 반영치는 예상값으로만 계산한다. */
|
||||
h_used += h_amount; avail = h_limit - h_used;
|
||||
userlog("[%s] 한도차감 위임 → LIMIT_DEC 체인 (예상 사용=%ld)", svcname, h_used);
|
||||
}
|
||||
|
||||
/* 5) 이력/재집계부: 당일 카드 승인 실적 재집계(감사 요약) */
|
||||
|
|
@ -212,6 +215,36 @@ void AUTH_PARTAPPR(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH_PARTAPPR → LIMIT_DEC (부분승인 확정액 한도차감)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && h_amount > 0) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_DEC card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_DEC", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_DEC) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7104L);
|
||||
Bchg(b, T_MSG, 0, "부분승인 한도차감 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7154L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "부분승인 한도차감 완료" : "부분승인 한도차감 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_DEC rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_AMT1, h_limit);
|
||||
setl(b, T_RC, rc);
|
||||
|
|
|
|||
|
|
@ -82,9 +82,12 @@ void AUTH_PARTCXL(TPSVCINFO *p)
|
|||
strcpy(res_status, "A"); rc = 0;
|
||||
/* 취소/역전/무효: 승인금액 한도 원복 */
|
||||
if (h_card[0] && h_amount > 0) {
|
||||
EXEC SQL UPDATE card_limit SET used_amount = GREATEST(used_amount - :h_amount, 0),
|
||||
updated_at = now() WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0) { setl(b, T_RC, 36L); FAIL(b); }
|
||||
/* 한도 원복은 아래 업무체인의 LIMIT_RST 가 수행한다(한도원장 단일 소유자).
|
||||
* 동일 card_limit 행을 상위/하위 두 XA 브랜치가 함께 쓰면 서로의 미커밋
|
||||
* 락을 기다려 교착되므로, 이 브랜치는 취소원장만 쓰고 원복은 위임한다. */
|
||||
h_used = (h_used > h_amount) ? (h_used - h_amount) : 0;
|
||||
avail = h_limit - h_used;
|
||||
userlog("[%s] 한도원복 위임 → LIMIT_RST 체인 (예상 사용=%ld)", svcname, h_used);
|
||||
}
|
||||
EXEC SQL SELECT nextval('au_cancel_seq') INTO :h_id;
|
||||
if (sqlca.sqlcode >= 0)
|
||||
|
|
@ -208,6 +211,36 @@ respond:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH_PARTCXL → LIMIT_RST (부분취소 한도원복)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && h_amount > 0) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_RST card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_RST", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_RST) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7111L);
|
||||
Bchg(b, T_MSG, 0, "부분취소 한도원복 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7161L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "부분취소 한도원복 완료" : "부분취소 한도원복 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_RST rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_CANCEL_ID, h_id);
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
|
|
|
|||
|
|
@ -202,6 +202,36 @@ respond:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH_RELEASE → LIMIT_RST (승인해제 한도원복)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0]) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_RST card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_RST", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_RST) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7112L);
|
||||
Bchg(b, T_MSG, 0, "해제 한도원복 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7162L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "해제분 한도원복 완료" : "해제분 한도원복 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_RST rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_RC, rc);
|
||||
Bchg(b, T_STATUS, 0, res_status, 0L);
|
||||
|
|
|
|||
|
|
@ -202,6 +202,39 @@ respond:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH_RESEND → MG_SEND (승인응답 전문 재송신)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && strlen(h_bizdate) >= 8) {
|
||||
long ch_len = 0, ch_rc = 0;
|
||||
char ch_str1[64], ch_chan[16];
|
||||
ch_str1[0] = 0; ch_chan[0] = 0;
|
||||
gets_(b, T_STR1, ch_str1, sizeof(ch_str1)); /* 원 전문값 보존 */
|
||||
gets_(b, T_CHANNEL, ch_chan, sizeof(ch_chan));
|
||||
if (strlen(ch_chan) < 2) strcpy(ch_chan, "CH01"); /* mg 기본 채널 */
|
||||
Bchg(b, T_CHANNEL, 0, ch_chan, 0L);
|
||||
Bchg(b, T_STR1, 0, "0210", 0L); /* MTI (전문유형) */
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → MG_SEND 채널=%s MTI=0210", svcname, ch_chan);
|
||||
if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(MG_SEND) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7130L);
|
||||
Bchg(b, T_MSG, 0, "승인응답 재송신 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 게이트웨이 응답 반영 */
|
||||
Bchg(b, T_STR1, 0, ch_str1, 0L); /* 원 전문값 복원 */
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
if (ch_rc != 0 && rc == 0) rc = 7130L;
|
||||
userlog("[%s] 승인응답 전문 재송신 요청 rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
setl(b, T_RC, rc);
|
||||
|
|
|
|||
|
|
@ -203,6 +203,39 @@ respond:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH_RETRY → MG_SEND (승인 전문 재전송)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && strlen(h_bizdate) >= 8) {
|
||||
long ch_len = 0, ch_rc = 0;
|
||||
char ch_str1[64], ch_chan[16];
|
||||
ch_str1[0] = 0; ch_chan[0] = 0;
|
||||
gets_(b, T_STR1, ch_str1, sizeof(ch_str1)); /* 원 전문값 보존 */
|
||||
gets_(b, T_CHANNEL, ch_chan, sizeof(ch_chan));
|
||||
if (strlen(ch_chan) < 2) strcpy(ch_chan, "CH01"); /* mg 기본 채널 */
|
||||
Bchg(b, T_CHANNEL, 0, ch_chan, 0L);
|
||||
Bchg(b, T_STR1, 0, "0200", 0L); /* MTI (전문유형) */
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → MG_SEND 채널=%s MTI=0200", svcname, ch_chan);
|
||||
if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(MG_SEND) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7129L);
|
||||
Bchg(b, T_MSG, 0, "승인 전문 재전송 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 게이트웨이 응답 반영 */
|
||||
Bchg(b, T_STR1, 0, ch_str1, 0L); /* 원 전문값 복원 */
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
if (ch_rc != 0 && rc == 0) rc = 7129L;
|
||||
userlog("[%s] 승인 전문 재전송 요청 rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_RC, rc);
|
||||
Bchg(b, T_STATUS, 0, res_status, 0L);
|
||||
|
|
|
|||
|
|
@ -80,9 +80,12 @@ void AUTH_REVERSE(TPSVCINFO *p)
|
|||
strcpy(res_status, "R"); rc = 0;
|
||||
/* 취소/역전/무효: 승인금액 한도 원복 */
|
||||
if (h_card[0] && h_amount > 0) {
|
||||
EXEC SQL UPDATE card_limit SET used_amount = GREATEST(used_amount - :h_amount, 0),
|
||||
updated_at = now() WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0) { setl(b, T_RC, 36L); FAIL(b); }
|
||||
/* 한도 원복은 아래 업무체인의 LIMIT_RST 가 수행한다(한도원장 단일 소유자).
|
||||
* 동일 card_limit 행을 상위/하위 두 XA 브랜치가 함께 쓰면 서로의 미커밋
|
||||
* 락을 기다려 교착되므로, 이 브랜치는 취소원장만 쓰고 원복은 위임한다. */
|
||||
h_used = (h_used > h_amount) ? (h_used - h_amount) : 0;
|
||||
avail = h_limit - h_used;
|
||||
userlog("[%s] 한도원복 위임 → LIMIT_RST 체인 (예상 사용=%ld)", svcname, h_used);
|
||||
}
|
||||
EXEC SQL SELECT nextval('au_cancel_seq') INTO :h_id;
|
||||
if (sqlca.sqlcode >= 0)
|
||||
|
|
@ -206,6 +209,36 @@ respond:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH_REVERSE → LIMIT_RST (승인역전 한도원복)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0]) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_RST card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_RST", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_RST) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7110L);
|
||||
Bchg(b, T_MSG, 0, "역전 한도원복 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7160L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "역전분 한도원복 완료" : "역전분 한도원복 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_RST rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
Bchg(b, T_STATUS, 0, res_status, 0L);
|
||||
setl(b, T_RC, rc);
|
||||
|
|
|
|||
|
|
@ -82,9 +82,12 @@ void AUTH_VOID(TPSVCINFO *p)
|
|||
strcpy(res_status, "V"); rc = 0;
|
||||
/* 취소/역전/무효: 승인금액 한도 원복 */
|
||||
if (h_card[0] && h_amount > 0) {
|
||||
EXEC SQL UPDATE card_limit SET used_amount = GREATEST(used_amount - :h_amount, 0),
|
||||
updated_at = now() WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0) { setl(b, T_RC, 36L); FAIL(b); }
|
||||
/* 한도 원복은 아래 업무체인의 LIMIT_RST 가 수행한다(한도원장 단일 소유자).
|
||||
* 동일 card_limit 행을 상위/하위 두 XA 브랜치가 함께 쓰면 서로의 미커밋
|
||||
* 락을 기다려 교착되므로, 이 브랜치는 취소원장만 쓰고 원복은 위임한다. */
|
||||
h_used = (h_used > h_amount) ? (h_used - h_amount) : 0;
|
||||
avail = h_limit - h_used;
|
||||
userlog("[%s] 한도원복 위임 → LIMIT_RST 체인 (예상 사용=%ld)", svcname, h_used);
|
||||
}
|
||||
EXEC SQL SELECT nextval('au_cancel_seq') INTO :h_id;
|
||||
if (sqlca.sqlcode >= 0)
|
||||
|
|
@ -208,6 +211,36 @@ respond:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: AUTH_VOID → LIMIT_RST (승인무효 한도원복)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0]) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_RST card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_RST", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_RST) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7109L);
|
||||
Bchg(b, T_MSG, 0, "무효 한도원복 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7159L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "무효분 한도원복 완료" : "무효분 한도원복 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_RST rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_CANCEL_ID, h_id);
|
||||
Bchg(b, T_STATUS, 0, res_status, 0L);
|
||||
|
|
|
|||
|
|
@ -183,6 +183,46 @@ void BLACKLIST_CHK(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: BLACKLIST_CHK → FRAUD_DETECT (블랙리스트 적중건 이상거래 판정)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
/* 이상거래 스코어링 대상 승인건 확보: 없으면 판정 대상이 아니므로 스킵 */
|
||||
h_prev = 0;
|
||||
if (h_card[0]) {
|
||||
EXEC SQL SELECT coalesce(max(auth_id), 0) INTO :h_prev
|
||||
FROM au_authorization WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0) h_prev = 0;
|
||||
}
|
||||
if (h_prev > 0 && strlen(h_bizdate) >= 8) {
|
||||
long ch_len = 0, ch_rc = 0, ch_score = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
setl(b, T_ID1, h_prev);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → FRAUD_DETECT card=%s auth=%ld", svcname, h_card, (long)(h_prev));
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("FRAUD_DETECT", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(FRAUD_DETECT) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7126L);
|
||||
Bchg(b, T_MSG, 0, "블랙리스트 이상거래 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 판정코드 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
ch_score = getl(b, T_ARG1);
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
if (ch_rc != 0) {
|
||||
if (rc == 0) rc = 7176L;
|
||||
Bchg(b, T_MSG, 0, "이상거래 판정 경보", 0L);
|
||||
}
|
||||
userlog("[%s] 체인 완료 FRAUD_DETECT rc=%ld 지표=%ld", svcname, ch_rc, ch_score);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_RC, rc);
|
||||
userlog("[%s] 완료: rc=%ld cnt=%ld sum=%ld id=%ld", svcname, rc, h_cnt, h_sum, (long)(h_auth?h_auth:h_id));
|
||||
|
|
|
|||
|
|
@ -191,6 +191,39 @@ card_done:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: CARD_LOST_REG → MG_SEND (분실등록 통보 전문 송신)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && strlen(h_bizdate) >= 8) {
|
||||
long ch_len = 0, ch_rc = 0;
|
||||
char ch_str1[64], ch_chan[16];
|
||||
ch_str1[0] = 0; ch_chan[0] = 0;
|
||||
gets_(b, T_STR1, ch_str1, sizeof(ch_str1)); /* 원 전문값 보존 */
|
||||
gets_(b, T_CHANNEL, ch_chan, sizeof(ch_chan));
|
||||
if (strlen(ch_chan) < 2) strcpy(ch_chan, "CH01"); /* mg 기본 채널 */
|
||||
Bchg(b, T_CHANNEL, 0, ch_chan, 0L);
|
||||
Bchg(b, T_STR1, 0, "0302", 0L); /* MTI (전문유형) */
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → MG_SEND 채널=%s MTI=0302", svcname, ch_chan);
|
||||
if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(MG_SEND) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7135L);
|
||||
Bchg(b, T_MSG, 0, "분실등록 통보 전문 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 게이트웨이 응답 반영 */
|
||||
Bchg(b, T_STR1, 0, ch_str1, 0L); /* 원 전문값 복원 */
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
if (ch_rc != 0 && rc == 0) rc = 7135L;
|
||||
userlog("[%s] 분실등록 통보 전문 송신 요청 rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_RC, rc);
|
||||
userlog("[%s] 완료: rc=%ld cnt=%ld sum=%ld id=%ld", svcname, rc, h_cnt, h_sum, (long)(h_auth?h_auth:h_id));
|
||||
|
|
|
|||
|
|
@ -193,6 +193,39 @@ card_done:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: CARD_STOLEN_REG → MG_SEND (도난등록 통보 전문 송신)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && strlen(h_bizdate) >= 8) {
|
||||
long ch_len = 0, ch_rc = 0;
|
||||
char ch_str1[64], ch_chan[16];
|
||||
ch_str1[0] = 0; ch_chan[0] = 0;
|
||||
gets_(b, T_STR1, ch_str1, sizeof(ch_str1)); /* 원 전문값 보존 */
|
||||
gets_(b, T_CHANNEL, ch_chan, sizeof(ch_chan));
|
||||
if (strlen(ch_chan) < 2) strcpy(ch_chan, "CH01"); /* mg 기본 채널 */
|
||||
Bchg(b, T_CHANNEL, 0, ch_chan, 0L);
|
||||
Bchg(b, T_STR1, 0, "0304", 0L); /* MTI (전문유형) */
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → MG_SEND 채널=%s MTI=0304", svcname, ch_chan);
|
||||
if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(MG_SEND) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7136L);
|
||||
Bchg(b, T_MSG, 0, "도난등록 통보 전문 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 게이트웨이 응답 반영 */
|
||||
Bchg(b, T_STR1, 0, ch_str1, 0L); /* 원 전문값 복원 */
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
if (ch_rc != 0 && rc == 0) rc = 7136L;
|
||||
userlog("[%s] 도난등록 통보 전문 송신 요청 rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_ID1, h_auth);
|
||||
setl(b, T_RC, rc);
|
||||
|
|
|
|||
|
|
@ -183,6 +183,42 @@ void CARD_VALIDATE(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: CARD_VALIDATE → CM_LUHN (카드번호 체크섬(Luhn) 검증)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0]) {
|
||||
long ch_len = 0, ch_rc = 0;
|
||||
char ch_str5[64];
|
||||
ch_str5[0] = 0;
|
||||
gets_(b, T_STR5, ch_str5, sizeof(ch_str5)); /* 원 전문값 보존 */
|
||||
Bchg(b, T_STR5, 0, h_card, 0L); /* 검증대상 PAN */
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
if (strlen(h_bizdate) == 10 && h_bizdate[4] == '-')
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
else
|
||||
Bchg(b, T_BIZDATE, 0, "", 0L); /* cm 은 형식 위반을 거절 */
|
||||
userlog("[%s] 체인 호출 → CM_LUHN 체크섬 검증 요청", svcname);
|
||||
if (tpcall("CM_LUHN", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(CM_LUHN) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7124L);
|
||||
Bchg(b, T_MSG, 0, "체크섬 검증 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 0=체크섬 유효 */
|
||||
Bchg(b, T_STR5, 0, ch_str5, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
if (ch_rc != 0) {
|
||||
if (rc == 0) rc = 7174L;
|
||||
Bchg(b, T_MSG, 0, "카드번호 체크섬 오류", 0L);
|
||||
}
|
||||
userlog("[%s] 체인 완료 CM_LUHN rc=%ld card=%s", svcname, ch_rc, h_card);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_RC, rc);
|
||||
userlog("[%s] 완료: rc=%ld cnt=%ld sum=%ld id=%ld", svcname, rc, h_cnt, h_sum, (long)(h_auth?h_auth:h_id));
|
||||
|
|
|
|||
|
|
@ -152,6 +152,21 @@ void FRAUD_DETECT(TPSVCINFO *p)
|
|||
}
|
||||
}
|
||||
|
||||
/* 체인 하위 호출 판별 (T_STR8 = "CHAIN"): 상위 서비스가 이미 자기 브랜치에서
|
||||
* au_summary 행을 잠근 채 이 서비스를 부른 상태다. 같은 글로벌 트랜잭션의 다른
|
||||
* XA 브랜치가 그 행을 다시 upsert 하면 서로의 미커밋 락을 기다려 교착된다.
|
||||
* 게다가 상위가 방금 넣은 승인원장은 이 브랜치에서 보이지 않아 재집계값이
|
||||
* 오히려 틀어진다. 따라서 체인 하위에서는 재집계를 상위(소유자)에게 위임한다. */
|
||||
{
|
||||
char ch_mark[16];
|
||||
ch_mark[0] = 0;
|
||||
gets_(b, T_STR8, ch_mark, sizeof(ch_mark));
|
||||
if (strcmp(ch_mark, "CHAIN") == 0) {
|
||||
h_merch[0] = 0;
|
||||
userlog("[%s] 체인 하위 호출 - au_summary 재집계는 상위 브랜치에 위임", svcname);
|
||||
}
|
||||
}
|
||||
|
||||
/* 6) 집계 갱신부: 가맹점 당일 승인 집계를 재계산해 au_summary 로 upsert */
|
||||
if (h_merch[0] && h_bizdate[0]) {
|
||||
EXEC SQL SELECT count(*), count(*) FILTER (WHERE status = 'A'),
|
||||
|
|
@ -192,6 +207,39 @@ void FRAUD_DETECT(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: FRAUD_DETECT → MG_LOG (이상거래 판정 전문로깅)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && strlen(h_bizdate) >= 8) {
|
||||
long ch_len = 0, ch_rc = 0;
|
||||
char ch_str1[64], ch_chan[16];
|
||||
ch_str1[0] = 0; ch_chan[0] = 0;
|
||||
gets_(b, T_STR1, ch_str1, sizeof(ch_str1)); /* 원 전문값 보존 */
|
||||
gets_(b, T_CHANNEL, ch_chan, sizeof(ch_chan));
|
||||
if (strlen(ch_chan) < 2) strcpy(ch_chan, "CH01"); /* mg 기본 채널 */
|
||||
Bchg(b, T_CHANNEL, 0, ch_chan, 0L);
|
||||
Bchg(b, T_STR1, 0, "0220", 0L); /* MTI (전문유형) */
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → MG_LOG 채널=%s MTI=0220", svcname, ch_chan);
|
||||
if (tpcall("MG_LOG", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(MG_LOG) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7304L);
|
||||
Bchg(b, T_MSG, 0, "이상거래 전문로깅 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 게이트웨이 응답 반영 */
|
||||
Bchg(b, T_STR1, 0, ch_str1, 0L); /* 원 전문값 복원 */
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
if (ch_rc != 0 && rc == 0) rc = 7304L;
|
||||
userlog("[%s] 이상거래 판정 전문로깅 완료 rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_ARG1, h_v1);
|
||||
setl(b, T_ID2, h_id);
|
||||
|
|
|
|||
|
|
@ -89,9 +89,12 @@ void INSTALL_AUTH(TPSVCINFO *p)
|
|||
"AUTH", res_status, h_bizdate) < 0) {
|
||||
setl(b, T_RC, 24L); Bchg(b, T_MSG, 0, "승인원장 적재 실패", 0L); FAIL(b); }
|
||||
if (res_status[0] == 'A') {
|
||||
if (audb_limit_dec(h_card, h_amount) < 0) {
|
||||
setl(b, T_RC, 25L); Bchg(b, T_MSG, 0, "한도 차감 실패", 0L); FAIL(b); }
|
||||
/* 한도 차감은 아래 업무체인의 LIMIT_DEC 가 수행한다(한도원장 단일 소유자).
|
||||
* 같은 글로벌 트랜잭션이라도 XA 브랜치가 다르므로, 여기서 card_limit 을
|
||||
* 직접 갱신하면 하위 브랜치가 이 미커밋 행 락을 기다려 교착된다.
|
||||
* 따라서 이 브랜치는 승인원장만 쓰고 한도 반영치는 예상값으로만 계산한다. */
|
||||
h_used += h_amount; avail = h_limit - h_used;
|
||||
userlog("[%s] 한도차감 위임 → LIMIT_DEC 체인 (예상 사용=%ld)", svcname, h_used);
|
||||
}
|
||||
|
||||
/* 5) 이력/재집계부: 당일 카드 승인 실적 재집계(감사 요약) */
|
||||
|
|
@ -214,6 +217,36 @@ void INSTALL_AUTH(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: INSTALL_AUTH → LIMIT_DEC (할부승인 원금 한도차감)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && h_amount > 0) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_DEC card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_DEC", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_DEC) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7106L);
|
||||
Bchg(b, T_MSG, 0, "할부승인 한도차감 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7156L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "할부 한도차감 완료" : "할부 한도차감 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_DEC rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_RC, rc);
|
||||
|
|
|
|||
|
|
@ -55,10 +55,17 @@ void LIMIT_CHK(TPSVCINFO *p)
|
|||
EXEC SQL SELECT daily_limit, used_amount, temp_limit, status
|
||||
INTO :h_limit, :h_used, :h_temp, :h_status
|
||||
FROM card_limit WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode == 100) { setl(b, T_RC, 41L);
|
||||
Bchg(b, T_MSG, 0, "카드 한도원장 미존재", 0L);
|
||||
userlog("[%s] 원장없음 card=%s", svcname, h_card); FAIL(b); }
|
||||
if (sqlca.sqlcode < 0) { setl(b, T_RC, 42L); FAIL(b); }
|
||||
if (sqlca.sqlcode == 100) {
|
||||
/* XA 브랜치 격리: 상위(AUTH/PREAUTH/STANDIN...)가 방금 만든 한도원장 행은
|
||||
* 아직 미커밋이라 이 브랜치에서 보이지 않는다. 여기서 FAIL 하면 체인 전체가
|
||||
* 롤백되므로, 미존재는 정상 흐름으로 보고 전문(T_*)에 실려온 값/기본 정책으로
|
||||
* 판정을 이어간다(RECONCILE.pgc 의 미커밋 캘러행 처리와 동일 규율). */
|
||||
h_limit = getl(b, T_AMT1); if (h_limit <= 0) h_limit = 1000000L;
|
||||
h_used = getl(b, T_AMT2); if (h_used < 0) h_used = 0;
|
||||
h_temp = 0; strcpy(h_status, "ACTIVE");
|
||||
userlog("[%s] 한도원장 미존재(체인 미커밋 가능) card=%s - 전문/기본정책 적용",
|
||||
svcname, h_card);
|
||||
} else if (sqlca.sqlcode < 0) { setl(b, T_RC, 42L); FAIL(b); }
|
||||
avail = h_limit + h_temp - h_used;
|
||||
|
||||
/* 3) 한도 판정 분기부: 상태/구간별 가용성 산출 */
|
||||
|
|
@ -151,6 +158,21 @@ void LIMIT_CHK(TPSVCINFO *p)
|
|||
}
|
||||
}
|
||||
|
||||
/* 체인 하위 호출 판별 (T_STR8 = "CHAIN"): 상위 서비스가 이미 자기 브랜치에서
|
||||
* au_summary 행을 잠근 채 이 서비스를 부른 상태다. 같은 글로벌 트랜잭션의 다른
|
||||
* XA 브랜치가 그 행을 다시 upsert 하면 서로의 미커밋 락을 기다려 교착된다.
|
||||
* 게다가 상위가 방금 넣은 승인원장은 이 브랜치에서 보이지 않아 재집계값이
|
||||
* 오히려 틀어진다. 따라서 체인 하위에서는 재집계를 상위(소유자)에게 위임한다. */
|
||||
{
|
||||
char ch_mark[16];
|
||||
ch_mark[0] = 0;
|
||||
gets_(b, T_STR8, ch_mark, sizeof(ch_mark));
|
||||
if (strcmp(ch_mark, "CHAIN") == 0) {
|
||||
h_merch[0] = 0;
|
||||
userlog("[%s] 체인 하위 호출 - au_summary 재집계는 상위 브랜치에 위임", svcname);
|
||||
}
|
||||
}
|
||||
|
||||
/* 6) 집계 갱신부: 가맹점 당일 승인 집계를 재계산해 au_summary 로 upsert */
|
||||
if (h_merch[0] && h_bizdate[0]) {
|
||||
EXEC SQL SELECT count(*), count(*) FILTER (WHERE status = 'A'),
|
||||
|
|
@ -191,6 +213,38 @@ void LIMIT_CHK(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: LIMIT_CHK → CM_LOG (한도점검 결과 공통감사로그)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && strlen(h_bizdate) == 10 && h_bizdate[4] == '-') {
|
||||
long ch_len = 0, ch_rc = 0;
|
||||
char ch_str1[64], ch_line[200];
|
||||
ch_str1[0] = 0;
|
||||
gets_(b, T_STR1, ch_str1, sizeof(ch_str1)); /* 원 전문값 보존 */
|
||||
snprintf(ch_line, sizeof(ch_line), "한도점검 card=%s 한도=%ld 사용=%ld 가용=%ld", h_card, h_limit, h_used, avail);
|
||||
Bchg(b, T_SVCNAME, 0, (char *)svcname, 0L);
|
||||
Bchg(b, T_MSG, 0, ch_line, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
Bchg(b, T_STR1, 0, "AU_ALERT", 0L);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → CM_LOG [%s]", svcname, ch_line);
|
||||
if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(CM_LOG) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7303L);
|
||||
Bchg(b, T_MSG, 0, "한도점검 공통로그 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 공통로그 결과 반영 */
|
||||
Bchg(b, T_STR1, 0, ch_str1, 0L);
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
Bchg(b, T_MSG, 0, ch_line, 0L);
|
||||
userlog("[%s] 체인 완료 CM_LOG rc=%ld id=%ld", svcname, ch_rc, getl(b, T_ID1));
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_AMT1, h_limit);
|
||||
setl(b, T_AMT2, h_used);
|
||||
|
|
|
|||
|
|
@ -154,6 +154,21 @@ void LIMIT_DEC(TPSVCINFO *p)
|
|||
}
|
||||
}
|
||||
|
||||
/* 체인 하위 호출 판별 (T_STR8 = "CHAIN"): 상위 서비스가 이미 자기 브랜치에서
|
||||
* au_summary 행을 잠근 채 이 서비스를 부른 상태다. 같은 글로벌 트랜잭션의 다른
|
||||
* XA 브랜치가 그 행을 다시 upsert 하면 서로의 미커밋 락을 기다려 교착된다.
|
||||
* 게다가 상위가 방금 넣은 승인원장은 이 브랜치에서 보이지 않아 재집계값이
|
||||
* 오히려 틀어진다. 따라서 체인 하위에서는 재집계를 상위(소유자)에게 위임한다. */
|
||||
{
|
||||
char ch_mark[16];
|
||||
ch_mark[0] = 0;
|
||||
gets_(b, T_STR8, ch_mark, sizeof(ch_mark));
|
||||
if (strcmp(ch_mark, "CHAIN") == 0) {
|
||||
h_merch[0] = 0;
|
||||
userlog("[%s] 체인 하위 호출 - au_summary 재집계는 상위 브랜치에 위임", svcname);
|
||||
}
|
||||
}
|
||||
|
||||
/* 6) 집계 갱신부: 가맹점 당일 승인 집계를 재계산해 au_summary 로 upsert */
|
||||
if (h_merch[0] && h_bizdate[0]) {
|
||||
EXEC SQL SELECT count(*), count(*) FILTER (WHERE status = 'A'),
|
||||
|
|
@ -194,6 +209,39 @@ void LIMIT_DEC(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: LIMIT_DEC → MG_LOG (한도차감 결과 전문로깅)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && strlen(h_bizdate) >= 8) {
|
||||
long ch_len = 0, ch_rc = 0;
|
||||
char ch_str1[64], ch_chan[16];
|
||||
ch_str1[0] = 0; ch_chan[0] = 0;
|
||||
gets_(b, T_STR1, ch_str1, sizeof(ch_str1)); /* 원 전문값 보존 */
|
||||
gets_(b, T_CHANNEL, ch_chan, sizeof(ch_chan));
|
||||
if (strlen(ch_chan) < 2) strcpy(ch_chan, "CH01"); /* mg 기본 채널 */
|
||||
Bchg(b, T_CHANNEL, 0, ch_chan, 0L);
|
||||
Bchg(b, T_STR1, 0, "0200", 0L); /* MTI (전문유형) */
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → MG_LOG 채널=%s MTI=0200", svcname, ch_chan);
|
||||
if (tpcall("MG_LOG", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(MG_LOG) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7301L);
|
||||
Bchg(b, T_MSG, 0, "한도차감 전문로깅 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 게이트웨이 응답 반영 */
|
||||
Bchg(b, T_STR1, 0, ch_str1, 0L); /* 원 전문값 복원 */
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
if (ch_rc != 0 && rc == 0) rc = 7301L;
|
||||
userlog("[%s] 한도차감 전문로깅 완료 rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_RC, rc);
|
||||
userlog("[%s] 완료: rc=%ld cnt=%ld sum=%ld id=%ld", svcname, rc, h_cnt, h_sum, (long)(h_auth?h_auth:h_id));
|
||||
|
|
|
|||
|
|
@ -191,6 +191,38 @@ cur_done:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: LIMIT_EXHAUST_LST → CM_LOG (한도소진 목록 공통로그 적재)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_bizdate[0] && strlen(h_bizdate) == 10 && h_bizdate[4] == '-') {
|
||||
long ch_len = 0, ch_rc = 0;
|
||||
char ch_str1[64], ch_line[200];
|
||||
ch_str1[0] = 0;
|
||||
gets_(b, T_STR1, ch_str1, sizeof(ch_str1)); /* 원 전문값 보존 */
|
||||
snprintf(ch_line, sizeof(ch_line), "한도소진 대상 %ld건 (영업일 %s)", h_cnt, h_bizdate);
|
||||
Bchg(b, T_SVCNAME, 0, (char *)svcname, 0L);
|
||||
Bchg(b, T_MSG, 0, ch_line, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
Bchg(b, T_STR1, 0, "AU_ALERT", 0L);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → CM_LOG [%s]", svcname, ch_line);
|
||||
if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(CM_LOG) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7132L);
|
||||
Bchg(b, T_MSG, 0, "한도소진 목록 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 공통로그 결과 반영 */
|
||||
Bchg(b, T_STR1, 0, ch_str1, 0L);
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
Bchg(b, T_MSG, 0, ch_line, 0L);
|
||||
userlog("[%s] 체인 완료 CM_LOG rc=%ld id=%ld", svcname, ch_rc, getl(b, T_ID1));
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_ARG1, h_v1);
|
||||
|
|
|
|||
|
|
@ -193,6 +193,38 @@ void LIMIT_FREEZE(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: LIMIT_FREEZE → CM_LOG (한도동결 조치 공통로그 적재)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && strlen(h_bizdate) == 10 && h_bizdate[4] == '-') {
|
||||
long ch_len = 0, ch_rc = 0;
|
||||
char ch_str1[64], ch_line[200];
|
||||
ch_str1[0] = 0;
|
||||
gets_(b, T_STR1, ch_str1, sizeof(ch_str1)); /* 원 전문값 보존 */
|
||||
snprintf(ch_line, sizeof(ch_line), "한도동결 card=%s 상태=%s", h_card, h_status);
|
||||
Bchg(b, T_SVCNAME, 0, (char *)svcname, 0L);
|
||||
Bchg(b, T_MSG, 0, ch_line, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
Bchg(b, T_STR1, 0, "AU_ALERT", 0L);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → CM_LOG [%s]", svcname, ch_line);
|
||||
if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(CM_LOG) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7133L);
|
||||
Bchg(b, T_MSG, 0, "한도동결 공통로그 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 공통로그 결과 반영 */
|
||||
Bchg(b, T_STR1, 0, ch_str1, 0L);
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
Bchg(b, T_MSG, 0, ch_line, 0L);
|
||||
userlog("[%s] 체인 완료 CM_LOG rc=%ld id=%ld", svcname, ch_rc, getl(b, T_ID1));
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_RC, rc);
|
||||
userlog("[%s] 완료: rc=%ld cnt=%ld sum=%ld id=%ld", svcname, rc, h_cnt, h_sum, (long)(h_auth?h_auth:h_id));
|
||||
|
|
|
|||
|
|
@ -190,6 +190,38 @@ void LIMIT_OVER_ALERT(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: LIMIT_OVER_ALERT → CM_LOG (한도초과 경보 공통로그 적재)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && strlen(h_bizdate) == 10 && h_bizdate[4] == '-') {
|
||||
long ch_len = 0, ch_rc = 0;
|
||||
char ch_str1[64], ch_line[200];
|
||||
ch_str1[0] = 0;
|
||||
gets_(b, T_STR1, ch_str1, sizeof(ch_str1)); /* 원 전문값 보존 */
|
||||
snprintf(ch_line, sizeof(ch_line), "한도초과경보 card=%s 한도=%ld 사용=%ld", h_card, h_limit, h_used);
|
||||
Bchg(b, T_SVCNAME, 0, (char *)svcname, 0L);
|
||||
Bchg(b, T_MSG, 0, ch_line, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
Bchg(b, T_STR1, 0, "AU_ALERT", 0L);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → CM_LOG [%s]", svcname, ch_line);
|
||||
if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(CM_LOG) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7131L);
|
||||
Bchg(b, T_MSG, 0, "한도초과 경보 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 공통로그 결과 반영 */
|
||||
Bchg(b, T_STR1, 0, ch_str1, 0L);
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
Bchg(b, T_MSG, 0, ch_line, 0L);
|
||||
userlog("[%s] 체인 완료 CM_LOG rc=%ld id=%ld", svcname, ch_rc, getl(b, T_ID1));
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_ARG1, h_v1);
|
||||
setl(b, T_AMT1, h_limit);
|
||||
|
|
|
|||
|
|
@ -153,6 +153,21 @@ void LIMIT_RST(TPSVCINFO *p)
|
|||
}
|
||||
}
|
||||
|
||||
/* 체인 하위 호출 판별 (T_STR8 = "CHAIN"): 상위 서비스가 이미 자기 브랜치에서
|
||||
* au_summary 행을 잠근 채 이 서비스를 부른 상태다. 같은 글로벌 트랜잭션의 다른
|
||||
* XA 브랜치가 그 행을 다시 upsert 하면 서로의 미커밋 락을 기다려 교착된다.
|
||||
* 게다가 상위가 방금 넣은 승인원장은 이 브랜치에서 보이지 않아 재집계값이
|
||||
* 오히려 틀어진다. 따라서 체인 하위에서는 재집계를 상위(소유자)에게 위임한다. */
|
||||
{
|
||||
char ch_mark[16];
|
||||
ch_mark[0] = 0;
|
||||
gets_(b, T_STR8, ch_mark, sizeof(ch_mark));
|
||||
if (strcmp(ch_mark, "CHAIN") == 0) {
|
||||
h_merch[0] = 0;
|
||||
userlog("[%s] 체인 하위 호출 - au_summary 재집계는 상위 브랜치에 위임", svcname);
|
||||
}
|
||||
}
|
||||
|
||||
/* 6) 집계 갱신부: 가맹점 당일 승인 집계를 재계산해 au_summary 로 upsert */
|
||||
if (h_merch[0] && h_bizdate[0]) {
|
||||
EXEC SQL SELECT count(*), count(*) FILTER (WHERE status = 'A'),
|
||||
|
|
@ -193,6 +208,39 @@ void LIMIT_RST(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: LIMIT_RST → MG_LOG (한도원복 결과 전문로깅)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && strlen(h_bizdate) >= 8) {
|
||||
long ch_len = 0, ch_rc = 0;
|
||||
char ch_str1[64], ch_chan[16];
|
||||
ch_str1[0] = 0; ch_chan[0] = 0;
|
||||
gets_(b, T_STR1, ch_str1, sizeof(ch_str1)); /* 원 전문값 보존 */
|
||||
gets_(b, T_CHANNEL, ch_chan, sizeof(ch_chan));
|
||||
if (strlen(ch_chan) < 2) strcpy(ch_chan, "CH01"); /* mg 기본 채널 */
|
||||
Bchg(b, T_CHANNEL, 0, ch_chan, 0L);
|
||||
Bchg(b, T_STR1, 0, "0400", 0L); /* MTI (전문유형) */
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → MG_LOG 채널=%s MTI=0400", svcname, ch_chan);
|
||||
if (tpcall("MG_LOG", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(MG_LOG) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7302L);
|
||||
Bchg(b, T_MSG, 0, "한도원복 전문로깅 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 게이트웨이 응답 반영 */
|
||||
Bchg(b, T_STR1, 0, ch_str1, 0L); /* 원 전문값 복원 */
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
if (ch_rc != 0 && rc == 0) rc = 7302L;
|
||||
userlog("[%s] 한도원복 전문로깅 완료 rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_RC, rc);
|
||||
userlog("[%s] 완료: rc=%ld cnt=%ld sum=%ld id=%ld", svcname, rc, h_cnt, h_sum, (long)(h_auth?h_auth:h_id));
|
||||
|
|
|
|||
|
|
@ -211,6 +211,36 @@ void NOAUTH_CAPTURE(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: NOAUTH_CAPTURE → ACQ_CORRAPPR (무승인매입 정정승인 연계)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
/* 매입 접수 연계 대상 확보: 전문에 실려온 매입 ID 우선, 없으면 스킵 */
|
||||
h_v3 = getl(b, T_PURCHASE_ID);
|
||||
if (h_v3 <= 0) userlog("[%s] 매입 ID 미지정 - 매입 연계 스킵", svcname);
|
||||
if (h_v3 > 0 && strlen(h_bizdate) == 10) {
|
||||
long ch_len = 0, ch_rc = 0, ch_pid = h_v3;
|
||||
setl(b, T_PURCHASE_ID, ch_pid);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → ACQ_CORRAPPR pid=%ld merch=%s", svcname, ch_pid, h_merch);
|
||||
if (tpcall("ACQ_CORRAPPR", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(ACQ_CORRAPPR) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7115L);
|
||||
Bchg(b, T_MSG, 0, "무승인매입 정정승인 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 매입 접수 결과 반영 */
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
if (ch_rc != 0 && rc == 0) rc = 7165L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "매입 접수 연동 완료" : "매입 접수 연동 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 ACQ_CORRAPPR rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_sum);
|
||||
|
|
|
|||
|
|
@ -87,9 +87,12 @@ void PREAUTH(TPSVCINFO *p)
|
|||
"AUTH", res_status, h_bizdate) < 0) {
|
||||
setl(b, T_RC, 24L); Bchg(b, T_MSG, 0, "승인원장 적재 실패", 0L); FAIL(b); }
|
||||
if (res_status[0] == 'A') {
|
||||
if (audb_limit_dec(h_card, h_amount) < 0) {
|
||||
setl(b, T_RC, 25L); Bchg(b, T_MSG, 0, "한도 차감 실패", 0L); FAIL(b); }
|
||||
/* 한도 차감은 아래 업무체인의 LIMIT_DEC 가 수행한다(한도원장 단일 소유자).
|
||||
* 같은 글로벌 트랜잭션이라도 XA 브랜치가 다르므로, 여기서 card_limit 을
|
||||
* 직접 갱신하면 하위 브랜치가 이 미커밋 행 락을 기다려 교착된다.
|
||||
* 따라서 이 브랜치는 승인원장만 쓰고 한도 반영치는 예상값으로만 계산한다. */
|
||||
h_used += h_amount; avail = h_limit - h_used;
|
||||
userlog("[%s] 한도차감 위임 → LIMIT_DEC 체인 (예상 사용=%ld)", svcname, h_used);
|
||||
}
|
||||
|
||||
/* 5) 이력/재집계부: 당일 카드 승인 실적 재집계(감사 요약) */
|
||||
|
|
@ -212,6 +215,36 @@ void PREAUTH(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: PREAUTH → LIMIT_DEC (예비승인 한도선점(차감))
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && h_amount > 0) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_DEC card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_DEC", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_DEC) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7116L);
|
||||
Bchg(b, T_MSG, 0, "예비승인 한도차감 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7166L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "예비승인 한도선점 완료" : "예비승인 한도선점 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_DEC rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_ID2, h_id);
|
||||
setl(b, T_RC, rc);
|
||||
|
|
|
|||
|
|
@ -201,6 +201,36 @@ respond:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: PREAUTH_CANCEL → LIMIT_RST (예비승인 취소 한도원복)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0]) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_RST card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_RST", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_RST) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7118L);
|
||||
Bchg(b, T_MSG, 0, "예비승인 취소 원복 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7168L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "예비승인 원복 완료" : "예비승인 원복 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_RST rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_RC, rc);
|
||||
setl(b, T_AMT1, h_limit);
|
||||
|
|
|
|||
|
|
@ -86,9 +86,12 @@ void PREAUTH_COMPLETE(TPSVCINFO *p)
|
|||
"AUTH", res_status, h_bizdate) < 0) {
|
||||
setl(b, T_RC, 24L); Bchg(b, T_MSG, 0, "승인원장 적재 실패", 0L); FAIL(b); }
|
||||
if (res_status[0] == 'A') {
|
||||
if (audb_limit_dec(h_card, h_amount) < 0) {
|
||||
setl(b, T_RC, 25L); Bchg(b, T_MSG, 0, "한도 차감 실패", 0L); FAIL(b); }
|
||||
/* 한도 차감은 아래 업무체인의 LIMIT_DEC 가 수행한다(한도원장 단일 소유자).
|
||||
* 같은 글로벌 트랜잭션이라도 XA 브랜치가 다르므로, 여기서 card_limit 을
|
||||
* 직접 갱신하면 하위 브랜치가 이 미커밋 행 락을 기다려 교착된다.
|
||||
* 따라서 이 브랜치는 승인원장만 쓰고 한도 반영치는 예상값으로만 계산한다. */
|
||||
h_used += h_amount; avail = h_limit - h_used;
|
||||
userlog("[%s] 한도차감 위임 → LIMIT_DEC 체인 (예상 사용=%ld)", svcname, h_used);
|
||||
}
|
||||
|
||||
/* 5) 이력/재집계부: 당일 카드 승인 실적 재집계(감사 요약) */
|
||||
|
|
@ -211,6 +214,36 @@ void PREAUTH_COMPLETE(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: PREAUTH_COMPLETE → LIMIT_DEC (예비승인 확정 한도차감)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && h_amount > 0) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_DEC card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_DEC", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_DEC) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7117L);
|
||||
Bchg(b, T_MSG, 0, "예비승인 확정 한도차감 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7167L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "예비승인 확정 차감 완료" : "예비승인 확정 차감 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_DEC rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_ID1, h_auth);
|
||||
setl(b, T_RC, rc);
|
||||
|
|
|
|||
|
|
@ -204,6 +204,36 @@ respond:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: PREAUTH_EXTEND → LIMIT_CHK (예비승인 연장 가용한도 점검)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0]) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_CHK card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_CHK", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_CHK) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7120L);
|
||||
Bchg(b, T_MSG, 0, "예비승인 연장 한도점검 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7170L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "연장 가능 한도 확보" : "연장 한도 부족"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_CHK rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_RC, rc);
|
||||
Bchg(b, T_STR1, 0, (res_status[0] ? res_status : outs), 0L);
|
||||
|
|
|
|||
|
|
@ -202,6 +202,36 @@ respond:
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: PREAUTH_PARTUSE → LIMIT_RST (예비승인 잔여분 한도원복)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0]) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_RST card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_RST", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_RST) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7119L);
|
||||
Bchg(b, T_MSG, 0, "예비승인 잔여 원복 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7169L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "잔여분 원복 완료" : "잔여분 원복 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_RST rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_RC, rc);
|
||||
setl(b, T_AMT1, h_limit);
|
||||
|
|
|
|||
|
|
@ -212,6 +212,70 @@ void STANDIN(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: STANDIN → LIMIT_CHK (대행승인 전 한도 사전점검)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0]) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_CHK card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_CHK", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_CHK) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7121L);
|
||||
Bchg(b, T_MSG, 0, "대행승인 한도점검 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7171L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "대행승인 한도 확보" : "대행승인 한도 부족"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_CHK rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: STANDIN → MG_LOG (대행승인 전문 로깅)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && strlen(h_bizdate) >= 8) {
|
||||
long ch_len = 0, ch_rc = 0;
|
||||
char ch_str1[64], ch_chan[16];
|
||||
ch_str1[0] = 0; ch_chan[0] = 0;
|
||||
gets_(b, T_STR1, ch_str1, sizeof(ch_str1)); /* 원 전문값 보존 */
|
||||
gets_(b, T_CHANNEL, ch_chan, sizeof(ch_chan));
|
||||
if (strlen(ch_chan) < 2) strcpy(ch_chan, "CH01"); /* mg 기본 채널 */
|
||||
Bchg(b, T_CHANNEL, 0, ch_chan, 0L);
|
||||
Bchg(b, T_STR1, 0, "0120", 0L); /* MTI (전문유형) */
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → MG_LOG 채널=%s MTI=0120", svcname, ch_chan);
|
||||
if (tpcall("MG_LOG", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(MG_LOG) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7122L);
|
||||
Bchg(b, T_MSG, 0, "대행승인 전문로깅 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 게이트웨이 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
Bchg(b, T_STR1, 0, ch_str1, 0L); /* 원 전문값 복원 */
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
if (ch_rc != 0 && rc == 0) rc = 7122L;
|
||||
userlog("[%s] 대행승인 전문로깅 완료 rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_RC, rc);
|
||||
setl(b, T_ID1, h_auth);
|
||||
|
|
|
|||
|
|
@ -85,9 +85,12 @@ void STANDIN_SETTLE(TPSVCINFO *p)
|
|||
"AUTH", res_status, h_bizdate) < 0) {
|
||||
setl(b, T_RC, 24L); Bchg(b, T_MSG, 0, "승인원장 적재 실패", 0L); FAIL(b); }
|
||||
if (res_status[0] == 'A') {
|
||||
if (audb_limit_dec(h_card, h_amount) < 0) {
|
||||
setl(b, T_RC, 25L); Bchg(b, T_MSG, 0, "한도 차감 실패", 0L); FAIL(b); }
|
||||
/* 한도 차감은 아래 업무체인의 LIMIT_DEC 가 수행한다(한도원장 단일 소유자).
|
||||
* 같은 글로벌 트랜잭션이라도 XA 브랜치가 다르므로, 여기서 card_limit 을
|
||||
* 직접 갱신하면 하위 브랜치가 이 미커밋 행 락을 기다려 교착된다.
|
||||
* 따라서 이 브랜치는 승인원장만 쓰고 한도 반영치는 예상값으로만 계산한다. */
|
||||
h_used += h_amount; avail = h_limit - h_used;
|
||||
userlog("[%s] 한도차감 위임 → LIMIT_DEC 체인 (예상 사용=%ld)", svcname, h_used);
|
||||
}
|
||||
|
||||
/* 5) 이력/재집계부: 당일 카드 승인 실적 재집계(감사 요약) */
|
||||
|
|
@ -210,6 +213,36 @@ void STANDIN_SETTLE(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: STANDIN_SETTLE → LIMIT_DEC (대행승인 정산분 한도차감)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0] && h_amount > 0) {
|
||||
long ch_len = 0, ch_rc = 0, ch_amt = h_amount;
|
||||
if (ch_amt < 0) ch_amt = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
if (h_bizdate[0]) Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, ch_amt);
|
||||
userlog("[%s] 체인 호출 → LIMIT_DEC card=%s 금액=%ld", svcname, h_card, ch_amt);
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("LIMIT_DEC", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(LIMIT_DEC) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7123L);
|
||||
Bchg(b, T_MSG, 0, "대행정산 한도차감 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 응답 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
setl(b, T_AMOUNT, h_amount); /* 요청 금액 복원 */
|
||||
if (ch_rc != 0 && rc == 0) rc = 7173L;
|
||||
Bchg(b, T_MSG, 0, (ch_rc == 0 ? "대행정산 한도차감 완료" : "대행정산 한도차감 경고"), 0L);
|
||||
userlog("[%s] 체인 완료 LIMIT_DEC rc=%ld", svcname, ch_rc);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_sum);
|
||||
|
|
|
|||
|
|
@ -184,6 +184,42 @@ void TOKEN_VERIFY(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: TOKEN_VERIFY → CM_LUHN (토큰 원카드번호 체크섬 검증)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
if (h_card[0]) {
|
||||
long ch_len = 0, ch_rc = 0;
|
||||
char ch_str5[64];
|
||||
ch_str5[0] = 0;
|
||||
gets_(b, T_STR5, ch_str5, sizeof(ch_str5)); /* 원 전문값 보존 */
|
||||
Bchg(b, T_STR5, 0, h_card, 0L); /* 검증대상 PAN */
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
if (strlen(h_bizdate) == 10 && h_bizdate[4] == '-')
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
else
|
||||
Bchg(b, T_BIZDATE, 0, "", 0L); /* cm 은 형식 위반을 거절 */
|
||||
userlog("[%s] 체인 호출 → CM_LUHN 체크섬 검증 요청", svcname);
|
||||
if (tpcall("CM_LUHN", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(CM_LUHN) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7125L);
|
||||
Bchg(b, T_MSG, 0, "토큰 체크섬 검증 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 0=체크섬 유효 */
|
||||
Bchg(b, T_STR5, 0, ch_str5, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
if (ch_rc != 0) {
|
||||
if (rc == 0) rc = 7175L;
|
||||
Bchg(b, T_MSG, 0, "토큰 원PAN 체크섬 오류", 0L);
|
||||
}
|
||||
userlog("[%s] 체인 완료 CM_LUHN rc=%ld card=%s", svcname, ch_rc, h_card);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_RC, rc);
|
||||
Bchg(b, T_STR1, 0, (res_status[0] ? res_status : outs), 0L);
|
||||
|
|
|
|||
|
|
@ -187,6 +187,46 @@ void VELOCITY_CHK(TPSVCINFO *p)
|
|||
if (outmsg[0]) Bchg(b, T_MSG, 0, outmsg, 0L);
|
||||
if (fee_amt > 0) setl(b, T_FEE, fee_amt);
|
||||
|
||||
/* ---------------------------------------------------------------
|
||||
* 업무체인: VELOCITY_CHK → FRAUD_DETECT (속도위반 감지건 이상거래 판정)
|
||||
* XA 규율: 하위 서비스는 같은 글로벌 트랜잭션의 '다른 브랜치'라서 이 서비스가
|
||||
* 방금 INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 하위가 필요로 하는
|
||||
* 값은 모두 전문(T_*)에 실어 넘기고, 하위 실패 시에는 T_RC/T_MSG 를 채운 뒤
|
||||
* FAIL(b) → tpreturn(TPFAIL) 로 체인 전체를 롤백한다(별도 보상 불필요).
|
||||
* --------------------------------------------------------------- */
|
||||
/* 이상거래 스코어링 대상 승인건 확보: 없으면 판정 대상이 아니므로 스킵 */
|
||||
h_prev = 0;
|
||||
if (h_card[0]) {
|
||||
EXEC SQL SELECT coalesce(max(auth_id), 0) INTO :h_prev
|
||||
FROM au_authorization WHERE card_no = :h_card;
|
||||
if (sqlca.sqlcode < 0) h_prev = 0;
|
||||
}
|
||||
if (h_prev > 0 && strlen(h_bizdate) >= 8) {
|
||||
long ch_len = 0, ch_rc = 0, ch_score = 0;
|
||||
Bchg(b, T_KEY1, 0, h_card, 0L);
|
||||
Bchg(b, T_BIZDATE, 0, h_bizdate, 0L);
|
||||
if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L);
|
||||
setl(b, T_ID1, h_prev);
|
||||
setl(b, T_AMOUNT, (h_amount > 0 ? h_amount : 0L));
|
||||
userlog("[%s] 체인 호출 → FRAUD_DETECT card=%s auth=%ld", svcname, h_card, (long)(h_prev));
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L); /* 체인 하위 호출 표식 */
|
||||
if (tpcall("FRAUD_DETECT", (char *)b, 0L, (char **)&b, &ch_len, 0L) < 0) {
|
||||
userlog("[%s] tpcall(FRAUD_DETECT) 실패: %s", svcname, tpstrerror(tperrno));
|
||||
setl(b, T_RC, 7127L);
|
||||
Bchg(b, T_MSG, 0, "속도위반 이상거래 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
ch_rc = getl(b, T_RC); /* 하위 판정코드 반영 */
|
||||
Bchg(b, T_STR8, 0, "", 0L); /* 체인 표식 해제 */
|
||||
ch_score = getl(b, T_ARG1);
|
||||
setl(b, T_AMOUNT, h_amount);
|
||||
if (ch_rc != 0) {
|
||||
if (rc == 0) rc = 7177L;
|
||||
Bchg(b, T_MSG, 0, "이상거래 판정 경보", 0L);
|
||||
}
|
||||
userlog("[%s] 체인 완료 FRAUD_DETECT rc=%ld 지표=%ld", svcname, ch_rc, ch_score);
|
||||
}
|
||||
|
||||
/* 8) 응답부: 성공 결과코드 + 계약상 출력 필드 세팅 */
|
||||
setl(b, T_COUNT, h_cnt);
|
||||
setl(b, T_GROSS, h_sum);
|
||||
|
|
|
|||
|
|
@ -162,6 +162,59 @@ void CL_AMTXCHECK(TPSVCINFO *p)
|
|||
setl(b, T_GROSS, o_amount);
|
||||
Bchg(b, T_MSG, 0, o_msg, 0L);
|
||||
userlog("CL_AMTXCHECK 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount);
|
||||
|
||||
/* ==== 10) 업무흐름 체인: VL_AXPURSETT 연동 (매입 대 정산 금액 교차 검증) ====
|
||||
* 동일 글로벌 트랜잭션이지만 VL_AXPURSETT 는 별도 XA 브랜치에서 수행된다.
|
||||
* 위에서 적재/갱신한 행은 아직 미커밋이라 하위 브랜치에서 보이지 않으므로
|
||||
* 판단에 필요한 값은 전문(UBF)에 실어 전달한다(owner-writes 규율).
|
||||
* 호출 실패는 보상 없이 FAIL(b) -> 글로벌 트랜잭션 전체 롤백. */
|
||||
{
|
||||
long cx0_rlen = 0, cx0_sub = 0;
|
||||
long cx0_rc, cx0_id1, cx0_id2, cx0_amt;
|
||||
long cx0_a5, cx0_a6, cx0_a7, cx0_a8, cx0_m2, cx0_m3;
|
||||
char cx0_bd[16], cx0_mid[64], cx0_st[16], cx0_msg[192];
|
||||
|
||||
/* 응답 계약 스냅샷 (하위 서비스가 덮어쓴 뒤 복원하기 위함) */
|
||||
cx0_rc = getl(b, T_RC); cx0_id1 = getl(b, T_ID1); cx0_id2 = getl(b, T_ID2);
|
||||
cx0_amt = getl(b, T_AMOUNT);
|
||||
cx0_a5 = getl(b, T_ARG5); cx0_a6 = getl(b, T_ARG6);
|
||||
cx0_a7 = getl(b, T_ARG7); cx0_a8 = getl(b, T_ARG8);
|
||||
cx0_m2 = getl(b, T_AMT2); cx0_m3 = getl(b, T_AMT3);
|
||||
gets_(b, T_STATUS, cx0_st, sizeof(cx0_st));
|
||||
gets_(b, T_MSG, cx0_msg, sizeof(cx0_msg));
|
||||
gets_(b, T_BIZDATE, cx0_bd, sizeof(cx0_bd));
|
||||
gets_(b, T_MERCHANT, cx0_mid, sizeof(cx0_mid));
|
||||
|
||||
/* 하위 서비스가 쓸 값을 전문에 적재 (미커밋 행 조회 의존 금지) */
|
||||
setl(b, T_ID1, cx0_id1);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
if (cx0_bd[0] != 0) Bchg(b, T_BIZDATE, 0, cx0_bd, 0L);
|
||||
if (cx0_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx0_mid, 0L);
|
||||
Bchg(b, T_SVCNAME, 0, "CL_AMTXCHECK", 0L);
|
||||
|
||||
userlog("[CL_AMTXCHECK] 체인 호출 -> VL_AXPURSETT bd=%s id=%ld amt=%ld",
|
||||
cx0_bd, cx0_id1, cx0_amt);
|
||||
if (tpcall("VL_AXPURSETT", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) {
|
||||
userlog("[CL_AMTXCHECK] tpcall(VL_AXPURSETT) 실패: %s", tpstrerror(tperrno));
|
||||
setl(b, T_RC, 9631);
|
||||
Bchg(b, T_MSG, 0, "매입-정산 금액교차 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
cx0_sub = getl(b, T_RC);
|
||||
if (cx0_sub != 0)
|
||||
userlog("[CL_AMTXCHECK] VL_AXPURSETT 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub);
|
||||
else
|
||||
userlog("[CL_AMTXCHECK] VL_AXPURSETT 체인 정상 완료 bd=%s", cx0_bd);
|
||||
|
||||
/* 응답 계약 복원: 원 서비스의 출력 필드는 하위 결과로 바뀌지 않는다 */
|
||||
setl(b, T_RC, cx0_rc); setl(b, T_ID1, cx0_id1); setl(b, T_ID2, cx0_id2);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
setl(b, T_ARG5, cx0_a5); setl(b, T_ARG6, cx0_a6);
|
||||
setl(b, T_ARG7, cx0_a7); setl(b, T_ARG8, cx0_a8);
|
||||
setl(b, T_AMT2, cx0_m2); setl(b, T_AMT3, cx0_m3);
|
||||
if (cx0_st[0] != 0) Bchg(b, T_STATUS, 0, cx0_st, 0L);
|
||||
if (cx0_msg[0] != 0) Bchg(b, T_MSG, 0, cx0_msg, 0L);
|
||||
}
|
||||
OK(b);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,6 +170,59 @@ void CL_APPRDELEG(TPSVCINFO *p)
|
|||
setl(b, T_GROSS, o_amount);
|
||||
Bchg(b, T_MSG, 0, o_msg, 0L);
|
||||
userlog("CL_APPRDELEG 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount);
|
||||
|
||||
/* ==== 10) 업무흐름 체인: CL_APPRSTAT 연동 (승인 위임 후 승인상태 갱신) ====
|
||||
* 동일 글로벌 트랜잭션이지만 CL_APPRSTAT 는 별도 XA 브랜치에서 수행된다.
|
||||
* 위에서 적재/갱신한 행은 아직 미커밋이라 하위 브랜치에서 보이지 않으므로
|
||||
* 판단에 필요한 값은 전문(UBF)에 실어 전달한다(owner-writes 규율).
|
||||
* 호출 실패는 보상 없이 FAIL(b) -> 글로벌 트랜잭션 전체 롤백. */
|
||||
{
|
||||
long cx0_rlen = 0, cx0_sub = 0;
|
||||
long cx0_rc, cx0_id1, cx0_id2, cx0_amt;
|
||||
long cx0_a5, cx0_a6, cx0_a7, cx0_a8, cx0_m2, cx0_m3;
|
||||
char cx0_bd[16], cx0_mid[64], cx0_st[16], cx0_msg[192];
|
||||
|
||||
/* 응답 계약 스냅샷 (하위 서비스가 덮어쓴 뒤 복원하기 위함) */
|
||||
cx0_rc = getl(b, T_RC); cx0_id1 = getl(b, T_ID1); cx0_id2 = getl(b, T_ID2);
|
||||
cx0_amt = getl(b, T_AMOUNT);
|
||||
cx0_a5 = getl(b, T_ARG5); cx0_a6 = getl(b, T_ARG6);
|
||||
cx0_a7 = getl(b, T_ARG7); cx0_a8 = getl(b, T_ARG8);
|
||||
cx0_m2 = getl(b, T_AMT2); cx0_m3 = getl(b, T_AMT3);
|
||||
gets_(b, T_STATUS, cx0_st, sizeof(cx0_st));
|
||||
gets_(b, T_MSG, cx0_msg, sizeof(cx0_msg));
|
||||
gets_(b, T_BIZDATE, cx0_bd, sizeof(cx0_bd));
|
||||
gets_(b, T_MERCHANT, cx0_mid, sizeof(cx0_mid));
|
||||
|
||||
/* 하위 서비스가 쓸 값을 전문에 적재 (미커밋 행 조회 의존 금지) */
|
||||
setl(b, T_ID1, cx0_id1);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
if (cx0_bd[0] != 0) Bchg(b, T_BIZDATE, 0, cx0_bd, 0L);
|
||||
if (cx0_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx0_mid, 0L);
|
||||
Bchg(b, T_SVCNAME, 0, "CL_APPRDELEG", 0L);
|
||||
|
||||
userlog("[CL_APPRDELEG] 체인 호출 -> CL_APPRSTAT bd=%s id=%ld amt=%ld",
|
||||
cx0_bd, cx0_id1, cx0_amt);
|
||||
if (tpcall("CL_APPRSTAT", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) {
|
||||
userlog("[CL_APPRDELEG] tpcall(CL_APPRSTAT) 실패: %s", tpstrerror(tperrno));
|
||||
setl(b, T_RC, 9663);
|
||||
Bchg(b, T_MSG, 0, "위임 승인상태 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
cx0_sub = getl(b, T_RC);
|
||||
if (cx0_sub != 0)
|
||||
userlog("[CL_APPRDELEG] CL_APPRSTAT 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub);
|
||||
else
|
||||
userlog("[CL_APPRDELEG] CL_APPRSTAT 체인 정상 완료 bd=%s", cx0_bd);
|
||||
|
||||
/* 응답 계약 복원: 원 서비스의 출력 필드는 하위 결과로 바뀌지 않는다 */
|
||||
setl(b, T_RC, cx0_rc); setl(b, T_ID1, cx0_id1); setl(b, T_ID2, cx0_id2);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
setl(b, T_ARG5, cx0_a5); setl(b, T_ARG6, cx0_a6);
|
||||
setl(b, T_ARG7, cx0_a7); setl(b, T_ARG8, cx0_a8);
|
||||
setl(b, T_AMT2, cx0_m2); setl(b, T_AMT3, cx0_m3);
|
||||
if (cx0_st[0] != 0) Bchg(b, T_STATUS, 0, cx0_st, 0L);
|
||||
if (cx0_msg[0] != 0) Bchg(b, T_MSG, 0, cx0_msg, 0L);
|
||||
}
|
||||
OK(b);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,8 +29,12 @@ void CL_APPRFINAL(TPSVCINFO *p)
|
|||
long h_kcid;
|
||||
char h_zbuf[192];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
/* 체인 하위 호출 표식/위임 상태 (섹션4 의 행소유권 판정에 사용) */
|
||||
char ch_mark[16], ch_ustat[8];
|
||||
int in_chain = 0;
|
||||
h_bizdate[0] = 0; h_period[0] = 0; h_zbuf[0] = 0;
|
||||
z_msg[0] = 0; z_buf[0] = 0; h_zopen = 0; h_zsev = 0;
|
||||
ch_mark[0] = 0; ch_ustat[0] = 0;
|
||||
|
||||
|
||||
/* --- 섹션9: 진입 로깅 --- */
|
||||
|
|
@ -40,6 +44,20 @@ void CL_APPRFINAL(TPSVCINFO *p)
|
|||
h_cid = getl(b, T_ID1);
|
||||
gets_(b, T_STR1, h_memo, sizeof(h_memo));
|
||||
|
||||
/* 체인 하위 호출 판별 (T_STR8 = "CHAIN"): 상위 서비스(CL_APPRL2)가 이미 자기
|
||||
* XA 브랜치에서 cl_close_log(close_id) 행을 잠근 채 이 서비스를 부른 상태다.
|
||||
* 같은 글로벌 트랜잭션의 다른 XA 브랜치가 그 행을 다시 UPDATE 하면 서로의
|
||||
* 미커밋 행락을 기다려 트랜잭션 타임아웃까지 교착된다. 게다가 상위가 방금
|
||||
* 전이시킨 상태는 이 브랜치에서 보이지 않아 상태판정도 틀어진다.
|
||||
* 따라서 체인 하위에서는 (1) 상태판정을 전문(T_STATUS)값 기준으로 하고,
|
||||
* (2) 행 UPDATE 는 생략한 뒤 확정할 상태/메모를 전문에 실어 소유자(상위)에게
|
||||
* 위임한다. 업무 판정/집계/이력 적재는 그대로 수행한다. */
|
||||
gets_(b, T_STR8, ch_mark, sizeof(ch_mark));
|
||||
if (strcmp(ch_mark, "CHAIN") == 0) {
|
||||
in_chain = 1;
|
||||
userlog("CL_APPRFINAL 체인 하위 호출 - cl_close_log(%ld) 행 쓰기는 상위 브랜치에 위임", h_cid);
|
||||
}
|
||||
|
||||
/* --- 섹션1: 입력 검증부 --- */
|
||||
if (h_cid <= 0) {
|
||||
setl(b, T_RC, 5601);
|
||||
|
|
@ -56,6 +74,17 @@ void CL_APPRFINAL(TPSVCINFO *p)
|
|||
}
|
||||
if (sqlca.sqlcode < 0) { setl(b, T_RC, 5603); FAIL(b); }
|
||||
st = h_status[0];
|
||||
/* 체인 하위: 상위가 방금 전이시킨 상태는 미커밋이라 위 SELECT 에 안 보인다.
|
||||
* 상위가 전문에 실어 준 T_STATUS 를 유효 현재상태로 삼는다(owner-writes 규율). */
|
||||
if (in_chain) {
|
||||
char ch_cur[8]; ch_cur[0] = 0;
|
||||
gets_(b, T_STATUS, ch_cur, sizeof(ch_cur));
|
||||
if (ch_cur[0] != 0) {
|
||||
st = ch_cur[0];
|
||||
strncpy(h_status, ch_cur, sizeof(h_status)-1); h_status[sizeof(h_status)-1] = 0;
|
||||
userlog("CL_APPRFINAL 체인 하위 - 전문 상태(%c)를 유효 현재상태로 사용", st);
|
||||
}
|
||||
}
|
||||
|
||||
/* --- 섹션3: 상태전이 가능여부 분기부 --- */
|
||||
if (!(st == 'C')) {
|
||||
|
|
@ -73,21 +102,37 @@ void CL_APPRFINAL(TPSVCINFO *p)
|
|||
else strcpy(newmemo, "APPR:FINAL");
|
||||
{ char nm[128]; strncpy(nm, newmemo, sizeof(nm)-1); nm[sizeof(nm)-1]=0;
|
||||
strncpy(h_memo, nm, sizeof(h_memo)-1); h_memo[sizeof(h_memo)-1]=0; }
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET status = 'A', memo = :h_memo, updated_at = now()
|
||||
WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0) {
|
||||
setl(b, T_RC, 5606);
|
||||
Bchg(b, T_MSG, 0, "상태전이 실패", 0L); FAIL(b);
|
||||
}
|
||||
if (sqlca.sqlerrd[2] != 1) {
|
||||
setl(b, T_RC, 5607);
|
||||
Bchg(b, T_MSG, 0, "전이 대상행 수 이상", 0L); FAIL(b);
|
||||
strcpy(ch_ustat, "A");
|
||||
if (!in_chain) {
|
||||
/* 행 소유자 브랜치: 직접 전이한다 */
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET status = 'A', memo = :h_memo, updated_at = now()
|
||||
WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0) {
|
||||
setl(b, T_RC, 5606);
|
||||
Bchg(b, T_MSG, 0, "상태전이 실패", 0L); FAIL(b);
|
||||
}
|
||||
if (sqlca.sqlerrd[2] != 1) {
|
||||
setl(b, T_RC, 5607);
|
||||
Bchg(b, T_MSG, 0, "전이 대상행 수 이상", 0L); FAIL(b);
|
||||
}
|
||||
} else {
|
||||
/* 체인 하위 브랜치: 행 UPDATE 를 하지 않고 확정할 상태/메모를 상위에 위임한다.
|
||||
* 상위(행 소유자)가 tpcall 복귀 후 자기 브랜치에서 한 번만 반영한다. */
|
||||
Bchg(b, T_STR7, 0, ch_ustat, 0L);
|
||||
Bchg(b, T_STR6, 0, h_memo, 0L);
|
||||
userlog("CL_APPRFINAL 체인 하위 - 전이(status=%s memo=%s) 를 상위 소유자에 위임 close_id=%ld",
|
||||
ch_ustat, h_memo, h_cid);
|
||||
}
|
||||
|
||||
/* --- 섹션6: 전이 후 상태 재확인부 --- */
|
||||
EXEC SQL SELECT status INTO :h_status FROM cl_close_log WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0) { setl(b, T_RC, 5608); FAIL(b); }
|
||||
if (!in_chain) {
|
||||
EXEC SQL SELECT status INTO :h_status FROM cl_close_log WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0) { setl(b, T_RC, 5608); FAIL(b); }
|
||||
} else {
|
||||
/* 위임분은 아직 미반영이므로 확정 예정 상태로 응답 계약을 채운다 */
|
||||
strncpy(h_status, ch_ustat, sizeof(h_status)-1); h_status[sizeof(h_status)-1] = 0;
|
||||
}
|
||||
Bchg(b, T_STATUS, 0, h_status, 0L);
|
||||
o_count = h_cnt; o_rc = 0;
|
||||
snprintf(o_msg, sizeof(o_msg), "최종 승인(A) 처리완료 상태=%c", h_status[0]);
|
||||
|
|
|
|||
|
|
@ -170,6 +170,100 @@ void CL_APPRL1(TPSVCINFO *p)
|
|||
setl(b, T_GROSS, o_amount);
|
||||
Bchg(b, T_MSG, 0, o_msg, 0L);
|
||||
userlog("CL_APPRL1 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount);
|
||||
|
||||
/* ==== 10) 업무흐름 체인: CL_APPRL2 연동 (1차 승인 후 2차 승인 요청) ====
|
||||
* 동일 글로벌 트랜잭션이지만 CL_APPRL2 는 별도 XA 브랜치에서 수행된다.
|
||||
* 위에서 적재/갱신한 행은 아직 미커밋이라 하위 브랜치에서 보이지 않으므로
|
||||
* 판단에 필요한 값은 전문(UBF)에 실어 전달한다(owner-writes 규율).
|
||||
* 호출 실패는 보상 없이 FAIL(b) -> 글로벌 트랜잭션 전체 롤백. */
|
||||
{
|
||||
long cx0_rlen = 0, cx0_sub = 0;
|
||||
long cx0_rc, cx0_id1, cx0_id2, cx0_amt;
|
||||
long cx0_a5, cx0_a6, cx0_a7, cx0_a8, cx0_m2, cx0_m3;
|
||||
char cx0_bd[16], cx0_mid[64], cx0_st[16], cx0_msg[192];
|
||||
|
||||
/* 응답 계약 스냅샷 (하위 서비스가 덮어쓴 뒤 복원하기 위함) */
|
||||
cx0_rc = getl(b, T_RC); cx0_id1 = getl(b, T_ID1); cx0_id2 = getl(b, T_ID2);
|
||||
cx0_amt = getl(b, T_AMOUNT);
|
||||
cx0_a5 = getl(b, T_ARG5); cx0_a6 = getl(b, T_ARG6);
|
||||
cx0_a7 = getl(b, T_ARG7); cx0_a8 = getl(b, T_ARG8);
|
||||
cx0_m2 = getl(b, T_AMT2); cx0_m3 = getl(b, T_AMT3);
|
||||
gets_(b, T_STATUS, cx0_st, sizeof(cx0_st));
|
||||
gets_(b, T_MSG, cx0_msg, sizeof(cx0_msg));
|
||||
gets_(b, T_BIZDATE, cx0_bd, sizeof(cx0_bd));
|
||||
gets_(b, T_MERCHANT, cx0_mid, sizeof(cx0_mid));
|
||||
|
||||
/* 하위 서비스가 쓸 값을 전문에 적재 (미커밋 행 조회 의존 금지) */
|
||||
setl(b, T_ID1, cx0_id1);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
if (cx0_bd[0] != 0) Bchg(b, T_BIZDATE, 0, cx0_bd, 0L);
|
||||
if (cx0_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx0_mid, 0L);
|
||||
Bchg(b, T_SVCNAME, 0, "CL_APPRL1", 0L);
|
||||
/* 체인 표식: 하위(CL_APPRL2/CL_APPRFINAL)는 cl_close_log 행을 직접
|
||||
* UPDATE 하지 않고 확정 상태를 T_STR7/T_STR6 로 위임한다.
|
||||
* 이 행의 소유자는 방금 전이시킨 이 브랜치이므로, 반영도 여기서 한다
|
||||
* (형제 XA 브랜치 간 동일행 쓰기 = 미커밋 행락 교착 방지). */
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L);
|
||||
/* 하위 승인단계는 '이 서비스의 전이 이전' 상태를 기준으로 진입 가능여부를
|
||||
* 판정한다(기존 동작과 동일: 하위 브랜치는 상위의 미커밋 전이를 못 본다).
|
||||
* 그 판정 기준값을 전문으로 명시 전달한다. */
|
||||
{ char cx0_pre[4]; cx0_pre[0] = st; cx0_pre[1] = 0;
|
||||
if (cx0_pre[0] != 0) Bchg(b, T_STATUS, 0, cx0_pre, 0L); }
|
||||
Bdel(b, T_STR7, 0); Bdel(b, T_STR6, 0);
|
||||
|
||||
userlog("[CL_APPRL1] 체인 호출 -> CL_APPRL2 bd=%s id=%ld amt=%ld",
|
||||
cx0_bd, cx0_id1, cx0_amt);
|
||||
if (tpcall("CL_APPRL2", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) {
|
||||
userlog("[CL_APPRL1] tpcall(CL_APPRL2) 실패: %s", tpstrerror(tperrno));
|
||||
setl(b, T_RC, 9671);
|
||||
Bchg(b, T_MSG, 0, "2차 승인 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
cx0_sub = getl(b, T_RC);
|
||||
if (cx0_sub != 0)
|
||||
userlog("[CL_APPRL1] CL_APPRL2 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub);
|
||||
else
|
||||
userlog("[CL_APPRL1] CL_APPRL2 체인 정상 완료 bd=%s", cx0_bd);
|
||||
|
||||
/* --- 위임 반영부: 하위 승인단계들이 위임한 cl_close_log 확정 전이를
|
||||
* 행 소유자인 이 브랜치에서 단 한 번만 반영한다. --- */
|
||||
{
|
||||
char dg_st[8], dg_memo[128];
|
||||
dg_st[0] = 0; dg_memo[0] = 0;
|
||||
gets_(b, T_STR7, dg_st, sizeof(dg_st));
|
||||
gets_(b, T_STR6, dg_memo, sizeof(dg_memo));
|
||||
if (dg_st[0] != 0) {
|
||||
strncpy(h_status, dg_st, sizeof(h_status)-1); h_status[sizeof(h_status)-1] = 0;
|
||||
if (dg_memo[0] != 0) {
|
||||
strncpy(h_memo, dg_memo, sizeof(h_memo)-1); h_memo[sizeof(h_memo)-1] = 0;
|
||||
}
|
||||
h_kcid = cx0_id1;
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET status = :h_status, memo = :h_memo, updated_at = now()
|
||||
WHERE close_id = :h_kcid;
|
||||
if (sqlca.sqlcode < 0) {
|
||||
setl(b, T_RC, 5609);
|
||||
Bchg(b, T_MSG, 0, "승인 체인 위임 반영 실패", 0L); FAIL(b);
|
||||
}
|
||||
if (sqlca.sqlerrd[2] != 1) {
|
||||
setl(b, T_RC, 5610);
|
||||
Bchg(b, T_MSG, 0, "승인 체인 위임 대상행 수 이상", 0L); FAIL(b);
|
||||
}
|
||||
strncpy(cx0_st, h_status, sizeof(cx0_st)-1); cx0_st[sizeof(cx0_st)-1] = 0;
|
||||
userlog("[CL_APPRL1] 위임 반영 완료 close_id=%ld status=%s", h_kcid, h_status);
|
||||
Bdel(b, T_STR7, 0); Bdel(b, T_STR6, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 응답 계약 복원: 원 서비스의 출력 필드는 하위 결과로 바뀌지 않는다 */
|
||||
setl(b, T_RC, cx0_rc); setl(b, T_ID1, cx0_id1); setl(b, T_ID2, cx0_id2);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
setl(b, T_ARG5, cx0_a5); setl(b, T_ARG6, cx0_a6);
|
||||
setl(b, T_ARG7, cx0_a7); setl(b, T_ARG8, cx0_a8);
|
||||
setl(b, T_AMT2, cx0_m2); setl(b, T_AMT3, cx0_m3);
|
||||
if (cx0_st[0] != 0) Bchg(b, T_STATUS, 0, cx0_st, 0L);
|
||||
if (cx0_msg[0] != 0) Bchg(b, T_MSG, 0, cx0_msg, 0L);
|
||||
}
|
||||
OK(b);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,8 +29,12 @@ void CL_APPRL2(TPSVCINFO *p)
|
|||
long h_kcid;
|
||||
char h_zbuf[192];
|
||||
EXEC SQL END DECLARE SECTION;
|
||||
/* 체인 하위 호출 표식/위임 상태 (섹션4 의 행소유권 판정에 사용) */
|
||||
char ch_mark[16], ch_ustat[8];
|
||||
int in_chain = 0;
|
||||
h_bizdate[0] = 0; h_period[0] = 0; h_zbuf[0] = 0;
|
||||
z_msg[0] = 0; z_buf[0] = 0; h_zopen = 0; h_zsev = 0;
|
||||
ch_mark[0] = 0; ch_ustat[0] = 0;
|
||||
|
||||
|
||||
/* --- 섹션9: 진입 로깅 --- */
|
||||
|
|
@ -40,6 +44,20 @@ void CL_APPRL2(TPSVCINFO *p)
|
|||
h_cid = getl(b, T_ID1);
|
||||
gets_(b, T_STR1, h_memo, sizeof(h_memo));
|
||||
|
||||
/* 체인 하위 호출 판별 (T_STR8 = "CHAIN"): 상위 서비스(CL_APPRL1/CL_APPROVE/
|
||||
* CL_APPRREQ)가 이미 자기 XA 브랜치에서 cl_close_log(close_id) 행을 잠근 채
|
||||
* 이 서비스를 부른 상태다. 같은 글로벌 트랜잭션의 다른 XA 브랜치가 그 행을
|
||||
* 다시 UPDATE 하면 서로의 미커밋 행락을 기다려 트랜잭션 타임아웃까지 교착된다.
|
||||
* 게다가 상위가 방금 전이시킨 상태는 이 브랜치에서 보이지 않아 상태판정도 틀어진다.
|
||||
* 따라서 체인 하위에서는 (1) 상태판정을 전문(T_STATUS)값 기준으로 하고,
|
||||
* (2) 행 UPDATE 는 생략한 뒤 확정할 상태/메모를 전문에 실어 소유자(상위)에게
|
||||
* 위임한다. 업무 판정/집계/이력 적재는 그대로 수행한다. */
|
||||
gets_(b, T_STR8, ch_mark, sizeof(ch_mark));
|
||||
if (strcmp(ch_mark, "CHAIN") == 0) {
|
||||
in_chain = 1;
|
||||
userlog("CL_APPRL2 체인 하위 호출 - cl_close_log(%ld) 행 쓰기는 상위 브랜치에 위임", h_cid);
|
||||
}
|
||||
|
||||
/* --- 섹션1: 입력 검증부 --- */
|
||||
if (h_cid <= 0) {
|
||||
setl(b, T_RC, 5601);
|
||||
|
|
@ -56,6 +74,17 @@ void CL_APPRL2(TPSVCINFO *p)
|
|||
}
|
||||
if (sqlca.sqlcode < 0) { setl(b, T_RC, 5603); FAIL(b); }
|
||||
st = h_status[0];
|
||||
/* 체인 하위: 상위가 방금 전이시킨 상태는 미커밋이라 위 SELECT 에 안 보인다.
|
||||
* 상위가 전문에 실어 준 T_STATUS 를 유효 현재상태로 삼는다(owner-writes 규율). */
|
||||
if (in_chain) {
|
||||
char ch_cur[8]; ch_cur[0] = 0;
|
||||
gets_(b, T_STATUS, ch_cur, sizeof(ch_cur));
|
||||
if (ch_cur[0] != 0) {
|
||||
st = ch_cur[0];
|
||||
strncpy(h_status, ch_cur, sizeof(h_status)-1); h_status[sizeof(h_status)-1] = 0;
|
||||
userlog("CL_APPRL2 체인 하위 - 전문 상태(%c)를 유효 현재상태로 사용", st);
|
||||
}
|
||||
}
|
||||
|
||||
/* --- 섹션3: 상태전이 가능여부 분기부 --- */
|
||||
if (!(st == 'C')) {
|
||||
|
|
@ -73,21 +102,37 @@ void CL_APPRL2(TPSVCINFO *p)
|
|||
else strcpy(newmemo, "APPR:L2");
|
||||
{ char nm[128]; strncpy(nm, newmemo, sizeof(nm)-1); nm[sizeof(nm)-1]=0;
|
||||
strncpy(h_memo, nm, sizeof(h_memo)-1); h_memo[sizeof(h_memo)-1]=0; }
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET status = 'C', memo = :h_memo, updated_at = now()
|
||||
WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0) {
|
||||
setl(b, T_RC, 5606);
|
||||
Bchg(b, T_MSG, 0, "상태전이 실패", 0L); FAIL(b);
|
||||
}
|
||||
if (sqlca.sqlerrd[2] != 1) {
|
||||
setl(b, T_RC, 5607);
|
||||
Bchg(b, T_MSG, 0, "전이 대상행 수 이상", 0L); FAIL(b);
|
||||
strcpy(ch_ustat, "C");
|
||||
if (!in_chain) {
|
||||
/* 행 소유자 브랜치: 직접 전이한다 */
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET status = 'C', memo = :h_memo, updated_at = now()
|
||||
WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0) {
|
||||
setl(b, T_RC, 5606);
|
||||
Bchg(b, T_MSG, 0, "상태전이 실패", 0L); FAIL(b);
|
||||
}
|
||||
if (sqlca.sqlerrd[2] != 1) {
|
||||
setl(b, T_RC, 5607);
|
||||
Bchg(b, T_MSG, 0, "전이 대상행 수 이상", 0L); FAIL(b);
|
||||
}
|
||||
} else {
|
||||
/* 체인 하위 브랜치: 행 UPDATE 를 하지 않고 확정할 상태/메모를 상위에 위임한다.
|
||||
* 상위(행 소유자)가 tpcall 복귀 후 자기 브랜치에서 한 번만 반영한다. */
|
||||
Bchg(b, T_STR7, 0, ch_ustat, 0L);
|
||||
Bchg(b, T_STR6, 0, h_memo, 0L);
|
||||
userlog("CL_APPRL2 체인 하위 - 전이(status=%s memo=%s) 를 상위 소유자에 위임 close_id=%ld",
|
||||
ch_ustat, h_memo, h_cid);
|
||||
}
|
||||
|
||||
/* --- 섹션6: 전이 후 상태 재확인부 --- */
|
||||
EXEC SQL SELECT status INTO :h_status FROM cl_close_log WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0) { setl(b, T_RC, 5608); FAIL(b); }
|
||||
if (!in_chain) {
|
||||
EXEC SQL SELECT status INTO :h_status FROM cl_close_log WHERE close_id = :h_cid;
|
||||
if (sqlca.sqlcode < 0) { setl(b, T_RC, 5608); FAIL(b); }
|
||||
} else {
|
||||
/* 위임분은 아직 미반영이므로 확정 예정 상태로 응답 계약을 채운다 */
|
||||
strncpy(h_status, ch_ustat, sizeof(h_status)-1); h_status[sizeof(h_status)-1] = 0;
|
||||
}
|
||||
Bchg(b, T_STATUS, 0, h_status, 0L);
|
||||
o_count = h_cnt; o_rc = 0;
|
||||
snprintf(o_msg, sizeof(o_msg), "2차 승인(L2) 처리완료 상태=%c", h_status[0]);
|
||||
|
|
@ -170,6 +215,101 @@ void CL_APPRL2(TPSVCINFO *p)
|
|||
setl(b, T_GROSS, o_amount);
|
||||
Bchg(b, T_MSG, 0, o_msg, 0L);
|
||||
userlog("CL_APPRL2 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount);
|
||||
|
||||
/* ==== 10) 업무흐름 체인: CL_APPRFINAL 연동 (2차 승인 후 최종 승인 확정) ====
|
||||
* 동일 글로벌 트랜잭션이지만 CL_APPRFINAL 는 별도 XA 브랜치에서 수행된다.
|
||||
* 위에서 적재/갱신한 행은 아직 미커밋이라 하위 브랜치에서 보이지 않으므로
|
||||
* 판단에 필요한 값은 전문(UBF)에 실어 전달한다(owner-writes 규율).
|
||||
* 호출 실패는 보상 없이 FAIL(b) -> 글로벌 트랜잭션 전체 롤백. */
|
||||
{
|
||||
long cx0_rlen = 0, cx0_sub = 0;
|
||||
long cx0_rc, cx0_id1, cx0_id2, cx0_amt;
|
||||
long cx0_a5, cx0_a6, cx0_a7, cx0_a8, cx0_m2, cx0_m3;
|
||||
char cx0_bd[16], cx0_mid[64], cx0_st[16], cx0_msg[192];
|
||||
|
||||
/* 응답 계약 스냅샷 (하위 서비스가 덮어쓴 뒤 복원하기 위함) */
|
||||
cx0_rc = getl(b, T_RC); cx0_id1 = getl(b, T_ID1); cx0_id2 = getl(b, T_ID2);
|
||||
cx0_amt = getl(b, T_AMOUNT);
|
||||
cx0_a5 = getl(b, T_ARG5); cx0_a6 = getl(b, T_ARG6);
|
||||
cx0_a7 = getl(b, T_ARG7); cx0_a8 = getl(b, T_ARG8);
|
||||
cx0_m2 = getl(b, T_AMT2); cx0_m3 = getl(b, T_AMT3);
|
||||
gets_(b, T_STATUS, cx0_st, sizeof(cx0_st));
|
||||
gets_(b, T_MSG, cx0_msg, sizeof(cx0_msg));
|
||||
gets_(b, T_BIZDATE, cx0_bd, sizeof(cx0_bd));
|
||||
gets_(b, T_MERCHANT, cx0_mid, sizeof(cx0_mid));
|
||||
|
||||
/* 하위 서비스가 쓸 값을 전문에 적재 (미커밋 행 조회 의존 금지) */
|
||||
setl(b, T_ID1, cx0_id1);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
if (cx0_bd[0] != 0) Bchg(b, T_BIZDATE, 0, cx0_bd, 0L);
|
||||
if (cx0_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx0_mid, 0L);
|
||||
Bchg(b, T_SVCNAME, 0, "CL_APPRL2", 0L);
|
||||
/* 체인 표식: 하위(CL_APPRFINAL)는 cl_close_log 행을 직접 UPDATE 하지 않고
|
||||
* 확정 상태를 T_STR7/T_STR6 로 위임한다(형제 브랜치 행락 교착 방지). */
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L);
|
||||
/* 하위 승인단계는 '이 서비스의 전이 이전' 상태를 기준으로 진입 가능여부를
|
||||
* 판정한다(기존 동작과 동일: 하위 브랜치는 상위의 미커밋 전이를 못 본다).
|
||||
* 그 판정 기준값을 전문으로 명시 전달한다. */
|
||||
{ char cx0_pre[4]; cx0_pre[0] = st; cx0_pre[1] = 0;
|
||||
if (cx0_pre[0] != 0) Bchg(b, T_STATUS, 0, cx0_pre, 0L); }
|
||||
Bdel(b, T_STR7, 0); Bdel(b, T_STR6, 0);
|
||||
|
||||
userlog("[CL_APPRL2] 체인 호출 -> CL_APPRFINAL bd=%s id=%ld amt=%ld",
|
||||
cx0_bd, cx0_id1, cx0_amt);
|
||||
if (tpcall("CL_APPRFINAL", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) {
|
||||
userlog("[CL_APPRL2] tpcall(CL_APPRFINAL) 실패: %s", tpstrerror(tperrno));
|
||||
setl(b, T_RC, 9661);
|
||||
Bchg(b, T_MSG, 0, "최종승인 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
cx0_sub = getl(b, T_RC);
|
||||
if (cx0_sub != 0)
|
||||
userlog("[CL_APPRL2] CL_APPRFINAL 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub);
|
||||
else
|
||||
userlog("[CL_APPRL2] CL_APPRFINAL 체인 정상 완료 bd=%s", cx0_bd);
|
||||
|
||||
/* --- 위임 반영부: 하위가 위임한 cl_close_log 확정 전이를 소유자 브랜치에서
|
||||
* 단 한 번 반영한다. CL_APPRL2 자신이 체인 하위였다면 행 소유자가 아니므로
|
||||
* 반영하지 않고 위임값을 그대로 상위로 흘려보낸다. --- */
|
||||
{
|
||||
char dg_st[8], dg_memo[128];
|
||||
dg_st[0] = 0; dg_memo[0] = 0;
|
||||
gets_(b, T_STR7, dg_st, sizeof(dg_st));
|
||||
gets_(b, T_STR6, dg_memo, sizeof(dg_memo));
|
||||
if (dg_st[0] != 0 && !in_chain) {
|
||||
strncpy(h_status, dg_st, sizeof(h_status)-1); h_status[sizeof(h_status)-1] = 0;
|
||||
if (dg_memo[0] != 0) {
|
||||
strncpy(h_memo, dg_memo, sizeof(h_memo)-1); h_memo[sizeof(h_memo)-1] = 0;
|
||||
}
|
||||
h_kcid = cx0_id1;
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET status = :h_status, memo = :h_memo, updated_at = now()
|
||||
WHERE close_id = :h_kcid;
|
||||
if (sqlca.sqlcode < 0) {
|
||||
setl(b, T_RC, 5609);
|
||||
Bchg(b, T_MSG, 0, "최종승인 위임 반영 실패", 0L); FAIL(b);
|
||||
}
|
||||
if (sqlca.sqlerrd[2] != 1) {
|
||||
setl(b, T_RC, 5610);
|
||||
Bchg(b, T_MSG, 0, "최종승인 위임 대상행 수 이상", 0L); FAIL(b);
|
||||
}
|
||||
strncpy(cx0_st, h_status, sizeof(cx0_st)-1); cx0_st[sizeof(cx0_st)-1] = 0;
|
||||
userlog("[CL_APPRL2] 위임 반영 완료 close_id=%ld status=%s", h_kcid, h_status);
|
||||
Bdel(b, T_STR7, 0); Bdel(b, T_STR6, 0);
|
||||
} else if (dg_st[0] != 0) {
|
||||
userlog("[CL_APPRL2] 체인 하위이므로 위임(status=%s)을 상위로 전달", dg_st);
|
||||
}
|
||||
}
|
||||
|
||||
/* 응답 계약 복원: 원 서비스의 출력 필드는 하위 결과로 바뀌지 않는다 */
|
||||
setl(b, T_RC, cx0_rc); setl(b, T_ID1, cx0_id1); setl(b, T_ID2, cx0_id2);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
setl(b, T_ARG5, cx0_a5); setl(b, T_ARG6, cx0_a6);
|
||||
setl(b, T_ARG7, cx0_a7); setl(b, T_ARG8, cx0_a8);
|
||||
setl(b, T_AMT2, cx0_m2); setl(b, T_AMT3, cx0_m3);
|
||||
if (cx0_st[0] != 0) Bchg(b, T_STATUS, 0, cx0_st, 0L);
|
||||
if (cx0_msg[0] != 0) Bchg(b, T_MSG, 0, cx0_msg, 0L);
|
||||
}
|
||||
OK(b);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -171,6 +171,100 @@ void CL_APPROVE(TPSVCINFO *p)
|
|||
setl(b, T_GROSS, o_amount);
|
||||
Bchg(b, T_MSG, 0, o_msg, 0L);
|
||||
userlog("CL_APPROVE 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount);
|
||||
|
||||
/* ==== 10) 업무흐름 체인: CL_APPRL2 연동 (승인 처리 후 2차 승인 확정) ====
|
||||
* 동일 글로벌 트랜잭션이지만 CL_APPRL2 는 별도 XA 브랜치에서 수행된다.
|
||||
* 위에서 적재/갱신한 행은 아직 미커밋이라 하위 브랜치에서 보이지 않으므로
|
||||
* 판단에 필요한 값은 전문(UBF)에 실어 전달한다(owner-writes 규율).
|
||||
* 호출 실패는 보상 없이 FAIL(b) -> 글로벌 트랜잭션 전체 롤백. */
|
||||
{
|
||||
long cx0_rlen = 0, cx0_sub = 0;
|
||||
long cx0_rc, cx0_id1, cx0_id2, cx0_amt;
|
||||
long cx0_a5, cx0_a6, cx0_a7, cx0_a8, cx0_m2, cx0_m3;
|
||||
char cx0_bd[16], cx0_mid[64], cx0_st[16], cx0_msg[192];
|
||||
|
||||
/* 응답 계약 스냅샷 (하위 서비스가 덮어쓴 뒤 복원하기 위함) */
|
||||
cx0_rc = getl(b, T_RC); cx0_id1 = getl(b, T_ID1); cx0_id2 = getl(b, T_ID2);
|
||||
cx0_amt = getl(b, T_AMOUNT);
|
||||
cx0_a5 = getl(b, T_ARG5); cx0_a6 = getl(b, T_ARG6);
|
||||
cx0_a7 = getl(b, T_ARG7); cx0_a8 = getl(b, T_ARG8);
|
||||
cx0_m2 = getl(b, T_AMT2); cx0_m3 = getl(b, T_AMT3);
|
||||
gets_(b, T_STATUS, cx0_st, sizeof(cx0_st));
|
||||
gets_(b, T_MSG, cx0_msg, sizeof(cx0_msg));
|
||||
gets_(b, T_BIZDATE, cx0_bd, sizeof(cx0_bd));
|
||||
gets_(b, T_MERCHANT, cx0_mid, sizeof(cx0_mid));
|
||||
|
||||
/* 하위 서비스가 쓸 값을 전문에 적재 (미커밋 행 조회 의존 금지) */
|
||||
setl(b, T_ID1, cx0_id1);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
if (cx0_bd[0] != 0) Bchg(b, T_BIZDATE, 0, cx0_bd, 0L);
|
||||
if (cx0_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx0_mid, 0L);
|
||||
Bchg(b, T_SVCNAME, 0, "CL_APPROVE", 0L);
|
||||
/* 체인 표식: 하위(CL_APPRL2/CL_APPRFINAL)는 cl_close_log 행을 직접
|
||||
* UPDATE 하지 않고 확정 상태를 T_STR7/T_STR6 로 위임한다.
|
||||
* 이 행의 소유자는 방금 전이시킨 이 브랜치이므로, 반영도 여기서 한다
|
||||
* (형제 XA 브랜치 간 동일행 쓰기 = 미커밋 행락 교착 방지). */
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L);
|
||||
/* 하위 승인단계는 '이 서비스의 전이 이전' 상태를 기준으로 진입 가능여부를
|
||||
* 판정한다(기존 동작과 동일: 하위 브랜치는 상위의 미커밋 전이를 못 본다).
|
||||
* 그 판정 기준값을 전문으로 명시 전달한다. */
|
||||
{ char cx0_pre[4]; cx0_pre[0] = st; cx0_pre[1] = 0;
|
||||
if (cx0_pre[0] != 0) Bchg(b, T_STATUS, 0, cx0_pre, 0L); }
|
||||
Bdel(b, T_STR7, 0); Bdel(b, T_STR6, 0);
|
||||
|
||||
userlog("[CL_APPROVE] 체인 호출 -> CL_APPRL2 bd=%s id=%ld amt=%ld",
|
||||
cx0_bd, cx0_id1, cx0_amt);
|
||||
if (tpcall("CL_APPRL2", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) {
|
||||
userlog("[CL_APPROVE] tpcall(CL_APPRL2) 실패: %s", tpstrerror(tperrno));
|
||||
setl(b, T_RC, 9673);
|
||||
Bchg(b, T_MSG, 0, "승인처리 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
cx0_sub = getl(b, T_RC);
|
||||
if (cx0_sub != 0)
|
||||
userlog("[CL_APPROVE] CL_APPRL2 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub);
|
||||
else
|
||||
userlog("[CL_APPROVE] CL_APPRL2 체인 정상 완료 bd=%s", cx0_bd);
|
||||
|
||||
/* --- 위임 반영부: 하위 승인단계들이 위임한 cl_close_log 확정 전이를
|
||||
* 행 소유자인 이 브랜치에서 단 한 번만 반영한다. --- */
|
||||
{
|
||||
char dg_st[8], dg_memo[128];
|
||||
dg_st[0] = 0; dg_memo[0] = 0;
|
||||
gets_(b, T_STR7, dg_st, sizeof(dg_st));
|
||||
gets_(b, T_STR6, dg_memo, sizeof(dg_memo));
|
||||
if (dg_st[0] != 0) {
|
||||
strncpy(h_status, dg_st, sizeof(h_status)-1); h_status[sizeof(h_status)-1] = 0;
|
||||
if (dg_memo[0] != 0) {
|
||||
strncpy(h_memo, dg_memo, sizeof(h_memo)-1); h_memo[sizeof(h_memo)-1] = 0;
|
||||
}
|
||||
h_kcid = cx0_id1;
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET status = :h_status, memo = :h_memo, updated_at = now()
|
||||
WHERE close_id = :h_kcid;
|
||||
if (sqlca.sqlcode < 0) {
|
||||
setl(b, T_RC, 5609);
|
||||
Bchg(b, T_MSG, 0, "승인 체인 위임 반영 실패", 0L); FAIL(b);
|
||||
}
|
||||
if (sqlca.sqlerrd[2] != 1) {
|
||||
setl(b, T_RC, 5610);
|
||||
Bchg(b, T_MSG, 0, "승인 체인 위임 대상행 수 이상", 0L); FAIL(b);
|
||||
}
|
||||
strncpy(cx0_st, h_status, sizeof(cx0_st)-1); cx0_st[sizeof(cx0_st)-1] = 0;
|
||||
userlog("[CL_APPROVE] 위임 반영 완료 close_id=%ld status=%s", h_kcid, h_status);
|
||||
Bdel(b, T_STR7, 0); Bdel(b, T_STR6, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 응답 계약 복원: 원 서비스의 출력 필드는 하위 결과로 바뀌지 않는다 */
|
||||
setl(b, T_RC, cx0_rc); setl(b, T_ID1, cx0_id1); setl(b, T_ID2, cx0_id2);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
setl(b, T_ARG5, cx0_a5); setl(b, T_ARG6, cx0_a6);
|
||||
setl(b, T_ARG7, cx0_a7); setl(b, T_ARG8, cx0_a8);
|
||||
setl(b, T_AMT2, cx0_m2); setl(b, T_AMT3, cx0_m3);
|
||||
if (cx0_st[0] != 0) Bchg(b, T_STATUS, 0, cx0_st, 0L);
|
||||
if (cx0_msg[0] != 0) Bchg(b, T_MSG, 0, cx0_msg, 0L);
|
||||
}
|
||||
OK(b);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -171,6 +171,59 @@ void CL_APPRREJECT(TPSVCINFO *p)
|
|||
setl(b, T_GROSS, o_amount);
|
||||
Bchg(b, T_MSG, 0, o_msg, 0L);
|
||||
userlog("CL_APPRREJECT 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount);
|
||||
|
||||
/* ==== 10) 업무흐름 체인: CL_ESCALATE 연동 (승인 반려 시 상위 에스컬레이션) ====
|
||||
* 동일 글로벌 트랜잭션이지만 CL_ESCALATE 는 별도 XA 브랜치에서 수행된다.
|
||||
* 위에서 적재/갱신한 행은 아직 미커밋이라 하위 브랜치에서 보이지 않으므로
|
||||
* 판단에 필요한 값은 전문(UBF)에 실어 전달한다(owner-writes 규율).
|
||||
* 호출 실패는 보상 없이 FAIL(b) -> 글로벌 트랜잭션 전체 롤백. */
|
||||
{
|
||||
long cx0_rlen = 0, cx0_sub = 0;
|
||||
long cx0_rc, cx0_id1, cx0_id2, cx0_amt;
|
||||
long cx0_a5, cx0_a6, cx0_a7, cx0_a8, cx0_m2, cx0_m3;
|
||||
char cx0_bd[16], cx0_mid[64], cx0_st[16], cx0_msg[192];
|
||||
|
||||
/* 응답 계약 스냅샷 (하위 서비스가 덮어쓴 뒤 복원하기 위함) */
|
||||
cx0_rc = getl(b, T_RC); cx0_id1 = getl(b, T_ID1); cx0_id2 = getl(b, T_ID2);
|
||||
cx0_amt = getl(b, T_AMOUNT);
|
||||
cx0_a5 = getl(b, T_ARG5); cx0_a6 = getl(b, T_ARG6);
|
||||
cx0_a7 = getl(b, T_ARG7); cx0_a8 = getl(b, T_ARG8);
|
||||
cx0_m2 = getl(b, T_AMT2); cx0_m3 = getl(b, T_AMT3);
|
||||
gets_(b, T_STATUS, cx0_st, sizeof(cx0_st));
|
||||
gets_(b, T_MSG, cx0_msg, sizeof(cx0_msg));
|
||||
gets_(b, T_BIZDATE, cx0_bd, sizeof(cx0_bd));
|
||||
gets_(b, T_MERCHANT, cx0_mid, sizeof(cx0_mid));
|
||||
|
||||
/* 하위 서비스가 쓸 값을 전문에 적재 (미커밋 행 조회 의존 금지) */
|
||||
setl(b, T_ID1, cx0_id1);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
if (cx0_bd[0] != 0) Bchg(b, T_BIZDATE, 0, cx0_bd, 0L);
|
||||
if (cx0_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx0_mid, 0L);
|
||||
Bchg(b, T_SVCNAME, 0, "CL_APPRREJECT", 0L);
|
||||
|
||||
userlog("[CL_APPRREJECT] 체인 호출 -> CL_ESCALATE bd=%s id=%ld amt=%ld",
|
||||
cx0_bd, cx0_id1, cx0_amt);
|
||||
if (tpcall("CL_ESCALATE", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) {
|
||||
userlog("[CL_APPRREJECT] tpcall(CL_ESCALATE) 실패: %s", tpstrerror(tperrno));
|
||||
setl(b, T_RC, 9662);
|
||||
Bchg(b, T_MSG, 0, "반려 에스컬레이션 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
cx0_sub = getl(b, T_RC);
|
||||
if (cx0_sub != 0)
|
||||
userlog("[CL_APPRREJECT] CL_ESCALATE 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub);
|
||||
else
|
||||
userlog("[CL_APPRREJECT] CL_ESCALATE 체인 정상 완료 bd=%s", cx0_bd);
|
||||
|
||||
/* 응답 계약 복원: 원 서비스의 출력 필드는 하위 결과로 바뀌지 않는다 */
|
||||
setl(b, T_RC, cx0_rc); setl(b, T_ID1, cx0_id1); setl(b, T_ID2, cx0_id2);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
setl(b, T_ARG5, cx0_a5); setl(b, T_ARG6, cx0_a6);
|
||||
setl(b, T_ARG7, cx0_a7); setl(b, T_ARG8, cx0_a8);
|
||||
setl(b, T_AMT2, cx0_m2); setl(b, T_AMT3, cx0_m3);
|
||||
if (cx0_st[0] != 0) Bchg(b, T_STATUS, 0, cx0_st, 0L);
|
||||
if (cx0_msg[0] != 0) Bchg(b, T_MSG, 0, cx0_msg, 0L);
|
||||
}
|
||||
OK(b);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -171,6 +171,100 @@ void CL_APPRREQ(TPSVCINFO *p)
|
|||
setl(b, T_GROSS, o_amount);
|
||||
Bchg(b, T_MSG, 0, o_msg, 0L);
|
||||
userlog("CL_APPRREQ 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount);
|
||||
|
||||
/* ==== 10) 업무흐름 체인: CL_APPRL2 연동 (승인 요청 접수 후 2차 승인 라우팅) ====
|
||||
* 동일 글로벌 트랜잭션이지만 CL_APPRL2 는 별도 XA 브랜치에서 수행된다.
|
||||
* 위에서 적재/갱신한 행은 아직 미커밋이라 하위 브랜치에서 보이지 않으므로
|
||||
* 판단에 필요한 값은 전문(UBF)에 실어 전달한다(owner-writes 규율).
|
||||
* 호출 실패는 보상 없이 FAIL(b) -> 글로벌 트랜잭션 전체 롤백. */
|
||||
{
|
||||
long cx0_rlen = 0, cx0_sub = 0;
|
||||
long cx0_rc, cx0_id1, cx0_id2, cx0_amt;
|
||||
long cx0_a5, cx0_a6, cx0_a7, cx0_a8, cx0_m2, cx0_m3;
|
||||
char cx0_bd[16], cx0_mid[64], cx0_st[16], cx0_msg[192];
|
||||
|
||||
/* 응답 계약 스냅샷 (하위 서비스가 덮어쓴 뒤 복원하기 위함) */
|
||||
cx0_rc = getl(b, T_RC); cx0_id1 = getl(b, T_ID1); cx0_id2 = getl(b, T_ID2);
|
||||
cx0_amt = getl(b, T_AMOUNT);
|
||||
cx0_a5 = getl(b, T_ARG5); cx0_a6 = getl(b, T_ARG6);
|
||||
cx0_a7 = getl(b, T_ARG7); cx0_a8 = getl(b, T_ARG8);
|
||||
cx0_m2 = getl(b, T_AMT2); cx0_m3 = getl(b, T_AMT3);
|
||||
gets_(b, T_STATUS, cx0_st, sizeof(cx0_st));
|
||||
gets_(b, T_MSG, cx0_msg, sizeof(cx0_msg));
|
||||
gets_(b, T_BIZDATE, cx0_bd, sizeof(cx0_bd));
|
||||
gets_(b, T_MERCHANT, cx0_mid, sizeof(cx0_mid));
|
||||
|
||||
/* 하위 서비스가 쓸 값을 전문에 적재 (미커밋 행 조회 의존 금지) */
|
||||
setl(b, T_ID1, cx0_id1);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
if (cx0_bd[0] != 0) Bchg(b, T_BIZDATE, 0, cx0_bd, 0L);
|
||||
if (cx0_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx0_mid, 0L);
|
||||
Bchg(b, T_SVCNAME, 0, "CL_APPRREQ", 0L);
|
||||
/* 체인 표식: 하위(CL_APPRL2/CL_APPRFINAL)는 cl_close_log 행을 직접
|
||||
* UPDATE 하지 않고 확정 상태를 T_STR7/T_STR6 로 위임한다.
|
||||
* 이 행의 소유자는 방금 전이시킨 이 브랜치이므로, 반영도 여기서 한다
|
||||
* (형제 XA 브랜치 간 동일행 쓰기 = 미커밋 행락 교착 방지). */
|
||||
Bchg(b, T_STR8, 0, "CHAIN", 0L);
|
||||
/* 하위 승인단계는 '이 서비스의 전이 이전' 상태를 기준으로 진입 가능여부를
|
||||
* 판정한다(기존 동작과 동일: 하위 브랜치는 상위의 미커밋 전이를 못 본다).
|
||||
* 그 판정 기준값을 전문으로 명시 전달한다. */
|
||||
{ char cx0_pre[4]; cx0_pre[0] = st; cx0_pre[1] = 0;
|
||||
if (cx0_pre[0] != 0) Bchg(b, T_STATUS, 0, cx0_pre, 0L); }
|
||||
Bdel(b, T_STR7, 0); Bdel(b, T_STR6, 0);
|
||||
|
||||
userlog("[CL_APPRREQ] 체인 호출 -> CL_APPRL2 bd=%s id=%ld amt=%ld",
|
||||
cx0_bd, cx0_id1, cx0_amt);
|
||||
if (tpcall("CL_APPRL2", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) {
|
||||
userlog("[CL_APPRREQ] tpcall(CL_APPRL2) 실패: %s", tpstrerror(tperrno));
|
||||
setl(b, T_RC, 9672);
|
||||
Bchg(b, T_MSG, 0, "승인요청 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
cx0_sub = getl(b, T_RC);
|
||||
if (cx0_sub != 0)
|
||||
userlog("[CL_APPRREQ] CL_APPRL2 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub);
|
||||
else
|
||||
userlog("[CL_APPRREQ] CL_APPRL2 체인 정상 완료 bd=%s", cx0_bd);
|
||||
|
||||
/* --- 위임 반영부: 하위 승인단계들이 위임한 cl_close_log 확정 전이를
|
||||
* 행 소유자인 이 브랜치에서 단 한 번만 반영한다. --- */
|
||||
{
|
||||
char dg_st[8], dg_memo[128];
|
||||
dg_st[0] = 0; dg_memo[0] = 0;
|
||||
gets_(b, T_STR7, dg_st, sizeof(dg_st));
|
||||
gets_(b, T_STR6, dg_memo, sizeof(dg_memo));
|
||||
if (dg_st[0] != 0) {
|
||||
strncpy(h_status, dg_st, sizeof(h_status)-1); h_status[sizeof(h_status)-1] = 0;
|
||||
if (dg_memo[0] != 0) {
|
||||
strncpy(h_memo, dg_memo, sizeof(h_memo)-1); h_memo[sizeof(h_memo)-1] = 0;
|
||||
}
|
||||
h_kcid = cx0_id1;
|
||||
EXEC SQL UPDATE cl_close_log
|
||||
SET status = :h_status, memo = :h_memo, updated_at = now()
|
||||
WHERE close_id = :h_kcid;
|
||||
if (sqlca.sqlcode < 0) {
|
||||
setl(b, T_RC, 5609);
|
||||
Bchg(b, T_MSG, 0, "승인 체인 위임 반영 실패", 0L); FAIL(b);
|
||||
}
|
||||
if (sqlca.sqlerrd[2] != 1) {
|
||||
setl(b, T_RC, 5610);
|
||||
Bchg(b, T_MSG, 0, "승인 체인 위임 대상행 수 이상", 0L); FAIL(b);
|
||||
}
|
||||
strncpy(cx0_st, h_status, sizeof(cx0_st)-1); cx0_st[sizeof(cx0_st)-1] = 0;
|
||||
userlog("[CL_APPRREQ] 위임 반영 완료 close_id=%ld status=%s", h_kcid, h_status);
|
||||
Bdel(b, T_STR7, 0); Bdel(b, T_STR6, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 응답 계약 복원: 원 서비스의 출력 필드는 하위 결과로 바뀌지 않는다 */
|
||||
setl(b, T_RC, cx0_rc); setl(b, T_ID1, cx0_id1); setl(b, T_ID2, cx0_id2);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
setl(b, T_ARG5, cx0_a5); setl(b, T_ARG6, cx0_a6);
|
||||
setl(b, T_ARG7, cx0_a7); setl(b, T_ARG8, cx0_a8);
|
||||
setl(b, T_AMT2, cx0_m2); setl(b, T_AMT3, cx0_m3);
|
||||
if (cx0_st[0] != 0) Bchg(b, T_STATUS, 0, cx0_st, 0L);
|
||||
if (cx0_msg[0] != 0) Bchg(b, T_MSG, 0, cx0_msg, 0L);
|
||||
}
|
||||
OK(b);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -171,6 +171,59 @@ void CL_BALVERIFY(TPSVCINFO *p)
|
|||
setl(b, T_GROSS, o_amount);
|
||||
Bchg(b, T_MSG, 0, o_msg, 0L);
|
||||
userlog("CL_BALVERIFY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount);
|
||||
|
||||
/* ==== 10) 업무흐름 체인: VL_LEDGBAL 연동 (마감 원장잔액 정합성 검증) ====
|
||||
* 동일 글로벌 트랜잭션이지만 VL_LEDGBAL 는 별도 XA 브랜치에서 수행된다.
|
||||
* 위에서 적재/갱신한 행은 아직 미커밋이라 하위 브랜치에서 보이지 않으므로
|
||||
* 판단에 필요한 값은 전문(UBF)에 실어 전달한다(owner-writes 규율).
|
||||
* 호출 실패는 보상 없이 FAIL(b) -> 글로벌 트랜잭션 전체 롤백. */
|
||||
{
|
||||
long cx0_rlen = 0, cx0_sub = 0;
|
||||
long cx0_rc, cx0_id1, cx0_id2, cx0_amt;
|
||||
long cx0_a5, cx0_a6, cx0_a7, cx0_a8, cx0_m2, cx0_m3;
|
||||
char cx0_bd[16], cx0_mid[64], cx0_st[16], cx0_msg[192];
|
||||
|
||||
/* 응답 계약 스냅샷 (하위 서비스가 덮어쓴 뒤 복원하기 위함) */
|
||||
cx0_rc = getl(b, T_RC); cx0_id1 = getl(b, T_ID1); cx0_id2 = getl(b, T_ID2);
|
||||
cx0_amt = getl(b, T_AMOUNT);
|
||||
cx0_a5 = getl(b, T_ARG5); cx0_a6 = getl(b, T_ARG6);
|
||||
cx0_a7 = getl(b, T_ARG7); cx0_a8 = getl(b, T_ARG8);
|
||||
cx0_m2 = getl(b, T_AMT2); cx0_m3 = getl(b, T_AMT3);
|
||||
gets_(b, T_STATUS, cx0_st, sizeof(cx0_st));
|
||||
gets_(b, T_MSG, cx0_msg, sizeof(cx0_msg));
|
||||
gets_(b, T_BIZDATE, cx0_bd, sizeof(cx0_bd));
|
||||
gets_(b, T_MERCHANT, cx0_mid, sizeof(cx0_mid));
|
||||
|
||||
/* 하위 서비스가 쓸 값을 전문에 적재 (미커밋 행 조회 의존 금지) */
|
||||
setl(b, T_ID1, cx0_id1);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
if (cx0_bd[0] != 0) Bchg(b, T_BIZDATE, 0, cx0_bd, 0L);
|
||||
if (cx0_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx0_mid, 0L);
|
||||
Bchg(b, T_SVCNAME, 0, "CL_BALVERIFY", 0L);
|
||||
|
||||
userlog("[CL_BALVERIFY] 체인 호출 -> VL_LEDGBAL bd=%s id=%ld amt=%ld",
|
||||
cx0_bd, cx0_id1, cx0_amt);
|
||||
if (tpcall("VL_LEDGBAL", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) {
|
||||
userlog("[CL_BALVERIFY] tpcall(VL_LEDGBAL) 실패: %s", tpstrerror(tperrno));
|
||||
setl(b, T_RC, 9613);
|
||||
Bchg(b, T_MSG, 0, "원장잔액 검증 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
cx0_sub = getl(b, T_RC);
|
||||
if (cx0_sub != 0)
|
||||
userlog("[CL_BALVERIFY] VL_LEDGBAL 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub);
|
||||
else
|
||||
userlog("[CL_BALVERIFY] VL_LEDGBAL 체인 정상 완료 bd=%s", cx0_bd);
|
||||
|
||||
/* 응답 계약 복원: 원 서비스의 출력 필드는 하위 결과로 바뀌지 않는다 */
|
||||
setl(b, T_RC, cx0_rc); setl(b, T_ID1, cx0_id1); setl(b, T_ID2, cx0_id2);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
setl(b, T_ARG5, cx0_a5); setl(b, T_ARG6, cx0_a6);
|
||||
setl(b, T_ARG7, cx0_a7); setl(b, T_ARG8, cx0_a8);
|
||||
setl(b, T_AMT2, cx0_m2); setl(b, T_AMT3, cx0_m3);
|
||||
if (cx0_st[0] != 0) Bchg(b, T_STATUS, 0, cx0_st, 0L);
|
||||
if (cx0_msg[0] != 0) Bchg(b, T_MSG, 0, cx0_msg, 0L);
|
||||
}
|
||||
OK(b);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -165,6 +165,59 @@ void CL_CANCEL(TPSVCINFO *p)
|
|||
setl(b, T_GROSS, o_amount);
|
||||
Bchg(b, T_MSG, 0, o_msg, 0L);
|
||||
userlog("CL_CANCEL 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount);
|
||||
|
||||
/* ==== 10) 업무흐름 체인: LG_REVERSE 연동 (마감 취소 대상 전표의 원장 역분개) ====
|
||||
* 동일 글로벌 트랜잭션이지만 LG_REVERSE 는 별도 XA 브랜치에서 수행된다.
|
||||
* 위에서 적재/갱신한 행은 아직 미커밋이라 하위 브랜치에서 보이지 않으므로
|
||||
* 판단에 필요한 값은 전문(UBF)에 실어 전달한다(owner-writes 규율).
|
||||
* 호출 실패는 보상 없이 FAIL(b) -> 글로벌 트랜잭션 전체 롤백. */
|
||||
{
|
||||
long cx0_rlen = 0, cx0_sub = 0;
|
||||
long cx0_rc, cx0_id1, cx0_id2, cx0_amt;
|
||||
long cx0_a5, cx0_a6, cx0_a7, cx0_a8, cx0_m2, cx0_m3;
|
||||
char cx0_bd[16], cx0_mid[64], cx0_st[16], cx0_msg[192];
|
||||
|
||||
/* 응답 계약 스냅샷 (하위 서비스가 덮어쓴 뒤 복원하기 위함) */
|
||||
cx0_rc = getl(b, T_RC); cx0_id1 = getl(b, T_ID1); cx0_id2 = getl(b, T_ID2);
|
||||
cx0_amt = getl(b, T_AMOUNT);
|
||||
cx0_a5 = getl(b, T_ARG5); cx0_a6 = getl(b, T_ARG6);
|
||||
cx0_a7 = getl(b, T_ARG7); cx0_a8 = getl(b, T_ARG8);
|
||||
cx0_m2 = getl(b, T_AMT2); cx0_m3 = getl(b, T_AMT3);
|
||||
gets_(b, T_STATUS, cx0_st, sizeof(cx0_st));
|
||||
gets_(b, T_MSG, cx0_msg, sizeof(cx0_msg));
|
||||
gets_(b, T_BIZDATE, cx0_bd, sizeof(cx0_bd));
|
||||
gets_(b, T_MERCHANT, cx0_mid, sizeof(cx0_mid));
|
||||
|
||||
/* 하위 서비스가 쓸 값을 전문에 적재 (미커밋 행 조회 의존 금지) */
|
||||
setl(b, T_ID1, cx0_id1);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
if (cx0_bd[0] != 0) Bchg(b, T_BIZDATE, 0, cx0_bd, 0L);
|
||||
if (cx0_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx0_mid, 0L);
|
||||
Bchg(b, T_SVCNAME, 0, "CL_CANCEL", 0L);
|
||||
|
||||
userlog("[CL_CANCEL] 체인 호출 -> LG_REVERSE bd=%s id=%ld amt=%ld",
|
||||
cx0_bd, cx0_id1, cx0_amt);
|
||||
if (tpcall("LG_REVERSE", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) {
|
||||
userlog("[CL_CANCEL] tpcall(LG_REVERSE) 실패: %s", tpstrerror(tperrno));
|
||||
setl(b, T_RC, 9698);
|
||||
Bchg(b, T_MSG, 0, "마감취소 역분개 체인 실패", 0L);
|
||||
FAIL(b);
|
||||
}
|
||||
cx0_sub = getl(b, T_RC);
|
||||
if (cx0_sub != 0)
|
||||
userlog("[CL_CANCEL] LG_REVERSE 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub);
|
||||
else
|
||||
userlog("[CL_CANCEL] LG_REVERSE 체인 정상 완료 bd=%s", cx0_bd);
|
||||
|
||||
/* 응답 계약 복원: 원 서비스의 출력 필드는 하위 결과로 바뀌지 않는다 */
|
||||
setl(b, T_RC, cx0_rc); setl(b, T_ID1, cx0_id1); setl(b, T_ID2, cx0_id2);
|
||||
setl(b, T_AMOUNT, cx0_amt);
|
||||
setl(b, T_ARG5, cx0_a5); setl(b, T_ARG6, cx0_a6);
|
||||
setl(b, T_ARG7, cx0_a7); setl(b, T_ARG8, cx0_a8);
|
||||
setl(b, T_AMT2, cx0_m2); setl(b, T_AMT3, cx0_m3);
|
||||
if (cx0_st[0] != 0) Bchg(b, T_STATUS, 0, cx0_st, 0L);
|
||||
if (cx0_msg[0] != 0) Bchg(b, T_MSG, 0, cx0_msg, 0L);
|
||||
}
|
||||
OK(b);
|
||||
}
|
||||
|
||||
|
|
|
|||
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