From 074d244bba7ba8649fae7f02d04c2187f3d52d60 Mon Sep 17 00:00:00 2001 From: hyeongwoo Date: Tue, 21 Jul 2026 14:55:49 +0000 Subject: [PATCH] =?UTF-8?q?Wave=20E/F:=20=EC=97=85=EB=AC=B4=ED=9D=90?= =?UTF-8?q?=EB=A6=84=20tpcall=20=EC=98=A4=EC=BC=80=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=85=98=20+=20=ED=81=AC=EB=A1=9C=EC=8A=A4?= =?UTF-8?q?=EB=B8=8C=EB=9E=9C=EC=B9=98=20=EA=B5=90=EC=B0=A9=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- app/build.sh | 9 +- app/conf/ndrxconfig.xml | 79 +- app/src/ac/svc/ACQ_ALERTDUP.pgc | 33 + app/src/ac/svc/ACQ_AMTFIX.pgc | 33 + app/src/ac/svc/ACQ_APPRLINK.pgc | 33 + app/src/ac/svc/ACQ_APPRMAP.pgc | 34 + app/src/ac/svc/ACQ_CANCEL.pgc | 71 + app/src/ac/svc/ACQ_CB_OPEN.pgc | 33 + app/src/ac/svc/ACQ_CB_REVERSE.pgc | 33 + app/src/ac/svc/ACQ_CLAIMREG.pgc | 33 + app/src/ac/svc/ACQ_CORRECT.pgc | 33 + app/src/ac/svc/ACQ_DDC.pgc | 34 + app/src/ac/svc/ACQ_DUPCHK.pgc | 33 + app/src/ac/svc/ACQ_EDC.pgc | 34 + app/src/ac/svc/ACQ_EDI.pgc | 34 + app/src/ac/svc/ACQ_EDIRESEND.pgc | 34 + app/src/ac/svc/ACQ_ESCROW.pgc | 33 + app/src/ac/svc/ACQ_ESCROWREL.pgc | 33 + app/src/ac/svc/ACQ_EXCHANGE.pgc | 33 + app/src/ac/svc/ACQ_FEEADJ.pgc | 33 + app/src/ac/svc/ACQ_FEERECALC.pgc | 33 + app/src/ac/svc/ACQ_FOREIGN.pgc | 34 + app/src/ac/svc/ACQ_FXCONVERT.pgc | 33 + app/src/ac/svc/ACQ_FXRATE.pgc | 33 + app/src/ac/svc/ACQ_GUARANTEE.pgc | 33 + app/src/ac/svc/ACQ_HOLD.pgc | 33 + app/src/ac/svc/ACQ_INSTALL.pgc | 33 + app/src/ac/svc/ACQ_INSTCXL.pgc | 33 + app/src/ac/svc/ACQ_LIMITCHK.pgc | 33 + app/src/ac/svc/ACQ_LIMITEXC.pgc | 33 + app/src/ac/svc/ACQ_MERCHSUM.pgc | 31 + app/src/ac/svc/ACQ_NETCALC.pgc | 33 + app/src/ac/svc/ACQ_PARTCXL.pgc | 44 + app/src/ac/svc/ACQ_PARTRFND.pgc | 33 + app/src/ac/svc/ACQ_PROMO.pgc | 33 + app/src/ac/svc/ACQ_REFUND.pgc | 44 + app/src/ac/svc/ACQ_RELEASE.pgc | 33 + app/src/ac/svc/ACQ_REMATCH.pgc | 33 + app/src/ac/svc/ACQ_REPROC.pgc | 33 + app/src/ac/svc/ACQ_RESERVE.pgc | 33 + app/src/ac/svc/ACQ_RESERVECXL.pgc | 33 + app/src/ac/svc/ACQ_RETURN.pgc | 33 + app/src/ac/svc/ACQ_SETTLELINK.pgc | 89 + app/src/ac/svc/ACQ_SPLITPAY.pgc | 33 + app/src/ac/svc/ACQ_TAXCXL.pgc | 33 + app/src/ac/svc/ACQ_TAXINV.pgc | 34 + app/src/ac/svc/ACQ_TAXREVERSE.pgc | 33 + app/src/ac/svc/ACQ_UNMATCH.pgc | 33 + app/src/ac/svc/ACQ_VELOCITY.pgc | 33 + app/src/ac/svc/ACQ_VOID.pgc | 33 + app/src/ac/svc/ACQ_WHT.pgc | 46 + app/src/ac/svc/ACQ_XFERLINK.pgc | 33 + app/src/au/svc/AUTH.pgc | 70 +- app/src/au/svc/AUTH_AMT_ADJUST.pgc | 30 + app/src/au/svc/AUTH_APPROVE.pgc | 30 + app/src/au/svc/AUTH_CANCEL.pgc | 39 +- app/src/au/svc/AUTH_CAPTURE.pgc | 30 + app/src/au/svc/AUTH_DECLINE.pgc | 32 + app/src/au/svc/AUTH_DUP_CHK.pgc | 40 + app/src/au/svc/AUTH_EXPIRE_CHK.pgc | 30 + app/src/au/svc/AUTH_HOLD.pgc | 30 + app/src/au/svc/AUTH_PARTAPPR.pgc | 37 +- app/src/au/svc/AUTH_PARTCXL.pgc | 39 +- app/src/au/svc/AUTH_RELEASE.pgc | 30 + app/src/au/svc/AUTH_RESEND.pgc | 33 + app/src/au/svc/AUTH_RETRY.pgc | 33 + app/src/au/svc/AUTH_REVERSE.pgc | 39 +- app/src/au/svc/AUTH_VOID.pgc | 39 +- app/src/au/svc/BLACKLIST_CHK.pgc | 40 + app/src/au/svc/CARD_LOST_REG.pgc | 33 + app/src/au/svc/CARD_STOLEN_REG.pgc | 33 + app/src/au/svc/CARD_VALIDATE.pgc | 36 + app/src/au/svc/FRAUD_DETECT.pgc | 48 + app/src/au/svc/INSTALL_AUTH.pgc | 37 +- app/src/au/svc/LIMIT_CHK.pgc | 62 +- app/src/au/svc/LIMIT_DEC.pgc | 48 + app/src/au/svc/LIMIT_EXHAUST_LST.pgc | 32 + app/src/au/svc/LIMIT_FREEZE.pgc | 32 + app/src/au/svc/LIMIT_OVER_ALERT.pgc | 32 + app/src/au/svc/LIMIT_RST.pgc | 48 + app/src/au/svc/NOAUTH_CAPTURE.pgc | 30 + app/src/au/svc/PREAUTH.pgc | 37 +- app/src/au/svc/PREAUTH_CANCEL.pgc | 30 + app/src/au/svc/PREAUTH_COMPLETE.pgc | 37 +- app/src/au/svc/PREAUTH_EXTEND.pgc | 30 + app/src/au/svc/PREAUTH_PARTUSE.pgc | 30 + app/src/au/svc/STANDIN.pgc | 64 + app/src/au/svc/STANDIN_SETTLE.pgc | 37 +- app/src/au/svc/TOKEN_VERIFY.pgc | 36 + app/src/au/svc/VELOCITY_CHK.pgc | 40 + app/src/cl/svc/CL_AMTXCHECK.pgc | 53 + app/src/cl/svc/CL_APPRDELEG.pgc | 53 + app/src/cl/svc/CL_APPRFINAL.pgc | 69 +- app/src/cl/svc/CL_APPRL1.pgc | 94 + app/src/cl/svc/CL_APPRL2.pgc | 164 +- app/src/cl/svc/CL_APPROVE.pgc | 94 + app/src/cl/svc/CL_APPRREJECT.pgc | 53 + app/src/cl/svc/CL_APPRREQ.pgc | 94 + app/src/cl/svc/CL_BALVERIFY.pgc | 53 + app/src/cl/svc/CL_CANCEL.pgc | 53 + app/src/cl/svc/CL_CHKALL.pgc | 53 + app/src/cl/svc/CL_CHKPENDING.pgc | 53 + app/src/cl/svc/CL_CHKUNMATCH.pgc | 53 + app/src/cl/svc/CL_CHKVOID.pgc | 53 + app/src/cl/svc/CL_CHNVERIFY.pgc | 53 + app/src/cl/svc/CL_CNTVERIFY.pgc | 53 + app/src/cl/svc/CL_CNTXCHECK.pgc | 53 + app/src/cl/svc/CL_CORPCLOSE.pgc | 53 + app/src/cl/svc/CL_CORPVERIFY.pgc | 53 + app/src/cl/svc/CL_DAILY.pgc | 106 + app/src/cl/svc/CL_DAYVERIFY.pgc | 53 + app/src/cl/svc/CL_DIFFCHK.pgc | 53 + app/src/cl/svc/CL_DIVCLOSE.pgc | 53 + app/src/cl/svc/CL_DUPCHK.pgc | 53 + app/src/cl/svc/CL_FEECROSS.pgc | 53 + app/src/cl/svc/CL_FEEVERIFY.pgc | 53 + app/src/cl/svc/CL_FORCECLOSE.pgc | 53 + app/src/cl/svc/CL_HALFCLOSE.pgc | 53 + app/src/cl/svc/CL_HYVERIFY.pgc | 53 + app/src/cl/svc/CL_MAINCLOSE.pgc | 53 + app/src/cl/svc/CL_MERCLOSE.pgc | 53 + app/src/cl/svc/CL_MERXCHECK.pgc | 53 + app/src/cl/svc/CL_MIDCLOSE.pgc | 53 + app/src/cl/svc/CL_MONTHLY.pgc | 53 + app/src/cl/svc/CL_MONVERIFY.pgc | 53 + app/src/cl/svc/CL_NETCROSS.pgc | 53 + app/src/cl/svc/CL_NETVERIFY.pgc | 53 + app/src/cl/svc/CL_POSTTRIG.pgc | 53 + app/src/cl/svc/CL_PRECHECK.pgc | 53 + app/src/cl/svc/CL_QTRVERIFY.pgc | 53 + app/src/cl/svc/CL_QUARTER.pgc | 53 + app/src/cl/svc/CL_RECLOSE.pgc | 53 + app/src/cl/svc/CL_RECON.pgc | 53 + app/src/cl/svc/CL_ROLLBACK.pgc | 53 + app/src/cl/svc/CL_SEGVERIFY.pgc | 53 + app/src/cl/svc/CL_SEMIMONTH.pgc | 53 + app/src/cl/svc/CL_SNAPSHOT.pgc | 53 + app/src/cl/svc/CL_SNAPXCHECK.pgc | 53 + app/src/cl/svc/CL_STCROSS.pgc | 53 + app/src/cl/svc/CL_TENDAY.pgc | 53 + app/src/cl/svc/CL_TRIGSETTLE.pgc | 53 + app/src/cl/svc/CL_VERIFY.pgc | 53 + app/src/cl/svc/CL_WEEKLY.pgc | 53 + app/src/cl/svc/CL_WEEKVERIFY.pgc | 53 + app/src/cl/svc/CL_YEAREND.pgc | 53 + app/src/cl/svc/CL_YEARVERIFY.pgc | 53 + app/src/cm/dbio/cm_code_dbio.pgc | 9 +- app/src/cm/dbio/cm_param_dbio.pgc | 15 +- app/src/cm/svc/CM_ADDDAYS.pgc | 47 + app/src/cm/svc/CM_BATDEP_CHK.pgc | 52 + app/src/cm/svc/CM_BATDEP_SET.pgc | 48 + app/src/cm/svc/CM_BATHIST_CNT.pgc | 58 + app/src/cm/svc/CM_BATRERUN_REQ.pgc | 52 + app/src/cm/svc/CM_BATSCHD_DEL.pgc | 50 + app/src/cm/svc/CM_BATSCHD_REG.pgc | 48 + app/src/cm/svc/CM_BIZDAY_ADD.pgc | 49 + app/src/cm/svc/CM_BIZDAY_CNT.pgc | 51 + app/src/cm/svc/CM_CACHE_INV.pgc | 45 + app/src/cm/svc/CM_CACHE_LOAD.pgc | 47 + app/src/cm/svc/CM_CODE.pgc | 45 + app/src/cm/svc/CM_CODEGRP_REG.pgc | 45 + app/src/cm/svc/CM_ERRMSG.pgc | 48 + app/src/cm/svc/CM_FX_CONV.pgc | 50 + app/src/cm/svc/CM_FX_CROSS.pgc | 54 + app/src/cm/svc/CM_FX_INVERT.pgc | 52 + app/src/cm/svc/CM_FX_MARGIN.pgc | 54 + app/src/cm/svc/CM_FX_PUBLISH.pgc | 48 + app/src/cm/svc/CM_FX_TRIANGLE.pgc | 52 + app/src/cm/svc/CM_MONTHEND.pgc | 49 + app/src/cm/svc/CM_MSG_RENDER.pgc | 48 + app/src/cm/svc/CM_NEXTBIZ.pgc | 47 + app/src/cm/svc/CM_NOTI_QUOTA.pgc | 54 + app/src/cm/svc/CM_NOTI_RETRY.pgc | 50 + app/src/cm/svc/CM_NOTI_SEND.pgc | 50 + app/src/cm/svc/CM_NOTI_TMPL.pgc | 50 + app/src/cm/svc/CM_PREVBIZ.pgc | 49 + app/src/cm/svc/CM_SEQ.pgc | 50 + app/src/cm/svc/CM_SEQ_ALLOC.pgc | 54 + app/src/cm/svc/CM_SEQ_DAILY.pgc | 52 + app/src/cm/svc/CM_SEQ_MULTI.pgc | 54 + app/src/cm/svc/CM_SEQ_RESET.pgc | 50 + app/src/cm/svc/CM_SEQ_STAMP.pgc | 52 + app/src/cm/svc/CM_SEQ_TYPED.pgc | 52 + app/src/lg/svc/LG_ACCRUEREV.pgc | 53 + app/src/lg/svc/LG_ACCTSUM.pgc | 58 + app/src/lg/svc/LG_ACQPOST.pgc | 53 + app/src/lg/svc/LG_ADJUST.pgc | 53 + app/src/lg/svc/LG_ALLOWANCE.pgc | 53 + app/src/lg/svc/LG_ALLOWRECALC.pgc | 53 + app/src/lg/svc/LG_BADDEBT.pgc | 53 + app/src/lg/svc/LG_BADDEBTRCV.pgc | 53 + app/src/lg/svc/LG_BALCERT.pgc | 53 + app/src/lg/svc/LG_BALPROOF.pgc | 53 + app/src/lg/svc/LG_BLACKENTRY.pgc | 53 + app/src/lg/svc/LG_BSSUMMARY.pgc | 53 + app/src/lg/svc/LG_CLOSE_LINK.pgc | 53 + app/src/lg/svc/LG_CORPSUM.pgc | 53 + app/src/lg/svc/LG_CORRECT.pgc | 53 + app/src/lg/svc/LG_DEPTSUM.pgc | 53 + app/src/lg/svc/LG_DOUBLE.pgc | 53 + app/src/lg/svc/LG_FEEACCRUE.pgc | 53 + app/src/lg/svc/LG_FEEPOST.pgc | 53 + app/src/lg/svc/LG_HALFCLOSE.pgc | 53 + app/src/lg/svc/LG_MERCHBAL.pgc | 53 + app/src/lg/svc/LG_MERCHPROOF.pgc | 53 + app/src/lg/svc/LG_MONTHCLOSE.pgc | 53 + app/src/lg/svc/LG_MONTHLYSUM.pgc | 53 + app/src/lg/svc/LG_PARTREVERSE.pgc | 53 + app/src/lg/svc/LG_PERIODTB.pgc | 53 + app/src/lg/svc/LG_PLSUMMARY.pgc | 53 + app/src/lg/svc/LG_POST.pgc | 53 + app/src/lg/svc/LG_PREPAIDAMORT.pgc | 53 + app/src/lg/svc/LG_PREPAIDPOST.pgc | 53 + app/src/lg/svc/LG_QTRCLOSE.pgc | 53 + app/src/lg/svc/LG_RECALC.pgc | 19 +- app/src/lg/svc/LG_REDADJUST.pgc | 53 + app/src/lg/svc/LG_REDBLACKNET.pgc | 53 + app/src/lg/svc/LG_REDENTRY.pgc | 53 + app/src/lg/svc/LG_REPOST.pgc | 53 + app/src/lg/svc/LG_REVERSE.pgc | 53 + app/src/lg/svc/LG_ROLLTB.pgc | 53 + app/src/lg/svc/LG_SETTLEPOST.pgc | 53 + app/src/lg/svc/LG_SPANTB.pgc | 53 + app/src/lg/svc/LG_SUSPENSE.pgc | 53 + app/src/lg/svc/LG_TRANSFER.pgc | 53 + app/src/lg/svc/LG_TRIALBAL.pgc | 53 + app/src/lg/svc/LG_UNEARNPOST.pgc | 53 + app/src/lg/svc/LG_UNEARNRECOG.pgc | 53 + app/src/lg/svc/LG_VOUCHER.pgc | 53 + app/src/lg/svc/LG_WEEKCLOSE.pgc | 53 + app/src/lg/svc/LG_WRITEOFF.pgc | 53 + app/src/lg/svc/LG_XFERPOST.pgc | 53 + app/src/lg/svc/LG_YEARCLOSE.pgc | 53 + app/src/mg/dbio/mg_bump_stan_dbio.pgc | 41 +- app/src/mg/svc/MG_ACK.pgc | 94 +- app/src/mg/svc/MG_ADVICE.pgc | 38 +- app/src/mg/svc/MG_AMTCHECK.pgc | 38 +- app/src/mg/svc/MG_AUTHREQ.pgc | 38 +- app/src/mg/svc/MG_AUTHRSP.pgc | 38 +- app/src/mg/svc/MG_BITMAP.pgc | 94 +- app/src/mg/svc/MG_BMPPARSE.pgc | 58 + app/src/mg/svc/MG_CAPRSP.pgc | 38 +- app/src/mg/svc/MG_CAPTURE.pgc | 38 +- app/src/mg/svc/MG_CHANAUTH.pgc | 38 +- app/src/mg/svc/MG_CHANFAILOVER.pgc | 58 + app/src/mg/svc/MG_CHANHEALTH.pgc | 96 +- app/src/mg/svc/MG_CHANLIST.pgc | 38 +- app/src/mg/svc/MG_CHANOPEN.pgc | 58 + app/src/mg/svc/MG_CHANPING.pgc | 70 +- app/src/mg/svc/MG_CHANSTAT.pgc | 38 +- app/src/mg/svc/MG_CHANSWITCH.pgc | 60 + app/src/mg/svc/MG_CONFIRM.pgc | 38 +- app/src/mg/svc/MG_CONVERT.pgc | 38 +- app/src/mg/svc/MG_DECODE.pgc | 58 + app/src/mg/svc/MG_DEQUEUE.pgc | 38 +- app/src/mg/svc/MG_DIRECTADPT.pgc | 38 +- app/src/mg/svc/MG_DUPCHK.pgc | 38 +- app/src/mg/svc/MG_DUPPURGE.pgc | 38 +- app/src/mg/svc/MG_ECHO.pgc | 38 +- app/src/mg/svc/MG_ENCODE.pgc | 58 + app/src/mg/svc/MG_ERRESCAL.pgc | 38 +- app/src/mg/svc/MG_ERRLIST.pgc | 38 +- app/src/mg/svc/MG_ERRMSG.pgc | 38 +- app/src/mg/svc/MG_ERRPURGE.pgc | 38 +- app/src/mg/svc/MG_ERRREQUEUE.pgc | 96 +- app/src/mg/svc/MG_ERRRETRY.pgc | 94 +- app/src/mg/svc/MG_FROMISO.pgc | 98 +- app/src/mg/svc/MG_GAPSCAN.pgc | 38 +- app/src/mg/svc/MG_HEALTH.pgc | 38 +- app/src/mg/svc/MG_INFLIGHT.pgc | 38 +- app/src/mg/svc/MG_ISO8583.pgc | 96 +- app/src/mg/svc/MG_KEYCHECK.pgc | 94 +- app/src/mg/svc/MG_KEYEXCH.pgc | 38 +- app/src/mg/svc/MG_KEYEXPIRE.pgc | 38 +- app/src/mg/svc/MG_KEYLOAD.pgc | 94 +- app/src/mg/svc/MG_KEYROTATE.pgc | 38 +- app/src/mg/svc/MG_KEYSTATUS.pgc | 38 +- app/src/mg/svc/MG_LOADBAL.pgc | 96 +- app/src/mg/svc/MG_LOG.pgc | 38 +- app/src/mg/svc/MG_MAC.pgc | 92 +- app/src/mg/svc/MG_MACGEN.pgc | 94 +- app/src/mg/svc/MG_MACSESSION.pgc | 92 +- app/src/mg/svc/MG_MACVERIFY.pgc | 92 +- app/src/mg/svc/MG_NACK.pgc | 94 +- app/src/mg/svc/MG_NETMGMT.pgc | 38 +- app/src/mg/svc/MG_PACK.pgc | 96 +- app/src/mg/svc/MG_PANMASK.pgc | 38 +- app/src/mg/svc/MG_PARSE.pgc | 100 +- app/src/mg/svc/MG_QDEPTH.pgc | 38 +- app/src/mg/svc/MG_QUEUE.pgc | 38 +- app/src/mg/svc/MG_RATELIMIT.pgc | 38 +- app/src/mg/svc/MG_READYZ.pgc | 38 +- app/src/mg/svc/MG_REASM.pgc | 98 +- app/src/mg/svc/MG_RECV.pgc | 96 +- app/src/mg/svc/MG_RESEND.pgc | 94 +- app/src/mg/svc/MG_RESNDONE.pgc | 94 +- app/src/mg/svc/MG_RETRY.pgc | 38 +- app/src/mg/svc/MG_REVADVICE.pgc | 56 +- app/src/mg/svc/MG_REVERSAL.pgc | 38 +- app/src/mg/svc/MG_ROUTE.pgc | 94 +- app/src/mg/svc/MG_RTADD.pgc | 38 +- app/src/mg/svc/MG_RTCOUNT.pgc | 38 +- app/src/mg/svc/MG_RTDISABLE.pgc | 38 +- app/src/mg/svc/MG_RTDROP.pgc | 38 +- app/src/mg/svc/MG_RTENABLE.pgc | 38 +- app/src/mg/svc/MG_RTFIND.pgc | 38 +- app/src/mg/svc/MG_RTLIST.pgc | 38 +- app/src/mg/svc/MG_RTSWITCH.pgc | 38 +- app/src/mg/svc/MG_SEND.pgc | 96 +- app/src/mg/svc/MG_SEQAUDIT.pgc | 38 +- app/src/mg/svc/MG_SEQFILL.pgc | 108 +- app/src/mg/svc/MG_SEQNEXT.pgc | 94 +- app/src/mg/svc/MG_SEQRESET.pgc | 63 +- app/src/mg/svc/MG_SESSION.pgc | 38 +- app/src/mg/svc/MG_SETTLEREQ.pgc | 38 +- app/src/mg/svc/MG_SETTLERSP.pgc | 38 +- app/src/mg/svc/MG_STALEMARK.pgc | 38 +- app/src/mg/svc/MG_STAN.pgc | 38 +- app/src/mg/svc/MG_STATAMT.pgc | 38 +- app/src/mg/svc/MG_STATCHAN.pgc | 38 +- app/src/mg/svc/MG_STATDIR.pgc | 38 +- app/src/mg/svc/MG_STATERR.pgc | 38 +- app/src/mg/svc/MG_STATHOUR.pgc | 38 +- app/src/mg/svc/MG_STATMTI.pgc | 38 +- app/src/mg/svc/MG_STATPEAK.pgc | 38 +- app/src/mg/svc/MG_STATRC.pgc | 38 +- app/src/mg/svc/MG_STATS.pgc | 38 +- app/src/mg/svc/MG_STATSUM.pgc | 38 +- app/src/mg/svc/MG_STATUS.pgc | 38 +- app/src/mg/svc/MG_THROTTLE.pgc | 38 +- app/src/mg/svc/MG_TIMEOUT.pgc | 38 +- app/src/mg/svc/MG_TIMEOUTSET.pgc | 38 +- app/src/mg/svc/MG_TOISO.pgc | 96 +- app/src/mg/svc/MG_TPSCHECK.pgc | 38 +- app/src/mg/svc/MG_UNPACK.pgc | 94 +- app/src/mg/svc/MG_VAN1ADPT.pgc | 38 +- app/src/mg/svc/MG_VAN2ADPT.pgc | 38 +- app/src/mm/svc/MM_ACCT_REG.pgc | 37 + app/src/mm/svc/MM_ACCT_VERIFY.pgc | 39 + app/src/mm/svc/MM_APPLY_APPROVE.pgc | 31 + app/src/mm/svc/MM_APPLY_REG.pgc | 39 + app/src/mm/svc/MM_BIN_REG.pgc | 28 + app/src/mm/svc/MM_BIZNO_CHECK.pgc | 40 + app/src/mm/svc/MM_CHK_LIMIT.pgc | 34 + app/src/mm/svc/MM_CODE_REG.pgc | 31 + app/src/mm/svc/MM_CONTRACT_AMEND.pgc | 39 + app/src/mm/svc/MM_CONTRACT_NEW.pgc | 39 + app/src/mm/svc/MM_CONTRACT_RENEW.pgc | 41 + app/src/mm/svc/MM_FEERATE_SET.pgc | 31 + app/src/mm/svc/MM_GRADE_ADJUST.pgc | 32 + app/src/mm/svc/MM_ISSUER_REG.pgc | 28 + app/src/mm/svc/MM_LIMIT_SET.pgc | 28 + app/src/mm/svc/MM_MCC_REG.pgc | 31 + app/src/mm/svc/MM_MCC_UPD.pgc | 33 + app/src/mm/svc/MM_MERCH_CLOSE.pgc | 44 + app/src/mm/svc/MM_MERCH_DORMANT.pgc | 44 + app/src/mm/svc/MM_MERCH_GRADE.pgc | 30 + app/src/mm/svc/MM_MERCH_PAUSE.pgc | 44 + app/src/mm/svc/MM_MERCH_REG.pgc | 31 + app/src/mm/svc/MM_MERCH_RESUME.pgc | 44 + app/src/mm/svc/MM_MERCH_STATUS.pgc | 29 + app/src/mm/svc/MM_MERCH_UPD.pgc | 29 + app/src/mm/svc/MM_RATE_APPROVE.pgc | 37 + app/src/mm/svc/MM_RATE_REQ.pgc | 44 + app/src/mm/svc/MM_RISK_SCORE.pgc | 44 + app/src/mm/svc/MM_RISK_SET.pgc | 30 + app/src/mm/svc/MM_TERMINAL_REG.pgc | 37 + app/src/mm/svc/MM_TERM_INSTALL.pgc | 39 + app/src/mm/svc/MM_VALIDATE.pgc | 42 + app/src/py/dbio/py_payout_reject_dbio.pgc | 9 +- app/src/py/svc/PAY_ACCTCHK.pgc | 61 + app/src/py/svc/PAY_ACCTVERIFY.pgc | 70 + app/src/py/svc/PAY_ADJUST.pgc | 66 + app/src/py/svc/PAY_APPRBULK.pgc | 98 + app/src/py/svc/PAY_APPROVE.pgc | 98 + app/src/py/svc/PAY_BANKFILE.pgc | 68 + app/src/py/svc/PAY_BANKVERIFY.pgc | 70 + app/src/py/svc/PAY_CANCEL.pgc | 126 + app/src/py/svc/PAY_CHARGEBACK.pgc | 61 + app/src/py/svc/PAY_CLOSE.pgc | 61 + app/src/py/svc/PAY_COMBINE.pgc | 70 + app/src/py/svc/PAY_CONFIRM.pgc | 61 + app/src/py/svc/PAY_FILEGEN.pgc | 122 +- app/src/py/svc/PAY_FILEREBUILD.pgc | 70 + app/src/py/svc/PAY_HOLD.pgc | 66 + app/src/py/svc/PAY_MERGE.pgc | 70 + app/src/py/svc/PAY_NETOFF.pgc | 61 + app/src/py/svc/PAY_RECLAIM.pgc | 126 + app/src/py/svc/PAY_REFUND.pgc | 61 + app/src/py/svc/PAY_RELEASE.pgc | 66 + app/src/py/svc/PAY_REMIT.pgc | 68 + app/src/py/svc/PAY_REPROC.pgc | 66 + app/src/py/svc/PAY_REQUEUE.pgc | 68 + app/src/py/svc/PAY_RESULT.pgc | 61 + app/src/py/svc/PAY_RESVMODIFY.pgc | 64 + app/src/py/svc/PAY_RETRY.pgc | 66 + app/src/py/svc/PAY_RETRYONE.pgc | 66 + app/src/py/svc/PAY_REVERSE.pgc | 126 + app/src/py/svc/PAY_ROLLFWD.pgc | 64 + app/src/py/svc/PAY_SCHEDULE.pgc | 64 + app/src/py/svc/PAY_SPLIT.pgc | 70 + app/src/py/svc/PAY_SPLITEVEN.pgc | 70 + app/src/py/svc/PAY_SPLITRATIO.pgc | 70 + app/src/py/svc/PAY_URGENT.pgc | 70 + app/src/py/svc/PAY_VOIDONE.pgc | 61 + app/src/py/svc/PAY_XFERLINK.pgc | 68 + app/src/rc/svc/RC_3WAY.pgc | 33 + app/src/rc/svc/RC_4WAY.pgc | 25 + app/src/rc/svc/RC_ACQMATCH.pgc | 25 + app/src/rc/svc/RC_ACQ_DEP.pgc | 25 + app/src/rc/svc/RC_ALERT.pgc | 38 +- app/src/rc/svc/RC_AMTDIFF.pgc | 25 + app/src/rc/svc/RC_APPRGAP.pgc | 29 + app/src/rc/svc/RC_APPRMATCH.pgc | 25 + app/src/rc/svc/RC_APPR_ACQ.pgc | 25 + app/src/rc/svc/RC_AUTOFIX.pgc | 29 + app/src/rc/svc/RC_CLOSEDAY.pgc | 25 + app/src/rc/svc/RC_CNTDIFF.pgc | 25 + app/src/rc/svc/RC_CONFIRM.pgc | 25 + app/src/rc/svc/RC_DEPGAP.pgc | 29 + app/src/rc/svc/RC_DEPMATCH.pgc | 25 + app/src/rc/svc/RC_DUPCHK.pgc | 25 + app/src/rc/svc/RC_ESCALATE.pgc | 25 + app/src/rc/svc/RC_EXCEPTION.pgc | 38 +- app/src/rc/svc/RC_EXCNOTIFY.pgc | 25 + app/src/rc/svc/RC_FEEDIFF.pgc | 25 + app/src/rc/svc/RC_FEERECON.pgc | 25 + app/src/rc/svc/RC_FIXFEE.pgc | 29 + app/src/rc/svc/RC_FIXFX.pgc | 29 + app/src/rc/svc/RC_FIXROUND.pgc | 29 + app/src/rc/svc/RC_FXDIFF.pgc | 25 + app/src/rc/svc/RC_FXRECON.pgc | 25 + app/src/rc/svc/RC_HOLDCLR.pgc | 25 + app/src/rc/svc/RC_HOLDSET.pgc | 25 + app/src/rc/svc/RC_LEDGERBAL.pgc | 25 + app/src/rc/svc/RC_LEDGERLINK.pgc | 25 + app/src/rc/svc/RC_LIMITCHK.pgc | 25 + app/src/rc/svc/RC_MANUAL.pgc | 25 + app/src/rc/svc/RC_NOTIFY.pgc | 25 + app/src/rc/svc/RC_ORPHAN.pgc | 29 + app/src/rc/svc/RC_OVERAMT.pgc | 29 + app/src/rc/svc/RC_PAYLEDGER.pgc | 25 + app/src/rc/svc/RC_PAYMATCH.pgc | 25 + app/src/rc/svc/RC_PROGRESS.pgc | 25 + app/src/rc/svc/RC_RECORR.pgc | 29 + app/src/rc/svc/RC_REDIFF.pgc | 29 + app/src/rc/svc/RC_REFULL.pgc | 25 + app/src/rc/svc/RC_RELEASE.pgc | 25 + app/src/rc/svc/RC_REMATCH.pgc | 38 +- app/src/rc/svc/RC_REPROC.pgc | 38 +- app/src/rc/svc/RC_RERUN.pgc | 25 + app/src/rc/svc/RC_ROUNDDIFF.pgc | 29 + app/src/rc/svc/RC_SNAPSHOT.pgc | 25 + app/src/rc/svc/RC_STATUS.pgc | 25 + app/src/rc/svc/RC_SUMCHK.pgc | 25 + app/src/rc/svc/RC_TOLERANCE.pgc | 25 + app/src/rc/svc/RC_UNDERAMT.pgc | 29 + app/src/rc/svc/RC_UNMATCH.pgc | 25 + app/src/st/svc/SETTLE.pgc | 66 + app/src/st/svc/ST_ADJHIST.pgc | 2 +- app/src/st/svc/ST_ADJREVERSE.pgc | 63 +- app/src/st/svc/ST_ADJUST.pgc | 63 +- app/src/st/svc/ST_ADVANCE.pgc | 2 +- app/src/st/svc/ST_APPEALSTAT.pgc | 2 +- app/src/st/svc/ST_APPROVE.pgc | 68 +- app/src/st/svc/ST_APPROVEALL.pgc | 68 +- app/src/st/svc/ST_BADDEBT.pgc | 2 +- app/src/st/svc/ST_BANDRATE.pgc | 2 +- app/src/st/svc/ST_BANDSIM.pgc | 2 +- app/src/st/svc/ST_BIWEEKLY.pgc | 2 +- app/src/st/svc/ST_BYMERCH.pgc | 2 +- app/src/st/svc/ST_CANCEL.pgc | 63 +- app/src/st/svc/ST_CAP.pgc | 2 +- app/src/st/svc/ST_CAPCHECK.pgc | 63 +- app/src/st/svc/ST_CARRYOVER.pgc | 2 +- app/src/st/svc/ST_CASHBACK.pgc | 2 +- app/src/st/svc/ST_CHAINSET.pgc | 2 +- app/src/st/svc/ST_CHARGEBACK.pgc | 63 +- app/src/st/svc/ST_CHNLSTAT.pgc | 2 +- app/src/st/svc/ST_COLLATERAL.pgc | 2 +- app/src/st/svc/ST_CONFIRM.pgc | 68 +- app/src/st/svc/ST_COUPONADJ.pgc | 2 +- app/src/st/svc/ST_CXLRECALC.pgc | 68 +- app/src/st/svc/ST_CYCLED1.pgc | 2 +- app/src/st/svc/ST_CYCLED2.pgc | 2 +- app/src/st/svc/ST_CYCLED3.pgc | 2 +- app/src/st/svc/ST_CYCLEMON.pgc | 2 +- app/src/st/svc/ST_CYCLEQTR.pgc | 2 +- app/src/st/svc/ST_CYCLESET.pgc | 2 +- app/src/st/svc/ST_CYCLEWEEK.pgc | 2 +- app/src/st/svc/ST_DAILYCLOSE.pgc | 63 +- app/src/st/svc/ST_DEBTCOLLECT.pgc | 2 +- app/src/st/svc/ST_DEBTNET.pgc | 2 +- app/src/st/svc/ST_DELAYINT.pgc | 2 +- app/src/st/svc/ST_DEPOSITCUT.pgc | 2 +- app/src/st/svc/ST_DEPOSITSET.pgc | 2 +- app/src/st/svc/ST_DIFFCHK.pgc | 63 +- app/src/st/svc/ST_DISPUTE.pgc | 2 +- app/src/st/svc/ST_DISPUTERSV.pgc | 2 +- app/src/st/svc/ST_DTLSUM.pgc | 2 +- app/src/st/svc/ST_EDIRECON.pgc | 2 +- app/src/st/svc/ST_EVENTFEE.pgc | 2 +- app/src/st/svc/ST_FEEPREVIEW.pgc | 2 +- app/src/st/svc/ST_FEERATIO.pgc | 2 +- app/src/st/svc/ST_FLATFEE.pgc | 2 +- app/src/st/svc/ST_FLATVSPCT.pgc | 2 +- app/src/st/svc/ST_FXCONV.pgc | 2 +- app/src/st/svc/ST_FXSETTLE.pgc | 2 +- app/src/st/svc/ST_GRADESTAT.pgc | 2 +- app/src/st/svc/ST_GROWTHINC.pgc | 2 +- app/src/st/svc/ST_GRPALLOC.pgc | 2 +- app/src/st/svc/ST_GRPROLLUP.pgc | 2 +- app/src/st/svc/ST_GRPSETTLE.pgc | 63 +- app/src/st/svc/ST_HOLD.pgc | 63 +- app/src/st/svc/ST_HOLDAMT.pgc | 2 +- app/src/st/svc/ST_INSTANTPAY.pgc | 68 +- app/src/st/svc/ST_ISSUERSTAT.pgc | 2 +- app/src/st/svc/ST_LEDGERLINK.pgc | 63 +- app/src/st/svc/ST_LEDGERSNAP.pgc | 2 +- app/src/st/svc/ST_LIMITCHK.pgc | 63 +- app/src/st/svc/ST_LOCKBATCH.pgc | 2 +- app/src/st/svc/ST_LOYALTY.pgc | 2 +- app/src/st/svc/ST_MDR.pgc | 61 + app/src/st/svc/ST_MERCHRATE.pgc | 2 +- app/src/st/svc/ST_MINFEE.pgc | 2 +- app/src/st/svc/ST_MKTGSHARE.pgc | 2 +- app/src/st/svc/ST_MONTHLY.pgc | 2 +- app/src/st/svc/ST_MONTHSTAT.pgc | 2 +- app/src/st/svc/ST_NEGSWEEP.pgc | 2 +- app/src/st/svc/ST_NETTING.pgc | 63 +- app/src/st/svc/ST_NEXTPAYDT.pgc | 66 +- app/src/st/svc/ST_OFFSET.pgc | 63 +- app/src/st/svc/ST_PARTIAL.pgc | 2 +- app/src/st/svc/ST_PARTNERSET.pgc | 2 +- app/src/st/svc/ST_PARTPAY.pgc | 2 +- app/src/st/svc/ST_PAYDATE.pgc | 66 +- app/src/st/svc/ST_PAYRETRY.pgc | 2 +- app/src/st/svc/ST_PAYSTATUS.pgc | 2 +- app/src/st/svc/ST_PCTFEE.pgc | 2 +- app/src/st/svc/ST_PRECONFIRM.pgc | 63 +- app/src/st/svc/ST_PROMOAPPLY.pgc | 2 +- app/src/st/svc/ST_PROMOCALC.pgc | 2 +- app/src/st/svc/ST_RATEAPPLY.pgc | 68 +- app/src/st/svc/ST_RATECARD.pgc | 2 +- app/src/st/svc/ST_RATECMP.pgc | 2 +- app/src/st/svc/ST_RATEFLOOR.pgc | 2 +- app/src/st/svc/ST_RATEMAX.pgc | 2 +- app/src/st/svc/ST_RATESIM.pgc | 2 +- app/src/st/svc/ST_REBATE.pgc | 2 +- app/src/st/svc/ST_RECALC.pgc | 68 +- app/src/st/svc/ST_RECVAGE.pgc | 2 +- app/src/st/svc/ST_RECVOFFSET.pgc | 2 +- app/src/st/svc/ST_RECVSTAT.pgc | 2 +- app/src/st/svc/ST_REFERRAL.pgc | 2 +- app/src/st/svc/ST_REFUNDCALC.pgc | 63 +- app/src/st/svc/ST_RELAYFEE.pgc | 2 +- app/src/st/svc/ST_RELAYSPLIT.pgc | 2 +- app/src/st/svc/ST_RELEASE.pgc | 63 +- app/src/st/svc/ST_REOPEN.pgc | 2 +- app/src/st/svc/ST_REPARTIAL.pgc | 2 +- app/src/st/svc/ST_REPORT.pgc | 2 +- app/src/st/svc/ST_RERUN.pgc | 68 +- app/src/st/svc/ST_RETRORATE.pgc | 2 +- app/src/st/svc/ST_ROUNDING.pgc | 2 +- app/src/st/svc/ST_SLABFEE.pgc | 2 +- app/src/st/svc/ST_SPLIT.pgc | 2 +- app/src/st/svc/ST_SPLITEVEN.pgc | 2 +- app/src/st/svc/ST_STATDETAIL.pgc | 2 +- app/src/st/svc/ST_STATS.pgc | 2 +- app/src/st/svc/ST_STATUS.pgc | 2 +- app/src/st/svc/ST_SUPPLYCALC.pgc | 2 +- app/src/st/svc/ST_TAXINVCHK.pgc | 63 +- app/src/st/svc/ST_TAXSUMMARY.pgc | 2 +- app/src/st/svc/ST_TIERFEE.pgc | 2 +- app/src/st/svc/ST_TIERINCENT.pgc | 2 +- app/src/st/svc/ST_TOPMERCH.pgc | 2 +- app/src/st/svc/ST_UNLOCK.pgc | 2 +- app/src/st/svc/ST_UNPAIDSUM.pgc | 2 +- app/src/st/svc/ST_VANDETAIL.pgc | 2 +- app/src/st/svc/ST_VANFEE.pgc | 2 +- app/src/st/svc/ST_VAT.pgc | 68 +- app/src/st/svc/ST_VATADJUST.pgc | 63 +- app/src/st/svc/ST_VATDETAIL.pgc | 2 +- app/src/st/svc/ST_VATREPORT.pgc | 2 +- app/src/st/svc/ST_VOIDRECALC.pgc | 63 +- app/src/st/svc/ST_VOLREBATE.pgc | 2 +- app/src/st/svc/ST_WHT.pgc | 68 +- app/src/st/svc/ST_WHTDETAIL.pgc | 2 +- app/src/st/svc/ST_WHTREPORT.pgc | 2 +- app/src/st/svc/ST_WORKFLOW.pgc | 2 +- app/src/st/svc/ST_XFERLINK.pgc | 63 +- app/src/vl/svc/VL_AMOUNT.pgc | 27 + app/src/vl/svc/VL_ANOMALY.pgc | 31 + app/src/vl/svc/VL_APPRAMT.pgc | 27 + app/src/vl/svc/VL_APPRNOPUR.pgc | 31 + app/src/vl/svc/VL_APPR_ACQ.pgc | 27 + app/src/vl/svc/VL_AXPURAPPR.pgc | 27 + app/src/vl/svc/VL_AXSETTPAY.pgc | 27 + app/src/vl/svc/VL_BALANCE.pgc | 31 + app/src/vl/svc/VL_BATCH_CHK.pgc | 27 + app/src/vl/svc/VL_BIN.pgc | 35 + app/src/vl/svc/VL_CARD.pgc | 27 + app/src/vl/svc/VL_CROSSCHK.pgc | 43 + app/src/vl/svc/VL_DAYLIMIT.pgc | 31 + app/src/vl/svc/VL_DUP.pgc | 35 + app/src/vl/svc/VL_DUPAPPR.pgc | 31 + app/src/vl/svc/VL_DUPAUTH.pgc | 35 + app/src/vl/svc/VL_DUPLEDGR.pgc | 31 + app/src/vl/svc/VL_DUPPAY.pgc | 35 + app/src/vl/svc/VL_DUPPURCH.pgc | 27 + app/src/vl/svc/VL_DUPSETTLE.pgc | 35 + app/src/vl/svc/VL_EXPIRY.pgc | 35 + app/src/vl/svc/VL_FEE.pgc | 27 + app/src/vl/svc/VL_FEERECALC.pgc | 27 + app/src/vl/svc/VL_FORMAT.pgc | 27 + app/src/vl/svc/VL_FXCHK.pgc | 27 + app/src/vl/svc/VL_LEDGBAL.pgc | 31 + app/src/vl/svc/VL_LEDGENTRY.pgc | 27 + app/src/vl/svc/VL_LEDGER.pgc | 27 + app/src/vl/svc/VL_LIMIT.pgc | 31 + app/src/vl/svc/VL_MDRRATE.pgc | 27 + app/src/vl/svc/VL_NEGBAL.pgc | 35 + app/src/vl/svc/VL_NEGFEE.pgc | 35 + app/src/vl/svc/VL_NEGNET.pgc | 35 + app/src/vl/svc/VL_NIGHTTXN.pgc | 31 + app/src/vl/svc/VL_OUTLIER.pgc | 31 + app/src/vl/svc/VL_OVERLIMIT.pgc | 31 + app/src/vl/svc/VL_PURNOAPPR.pgc | 31 + app/src/vl/svc/VL_REFINTEG.pgc | 27 + app/src/vl/svc/VL_RIAPPR.pgc | 27 + app/src/vl/svc/VL_RICANCEL.pgc | 27 + app/src/vl/svc/VL_RIFX.pgc | 27 + app/src/vl/svc/VL_RIINSTALL.pgc | 27 + app/src/vl/svc/VL_RILEDGER.pgc | 27 + app/src/vl/svc/VL_RIMERCH.pgc | 27 + app/src/vl/svc/VL_RIPAY.pgc | 27 + app/src/vl/svc/VL_RIPURCH.pgc | 27 + app/src/vl/svc/VL_RISETTLE.pgc | 27 + app/src/vl/svc/VL_RITAXINV.pgc | 27 + app/src/vl/svc/VL_SALES.pgc | 35 + app/src/vl/svc/VL_SETTLE.pgc | 35 + app/src/vl/svc/VL_SPIKEAMT.pgc | 31 + app/src/vl/svc/VL_STATUS_CHK.pgc | 27 + app/src/vl/svc/VL_SUMFEECHK.pgc | 27 + app/src/vl/svc/VL_SUMGROSS.pgc | 27 + app/src/vl/svc/VL_SUMRECON.pgc | 27 + app/src/vl/svc/VL_SUMTXNCNT.pgc | 27 + app/src/vl/svc/VL_SUSPACT.pgc | 31 + app/src/vl/svc/VL_SUSPESCAL.pgc | 35 + app/src/vl/svc/VL_THRESHOLD.pgc | 31 + app/src/vl/svc/VL_VELOCITY.pgc | 31 + app/src/vl/svc/VL_ZERONET.pgc | 35 + app/ui/index.html | 6345 ++++++++++++++++++--- app/ui/screens.js | 6321 +++++++++++++++++--- 654 files changed, 36008 insertions(+), 2805 deletions(-) diff --git a/app/build.sh b/app/build.sh index c4eae8c..b92bde5 100644 --- a/app/build.sh +++ b/app/build.sh @@ -170,8 +170,11 @@ gen_servers() { cat < ${srvid} - 1 - 1 + + 4 + 4 -e \${NDRX_APPHOME}/log/${m}_svr.log -r EOF @@ -208,7 +211,7 @@ cat > "$CONF/ndrxconfig.xml" <40 1 1 - -e \${NDRX_APPHOME}/log/tmsrv-rm1.log -r -- -t1 -l\${NDRX_APPHOME}/tmlogs/rm1 -m10 + -e \${NDRX_APPHOME}/log/tmsrv-rm1.log -r -- -t3 -l\${NDRX_APPHOME}/tmlogs/rm1 -m20 $(gen_servers) diff --git a/app/conf/ndrxconfig.xml b/app/conf/ndrxconfig.xml index 9809bae..9b359b2 100644 --- a/app/conf/ndrxconfig.xml +++ b/app/conf/ndrxconfig.xml @@ -27,72 +27,105 @@ 40 1 1 - -e ${NDRX_APPHOME}/log/tmsrv-rm1.log -r -- -t1 -l${NDRX_APPHOME}/tmlogs/rm1 -m10 + -e ${NDRX_APPHOME}/log/tmsrv-rm1.log -r -- -t3 -l${NDRX_APPHOME}/tmlogs/rm1 -m20 100 - 1 - 1 + + 4 + 4 -e ${NDRX_APPHOME}/log/ac_svr.log -r 110 - 1 - 1 + + 4 + 4 -e ${NDRX_APPHOME}/log/au_svr.log -r 120 - 1 - 1 + + 4 + 4 -e ${NDRX_APPHOME}/log/cl_svr.log -r 130 - 1 - 1 + + 4 + 4 -e ${NDRX_APPHOME}/log/cm_svr.log -r 140 - 1 - 1 + + 4 + 4 -e ${NDRX_APPHOME}/log/lg_svr.log -r 150 - 1 - 1 + + 4 + 4 -e ${NDRX_APPHOME}/log/mg_svr.log -r 160 - 1 - 1 + + 4 + 4 -e ${NDRX_APPHOME}/log/mm_svr.log -r 170 - 1 - 1 + + 4 + 4 -e ${NDRX_APPHOME}/log/py_svr.log -r 180 - 1 - 1 + + 4 + 4 -e ${NDRX_APPHOME}/log/rc_svr.log -r 190 - 1 - 1 + + 4 + 4 -e ${NDRX_APPHOME}/log/st_svr.log -r 200 - 1 - 1 + + 4 + 4 -e ${NDRX_APPHOME}/log/vl_svr.log -r diff --git a/app/src/ac/svc/ACQ_ALERTDUP.pgc b/app/src/ac/svc/ACQ_ALERTDUP.pgc index c5c414b..1a41a74 100644 --- a/app/src/ac/svc/ACQ_ALERTDUP.pgc +++ b/app/src/ac/svc/ACQ_ALERTDUP.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_AMTFIX.pgc b/app/src/ac/svc/ACQ_AMTFIX.pgc index af24df1..3f9fcc8 100644 --- a/app/src/ac/svc/ACQ_AMTFIX.pgc +++ b/app/src/ac/svc/ACQ_AMTFIX.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_APPRLINK.pgc b/app/src/ac/svc/ACQ_APPRLINK.pgc index 8f34858..76c0a53 100644 --- a/app/src/ac/svc/ACQ_APPRLINK.pgc +++ b/app/src/ac/svc/ACQ_APPRLINK.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_APPRMAP.pgc b/app/src/ac/svc/ACQ_APPRMAP.pgc index f361325..f082496 100644 --- a/app/src/ac/svc/ACQ_APPRMAP.pgc +++ b/app/src/ac/svc/ACQ_APPRMAP.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_CANCEL.pgc b/app/src/ac/svc/ACQ_CANCEL.pgc index 6e38039..414f2c3 100644 --- a/app/src/ac/svc/ACQ_CANCEL.pgc +++ b/app/src/ac/svc/ACQ_CANCEL.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_CB_OPEN.pgc b/app/src/ac/svc/ACQ_CB_OPEN.pgc index c5f1a64..eec78d1 100644 --- a/app/src/ac/svc/ACQ_CB_OPEN.pgc +++ b/app/src/ac/svc/ACQ_CB_OPEN.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_CB_REVERSE.pgc b/app/src/ac/svc/ACQ_CB_REVERSE.pgc index 89beaf9..3eca63b 100644 --- a/app/src/ac/svc/ACQ_CB_REVERSE.pgc +++ b/app/src/ac/svc/ACQ_CB_REVERSE.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_CLAIMREG.pgc b/app/src/ac/svc/ACQ_CLAIMREG.pgc index ffaba8f..0e96d4b 100644 --- a/app/src/ac/svc/ACQ_CLAIMREG.pgc +++ b/app/src/ac/svc/ACQ_CLAIMREG.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_CORRECT.pgc b/app/src/ac/svc/ACQ_CORRECT.pgc index 1d51771..a4de700 100644 --- a/app/src/ac/svc/ACQ_CORRECT.pgc +++ b/app/src/ac/svc/ACQ_CORRECT.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_DDC.pgc b/app/src/ac/svc/ACQ_DDC.pgc index 972ed98..e67cd9b 100644 --- a/app/src/ac/svc/ACQ_DDC.pgc +++ b/app/src/ac/svc/ACQ_DDC.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_DUPCHK.pgc b/app/src/ac/svc/ACQ_DUPCHK.pgc index 122baa8..4684448 100644 --- a/app/src/ac/svc/ACQ_DUPCHK.pgc +++ b/app/src/ac/svc/ACQ_DUPCHK.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_EDC.pgc b/app/src/ac/svc/ACQ_EDC.pgc index dac4244..e9d104e 100644 --- a/app/src/ac/svc/ACQ_EDC.pgc +++ b/app/src/ac/svc/ACQ_EDC.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_EDI.pgc b/app/src/ac/svc/ACQ_EDI.pgc index 0d07f3c..07c0de1 100644 --- a/app/src/ac/svc/ACQ_EDI.pgc +++ b/app/src/ac/svc/ACQ_EDI.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_EDIRESEND.pgc b/app/src/ac/svc/ACQ_EDIRESEND.pgc index a65e4c7..81551d0 100644 --- a/app/src/ac/svc/ACQ_EDIRESEND.pgc +++ b/app/src/ac/svc/ACQ_EDIRESEND.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_ESCROW.pgc b/app/src/ac/svc/ACQ_ESCROW.pgc index 63fd242..a8b0af3 100644 --- a/app/src/ac/svc/ACQ_ESCROW.pgc +++ b/app/src/ac/svc/ACQ_ESCROW.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_ESCROWREL.pgc b/app/src/ac/svc/ACQ_ESCROWREL.pgc index 6324248..9ab5fb4 100644 --- a/app/src/ac/svc/ACQ_ESCROWREL.pgc +++ b/app/src/ac/svc/ACQ_ESCROWREL.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_EXCHANGE.pgc b/app/src/ac/svc/ACQ_EXCHANGE.pgc index e79dc14..be2abcb 100644 --- a/app/src/ac/svc/ACQ_EXCHANGE.pgc +++ b/app/src/ac/svc/ACQ_EXCHANGE.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_FEEADJ.pgc b/app/src/ac/svc/ACQ_FEEADJ.pgc index 26841b9..1af3476 100644 --- a/app/src/ac/svc/ACQ_FEEADJ.pgc +++ b/app/src/ac/svc/ACQ_FEEADJ.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_FEERECALC.pgc b/app/src/ac/svc/ACQ_FEERECALC.pgc index aa1731e..2b6fd1e 100644 --- a/app/src/ac/svc/ACQ_FEERECALC.pgc +++ b/app/src/ac/svc/ACQ_FEERECALC.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_FOREIGN.pgc b/app/src/ac/svc/ACQ_FOREIGN.pgc index da4fe35..cc87f4c 100644 --- a/app/src/ac/svc/ACQ_FOREIGN.pgc +++ b/app/src/ac/svc/ACQ_FOREIGN.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_FXCONVERT.pgc b/app/src/ac/svc/ACQ_FXCONVERT.pgc index 8afdb82..c95d4d7 100644 --- a/app/src/ac/svc/ACQ_FXCONVERT.pgc +++ b/app/src/ac/svc/ACQ_FXCONVERT.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_FXRATE.pgc b/app/src/ac/svc/ACQ_FXRATE.pgc index 779ee4a..c167bdb 100644 --- a/app/src/ac/svc/ACQ_FXRATE.pgc +++ b/app/src/ac/svc/ACQ_FXRATE.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_GUARANTEE.pgc b/app/src/ac/svc/ACQ_GUARANTEE.pgc index aad1bda..a9c480c 100644 --- a/app/src/ac/svc/ACQ_GUARANTEE.pgc +++ b/app/src/ac/svc/ACQ_GUARANTEE.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_HOLD.pgc b/app/src/ac/svc/ACQ_HOLD.pgc index c930fc7..53b11cd 100644 --- a/app/src/ac/svc/ACQ_HOLD.pgc +++ b/app/src/ac/svc/ACQ_HOLD.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_INSTALL.pgc b/app/src/ac/svc/ACQ_INSTALL.pgc index 9fd5f1a..23a5783 100644 --- a/app/src/ac/svc/ACQ_INSTALL.pgc +++ b/app/src/ac/svc/ACQ_INSTALL.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_INSTCXL.pgc b/app/src/ac/svc/ACQ_INSTCXL.pgc index ac1dbb8..1bcd35a 100644 --- a/app/src/ac/svc/ACQ_INSTCXL.pgc +++ b/app/src/ac/svc/ACQ_INSTCXL.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_LIMITCHK.pgc b/app/src/ac/svc/ACQ_LIMITCHK.pgc index f1d1855..38ed1da 100644 --- a/app/src/ac/svc/ACQ_LIMITCHK.pgc +++ b/app/src/ac/svc/ACQ_LIMITCHK.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_LIMITEXC.pgc b/app/src/ac/svc/ACQ_LIMITEXC.pgc index afb0919..d670d85 100644 --- a/app/src/ac/svc/ACQ_LIMITEXC.pgc +++ b/app/src/ac/svc/ACQ_LIMITEXC.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_MERCHSUM.pgc b/app/src/ac/svc/ACQ_MERCHSUM.pgc index 0859c84..57ca550 100644 --- a/app/src/ac/svc/ACQ_MERCHSUM.pgc +++ b/app/src/ac/svc/ACQ_MERCHSUM.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_NETCALC.pgc b/app/src/ac/svc/ACQ_NETCALC.pgc index e33c130..5a5b82d 100644 --- a/app/src/ac/svc/ACQ_NETCALC.pgc +++ b/app/src/ac/svc/ACQ_NETCALC.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_PARTCXL.pgc b/app/src/ac/svc/ACQ_PARTCXL.pgc index c9cb6cb..b59677e 100644 --- a/app/src/ac/svc/ACQ_PARTCXL.pgc +++ b/app/src/ac/svc/ACQ_PARTCXL.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_PARTRFND.pgc b/app/src/ac/svc/ACQ_PARTRFND.pgc index 22a79ba..6fd0097 100644 --- a/app/src/ac/svc/ACQ_PARTRFND.pgc +++ b/app/src/ac/svc/ACQ_PARTRFND.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_PROMO.pgc b/app/src/ac/svc/ACQ_PROMO.pgc index 7e36e1e..4a71c30 100644 --- a/app/src/ac/svc/ACQ_PROMO.pgc +++ b/app/src/ac/svc/ACQ_PROMO.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_REFUND.pgc b/app/src/ac/svc/ACQ_REFUND.pgc index 6ea316c..643c661 100644 --- a/app/src/ac/svc/ACQ_REFUND.pgc +++ b/app/src/ac/svc/ACQ_REFUND.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_RELEASE.pgc b/app/src/ac/svc/ACQ_RELEASE.pgc index de1fc63..6ff07af 100644 --- a/app/src/ac/svc/ACQ_RELEASE.pgc +++ b/app/src/ac/svc/ACQ_RELEASE.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_REMATCH.pgc b/app/src/ac/svc/ACQ_REMATCH.pgc index 07543f6..772e62a 100644 --- a/app/src/ac/svc/ACQ_REMATCH.pgc +++ b/app/src/ac/svc/ACQ_REMATCH.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_REPROC.pgc b/app/src/ac/svc/ACQ_REPROC.pgc index cee5c16..2146984 100644 --- a/app/src/ac/svc/ACQ_REPROC.pgc +++ b/app/src/ac/svc/ACQ_REPROC.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_RESERVE.pgc b/app/src/ac/svc/ACQ_RESERVE.pgc index bdb69a4..7e2a887 100644 --- a/app/src/ac/svc/ACQ_RESERVE.pgc +++ b/app/src/ac/svc/ACQ_RESERVE.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_RESERVECXL.pgc b/app/src/ac/svc/ACQ_RESERVECXL.pgc index ee5694b..167018b 100644 --- a/app/src/ac/svc/ACQ_RESERVECXL.pgc +++ b/app/src/ac/svc/ACQ_RESERVECXL.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_RETURN.pgc b/app/src/ac/svc/ACQ_RETURN.pgc index 98856dc..546793a 100644 --- a/app/src/ac/svc/ACQ_RETURN.pgc +++ b/app/src/ac/svc/ACQ_RETURN.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_SETTLELINK.pgc b/app/src/ac/svc/ACQ_SETTLELINK.pgc index e4e616d..fa6d3f2 100644 --- a/app/src/ac/svc/ACQ_SETTLELINK.pgc +++ b/app/src/ac/svc/ACQ_SETTLELINK.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_SPLITPAY.pgc b/app/src/ac/svc/ACQ_SPLITPAY.pgc index 01073b6..a8789b9 100644 --- a/app/src/ac/svc/ACQ_SPLITPAY.pgc +++ b/app/src/ac/svc/ACQ_SPLITPAY.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_TAXCXL.pgc b/app/src/ac/svc/ACQ_TAXCXL.pgc index 39b10fc..d0ef883 100644 --- a/app/src/ac/svc/ACQ_TAXCXL.pgc +++ b/app/src/ac/svc/ACQ_TAXCXL.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_TAXINV.pgc b/app/src/ac/svc/ACQ_TAXINV.pgc index 837f99f..ab26769 100644 --- a/app/src/ac/svc/ACQ_TAXINV.pgc +++ b/app/src/ac/svc/ACQ_TAXINV.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_TAXREVERSE.pgc b/app/src/ac/svc/ACQ_TAXREVERSE.pgc index 260c523..353d15b 100644 --- a/app/src/ac/svc/ACQ_TAXREVERSE.pgc +++ b/app/src/ac/svc/ACQ_TAXREVERSE.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_UNMATCH.pgc b/app/src/ac/svc/ACQ_UNMATCH.pgc index 3993503..02f9893 100644 --- a/app/src/ac/svc/ACQ_UNMATCH.pgc +++ b/app/src/ac/svc/ACQ_UNMATCH.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_VELOCITY.pgc b/app/src/ac/svc/ACQ_VELOCITY.pgc index f33687d..a64f117 100644 --- a/app/src/ac/svc/ACQ_VELOCITY.pgc +++ b/app/src/ac/svc/ACQ_VELOCITY.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_VOID.pgc b/app/src/ac/svc/ACQ_VOID.pgc index 1d6c629..21533e3 100644 --- a/app/src/ac/svc/ACQ_VOID.pgc +++ b/app/src/ac/svc/ACQ_VOID.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_WHT.pgc b/app/src/ac/svc/ACQ_WHT.pgc index 79c10e4..9e671bf 100644 --- a/app/src/ac/svc/ACQ_WHT.pgc +++ b/app/src/ac/svc/ACQ_WHT.pgc @@ -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); diff --git a/app/src/ac/svc/ACQ_XFERLINK.pgc b/app/src/ac/svc/ACQ_XFERLINK.pgc index 0ba1805..145f247 100644 --- a/app/src/ac/svc/ACQ_XFERLINK.pgc +++ b/app/src/ac/svc/ACQ_XFERLINK.pgc @@ -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); diff --git a/app/src/au/svc/AUTH.pgc b/app/src/au/svc/AUTH.pgc index 4888afd..208447e 100644 --- a/app/src/au/svc/AUTH.pgc +++ b/app/src/au/svc/AUTH.pgc @@ -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); diff --git a/app/src/au/svc/AUTH_AMT_ADJUST.pgc b/app/src/au/svc/AUTH_AMT_ADJUST.pgc index 15026fa..b11b91f 100644 --- a/app/src/au/svc/AUTH_AMT_ADJUST.pgc +++ b/app/src/au/svc/AUTH_AMT_ADJUST.pgc @@ -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); diff --git a/app/src/au/svc/AUTH_APPROVE.pgc b/app/src/au/svc/AUTH_APPROVE.pgc index 1617762..0ccc3d4 100644 --- a/app/src/au/svc/AUTH_APPROVE.pgc +++ b/app/src/au/svc/AUTH_APPROVE.pgc @@ -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); diff --git a/app/src/au/svc/AUTH_CANCEL.pgc b/app/src/au/svc/AUTH_CANCEL.pgc index a9e3b34..73fa2d1 100644 --- a/app/src/au/svc/AUTH_CANCEL.pgc +++ b/app/src/au/svc/AUTH_CANCEL.pgc @@ -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); diff --git a/app/src/au/svc/AUTH_CAPTURE.pgc b/app/src/au/svc/AUTH_CAPTURE.pgc index 166b95f..c422645 100644 --- a/app/src/au/svc/AUTH_CAPTURE.pgc +++ b/app/src/au/svc/AUTH_CAPTURE.pgc @@ -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); diff --git a/app/src/au/svc/AUTH_DECLINE.pgc b/app/src/au/svc/AUTH_DECLINE.pgc index a272139..840c3bf 100644 --- a/app/src/au/svc/AUTH_DECLINE.pgc +++ b/app/src/au/svc/AUTH_DECLINE.pgc @@ -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); diff --git a/app/src/au/svc/AUTH_DUP_CHK.pgc b/app/src/au/svc/AUTH_DUP_CHK.pgc index 6da609b..2bad87c 100644 --- a/app/src/au/svc/AUTH_DUP_CHK.pgc +++ b/app/src/au/svc/AUTH_DUP_CHK.pgc @@ -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); diff --git a/app/src/au/svc/AUTH_EXPIRE_CHK.pgc b/app/src/au/svc/AUTH_EXPIRE_CHK.pgc index 8732d4a..a75705e 100644 --- a/app/src/au/svc/AUTH_EXPIRE_CHK.pgc +++ b/app/src/au/svc/AUTH_EXPIRE_CHK.pgc @@ -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); diff --git a/app/src/au/svc/AUTH_HOLD.pgc b/app/src/au/svc/AUTH_HOLD.pgc index 5bb675a..5e3e663 100644 --- a/app/src/au/svc/AUTH_HOLD.pgc +++ b/app/src/au/svc/AUTH_HOLD.pgc @@ -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); diff --git a/app/src/au/svc/AUTH_PARTAPPR.pgc b/app/src/au/svc/AUTH_PARTAPPR.pgc index 87a23f7..62c4365 100644 --- a/app/src/au/svc/AUTH_PARTAPPR.pgc +++ b/app/src/au/svc/AUTH_PARTAPPR.pgc @@ -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); diff --git a/app/src/au/svc/AUTH_PARTCXL.pgc b/app/src/au/svc/AUTH_PARTCXL.pgc index 1d80f73..fc41e3f 100644 --- a/app/src/au/svc/AUTH_PARTCXL.pgc +++ b/app/src/au/svc/AUTH_PARTCXL.pgc @@ -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); diff --git a/app/src/au/svc/AUTH_RELEASE.pgc b/app/src/au/svc/AUTH_RELEASE.pgc index d459318..6211b42 100644 --- a/app/src/au/svc/AUTH_RELEASE.pgc +++ b/app/src/au/svc/AUTH_RELEASE.pgc @@ -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); diff --git a/app/src/au/svc/AUTH_RESEND.pgc b/app/src/au/svc/AUTH_RESEND.pgc index b6e50a1..572405a 100644 --- a/app/src/au/svc/AUTH_RESEND.pgc +++ b/app/src/au/svc/AUTH_RESEND.pgc @@ -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); diff --git a/app/src/au/svc/AUTH_RETRY.pgc b/app/src/au/svc/AUTH_RETRY.pgc index 73f6270..41b027a 100644 --- a/app/src/au/svc/AUTH_RETRY.pgc +++ b/app/src/au/svc/AUTH_RETRY.pgc @@ -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); diff --git a/app/src/au/svc/AUTH_REVERSE.pgc b/app/src/au/svc/AUTH_REVERSE.pgc index d7c9f5d..6622f8b 100644 --- a/app/src/au/svc/AUTH_REVERSE.pgc +++ b/app/src/au/svc/AUTH_REVERSE.pgc @@ -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); diff --git a/app/src/au/svc/AUTH_VOID.pgc b/app/src/au/svc/AUTH_VOID.pgc index 2941f7d..2033232 100644 --- a/app/src/au/svc/AUTH_VOID.pgc +++ b/app/src/au/svc/AUTH_VOID.pgc @@ -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); diff --git a/app/src/au/svc/BLACKLIST_CHK.pgc b/app/src/au/svc/BLACKLIST_CHK.pgc index 32ea706..818a51b 100644 --- a/app/src/au/svc/BLACKLIST_CHK.pgc +++ b/app/src/au/svc/BLACKLIST_CHK.pgc @@ -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)); diff --git a/app/src/au/svc/CARD_LOST_REG.pgc b/app/src/au/svc/CARD_LOST_REG.pgc index 064d47d..c3b1587 100644 --- a/app/src/au/svc/CARD_LOST_REG.pgc +++ b/app/src/au/svc/CARD_LOST_REG.pgc @@ -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)); diff --git a/app/src/au/svc/CARD_STOLEN_REG.pgc b/app/src/au/svc/CARD_STOLEN_REG.pgc index efd3695..68602ea 100644 --- a/app/src/au/svc/CARD_STOLEN_REG.pgc +++ b/app/src/au/svc/CARD_STOLEN_REG.pgc @@ -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); diff --git a/app/src/au/svc/CARD_VALIDATE.pgc b/app/src/au/svc/CARD_VALIDATE.pgc index 08da3aa..b29b8db 100644 --- a/app/src/au/svc/CARD_VALIDATE.pgc +++ b/app/src/au/svc/CARD_VALIDATE.pgc @@ -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)); diff --git a/app/src/au/svc/FRAUD_DETECT.pgc b/app/src/au/svc/FRAUD_DETECT.pgc index 46bedcb..27c52a3 100644 --- a/app/src/au/svc/FRAUD_DETECT.pgc +++ b/app/src/au/svc/FRAUD_DETECT.pgc @@ -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); diff --git a/app/src/au/svc/INSTALL_AUTH.pgc b/app/src/au/svc/INSTALL_AUTH.pgc index 9225553..a4d7a0e 100644 --- a/app/src/au/svc/INSTALL_AUTH.pgc +++ b/app/src/au/svc/INSTALL_AUTH.pgc @@ -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); diff --git a/app/src/au/svc/LIMIT_CHK.pgc b/app/src/au/svc/LIMIT_CHK.pgc index 4e6052e..3d7facf 100644 --- a/app/src/au/svc/LIMIT_CHK.pgc +++ b/app/src/au/svc/LIMIT_CHK.pgc @@ -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); diff --git a/app/src/au/svc/LIMIT_DEC.pgc b/app/src/au/svc/LIMIT_DEC.pgc index 5a3a076..cedbf1f 100644 --- a/app/src/au/svc/LIMIT_DEC.pgc +++ b/app/src/au/svc/LIMIT_DEC.pgc @@ -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)); diff --git a/app/src/au/svc/LIMIT_EXHAUST_LST.pgc b/app/src/au/svc/LIMIT_EXHAUST_LST.pgc index 7d26b6a..3fc015f 100644 --- a/app/src/au/svc/LIMIT_EXHAUST_LST.pgc +++ b/app/src/au/svc/LIMIT_EXHAUST_LST.pgc @@ -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); diff --git a/app/src/au/svc/LIMIT_FREEZE.pgc b/app/src/au/svc/LIMIT_FREEZE.pgc index c2dda32..6d628ab 100644 --- a/app/src/au/svc/LIMIT_FREEZE.pgc +++ b/app/src/au/svc/LIMIT_FREEZE.pgc @@ -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)); diff --git a/app/src/au/svc/LIMIT_OVER_ALERT.pgc b/app/src/au/svc/LIMIT_OVER_ALERT.pgc index ae8c0b2..ff1d7e4 100644 --- a/app/src/au/svc/LIMIT_OVER_ALERT.pgc +++ b/app/src/au/svc/LIMIT_OVER_ALERT.pgc @@ -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); diff --git a/app/src/au/svc/LIMIT_RST.pgc b/app/src/au/svc/LIMIT_RST.pgc index d1aefb5..97461a5 100644 --- a/app/src/au/svc/LIMIT_RST.pgc +++ b/app/src/au/svc/LIMIT_RST.pgc @@ -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)); diff --git a/app/src/au/svc/NOAUTH_CAPTURE.pgc b/app/src/au/svc/NOAUTH_CAPTURE.pgc index 5122193..53faf22 100644 --- a/app/src/au/svc/NOAUTH_CAPTURE.pgc +++ b/app/src/au/svc/NOAUTH_CAPTURE.pgc @@ -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); diff --git a/app/src/au/svc/PREAUTH.pgc b/app/src/au/svc/PREAUTH.pgc index 7117522..7d7c7ab 100644 --- a/app/src/au/svc/PREAUTH.pgc +++ b/app/src/au/svc/PREAUTH.pgc @@ -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); diff --git a/app/src/au/svc/PREAUTH_CANCEL.pgc b/app/src/au/svc/PREAUTH_CANCEL.pgc index 33bf44c..8b768f9 100644 --- a/app/src/au/svc/PREAUTH_CANCEL.pgc +++ b/app/src/au/svc/PREAUTH_CANCEL.pgc @@ -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); diff --git a/app/src/au/svc/PREAUTH_COMPLETE.pgc b/app/src/au/svc/PREAUTH_COMPLETE.pgc index 7de498b..3bbcc7c 100644 --- a/app/src/au/svc/PREAUTH_COMPLETE.pgc +++ b/app/src/au/svc/PREAUTH_COMPLETE.pgc @@ -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); diff --git a/app/src/au/svc/PREAUTH_EXTEND.pgc b/app/src/au/svc/PREAUTH_EXTEND.pgc index fc34abb..0f8fb57 100644 --- a/app/src/au/svc/PREAUTH_EXTEND.pgc +++ b/app/src/au/svc/PREAUTH_EXTEND.pgc @@ -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); diff --git a/app/src/au/svc/PREAUTH_PARTUSE.pgc b/app/src/au/svc/PREAUTH_PARTUSE.pgc index 805fd25..f0037c9 100644 --- a/app/src/au/svc/PREAUTH_PARTUSE.pgc +++ b/app/src/au/svc/PREAUTH_PARTUSE.pgc @@ -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); diff --git a/app/src/au/svc/STANDIN.pgc b/app/src/au/svc/STANDIN.pgc index 5bd2a2d..e98b2ff 100644 --- a/app/src/au/svc/STANDIN.pgc +++ b/app/src/au/svc/STANDIN.pgc @@ -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); diff --git a/app/src/au/svc/STANDIN_SETTLE.pgc b/app/src/au/svc/STANDIN_SETTLE.pgc index 925795f..866c6cc 100644 --- a/app/src/au/svc/STANDIN_SETTLE.pgc +++ b/app/src/au/svc/STANDIN_SETTLE.pgc @@ -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); diff --git a/app/src/au/svc/TOKEN_VERIFY.pgc b/app/src/au/svc/TOKEN_VERIFY.pgc index 6ba31ee..73db32d 100644 --- a/app/src/au/svc/TOKEN_VERIFY.pgc +++ b/app/src/au/svc/TOKEN_VERIFY.pgc @@ -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); diff --git a/app/src/au/svc/VELOCITY_CHK.pgc b/app/src/au/svc/VELOCITY_CHK.pgc index 808fdac..d6bd8dc 100644 --- a/app/src/au/svc/VELOCITY_CHK.pgc +++ b/app/src/au/svc/VELOCITY_CHK.pgc @@ -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); diff --git a/app/src/cl/svc/CL_AMTXCHECK.pgc b/app/src/cl/svc/CL_AMTXCHECK.pgc index 0a24a60..d632ef8 100644 --- a/app/src/cl/svc/CL_AMTXCHECK.pgc +++ b/app/src/cl/svc/CL_AMTXCHECK.pgc @@ -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); } diff --git a/app/src/cl/svc/CL_APPRDELEG.pgc b/app/src/cl/svc/CL_APPRDELEG.pgc index 640e673..3cc90f4 100644 --- a/app/src/cl/svc/CL_APPRDELEG.pgc +++ b/app/src/cl/svc/CL_APPRDELEG.pgc @@ -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); } diff --git a/app/src/cl/svc/CL_APPRFINAL.pgc b/app/src/cl/svc/CL_APPRFINAL.pgc index 6332022..5f38d04 100644 --- a/app/src/cl/svc/CL_APPRFINAL.pgc +++ b/app/src/cl/svc/CL_APPRFINAL.pgc @@ -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]); diff --git a/app/src/cl/svc/CL_APPRL1.pgc b/app/src/cl/svc/CL_APPRL1.pgc index 43e99dc..dd03426 100644 --- a/app/src/cl/svc/CL_APPRL1.pgc +++ b/app/src/cl/svc/CL_APPRL1.pgc @@ -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); } diff --git a/app/src/cl/svc/CL_APPRL2.pgc b/app/src/cl/svc/CL_APPRL2.pgc index 8696ff2..3dba5ae 100644 --- a/app/src/cl/svc/CL_APPRL2.pgc +++ b/app/src/cl/svc/CL_APPRL2.pgc @@ -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); } diff --git a/app/src/cl/svc/CL_APPROVE.pgc b/app/src/cl/svc/CL_APPROVE.pgc index 49eaaed..28a5136 100644 --- a/app/src/cl/svc/CL_APPROVE.pgc +++ b/app/src/cl/svc/CL_APPROVE.pgc @@ -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); } diff --git a/app/src/cl/svc/CL_APPRREJECT.pgc b/app/src/cl/svc/CL_APPRREJECT.pgc index f5540da..5a28b27 100644 --- a/app/src/cl/svc/CL_APPRREJECT.pgc +++ b/app/src/cl/svc/CL_APPRREJECT.pgc @@ -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); } diff --git a/app/src/cl/svc/CL_APPRREQ.pgc b/app/src/cl/svc/CL_APPRREQ.pgc index 1cfc8a8..7db44bc 100644 --- a/app/src/cl/svc/CL_APPRREQ.pgc +++ b/app/src/cl/svc/CL_APPRREQ.pgc @@ -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); } diff --git a/app/src/cl/svc/CL_BALVERIFY.pgc b/app/src/cl/svc/CL_BALVERIFY.pgc index 29d151e..8f20717 100644 --- a/app/src/cl/svc/CL_BALVERIFY.pgc +++ b/app/src/cl/svc/CL_BALVERIFY.pgc @@ -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); } diff --git a/app/src/cl/svc/CL_CANCEL.pgc b/app/src/cl/svc/CL_CANCEL.pgc index e8c895e..60a6f10 100644 --- a/app/src/cl/svc/CL_CANCEL.pgc +++ b/app/src/cl/svc/CL_CANCEL.pgc @@ -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); } diff --git a/app/src/cl/svc/CL_CHKALL.pgc b/app/src/cl/svc/CL_CHKALL.pgc index 83ef0c1..2754e73 100644 --- a/app/src/cl/svc/CL_CHKALL.pgc +++ b/app/src/cl/svc/CL_CHKALL.pgc @@ -162,6 +162,59 @@ void CL_CHKALL(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_CHKALL 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_CROSSCHK 연동 (마감 전수 점검의 교차 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_CROSSCHK 는 별도 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_CHKALL", 0L); + + userlog("[CL_CHKALL] 체인 호출 -> VL_CROSSCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_CROSSCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_CHKALL] tpcall(VL_CROSSCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9612); + Bchg(b, T_MSG, 0, "마감 교차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_CHKALL] VL_CROSSCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_CHKALL] VL_CROSSCHK 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_CHKPENDING.pgc b/app/src/cl/svc/CL_CHKPENDING.pgc index 8b3adb7..32953fd 100644 --- a/app/src/cl/svc/CL_CHKPENDING.pgc +++ b/app/src/cl/svc/CL_CHKPENDING.pgc @@ -151,6 +151,59 @@ void CL_CHKPENDING(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_CHKPENDING 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_LONGOPEN 연동 (장기 미결 건 잔여 점검) ==== + * 동일 글로벌 트랜잭션이지만 VL_LONGOPEN 는 별도 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_CHKPENDING", 0L); + + userlog("[CL_CHKPENDING] 체인 호출 -> VL_LONGOPEN bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_LONGOPEN", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_CHKPENDING] tpcall(VL_LONGOPEN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9641); + Bchg(b, T_MSG, 0, "장기미결 점검 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_CHKPENDING] VL_LONGOPEN 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_CHKPENDING] VL_LONGOPEN 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_CHKUNMATCH.pgc b/app/src/cl/svc/CL_CHKUNMATCH.pgc index c8d590a..68b2c60 100644 --- a/app/src/cl/svc/CL_CHKUNMATCH.pgc +++ b/app/src/cl/svc/CL_CHKUNMATCH.pgc @@ -151,6 +151,59 @@ void CL_CHKUNMATCH(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_CHKUNMATCH 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_PURNOAPPR 연동 (승인 없는 매입 잔여 점검) ==== + * 동일 글로벌 트랜잭션이지만 VL_PURNOAPPR 는 별도 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_CHKUNMATCH", 0L); + + userlog("[CL_CHKUNMATCH] 체인 호출 -> VL_PURNOAPPR bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_PURNOAPPR", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_CHKUNMATCH] tpcall(VL_PURNOAPPR) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9639); + Bchg(b, T_MSG, 0, "미승인매입 점검 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_CHKUNMATCH] VL_PURNOAPPR 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_CHKUNMATCH] VL_PURNOAPPR 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_CHKVOID.pgc b/app/src/cl/svc/CL_CHKVOID.pgc index 4b3744d..73a7360 100644 --- a/app/src/cl/svc/CL_CHKVOID.pgc +++ b/app/src/cl/svc/CL_CHKVOID.pgc @@ -151,6 +151,59 @@ void CL_CHKVOID(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_CHKVOID 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_CANCELMIS 연동 (취소 불일치 잔여 점검) ==== + * 동일 글로벌 트랜잭션이지만 VL_CANCELMIS 는 별도 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_CHKVOID", 0L); + + userlog("[CL_CHKVOID] 체인 호출 -> VL_CANCELMIS bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_CANCELMIS", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_CHKVOID] tpcall(VL_CANCELMIS) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9640); + Bchg(b, T_MSG, 0, "취소불일치 점검 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_CHKVOID] VL_CANCELMIS 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_CHKVOID] VL_CANCELMIS 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_CHNVERIFY.pgc b/app/src/cl/svc/CL_CHNVERIFY.pgc index a791be5..cdd6864 100644 --- a/app/src/cl/svc/CL_CHNVERIFY.pgc +++ b/app/src/cl/svc/CL_CHNVERIFY.pgc @@ -171,6 +171,59 @@ void CL_CHNVERIFY(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_CHNVERIFY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_CHANSPLIT 연동 (채널별 마감 분할 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_CHANSPLIT 는 별도 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_CHNVERIFY", 0L); + + userlog("[CL_CHNVERIFY] 체인 호출 -> VL_CHANSPLIT bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_CHANSPLIT", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_CHNVERIFY] tpcall(VL_CHANSPLIT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9622); + Bchg(b, T_MSG, 0, "채널마감 분할검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_CHNVERIFY] VL_CHANSPLIT 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_CHNVERIFY] VL_CHANSPLIT 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_CNTVERIFY.pgc b/app/src/cl/svc/CL_CNTVERIFY.pgc index 3e8e800..6b9fc1a 100644 --- a/app/src/cl/svc/CL_CNTVERIFY.pgc +++ b/app/src/cl/svc/CL_CNTVERIFY.pgc @@ -170,6 +170,59 @@ void CL_CNTVERIFY(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_CNTVERIFY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_RULECOUNT 연동 (마감 룰 적용 건수 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_RULECOUNT 는 별도 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_CNTVERIFY", 0L); + + userlog("[CL_CNTVERIFY] 체인 호출 -> VL_RULECOUNT bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_RULECOUNT", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_CNTVERIFY] tpcall(VL_RULECOUNT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9625); + Bchg(b, T_MSG, 0, "룰 건수검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_CNTVERIFY] VL_RULECOUNT 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_CNTVERIFY] VL_RULECOUNT 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_CNTXCHECK.pgc b/app/src/cl/svc/CL_CNTXCHECK.pgc index 9c66e6e..1aa1303 100644 --- a/app/src/cl/svc/CL_CNTXCHECK.pgc +++ b/app/src/cl/svc/CL_CNTXCHECK.pgc @@ -162,6 +162,59 @@ void CL_CNTXCHECK(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_CNTXCHECK 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_AXSETTPAY 연동 (정산 대 지급 건수 교차 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_AXSETTPAY 는 별도 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_CNTXCHECK", 0L); + + userlog("[CL_CNTXCHECK] 체인 호출 -> VL_AXSETTPAY bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_AXSETTPAY", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_CNTXCHECK] tpcall(VL_AXSETTPAY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9632); + Bchg(b, T_MSG, 0, "정산-지급 건수교차 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_CNTXCHECK] VL_AXSETTPAY 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_CNTXCHECK] VL_AXSETTPAY 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_CORPCLOSE.pgc b/app/src/cl/svc/CL_CORPCLOSE.pgc index 2324580..24e38b6 100644 --- a/app/src/cl/svc/CL_CORPCLOSE.pgc +++ b/app/src/cl/svc/CL_CORPCLOSE.pgc @@ -215,6 +215,59 @@ void CL_CORPCLOSE(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_CORPCLOSE 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: LG_CORPSUM 연동 (법인 마감 확정분의 법인집계 연동) ==== + * 동일 글로벌 트랜잭션이지만 LG_CORPSUM 는 별도 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_CORPCLOSE", 0L); + + userlog("[CL_CORPCLOSE] 체인 호출 -> LG_CORPSUM bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_CORPSUM", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_CORPCLOSE] tpcall(LG_CORPSUM) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9693); + Bchg(b, T_MSG, 0, "법인마감 집계 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_CORPCLOSE] LG_CORPSUM 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_CORPCLOSE] LG_CORPSUM 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_CORPVERIFY.pgc b/app/src/cl/svc/CL_CORPVERIFY.pgc index cfc4a00..9609e5f 100644 --- a/app/src/cl/svc/CL_CORPVERIFY.pgc +++ b/app/src/cl/svc/CL_CORPVERIFY.pgc @@ -170,6 +170,59 @@ void CL_CORPVERIFY(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_CORPVERIFY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_REPORT 연동 (법인 마감 보고자료 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_REPORT 는 별도 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_CORPVERIFY", 0L); + + userlog("[CL_CORPVERIFY] 체인 호출 -> VL_REPORT bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_REPORT", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_CORPVERIFY] tpcall(VL_REPORT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9621); + Bchg(b, T_MSG, 0, "법인마감 보고검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_CORPVERIFY] VL_REPORT 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_CORPVERIFY] VL_REPORT 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_DAILY.pgc b/app/src/cl/svc/CL_DAILY.pgc index b5a90a6..85c4517 100644 --- a/app/src/cl/svc/CL_DAILY.pgc +++ b/app/src/cl/svc/CL_DAILY.pgc @@ -167,6 +167,112 @@ void CL_DAILY(TPSVCINFO *p) setl(b, T_RC, o_rc); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_DAILY cid=%ld bizdate=%s 일마감 완료", cid, bizdate); + + /* ==== 10) 업무흐름 체인: VL_SALES 연동 (일마감 착수 전 매출 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_SALES 는 별도 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_DAILY", 0L); + + userlog("[CL_DAILY] 체인 호출 -> VL_SALES bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_SALES", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_DAILY] tpcall(VL_SALES) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9681); + Bchg(b, T_MSG, 0, "일마감 사전 매출검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_DAILY] VL_SALES 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_DAILY] VL_SALES 체인 정상 완료 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); + } + + /* ==== 11) 업무흐름 체인: LG_CLOSE_LINK 연동 (일마감 확정분의 원장 마감연계) ==== + * 동일 글로벌 트랜잭션이지만 LG_CLOSE_LINK 는 별도 XA 브랜치에서 수행된다. + * 위에서 적재/갱신한 행은 아직 미커밋이라 하위 브랜치에서 보이지 않으므로 + * 판단에 필요한 값은 전문(UBF)에 실어 전달한다(owner-writes 규율). + * 호출 실패는 보상 없이 FAIL(b) -> 글로벌 트랜잭션 전체 롤백. */ + { + long cx1_rlen = 0, cx1_sub = 0; + long cx1_rc, cx1_id1, cx1_id2, cx1_amt; + long cx1_a5, cx1_a6, cx1_a7, cx1_a8, cx1_m2, cx1_m3; + char cx1_bd[16], cx1_mid[64], cx1_st[16], cx1_msg[192]; + + /* 응답 계약 스냅샷 (하위 서비스가 덮어쓴 뒤 복원하기 위함) */ + cx1_rc = getl(b, T_RC); cx1_id1 = getl(b, T_ID1); cx1_id2 = getl(b, T_ID2); + cx1_amt = getl(b, T_AMOUNT); + cx1_a5 = getl(b, T_ARG5); cx1_a6 = getl(b, T_ARG6); + cx1_a7 = getl(b, T_ARG7); cx1_a8 = getl(b, T_ARG8); + cx1_m2 = getl(b, T_AMT2); cx1_m3 = getl(b, T_AMT3); + gets_(b, T_STATUS, cx1_st, sizeof(cx1_st)); + gets_(b, T_MSG, cx1_msg, sizeof(cx1_msg)); + gets_(b, T_BIZDATE, cx1_bd, sizeof(cx1_bd)); + gets_(b, T_MERCHANT, cx1_mid, sizeof(cx1_mid)); + + /* 하위 서비스가 쓸 값을 전문에 적재 (미커밋 행 조회 의존 금지) */ + setl(b, T_ID1, cx1_id1); + setl(b, T_AMOUNT, cx1_amt); + if (cx1_bd[0] != 0) Bchg(b, T_BIZDATE, 0, cx1_bd, 0L); + if (cx1_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx1_mid, 0L); + Bchg(b, T_SVCNAME, 0, "CL_DAILY", 0L); + + userlog("[CL_DAILY] 체인 호출 -> LG_CLOSE_LINK bd=%s id=%ld amt=%ld", + cx1_bd, cx1_id1, cx1_amt); + if (tpcall("LG_CLOSE_LINK", (char *)b, 0L, (char **)&b, &cx1_rlen, 0L) < 0) { + userlog("[CL_DAILY] tpcall(LG_CLOSE_LINK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9682); + Bchg(b, T_MSG, 0, "일마감 원장연계 체인 실패", 0L); + FAIL(b); + } + cx1_sub = getl(b, T_RC); + if (cx1_sub != 0) + userlog("[CL_DAILY] LG_CLOSE_LINK 경고 통보 rc=%ld — 상위 판단 계속", cx1_sub); + else + userlog("[CL_DAILY] LG_CLOSE_LINK 체인 정상 완료 bd=%s", cx1_bd); + + /* 응답 계약 복원: 원 서비스의 출력 필드는 하위 결과로 바뀌지 않는다 */ + setl(b, T_RC, cx1_rc); setl(b, T_ID1, cx1_id1); setl(b, T_ID2, cx1_id2); + setl(b, T_AMOUNT, cx1_amt); + setl(b, T_ARG5, cx1_a5); setl(b, T_ARG6, cx1_a6); + setl(b, T_ARG7, cx1_a7); setl(b, T_ARG8, cx1_a8); + setl(b, T_AMT2, cx1_m2); setl(b, T_AMT3, cx1_m3); + if (cx1_st[0] != 0) Bchg(b, T_STATUS, 0, cx1_st, 0L); + if (cx1_msg[0] != 0) Bchg(b, T_MSG, 0, cx1_msg, 0L); + } OK(b); } diff --git a/app/src/cl/svc/CL_DAYVERIFY.pgc b/app/src/cl/svc/CL_DAYVERIFY.pgc index 9f68254..aacbd04 100644 --- a/app/src/cl/svc/CL_DAYVERIFY.pgc +++ b/app/src/cl/svc/CL_DAYVERIFY.pgc @@ -170,6 +170,59 @@ void CL_DAYVERIFY(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_DAYVERIFY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_SALES 연동 (일마감 매출 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_SALES 는 별도 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_DAYVERIFY", 0L); + + userlog("[CL_DAYVERIFY] 체인 호출 -> VL_SALES bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_SALES", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_DAYVERIFY] tpcall(VL_SALES) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9614); + Bchg(b, T_MSG, 0, "일마감 매출검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_DAYVERIFY] VL_SALES 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_DAYVERIFY] VL_SALES 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_DIFFCHK.pgc b/app/src/cl/svc/CL_DIFFCHK.pgc index 76dbbc7..139a6ad 100644 --- a/app/src/cl/svc/CL_DIFFCHK.pgc +++ b/app/src/cl/svc/CL_DIFFCHK.pgc @@ -150,6 +150,59 @@ void CL_DIFFCHK(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_DIFFCHK 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_AMOUNT 연동 (마감 차이 금액 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_AMOUNT 는 별도 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_DIFFCHK", 0L); + + userlog("[CL_DIFFCHK] 체인 호출 -> VL_AMOUNT bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_AMOUNT", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_DIFFCHK] tpcall(VL_AMOUNT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9643); + Bchg(b, T_MSG, 0, "차이 금액검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_DIFFCHK] VL_AMOUNT 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_DIFFCHK] VL_AMOUNT 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_DIVCLOSE.pgc b/app/src/cl/svc/CL_DIVCLOSE.pgc index de7bc24..77ea271 100644 --- a/app/src/cl/svc/CL_DIVCLOSE.pgc +++ b/app/src/cl/svc/CL_DIVCLOSE.pgc @@ -215,6 +215,59 @@ void CL_DIVCLOSE(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_DIVCLOSE 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: LG_DEPTSUM 연동 (사업부 마감 확정분의 부서집계 연동) ==== + * 동일 글로벌 트랜잭션이지만 LG_DEPTSUM 는 별도 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_DIVCLOSE", 0L); + + userlog("[CL_DIVCLOSE] 체인 호출 -> LG_DEPTSUM bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_DEPTSUM", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_DIVCLOSE] tpcall(LG_DEPTSUM) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9694); + Bchg(b, T_MSG, 0, "사업부마감 집계 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_DIVCLOSE] LG_DEPTSUM 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_DIVCLOSE] LG_DEPTSUM 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_DUPCHK.pgc b/app/src/cl/svc/CL_DUPCHK.pgc index 248acbe..324ae9d 100644 --- a/app/src/cl/svc/CL_DUPCHK.pgc +++ b/app/src/cl/svc/CL_DUPCHK.pgc @@ -157,6 +157,59 @@ void CL_DUPCHK(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_DUPCHK 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_DUP 연동 (마감 대상 중복 점검) ==== + * 동일 글로벌 트랜잭션이지만 VL_DUP 는 별도 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_DUPCHK", 0L); + + userlog("[CL_DUPCHK] 체인 호출 -> VL_DUP bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_DUP", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_DUPCHK] tpcall(VL_DUP) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9642); + Bchg(b, T_MSG, 0, "중복 점검 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_DUPCHK] VL_DUP 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_DUPCHK] VL_DUP 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_FEECROSS.pgc b/app/src/cl/svc/CL_FEECROSS.pgc index 79e6a21..95880a2 100644 --- a/app/src/cl/svc/CL_FEECROSS.pgc +++ b/app/src/cl/svc/CL_FEECROSS.pgc @@ -161,6 +161,59 @@ void CL_FEECROSS(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_FEECROSS 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_SUMFEECHK 연동 (수수료 합계 교차 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_SUMFEECHK 는 별도 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_FEECROSS", 0L); + + userlog("[CL_FEECROSS] 체인 호출 -> VL_SUMFEECHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_SUMFEECHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_FEECROSS] tpcall(VL_SUMFEECHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9637); + Bchg(b, T_MSG, 0, "수수료 합계교차 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_FEECROSS] VL_SUMFEECHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_FEECROSS] VL_SUMFEECHK 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_FEEVERIFY.pgc b/app/src/cl/svc/CL_FEEVERIFY.pgc index cb141aa..5f62a79 100644 --- a/app/src/cl/svc/CL_FEEVERIFY.pgc +++ b/app/src/cl/svc/CL_FEEVERIFY.pgc @@ -171,6 +171,59 @@ void CL_FEEVERIFY(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_FEEVERIFY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_FEE 연동 (마감 수수료 산출 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_FEE 는 별도 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_FEEVERIFY", 0L); + + userlog("[CL_FEEVERIFY] 체인 호출 -> VL_FEE bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_FEE", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_FEEVERIFY] tpcall(VL_FEE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9624); + Bchg(b, T_MSG, 0, "수수료 검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_FEEVERIFY] VL_FEE 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_FEEVERIFY] VL_FEE 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_FORCECLOSE.pgc b/app/src/cl/svc/CL_FORCECLOSE.pgc index f5560dd..2ce2f48 100644 --- a/app/src/cl/svc/CL_FORCECLOSE.pgc +++ b/app/src/cl/svc/CL_FORCECLOSE.pgc @@ -208,6 +208,59 @@ void CL_FORCECLOSE(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_FORCECLOSE 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: LG_CLOSE_LINK 연동 (강제 마감 확정분의 원장 마감연계) ==== + * 동일 글로벌 트랜잭션이지만 LG_CLOSE_LINK 는 별도 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_FORCECLOSE", 0L); + + userlog("[CL_FORCECLOSE] 체인 호출 -> LG_CLOSE_LINK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_CLOSE_LINK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_FORCECLOSE] tpcall(LG_CLOSE_LINK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9696); + Bchg(b, T_MSG, 0, "강제마감 원장연계 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_FORCECLOSE] LG_CLOSE_LINK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_FORCECLOSE] LG_CLOSE_LINK 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_HALFCLOSE.pgc b/app/src/cl/svc/CL_HALFCLOSE.pgc index 9c99e3a..2e7c753 100644 --- a/app/src/cl/svc/CL_HALFCLOSE.pgc +++ b/app/src/cl/svc/CL_HALFCLOSE.pgc @@ -208,6 +208,59 @@ void CL_HALFCLOSE(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_HALFCLOSE 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: LG_ROLLTB 연동 (반기마감 확정분의 이월 시산표 연동) ==== + * 동일 글로벌 트랜잭션이지만 LG_ROLLTB 는 별도 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_HALFCLOSE", 0L); + + userlog("[CL_HALFCLOSE] 체인 호출 -> LG_ROLLTB bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_ROLLTB", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_HALFCLOSE] tpcall(LG_ROLLTB) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9687); + Bchg(b, T_MSG, 0, "반기마감 이월시산 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_HALFCLOSE] LG_ROLLTB 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_HALFCLOSE] LG_ROLLTB 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_HYVERIFY.pgc b/app/src/cl/svc/CL_HYVERIFY.pgc index 38b7d75..e77a7b9 100644 --- a/app/src/cl/svc/CL_HYVERIFY.pgc +++ b/app/src/cl/svc/CL_HYVERIFY.pgc @@ -170,6 +170,59 @@ void CL_HYVERIFY(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_HYVERIFY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_SUMFEE 연동 (반기마감 수수료 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_SUMFEE 는 별도 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_HYVERIFY", 0L); + + userlog("[CL_HYVERIFY] 체인 호출 -> VL_SUMFEE bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_SUMFEE", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_HYVERIFY] tpcall(VL_SUMFEE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9619); + Bchg(b, T_MSG, 0, "반기마감 수수료검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_HYVERIFY] VL_SUMFEE 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_HYVERIFY] VL_SUMFEE 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_MAINCLOSE.pgc b/app/src/cl/svc/CL_MAINCLOSE.pgc index 8177c29..c3755a3 100644 --- a/app/src/cl/svc/CL_MAINCLOSE.pgc +++ b/app/src/cl/svc/CL_MAINCLOSE.pgc @@ -207,6 +207,59 @@ void CL_MAINCLOSE(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_MAINCLOSE 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: LG_CLOSE_LINK 연동 (본마감 확정분의 원장 마감연계) ==== + * 동일 글로벌 트랜잭션이지만 LG_CLOSE_LINK 는 별도 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_MAINCLOSE", 0L); + + userlog("[CL_MAINCLOSE] 체인 호출 -> LG_CLOSE_LINK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_CLOSE_LINK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_MAINCLOSE] tpcall(LG_CLOSE_LINK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9695); + Bchg(b, T_MSG, 0, "본마감 원장연계 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_MAINCLOSE] LG_CLOSE_LINK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_MAINCLOSE] LG_CLOSE_LINK 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_MERCLOSE.pgc b/app/src/cl/svc/CL_MERCLOSE.pgc index 5a09a3b..a71e553 100644 --- a/app/src/cl/svc/CL_MERCLOSE.pgc +++ b/app/src/cl/svc/CL_MERCLOSE.pgc @@ -215,6 +215,59 @@ void CL_MERCLOSE(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_MERCLOSE 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: LG_MERCHPROOF 연동 (가맹점 마감 확정분의 잔액증명 연동) ==== + * 동일 글로벌 트랜잭션이지만 LG_MERCHPROOF 는 별도 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_MERCLOSE", 0L); + + userlog("[CL_MERCLOSE] 체인 호출 -> LG_MERCHPROOF bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_MERCHPROOF", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_MERCLOSE] tpcall(LG_MERCHPROOF) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9692); + Bchg(b, T_MSG, 0, "가맹점마감 증명 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_MERCLOSE] LG_MERCHPROOF 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_MERCLOSE] LG_MERCHPROOF 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_MERXCHECK.pgc b/app/src/cl/svc/CL_MERXCHECK.pgc index 2320a12..ce1b5c5 100644 --- a/app/src/cl/svc/CL_MERXCHECK.pgc +++ b/app/src/cl/svc/CL_MERXCHECK.pgc @@ -162,6 +162,59 @@ void CL_MERXCHECK(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_MERXCHECK 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_RIMERCH 연동 (가맹점 참조무결성 교차 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_RIMERCH 는 별도 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_MERXCHECK", 0L); + + userlog("[CL_MERXCHECK] 체인 호출 -> VL_RIMERCH bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_RIMERCH", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_MERXCHECK] tpcall(VL_RIMERCH) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9633); + Bchg(b, T_MSG, 0, "가맹점 참조무결성 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_MERXCHECK] VL_RIMERCH 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_MERXCHECK] VL_RIMERCH 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_MIDCLOSE.pgc b/app/src/cl/svc/CL_MIDCLOSE.pgc index d3fab18..6dc8c1e 100644 --- a/app/src/cl/svc/CL_MIDCLOSE.pgc +++ b/app/src/cl/svc/CL_MIDCLOSE.pgc @@ -208,6 +208,59 @@ void CL_MIDCLOSE(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_MIDCLOSE 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: LG_MERCHBAL 연동 (중간마감 확정분의 가맹점 잔액 연동) ==== + * 동일 글로벌 트랜잭션이지만 LG_MERCHBAL 는 별도 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_MIDCLOSE", 0L); + + userlog("[CL_MIDCLOSE] 체인 호출 -> LG_MERCHBAL bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_MERCHBAL", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_MIDCLOSE] tpcall(LG_MERCHBAL) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9691); + Bchg(b, T_MSG, 0, "중간마감 가맹점잔액 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_MIDCLOSE] LG_MERCHBAL 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_MIDCLOSE] LG_MERCHBAL 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_MONTHLY.pgc b/app/src/cl/svc/CL_MONTHLY.pgc index 0152633..c049d47 100644 --- a/app/src/cl/svc/CL_MONTHLY.pgc +++ b/app/src/cl/svc/CL_MONTHLY.pgc @@ -208,6 +208,59 @@ void CL_MONTHLY(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_MONTHLY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: LG_MONTHLYSUM 연동 (월마감 확정분의 원장 월집계 연동) ==== + * 동일 글로벌 트랜잭션이지만 LG_MONTHLYSUM 는 별도 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_MONTHLY", 0L); + + userlog("[CL_MONTHLY] 체인 호출 -> LG_MONTHLYSUM bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_MONTHLYSUM", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_MONTHLY] tpcall(LG_MONTHLYSUM) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9683); + Bchg(b, T_MSG, 0, "월마감 원장집계 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_MONTHLY] LG_MONTHLYSUM 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_MONTHLY] LG_MONTHLYSUM 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_MONVERIFY.pgc b/app/src/cl/svc/CL_MONVERIFY.pgc index a3c61e6..ee8c545 100644 --- a/app/src/cl/svc/CL_MONVERIFY.pgc +++ b/app/src/cl/svc/CL_MONVERIFY.pgc @@ -170,6 +170,59 @@ void CL_MONVERIFY(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_MONVERIFY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_SUMMARY 연동 (월마감 요약 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_SUMMARY 는 별도 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_MONVERIFY", 0L); + + userlog("[CL_MONVERIFY] 체인 호출 -> VL_SUMMARY bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_SUMMARY", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_MONVERIFY] tpcall(VL_SUMMARY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9615); + Bchg(b, T_MSG, 0, "월마감 요약검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_MONVERIFY] VL_SUMMARY 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_MONVERIFY] VL_SUMMARY 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_NETCROSS.pgc b/app/src/cl/svc/CL_NETCROSS.pgc index 1c57825..2ad17b9 100644 --- a/app/src/cl/svc/CL_NETCROSS.pgc +++ b/app/src/cl/svc/CL_NETCROSS.pgc @@ -161,6 +161,59 @@ void CL_NETCROSS(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_NETCROSS 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_SETTLE 연동 (정산 순액 교차 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_SETTLE 는 별도 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_NETCROSS", 0L); + + userlog("[CL_NETCROSS] 체인 호출 -> VL_SETTLE bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_SETTLE", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_NETCROSS] tpcall(VL_SETTLE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9636); + Bchg(b, T_MSG, 0, "정산 순액교차 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_NETCROSS] VL_SETTLE 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_NETCROSS] VL_SETTLE 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_NETVERIFY.pgc b/app/src/cl/svc/CL_NETVERIFY.pgc index bb15cd1..03b9431 100644 --- a/app/src/cl/svc/CL_NETVERIFY.pgc +++ b/app/src/cl/svc/CL_NETVERIFY.pgc @@ -171,6 +171,59 @@ void CL_NETVERIFY(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_NETVERIFY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_NEGNET 연동 (마감 순액 음수 이상 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_NEGNET 는 별도 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_NETVERIFY", 0L); + + userlog("[CL_NETVERIFY] 체인 호출 -> VL_NEGNET bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_NEGNET", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_NETVERIFY] tpcall(VL_NEGNET) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9623); + Bchg(b, T_MSG, 0, "순액 음수검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_NETVERIFY] VL_NEGNET 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_NETVERIFY] VL_NEGNET 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_POSTTRIG.pgc b/app/src/cl/svc/CL_POSTTRIG.pgc index 050a2ae..855b9c3 100644 --- a/app/src/cl/svc/CL_POSTTRIG.pgc +++ b/app/src/cl/svc/CL_POSTTRIG.pgc @@ -148,6 +148,59 @@ void CL_POSTTRIG(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_POSTTRIG 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: ST_DAILYCLOSE 연동 (마감 후처리로 정산 일마감 트리거) ==== + * 동일 글로벌 트랜잭션이지만 ST_DAILYCLOSE 는 별도 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_POSTTRIG", 0L); + + userlog("[CL_POSTTRIG] 체인 호출 -> ST_DAILYCLOSE bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("ST_DAILYCLOSE", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_POSTTRIG] tpcall(ST_DAILYCLOSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9652); + Bchg(b, T_MSG, 0, "정산 일마감 트리거 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_POSTTRIG] ST_DAILYCLOSE 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_POSTTRIG] ST_DAILYCLOSE 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_PRECHECK.pgc b/app/src/cl/svc/CL_PRECHECK.pgc index c2cbf98..83d1cea 100644 --- a/app/src/cl/svc/CL_PRECHECK.pgc +++ b/app/src/cl/svc/CL_PRECHECK.pgc @@ -159,6 +159,59 @@ void CL_PRECHECK(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_PRECHECK 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_REQUIRED 연동 (마감 착수 전 필수항목 점검) ==== + * 동일 글로벌 트랜잭션이지만 VL_REQUIRED 는 별도 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_PRECHECK", 0L); + + userlog("[CL_PRECHECK] 체인 호출 -> VL_REQUIRED bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_REQUIRED", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_PRECHECK] tpcall(VL_REQUIRED) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9638); + Bchg(b, T_MSG, 0, "마감 필수항목 점검 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_PRECHECK] VL_REQUIRED 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_PRECHECK] VL_REQUIRED 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_QTRVERIFY.pgc b/app/src/cl/svc/CL_QTRVERIFY.pgc index e20d97b..5dfbff5 100644 --- a/app/src/cl/svc/CL_QTRVERIFY.pgc +++ b/app/src/cl/svc/CL_QTRVERIFY.pgc @@ -170,6 +170,59 @@ void CL_QTRVERIFY(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_QTRVERIFY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_SUMRECON 연동 (분기마감 대사 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_SUMRECON 는 별도 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_QTRVERIFY", 0L); + + userlog("[CL_QTRVERIFY] 체인 호출 -> VL_SUMRECON bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_SUMRECON", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_QTRVERIFY] tpcall(VL_SUMRECON) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9616); + Bchg(b, T_MSG, 0, "분기마감 대사검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_QTRVERIFY] VL_SUMRECON 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_QTRVERIFY] VL_SUMRECON 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_QUARTER.pgc b/app/src/cl/svc/CL_QUARTER.pgc index b6d8116..27f2153 100644 --- a/app/src/cl/svc/CL_QUARTER.pgc +++ b/app/src/cl/svc/CL_QUARTER.pgc @@ -208,6 +208,59 @@ void CL_QUARTER(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_QUARTER 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: LG_PERIODTB 연동 (분기마감 확정분의 기간 시산표 연동) ==== + * 동일 글로벌 트랜잭션이지만 LG_PERIODTB 는 별도 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_QUARTER", 0L); + + userlog("[CL_QUARTER] 체인 호출 -> LG_PERIODTB bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_PERIODTB", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_QUARTER] tpcall(LG_PERIODTB) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9684); + Bchg(b, T_MSG, 0, "분기마감 기간시산 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_QUARTER] LG_PERIODTB 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_QUARTER] LG_PERIODTB 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_RECLOSE.pgc b/app/src/cl/svc/CL_RECLOSE.pgc index 2369dc4..432eac7 100644 --- a/app/src/cl/svc/CL_RECLOSE.pgc +++ b/app/src/cl/svc/CL_RECLOSE.pgc @@ -172,6 +172,59 @@ void CL_RECLOSE(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_RECLOSE 완료: 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_RECLOSE", 0L); + + userlog("[CL_RECLOSE] 체인 호출 -> 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_RECLOSE] tpcall(LG_REVERSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9697); + Bchg(b, T_MSG, 0, "재마감 역분개 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_RECLOSE] LG_REVERSE 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_RECLOSE] 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); } diff --git a/app/src/cl/svc/CL_RECON.pgc b/app/src/cl/svc/CL_RECON.pgc index da141c1..f61b9d9 100644 --- a/app/src/cl/svc/CL_RECON.pgc +++ b/app/src/cl/svc/CL_RECON.pgc @@ -171,6 +171,59 @@ void CL_RECON(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_RECON 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_SUMRECON 연동 (마감 대사 합계 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_SUMRECON 는 별도 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_RECON", 0L); + + userlog("[CL_RECON] 체인 호출 -> VL_SUMRECON bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_SUMRECON", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_RECON] tpcall(VL_SUMRECON) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9644); + Bchg(b, T_MSG, 0, "마감 대사 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_RECON] VL_SUMRECON 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_RECON] VL_SUMRECON 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_ROLLBACK.pgc b/app/src/cl/svc/CL_ROLLBACK.pgc index 9b68c75..fa5ed2c 100644 --- a/app/src/cl/svc/CL_ROLLBACK.pgc +++ b/app/src/cl/svc/CL_ROLLBACK.pgc @@ -162,6 +162,59 @@ void CL_ROLLBACK(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_ROLLBACK 완료: 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_ROLLBACK", 0L); + + userlog("[CL_ROLLBACK] 체인 호출 -> 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_ROLLBACK] tpcall(LG_REVERSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9699); + Bchg(b, T_MSG, 0, "마감롤백 역분개 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_ROLLBACK] LG_REVERSE 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_ROLLBACK] 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); } diff --git a/app/src/cl/svc/CL_SEGVERIFY.pgc b/app/src/cl/svc/CL_SEGVERIFY.pgc index 17d812c..d0c1d7e 100644 --- a/app/src/cl/svc/CL_SEGVERIFY.pgc +++ b/app/src/cl/svc/CL_SEGVERIFY.pgc @@ -170,6 +170,59 @@ void CL_SEGVERIFY(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_SEGVERIFY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_SUMNETCHK 연동 (세그먼트 마감 순액 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_SUMNETCHK 는 별도 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_SEGVERIFY", 0L); + + userlog("[CL_SEGVERIFY] 체인 호출 -> VL_SUMNETCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_SUMNETCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_SEGVERIFY] tpcall(VL_SUMNETCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9620); + Bchg(b, T_MSG, 0, "세그먼트 순액검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_SEGVERIFY] VL_SUMNETCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_SEGVERIFY] VL_SUMNETCHK 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_SEMIMONTH.pgc b/app/src/cl/svc/CL_SEMIMONTH.pgc index a3329eb..165a15a 100644 --- a/app/src/cl/svc/CL_SEMIMONTH.pgc +++ b/app/src/cl/svc/CL_SEMIMONTH.pgc @@ -207,6 +207,59 @@ void CL_SEMIMONTH(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_SEMIMONTH 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: LG_CORPSUM 연동 (반월마감 확정분의 법인집계 연동) ==== + * 동일 글로벌 트랜잭션이지만 LG_CORPSUM 는 별도 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_SEMIMONTH", 0L); + + userlog("[CL_SEMIMONTH] 체인 호출 -> LG_CORPSUM bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_CORPSUM", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_SEMIMONTH] tpcall(LG_CORPSUM) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9690); + Bchg(b, T_MSG, 0, "반월마감 법인집계 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_SEMIMONTH] LG_CORPSUM 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_SEMIMONTH] LG_CORPSUM 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_SNAPSHOT.pgc b/app/src/cl/svc/CL_SNAPSHOT.pgc index fec43e0..d3c7d2e 100644 --- a/app/src/cl/svc/CL_SNAPSHOT.pgc +++ b/app/src/cl/svc/CL_SNAPSHOT.pgc @@ -175,6 +175,59 @@ void CL_SNAPSHOT(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_SNAPSHOT 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: LG_TRIALBAL 연동 (마감 스냅샷 생성 시 시산표 연동) ==== + * 동일 글로벌 트랜잭션이지만 LG_TRIALBAL 는 별도 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_SNAPSHOT", 0L); + + userlog("[CL_SNAPSHOT] 체인 호출 -> LG_TRIALBAL bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_TRIALBAL", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_SNAPSHOT] tpcall(LG_TRIALBAL) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9686); + Bchg(b, T_MSG, 0, "스냅샷 시산표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_SNAPSHOT] LG_TRIALBAL 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_SNAPSHOT] LG_TRIALBAL 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_SNAPXCHECK.pgc b/app/src/cl/svc/CL_SNAPXCHECK.pgc index 8c7e51b..c3372e7 100644 --- a/app/src/cl/svc/CL_SNAPXCHECK.pgc +++ b/app/src/cl/svc/CL_SNAPXCHECK.pgc @@ -162,6 +162,59 @@ void CL_SNAPXCHECK(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_SNAPXCHECK 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_AXLEDGDC 연동 (스냅샷 대 원장 차대 교차 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_AXLEDGDC 는 별도 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_SNAPXCHECK", 0L); + + userlog("[CL_SNAPXCHECK] 체인 호출 -> VL_AXLEDGDC bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_AXLEDGDC", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_SNAPXCHECK] tpcall(VL_AXLEDGDC) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9634); + Bchg(b, T_MSG, 0, "스냅샷 차대교차 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_SNAPXCHECK] VL_AXLEDGDC 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_SNAPXCHECK] VL_AXLEDGDC 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_STCROSS.pgc b/app/src/cl/svc/CL_STCROSS.pgc index b96dc00..1e11a1e 100644 --- a/app/src/cl/svc/CL_STCROSS.pgc +++ b/app/src/cl/svc/CL_STCROSS.pgc @@ -162,6 +162,59 @@ void CL_STCROSS(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_STCROSS 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_RISETTLE 연동 (정산 참조무결성 교차 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_RISETTLE 는 별도 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_STCROSS", 0L); + + userlog("[CL_STCROSS] 체인 호출 -> VL_RISETTLE bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_RISETTLE", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_STCROSS] tpcall(VL_RISETTLE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9635); + Bchg(b, T_MSG, 0, "정산 참조무결성 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_STCROSS] VL_RISETTLE 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_STCROSS] VL_RISETTLE 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_TENDAY.pgc b/app/src/cl/svc/CL_TENDAY.pgc index dcdb436..c05eca3 100644 --- a/app/src/cl/svc/CL_TENDAY.pgc +++ b/app/src/cl/svc/CL_TENDAY.pgc @@ -207,6 +207,59 @@ void CL_TENDAY(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_TENDAY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: LG_DEPTSUM 연동 (순(10일)마감 확정분의 부서집계 연동) ==== + * 동일 글로벌 트랜잭션이지만 LG_DEPTSUM 는 별도 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_TENDAY", 0L); + + userlog("[CL_TENDAY] 체인 호출 -> LG_DEPTSUM bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_DEPTSUM", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_TENDAY] tpcall(LG_DEPTSUM) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9689); + Bchg(b, T_MSG, 0, "순마감 부서집계 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_TENDAY] LG_DEPTSUM 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_TENDAY] LG_DEPTSUM 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_TRIGSETTLE.pgc b/app/src/cl/svc/CL_TRIGSETTLE.pgc index 211349b..d93a982 100644 --- a/app/src/cl/svc/CL_TRIGSETTLE.pgc +++ b/app/src/cl/svc/CL_TRIGSETTLE.pgc @@ -148,6 +148,59 @@ void CL_TRIGSETTLE(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_TRIGSETTLE 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: SETTLE 연동 (마감 확정에 따른 정산 실행 트리거) ==== + * 동일 글로벌 트랜잭션이지만 SETTLE 는 별도 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_TRIGSETTLE", 0L); + + userlog("[CL_TRIGSETTLE] 체인 호출 -> SETTLE bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("SETTLE", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_TRIGSETTLE] tpcall(SETTLE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9651); + Bchg(b, T_MSG, 0, "정산 트리거 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_TRIGSETTLE] SETTLE 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_TRIGSETTLE] SETTLE 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_VERIFY.pgc b/app/src/cl/svc/CL_VERIFY.pgc index a7b4520..7b48d07 100644 --- a/app/src/cl/svc/CL_VERIFY.pgc +++ b/app/src/cl/svc/CL_VERIFY.pgc @@ -171,6 +171,59 @@ void CL_VERIFY(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_VERIFY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_BALANCE 연동 (마감 확정 전 잔액 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_BALANCE 는 별도 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_VERIFY", 0L); + + userlog("[CL_VERIFY] 체인 호출 -> VL_BALANCE bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_BALANCE", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_VERIFY] tpcall(VL_BALANCE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9611); + Bchg(b, T_MSG, 0, "마감 잔액검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_VERIFY] VL_BALANCE 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_VERIFY] VL_BALANCE 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_WEEKLY.pgc b/app/src/cl/svc/CL_WEEKLY.pgc index 6e5a580..06e87e6 100644 --- a/app/src/cl/svc/CL_WEEKLY.pgc +++ b/app/src/cl/svc/CL_WEEKLY.pgc @@ -207,6 +207,59 @@ void CL_WEEKLY(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_WEEKLY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: LG_ACCTSUM 연동 (주마감 확정분의 계정집계 연동) ==== + * 동일 글로벌 트랜잭션이지만 LG_ACCTSUM 는 별도 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_WEEKLY", 0L); + + userlog("[CL_WEEKLY] 체인 호출 -> LG_ACCTSUM bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_ACCTSUM", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_WEEKLY] tpcall(LG_ACCTSUM) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9688); + Bchg(b, T_MSG, 0, "주마감 계정집계 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_WEEKLY] LG_ACCTSUM 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_WEEKLY] LG_ACCTSUM 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_WEEKVERIFY.pgc b/app/src/cl/svc/CL_WEEKVERIFY.pgc index c7f19d0..f884460 100644 --- a/app/src/cl/svc/CL_WEEKVERIFY.pgc +++ b/app/src/cl/svc/CL_WEEKVERIFY.pgc @@ -170,6 +170,59 @@ void CL_WEEKVERIFY(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_WEEKVERIFY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_SUMTXNCNT 연동 (주마감 거래건수 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_SUMTXNCNT 는 별도 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_WEEKVERIFY", 0L); + + userlog("[CL_WEEKVERIFY] 체인 호출 -> VL_SUMTXNCNT bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_SUMTXNCNT", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_WEEKVERIFY] tpcall(VL_SUMTXNCNT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9618); + Bchg(b, T_MSG, 0, "주마감 건수검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_WEEKVERIFY] VL_SUMTXNCNT 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_WEEKVERIFY] VL_SUMTXNCNT 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_YEAREND.pgc b/app/src/cl/svc/CL_YEAREND.pgc index ca51f7f..ea17527 100644 --- a/app/src/cl/svc/CL_YEAREND.pgc +++ b/app/src/cl/svc/CL_YEAREND.pgc @@ -208,6 +208,59 @@ void CL_YEAREND(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_YEAREND 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: LG_SPANTB 연동 (연마감 확정분의 구간 시산표 연동) ==== + * 동일 글로벌 트랜잭션이지만 LG_SPANTB 는 별도 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_YEAREND", 0L); + + userlog("[CL_YEAREND] 체인 호출 -> LG_SPANTB bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_SPANTB", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_YEAREND] tpcall(LG_SPANTB) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9685); + Bchg(b, T_MSG, 0, "연마감 구간시산 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_YEAREND] LG_SPANTB 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_YEAREND] LG_SPANTB 체인 정상 완료 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); } diff --git a/app/src/cl/svc/CL_YEARVERIFY.pgc b/app/src/cl/svc/CL_YEARVERIFY.pgc index a41bb63..65f8831 100644 --- a/app/src/cl/svc/CL_YEARVERIFY.pgc +++ b/app/src/cl/svc/CL_YEARVERIFY.pgc @@ -170,6 +170,59 @@ void CL_YEARVERIFY(TPSVCINFO *p) setl(b, T_GROSS, o_amount); Bchg(b, T_MSG, 0, o_msg, 0L); userlog("CL_YEARVERIFY 완료: rc=%ld count=%ld amount=%ld", o_rc, o_count, o_amount); + + /* ==== 10) 업무흐름 체인: VL_SUMGROSS 연동 (연마감 총액 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_SUMGROSS 는 별도 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_YEARVERIFY", 0L); + + userlog("[CL_YEARVERIFY] 체인 호출 -> VL_SUMGROSS bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_SUMGROSS", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[CL_YEARVERIFY] tpcall(VL_SUMGROSS) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9617); + Bchg(b, T_MSG, 0, "연마감 총액검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[CL_YEARVERIFY] VL_SUMGROSS 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[CL_YEARVERIFY] VL_SUMGROSS 체인 정상 완료 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); } diff --git a/app/src/cm/dbio/cm_code_dbio.pgc b/app/src/cm/dbio/cm_code_dbio.pgc index ded04ce..1d88c90 100644 --- a/app/src/cm/dbio/cm_code_dbio.pgc +++ b/app/src/cm/dbio/cm_code_dbio.pgc @@ -22,7 +22,14 @@ int cmdb_get_code_name(const char *grp, const char *code, char *out) userlog("cmdb_get_code_name FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); return -1; } - strncpy(out, h_name, 127); out[127] = 0; + /* 실제 값 길이만 복사 (strncpy 의 NUL 패딩으로 호출자 스택을 넘어 쓰는 것 방지). + * 상세 사유는 cm_param_dbio.pgc 의 cmdb_get_param 주석 참조. */ + { + size_t vn = strlen(h_name); + if (vn > 127) vn = 127; + memcpy(out, h_name, vn); + out[vn] = 0; + } return 0; } diff --git a/app/src/cm/dbio/cm_param_dbio.pgc b/app/src/cm/dbio/cm_param_dbio.pgc index 2b62cff..2669c8a 100644 --- a/app/src/cm/dbio/cm_param_dbio.pgc +++ b/app/src/cm/dbio/cm_param_dbio.pgc @@ -19,7 +19,20 @@ int cmdb_get_param(const char *key, char *out) userlog("cmdb_get_param FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); return -1; } - strncpy(out, h_val, 127); out[127] = 0; + /* 실제 값 길이만 복사한다. + * 기존 strncpy(out, h_val, 127) 은 값이 짧아도 남는 자리를 NUL 로 '채워 쓰기' + * 때문에 항상 128바이트를 기록했다. 호출자 대부분은 hz_bizdate[16] 같은 작은 + * ecpg 호스트변수를 넘기므로(BIZ_DATE 조회 133곳) 매번 112바이트가 호출자 + * 스택을 넘어 파손시켰고, 인접 호스트변수(예: ccy)가 깨지거나 서버 카피가 + * SIGSEGV 로 죽었다. 서버 카피가 죽으면 호출자는 응답을 못 받고 트랜잭션 + * 타임아웃(60초, TPETIME)까지 블록된다 — 이번 웨이브가 잡는 장기블록의 + * 또 다른 원인이다. */ + { + size_t vn = strlen(h_val); + if (vn > 127) vn = 127; + memcpy(out, h_val, vn); + out[vn] = 0; + } return 0; } diff --git a/app/src/cm/svc/CM_ADDDAYS.pgc b/app/src/cm/svc/CM_ADDDAYS.pgc index fa8cb06..4ce8261 100644 --- a/app/src/cm/svc/CM_ADDDAYS.pgc +++ b/app/src/cm/svc/CM_ADDDAYS.pgc @@ -163,5 +163,52 @@ void CM_ADDDAYS(TPSVCINFO *p) setl(b, T_RC, 0); userlog("CM_ADDDAYS 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_ADDDAYS -> CM_HOLIDAY_CHK (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str3[256]; gets_(b, T_STR3, ch_o_str3, sizeof(ch_o_str3)); + if (ch_do) { + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + { char ch_dt[16]; gets_(b, T_BIZDATE, ch_dt, sizeof(ch_dt)); + Bchg(b, T_STR1, 0, ch_dt, 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("CM_HOLIDAY_CHK", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_ADDDAYS] tpcall(CM_HOLIDAY_CHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7334); + Bchg(b, T_MSG, 0, "일수가산 휴일판정 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_ADDDAYS] 휴일판정 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR3, 0, ch_o_str3, 0L); + } else { + userlog("[CM_ADDDAYS] 체인 대상 컨텍스트 없음 - CM_HOLIDAY_CHK 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_BATDEP_CHK.pgc b/app/src/cm/svc/CM_BATDEP_CHK.pgc index 1cfd4a7..3f602e6 100644 --- a/app/src/cm/svc/CM_BATDEP_CHK.pgc +++ b/app/src/cm/svc/CM_BATDEP_CHK.pgc @@ -164,5 +164,57 @@ void CM_BATDEP_CHK(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_BATDEP_CHK 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_BATDEP_CHK -> CM_BATLAST (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_key1[256]; gets_(b, T_KEY1, ch_o_key1, sizeof(ch_o_key1)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str4[256]; gets_(b, T_STR4, ch_o_str4, sizeof(ch_o_str4)); + if (ch_do) { + Bchg(b, T_KEY1, 0, "BATCH", 0L); + Bchg(b, T_STR1, 0, "CM_BATDEP_CHK", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_BATLAST", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_BATDEP_CHK] tpcall(CM_BATLAST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7341); + Bchg(b, T_MSG, 0, "선행배치 확인 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + { char ch_ld[16]; gets_(b, T_STR4, ch_ld, sizeof(ch_ld)); + userlog("[CM_BATDEP_CHK] 선행수행 연동 완료 최종일=%s", ch_ld); } + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_KEY1, 0, ch_o_key1, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR4, 0, ch_o_str4, 0L); + } else { + userlog("[CM_BATDEP_CHK] 체인 대상 컨텍스트 없음 - CM_BATLAST 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_BATDEP_SET.pgc b/app/src/cm/svc/CM_BATDEP_SET.pgc index 027b263..a6f25c1 100644 --- a/app/src/cm/svc/CM_BATDEP_SET.pgc +++ b/app/src/cm/svc/CM_BATDEP_SET.pgc @@ -155,5 +155,53 @@ void CM_BATDEP_SET(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_BATDEP_SET 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_BATDEP_SET -> CM_BATLAST (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_key1[256]; gets_(b, T_KEY1, ch_o_key1, sizeof(ch_o_key1)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + Bchg(b, T_KEY1, 0, "BATCH", 0L); + Bchg(b, T_STR1, 0, "CM_BATDEP_SET", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_BATLAST", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_BATDEP_SET] tpcall(CM_BATLAST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7342); + Bchg(b, T_MSG, 0, "선행배치 등록확인 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + { char ch_ld[16]; gets_(b, T_STR4, ch_ld, sizeof(ch_ld)); + userlog("[CM_BATDEP_SET] 선행수행 연동 완료 최종일=%s", ch_ld); } + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_KEY1, 0, ch_o_key1, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[CM_BATDEP_SET] 체인 대상 컨텍스트 없음 - CM_BATLAST 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_BATHIST_CNT.pgc b/app/src/cm/svc/CM_BATHIST_CNT.pgc index 766a224..2b54836 100644 --- a/app/src/cm/svc/CM_BATHIST_CNT.pgc +++ b/app/src/cm/svc/CM_BATHIST_CNT.pgc @@ -163,5 +163,63 @@ void CM_BATHIST_CNT(TPSVCINFO *p) setl(b, T_RC, 0); userlog("CM_BATHIST_CNT 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_BATHIST_CNT -> CM_BATLAST (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg1 = getl(b, T_ARG1); + long ch_o_arg2 = getl(b, T_ARG2); + long ch_o_arg3 = getl(b, T_ARG3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_count = getl(b, T_COUNT); + long ch_o_id1 = getl(b, T_ID1); + char ch_o_key1[256]; gets_(b, T_KEY1, ch_o_key1, sizeof(ch_o_key1)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + Bchg(b, T_KEY1, 0, "BATCH", 0L); + Bchg(b, T_STR1, 0, "CM_BATHIST_CNT", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_BATLAST", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_BATHIST_CNT] tpcall(CM_BATLAST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7344); + Bchg(b, T_MSG, 0, "수행이력 최종실행 확인 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + { char ch_ld[16]; gets_(b, T_STR4, ch_ld, sizeof(ch_ld)); + userlog("[CM_BATHIST_CNT] 선행수행 연동 완료 최종일=%s", ch_ld); } + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG1, ch_o_arg1); + setl(b, T_ARG2, ch_o_arg2); + setl(b, T_ARG3, ch_o_arg3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_COUNT, ch_o_count); + setl(b, T_ID1, ch_o_id1); + Bchg(b, T_KEY1, 0, ch_o_key1, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[CM_BATHIST_CNT] 체인 대상 컨텍스트 없음 - CM_BATLAST 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_BATRERUN_REQ.pgc b/app/src/cm/svc/CM_BATRERUN_REQ.pgc index fc4a4d9..c70ceac 100644 --- a/app/src/cm/svc/CM_BATRERUN_REQ.pgc +++ b/app/src/cm/svc/CM_BATRERUN_REQ.pgc @@ -162,5 +162,57 @@ void CM_BATRERUN_REQ(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_BATRERUN_REQ 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_BATRERUN_REQ -> CM_BATLAST (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_count = getl(b, T_COUNT); + long ch_o_id1 = getl(b, T_ID1); + char ch_o_key1[256]; gets_(b, T_KEY1, ch_o_key1, sizeof(ch_o_key1)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + Bchg(b, T_KEY1, 0, "BATCH", 0L); + Bchg(b, T_STR1, 0, "CM_BATRERUN_REQ", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_BATLAST", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_BATRERUN_REQ] tpcall(CM_BATLAST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7343); + Bchg(b, T_MSG, 0, "재수행 최종실행 확인 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + { char ch_ld[16]; gets_(b, T_STR4, ch_ld, sizeof(ch_ld)); + userlog("[CM_BATRERUN_REQ] 선행수행 연동 완료 최종일=%s", ch_ld); } + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_COUNT, ch_o_count); + setl(b, T_ID1, ch_o_id1); + Bchg(b, T_KEY1, 0, ch_o_key1, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[CM_BATRERUN_REQ] 체인 대상 컨텍스트 없음 - CM_BATLAST 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_BATSCHD_DEL.pgc b/app/src/cm/svc/CM_BATSCHD_DEL.pgc index 1e87d7a..88ac086 100644 --- a/app/src/cm/svc/CM_BATSCHD_DEL.pgc +++ b/app/src/cm/svc/CM_BATSCHD_DEL.pgc @@ -157,5 +157,55 @@ void CM_BATSCHD_DEL(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_BATSCHD_DEL 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_BATSCHD_DEL -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "CM_BATSCHD_DEL", 0L); + Bchg(b, T_MSG, 0, "배치 스케줄 삭제", 0L); + Bchg(b, T_STR1, 0, "CM_BATSCHD_DEL", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_BATSCHD_DEL] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7314); + Bchg(b, T_MSG, 0, "배치삭제 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_BATSCHD_DEL] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[CM_BATSCHD_DEL] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_BATSCHD_REG.pgc b/app/src/cm/svc/CM_BATSCHD_REG.pgc index 577889e..9634977 100644 --- a/app/src/cm/svc/CM_BATSCHD_REG.pgc +++ b/app/src/cm/svc/CM_BATSCHD_REG.pgc @@ -159,5 +159,53 @@ void CM_BATSCHD_REG(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_BATSCHD_REG 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_BATSCHD_REG -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "CM_BATSCHD_REG", 0L); + Bchg(b, T_MSG, 0, "배치 스케줄 등록", 0L); + Bchg(b, T_STR1, 0, "CM_BATSCHD_REG", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_BATSCHD_REG] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7313); + Bchg(b, T_MSG, 0, "배치등록 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_BATSCHD_REG] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[CM_BATSCHD_REG] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_BIZDAY_ADD.pgc b/app/src/cm/svc/CM_BIZDAY_ADD.pgc index 00f0f30..f1eeffd 100644 --- a/app/src/cm/svc/CM_BIZDAY_ADD.pgc +++ b/app/src/cm/svc/CM_BIZDAY_ADD.pgc @@ -170,5 +170,54 @@ void CM_BIZDAY_ADD(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_BIZDAY_ADD 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_BIZDAY_ADD -> CM_HOLIDAY_CHK (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg2 = getl(b, T_ARG2); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str4[256]; gets_(b, T_STR4, ch_o_str4, sizeof(ch_o_str4)); + if (ch_do) { + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + { char ch_dt[16]; gets_(b, T_BIZDATE, ch_dt, sizeof(ch_dt)); + Bchg(b, T_STR1, 0, ch_dt, 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("CM_HOLIDAY_CHK", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_BIZDAY_ADD] tpcall(CM_HOLIDAY_CHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7335); + Bchg(b, T_MSG, 0, "영업일가산 휴일판정 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_BIZDAY_ADD] 휴일판정 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG2, ch_o_arg2); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR4, 0, ch_o_str4, 0L); + } else { + userlog("[CM_BIZDAY_ADD] 체인 대상 컨텍스트 없음 - CM_HOLIDAY_CHK 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_BIZDAY_CNT.pgc b/app/src/cm/svc/CM_BIZDAY_CNT.pgc index 3512806..0ed6604 100644 --- a/app/src/cm/svc/CM_BIZDAY_CNT.pgc +++ b/app/src/cm/svc/CM_BIZDAY_CNT.pgc @@ -178,5 +178,56 @@ void CM_BIZDAY_CNT(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_BIZDAY_CNT 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_BIZDAY_CNT -> CM_HOLIDAY_CHK (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg1 = getl(b, T_ARG1); + long ch_o_arg2 = getl(b, T_ARG2); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + { char ch_dt[16]; gets_(b, T_BIZDATE, ch_dt, sizeof(ch_dt)); + Bchg(b, T_STR1, 0, ch_dt, 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("CM_HOLIDAY_CHK", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_BIZDAY_CNT] tpcall(CM_HOLIDAY_CHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7336); + Bchg(b, T_MSG, 0, "영업일수 휴일판정 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_BIZDAY_CNT] 휴일판정 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG1, ch_o_arg1); + setl(b, T_ARG2, ch_o_arg2); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[CM_BIZDAY_CNT] 체인 대상 컨텍스트 없음 - CM_HOLIDAY_CHK 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_CACHE_INV.pgc b/app/src/cm/svc/CM_CACHE_INV.pgc index 6ed29ee..b9db2f2 100644 --- a/app/src/cm/svc/CM_CACHE_INV.pgc +++ b/app/src/cm/svc/CM_CACHE_INV.pgc @@ -141,5 +141,50 @@ void CM_CACHE_INV(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_CACHE_INV 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_CACHE_INV -> CM_PARAM (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + Bchg(b, T_STR1, 0, "BIZ_DATE", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_PARAM", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_CACHE_INV] tpcall(CM_PARAM) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7352); + Bchg(b, T_MSG, 0, "캐시무효화 파라미터 조회 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + { char ch_pv[128]; gets_(b, T_STR3, ch_pv, sizeof(ch_pv)); + userlog("[CM_CACHE_INV] 파라미터 연동 완료 BIZ_DATE=%s", ch_pv); } + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[CM_CACHE_INV] 체인 대상 컨텍스트 없음 - CM_PARAM 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_CACHE_LOAD.pgc b/app/src/cm/svc/CM_CACHE_LOAD.pgc index 13fe7ff..db092dd 100644 --- a/app/src/cm/svc/CM_CACHE_LOAD.pgc +++ b/app/src/cm/svc/CM_CACHE_LOAD.pgc @@ -147,5 +147,52 @@ void CM_CACHE_LOAD(TPSVCINFO *p) setl(b, T_RC, 0); userlog("CM_CACHE_LOAD 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_CACHE_LOAD -> CM_PARAM (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + Bchg(b, T_STR1, 0, "BIZ_DATE", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_PARAM", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_CACHE_LOAD] tpcall(CM_PARAM) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7351); + Bchg(b, T_MSG, 0, "캐시적재 파라미터 조회 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + { char ch_pv[128]; gets_(b, T_STR3, ch_pv, sizeof(ch_pv)); + userlog("[CM_CACHE_LOAD] 파라미터 연동 완료 BIZ_DATE=%s", ch_pv); } + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[CM_CACHE_LOAD] 체인 대상 컨텍스트 없음 - CM_PARAM 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_CODE.pgc b/app/src/cm/svc/CM_CODE.pgc index eb2e644..412aa3f 100644 --- a/app/src/cm/svc/CM_CODE.pgc +++ b/app/src/cm/svc/CM_CODE.pgc @@ -142,5 +142,50 @@ void CM_CODE(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_CODE 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_CODE -> CM_PARAM (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + Bchg(b, T_STR1, 0, "BIZ_DATE", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_PARAM", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_CODE] tpcall(CM_PARAM) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7353); + Bchg(b, T_MSG, 0, "코드조회 파라미터 조회 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + { char ch_pv[128]; gets_(b, T_STR3, ch_pv, sizeof(ch_pv)); + userlog("[CM_CODE] 파라미터 연동 완료 BIZ_DATE=%s", ch_pv); } + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[CM_CODE] 체인 대상 컨텍스트 없음 - CM_PARAM 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_CODEGRP_REG.pgc b/app/src/cm/svc/CM_CODEGRP_REG.pgc index 342232c..a560346 100644 --- a/app/src/cm/svc/CM_CODEGRP_REG.pgc +++ b/app/src/cm/svc/CM_CODEGRP_REG.pgc @@ -161,5 +161,50 @@ void CM_CODEGRP_REG(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_CODEGRP_REG 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_CODEGRP_REG -> CM_PARAM (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + Bchg(b, T_STR1, 0, "BIZ_DATE", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_PARAM", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_CODEGRP_REG] tpcall(CM_PARAM) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7354); + Bchg(b, T_MSG, 0, "코드그룹 파라미터 조회 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + { char ch_pv[128]; gets_(b, T_STR3, ch_pv, sizeof(ch_pv)); + userlog("[CM_CODEGRP_REG] 파라미터 연동 완료 BIZ_DATE=%s", ch_pv); } + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[CM_CODEGRP_REG] 체인 대상 컨텍스트 없음 - CM_PARAM 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_ERRMSG.pgc b/app/src/cm/svc/CM_ERRMSG.pgc index 1aad152..08acf7d 100644 --- a/app/src/cm/svc/CM_ERRMSG.pgc +++ b/app/src/cm/svc/CM_ERRMSG.pgc @@ -147,5 +147,53 @@ void CM_ERRMSG(TPSVCINFO *p) setl(b, T_RC, 0); userlog("CM_ERRMSG 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_ERRMSG -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "CM_ERRMSG", 0L); + Bchg(b, T_MSG, 0, "오류 메시지 조회", 0L); + Bchg(b, T_STR1, 0, "CM_ERRMSG", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_ERRMSG] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7316); + Bchg(b, T_MSG, 0, "오류메시지 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_ERRMSG] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[CM_ERRMSG] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_FX_CONV.pgc b/app/src/cm/svc/CM_FX_CONV.pgc index 3092905..9300e32 100644 --- a/app/src/cm/svc/CM_FX_CONV.pgc +++ b/app/src/cm/svc/CM_FX_CONV.pgc @@ -149,5 +149,55 @@ void CM_FX_CONV(TPSVCINFO *p) setl(b, T_RC, 0); userlog("CM_FX_CONV 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_FX_CONV -> CM_FX (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg1 = getl(b, T_ARG1); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_ccy[256]; gets_(b, T_CCY, ch_o_ccy, sizeof(ch_o_ccy)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + { char ch_cy[8]; gets_(b, T_CCY, ch_cy, sizeof(ch_cy)); + if (ch_cy[0] == 0) Bchg(b, T_CCY, 0, "USD", 0L); } + Bchg(b, T_STR1, 0, "CM_FX_CONV", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_FX", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_FX_CONV] tpcall(CM_FX) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7321); + Bchg(b, T_MSG, 0, "환율 조회 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_FX_CONV] 환율 연동 완료 rate=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG1, ch_o_arg1); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CCY, 0, ch_o_ccy, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[CM_FX_CONV] 체인 대상 컨텍스트 없음 - CM_FX 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_FX_CROSS.pgc b/app/src/cm/svc/CM_FX_CROSS.pgc index 366294a..3ef606b 100644 --- a/app/src/cm/svc/CM_FX_CROSS.pgc +++ b/app/src/cm/svc/CM_FX_CROSS.pgc @@ -153,5 +153,59 @@ void CM_FX_CROSS(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_FX_CROSS 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_FX_CROSS -> CM_FX (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt1 = getl(b, T_AMT1); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_arg1 = getl(b, T_ARG1); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_ccy[256]; gets_(b, T_CCY, ch_o_ccy, sizeof(ch_o_ccy)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + { char ch_cy[8]; gets_(b, T_CCY, ch_cy, sizeof(ch_cy)); + if (ch_cy[0] == 0) Bchg(b, T_CCY, 0, "USD", 0L); } + Bchg(b, T_STR1, 0, "CM_FX_CROSS", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_FX", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_FX_CROSS] tpcall(CM_FX) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7322); + Bchg(b, T_MSG, 0, "크로스환율 조회 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_FX_CROSS] 환율 연동 완료 rate=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT1, ch_o_amt1); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_ARG1, ch_o_arg1); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CCY, 0, ch_o_ccy, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[CM_FX_CROSS] 체인 대상 컨텍스트 없음 - CM_FX 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_FX_INVERT.pgc b/app/src/cm/svc/CM_FX_INVERT.pgc index e7bf508..02592ed 100644 --- a/app/src/cm/svc/CM_FX_INVERT.pgc +++ b/app/src/cm/svc/CM_FX_INVERT.pgc @@ -151,5 +151,57 @@ void CM_FX_INVERT(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_FX_INVERT 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_FX_INVERT -> CM_FX (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg1 = getl(b, T_ARG1); + long ch_o_arg2 = getl(b, T_ARG2); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_ccy[256]; gets_(b, T_CCY, ch_o_ccy, sizeof(ch_o_ccy)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + { char ch_cy[8]; gets_(b, T_CCY, ch_cy, sizeof(ch_cy)); + if (ch_cy[0] == 0) Bchg(b, T_CCY, 0, "USD", 0L); } + Bchg(b, T_STR1, 0, "CM_FX_INVERT", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_FX", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_FX_INVERT] tpcall(CM_FX) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7323); + Bchg(b, T_MSG, 0, "역환율 조회 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_FX_INVERT] 환율 연동 완료 rate=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG1, ch_o_arg1); + setl(b, T_ARG2, ch_o_arg2); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CCY, 0, ch_o_ccy, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[CM_FX_INVERT] 체인 대상 컨텍스트 없음 - CM_FX 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_FX_MARGIN.pgc b/app/src/cm/svc/CM_FX_MARGIN.pgc index c919603..960b770 100644 --- a/app/src/cm/svc/CM_FX_MARGIN.pgc +++ b/app/src/cm/svc/CM_FX_MARGIN.pgc @@ -149,5 +149,59 @@ void CM_FX_MARGIN(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_FX_MARGIN 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_FX_MARGIN -> CM_FX (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg3 = getl(b, T_ARG3); + long ch_o_arg4 = getl(b, T_ARG4); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_ccy[256]; gets_(b, T_CCY, ch_o_ccy, sizeof(ch_o_ccy)); + long ch_o_delta = getl(b, T_DELTA); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + { char ch_cy[8]; gets_(b, T_CCY, ch_cy, sizeof(ch_cy)); + if (ch_cy[0] == 0) Bchg(b, T_CCY, 0, "USD", 0L); } + Bchg(b, T_STR1, 0, "CM_FX_MARGIN", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_FX", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_FX_MARGIN] tpcall(CM_FX) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7324); + Bchg(b, T_MSG, 0, "환마진 기준환율 조회 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_FX_MARGIN] 환율 연동 완료 rate=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG3, ch_o_arg3); + setl(b, T_ARG4, ch_o_arg4); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CCY, 0, ch_o_ccy, 0L); + setl(b, T_DELTA, ch_o_delta); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[CM_FX_MARGIN] 체인 대상 컨텍스트 없음 - CM_FX 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_FX_PUBLISH.pgc b/app/src/cm/svc/CM_FX_PUBLISH.pgc index d796c11..8c4e3ea 100644 --- a/app/src/cm/svc/CM_FX_PUBLISH.pgc +++ b/app/src/cm/svc/CM_FX_PUBLISH.pgc @@ -162,5 +162,53 @@ void CM_FX_PUBLISH(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_FX_PUBLISH 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_FX_PUBLISH -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "CM_FX_PUBLISH", 0L); + Bchg(b, T_MSG, 0, "환율 고시 반영", 0L); + Bchg(b, T_STR1, 0, "CM_FX_PUBLISH", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_FX_PUBLISH] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7308); + Bchg(b, T_MSG, 0, "환율고시 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_FX_PUBLISH] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[CM_FX_PUBLISH] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_FX_TRIANGLE.pgc b/app/src/cm/svc/CM_FX_TRIANGLE.pgc index 07f82b7..2f2d6b8 100644 --- a/app/src/cm/svc/CM_FX_TRIANGLE.pgc +++ b/app/src/cm/svc/CM_FX_TRIANGLE.pgc @@ -157,5 +157,57 @@ void CM_FX_TRIANGLE(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_FX_TRIANGLE 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_FX_TRIANGLE -> CM_FX (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg2 = getl(b, T_ARG2); + long ch_o_arg3 = getl(b, T_ARG3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_ccy[256]; gets_(b, T_CCY, ch_o_ccy, sizeof(ch_o_ccy)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + { char ch_cy[8]; gets_(b, T_CCY, ch_cy, sizeof(ch_cy)); + if (ch_cy[0] == 0) Bchg(b, T_CCY, 0, "USD", 0L); } + Bchg(b, T_STR1, 0, "CM_FX_TRIANGLE", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_FX", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_FX_TRIANGLE] tpcall(CM_FX) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7325); + Bchg(b, T_MSG, 0, "삼각환율 조회 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_FX_TRIANGLE] 환율 연동 완료 rate=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG2, ch_o_arg2); + setl(b, T_ARG3, ch_o_arg3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CCY, 0, ch_o_ccy, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[CM_FX_TRIANGLE] 체인 대상 컨텍스트 없음 - CM_FX 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_MONTHEND.pgc b/app/src/cm/svc/CM_MONTHEND.pgc index 72fcbe5..ee541ba 100644 --- a/app/src/cm/svc/CM_MONTHEND.pgc +++ b/app/src/cm/svc/CM_MONTHEND.pgc @@ -159,5 +159,54 @@ void CM_MONTHEND(TPSVCINFO *p) setl(b, T_RC, 0); userlog("CM_MONTHEND 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_MONTHEND -> CM_BIZDAY (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg1 = getl(b, T_ARG1); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str3[256]; gets_(b, T_STR3, ch_o_str3, sizeof(ch_o_str3)); + if (ch_do) { + Bchg(b, T_STR1, 0, "CM_MONTHEND", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_BIZDAY", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_MONTHEND] tpcall(CM_BIZDAY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7333); + Bchg(b, T_MSG, 0, "월말 기준영업일 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + { char ch_bz[16]; gets_(b, T_BIZDATE, ch_bz, sizeof(ch_bz)); + userlog("[CM_MONTHEND] 기준영업일 연동 완료 biz=%s", ch_bz); } + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG1, ch_o_arg1); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR3, 0, ch_o_str3, 0L); + } else { + userlog("[CM_MONTHEND] 체인 대상 컨텍스트 없음 - CM_BIZDAY 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_MSG_RENDER.pgc b/app/src/cm/svc/CM_MSG_RENDER.pgc index b783963..5b40a53 100644 --- a/app/src/cm/svc/CM_MSG_RENDER.pgc +++ b/app/src/cm/svc/CM_MSG_RENDER.pgc @@ -169,5 +169,53 @@ void CM_MSG_RENDER(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_MSG_RENDER 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_MSG_RENDER -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "CM_MSG_RENDER", 0L); + Bchg(b, T_MSG, 0, "메시지 렌더링 수행", 0L); + Bchg(b, T_STR1, 0, "CM_MSG_RENDER", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_MSG_RENDER] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7315); + Bchg(b, T_MSG, 0, "메시지렌더 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_MSG_RENDER] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[CM_MSG_RENDER] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_NEXTBIZ.pgc b/app/src/cm/svc/CM_NEXTBIZ.pgc index 5512c4d..7153c1d 100644 --- a/app/src/cm/svc/CM_NEXTBIZ.pgc +++ b/app/src/cm/svc/CM_NEXTBIZ.pgc @@ -152,5 +152,52 @@ void CM_NEXTBIZ(TPSVCINFO *p) setl(b, T_RC, 0); userlog("CM_NEXTBIZ 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_NEXTBIZ -> CM_BIZDAY (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str3[256]; gets_(b, T_STR3, ch_o_str3, sizeof(ch_o_str3)); + if (ch_do) { + Bchg(b, T_STR1, 0, "CM_NEXTBIZ", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_BIZDAY", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_NEXTBIZ] tpcall(CM_BIZDAY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7331); + Bchg(b, T_MSG, 0, "기준영업일 조회 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + { char ch_bz[16]; gets_(b, T_BIZDATE, ch_bz, sizeof(ch_bz)); + userlog("[CM_NEXTBIZ] 기준영업일 연동 완료 biz=%s", ch_bz); } + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR3, 0, ch_o_str3, 0L); + } else { + userlog("[CM_NEXTBIZ] 체인 대상 컨텍스트 없음 - CM_BIZDAY 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_NOTI_QUOTA.pgc b/app/src/cm/svc/CM_NOTI_QUOTA.pgc index 8da0128..c3bd0ea 100644 --- a/app/src/cm/svc/CM_NOTI_QUOTA.pgc +++ b/app/src/cm/svc/CM_NOTI_QUOTA.pgc @@ -164,5 +164,59 @@ void CM_NOTI_QUOTA(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_NOTI_QUOTA 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_NOTI_QUOTA -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg2 = getl(b, T_ARG2); + long ch_o_arg3 = getl(b, T_ARG3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "CM_NOTI_QUOTA", 0L); + Bchg(b, T_MSG, 0, "알림 쿼터 점검", 0L); + Bchg(b, T_STR1, 0, "CM_NOTI_QUOTA", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_NOTI_QUOTA] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7311); + Bchg(b, T_MSG, 0, "알림쿼터 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_NOTI_QUOTA] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG2, ch_o_arg2); + setl(b, T_ARG3, ch_o_arg3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[CM_NOTI_QUOTA] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_NOTI_RETRY.pgc b/app/src/cm/svc/CM_NOTI_RETRY.pgc index 23e195e..ebfe988 100644 --- a/app/src/cm/svc/CM_NOTI_RETRY.pgc +++ b/app/src/cm/svc/CM_NOTI_RETRY.pgc @@ -155,5 +155,55 @@ void CM_NOTI_RETRY(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_NOTI_RETRY 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_NOTI_RETRY -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_id2 = getl(b, T_ID2); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "CM_NOTI_RETRY", 0L); + Bchg(b, T_MSG, 0, "알림 재발송 처리", 0L); + Bchg(b, T_STR1, 0, "CM_NOTI_RETRY", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_NOTI_RETRY] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7310); + Bchg(b, T_MSG, 0, "알림재발송 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_NOTI_RETRY] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_ID2, ch_o_id2); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[CM_NOTI_RETRY] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_NOTI_SEND.pgc b/app/src/cm/svc/CM_NOTI_SEND.pgc index 93ff52a..3f0e50d 100644 --- a/app/src/cm/svc/CM_NOTI_SEND.pgc +++ b/app/src/cm/svc/CM_NOTI_SEND.pgc @@ -156,5 +156,55 @@ void CM_NOTI_SEND(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_NOTI_SEND 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_NOTI_SEND -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_id1 = getl(b, T_ID1); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "CM_NOTI_SEND", 0L); + Bchg(b, T_MSG, 0, "공통 알림 발송", 0L); + Bchg(b, T_STR1, 0, "CM_NOTI_SEND", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_NOTI_SEND] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7309); + Bchg(b, T_MSG, 0, "알림발송 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_NOTI_SEND] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_ID1, ch_o_id1); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[CM_NOTI_SEND] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_NOTI_TMPL.pgc b/app/src/cm/svc/CM_NOTI_TMPL.pgc index 1f849a5..8249125 100644 --- a/app/src/cm/svc/CM_NOTI_TMPL.pgc +++ b/app/src/cm/svc/CM_NOTI_TMPL.pgc @@ -175,5 +175,55 @@ void CM_NOTI_TMPL(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_NOTI_TMPL 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_NOTI_TMPL -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_id1 = getl(b, T_ID1); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "CM_NOTI_TMPL", 0L); + Bchg(b, T_MSG, 0, "알림 템플릿 변경", 0L); + Bchg(b, T_STR1, 0, "CM_NOTI_TMPL", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_NOTI_TMPL] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7312); + Bchg(b, T_MSG, 0, "알림템플릿 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_NOTI_TMPL] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_ID1, ch_o_id1); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[CM_NOTI_TMPL] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_PREVBIZ.pgc b/app/src/cm/svc/CM_PREVBIZ.pgc index 102c1a5..ddd2de1 100644 --- a/app/src/cm/svc/CM_PREVBIZ.pgc +++ b/app/src/cm/svc/CM_PREVBIZ.pgc @@ -175,5 +175,54 @@ void CM_PREVBIZ(TPSVCINFO *p) setl(b, T_RC, 0); userlog("CM_PREVBIZ 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_PREVBIZ -> CM_BIZDAY (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg1 = getl(b, T_ARG1); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str3[256]; gets_(b, T_STR3, ch_o_str3, sizeof(ch_o_str3)); + if (ch_do) { + Bchg(b, T_STR1, 0, "CM_PREVBIZ", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_BIZDAY", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_PREVBIZ] tpcall(CM_BIZDAY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7332); + Bchg(b, T_MSG, 0, "전영업일 기준조회 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + { char ch_bz[16]; gets_(b, T_BIZDATE, ch_bz, sizeof(ch_bz)); + userlog("[CM_PREVBIZ] 기준영업일 연동 완료 biz=%s", ch_bz); } + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG1, ch_o_arg1); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR3, 0, ch_o_str3, 0L); + } else { + userlog("[CM_PREVBIZ] 체인 대상 컨텍스트 없음 - CM_BIZDAY 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_SEQ.pgc b/app/src/cm/svc/CM_SEQ.pgc index a1b711f..5111376 100644 --- a/app/src/cm/svc/CM_SEQ.pgc +++ b/app/src/cm/svc/CM_SEQ.pgc @@ -143,5 +143,55 @@ void CM_SEQ(TPSVCINFO *p) setl(b, T_RC, 0); userlog("CM_SEQ 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_SEQ -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg1 = getl(b, T_ARG1); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "CM_SEQ", 0L); + Bchg(b, T_MSG, 0, "공통 채번 수행", 0L); + Bchg(b, T_STR1, 0, "CM_SEQ", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_SEQ] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7301); + Bchg(b, T_MSG, 0, "채번 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_SEQ] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG1, ch_o_arg1); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[CM_SEQ] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_SEQ_ALLOC.pgc b/app/src/cm/svc/CM_SEQ_ALLOC.pgc index 3a10c62..6ff0a32 100644 --- a/app/src/cm/svc/CM_SEQ_ALLOC.pgc +++ b/app/src/cm/svc/CM_SEQ_ALLOC.pgc @@ -157,5 +157,59 @@ void CM_SEQ_ALLOC(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_SEQ_ALLOC 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_SEQ_ALLOC -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_count = getl(b, T_COUNT); + long ch_o_id1 = getl(b, T_ID1); + long ch_o_id2 = getl(b, T_ID2); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "CM_SEQ_ALLOC", 0L); + Bchg(b, T_MSG, 0, "채번 구간 할당", 0L); + Bchg(b, T_STR1, 0, "CM_SEQ_ALLOC", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_SEQ_ALLOC] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7305); + Bchg(b, T_MSG, 0, "구간할당 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_SEQ_ALLOC] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_COUNT, ch_o_count); + setl(b, T_ID1, ch_o_id1); + setl(b, T_ID2, ch_o_id2); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[CM_SEQ_ALLOC] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_SEQ_DAILY.pgc b/app/src/cm/svc/CM_SEQ_DAILY.pgc index c2778cf..af72b19 100644 --- a/app/src/cm/svc/CM_SEQ_DAILY.pgc +++ b/app/src/cm/svc/CM_SEQ_DAILY.pgc @@ -157,5 +157,57 @@ void CM_SEQ_DAILY(TPSVCINFO *p) setl(b, T_RC, 0); userlog("CM_SEQ_DAILY 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_SEQ_DAILY -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg1 = getl(b, T_ARG1); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str4[256]; gets_(b, T_STR4, ch_o_str4, sizeof(ch_o_str4)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "CM_SEQ_DAILY", 0L); + Bchg(b, T_MSG, 0, "일별 채번 수행", 0L); + Bchg(b, T_STR1, 0, "CM_SEQ_DAILY", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_SEQ_DAILY] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7303); + Bchg(b, T_MSG, 0, "일별채번 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_SEQ_DAILY] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG1, ch_o_arg1); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR4, 0, ch_o_str4, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[CM_SEQ_DAILY] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_SEQ_MULTI.pgc b/app/src/cm/svc/CM_SEQ_MULTI.pgc index a8fc776..49c027f 100644 --- a/app/src/cm/svc/CM_SEQ_MULTI.pgc +++ b/app/src/cm/svc/CM_SEQ_MULTI.pgc @@ -153,5 +153,59 @@ void CM_SEQ_MULTI(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_SEQ_MULTI 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_SEQ_MULTI -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_count = getl(b, T_COUNT); + long ch_o_id1 = getl(b, T_ID1); + long ch_o_id2 = getl(b, T_ID2); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "CM_SEQ_MULTI", 0L); + Bchg(b, T_MSG, 0, "다건 채번 수행", 0L); + Bchg(b, T_STR1, 0, "CM_SEQ_MULTI", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_SEQ_MULTI] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7302); + Bchg(b, T_MSG, 0, "다건채번 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_SEQ_MULTI] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_COUNT, ch_o_count); + setl(b, T_ID1, ch_o_id1); + setl(b, T_ID2, ch_o_id2); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[CM_SEQ_MULTI] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_SEQ_RESET.pgc b/app/src/cm/svc/CM_SEQ_RESET.pgc index 107b57f..0e92acd 100644 --- a/app/src/cm/svc/CM_SEQ_RESET.pgc +++ b/app/src/cm/svc/CM_SEQ_RESET.pgc @@ -162,5 +162,55 @@ void CM_SEQ_RESET(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_SEQ_RESET 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_SEQ_RESET -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg2 = getl(b, T_ARG2); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "CM_SEQ_RESET", 0L); + Bchg(b, T_MSG, 0, "채번 초기화 수행", 0L); + Bchg(b, T_STR1, 0, "CM_SEQ_RESET", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_SEQ_RESET] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7306); + Bchg(b, T_MSG, 0, "채번초기화 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_SEQ_RESET] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG2, ch_o_arg2); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[CM_SEQ_RESET] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_SEQ_STAMP.pgc b/app/src/cm/svc/CM_SEQ_STAMP.pgc index 14f68c0..2b8b8f8 100644 --- a/app/src/cm/svc/CM_SEQ_STAMP.pgc +++ b/app/src/cm/svc/CM_SEQ_STAMP.pgc @@ -155,5 +155,57 @@ void CM_SEQ_STAMP(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_SEQ_STAMP 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_SEQ_STAMP -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg1 = getl(b, T_ARG1); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str4[256]; gets_(b, T_STR4, ch_o_str4, sizeof(ch_o_str4)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "CM_SEQ_STAMP", 0L); + Bchg(b, T_MSG, 0, "채번 스탬프 발급", 0L); + Bchg(b, T_STR1, 0, "CM_SEQ_STAMP", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_SEQ_STAMP] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7307); + Bchg(b, T_MSG, 0, "채번스탬프 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_SEQ_STAMP] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG1, ch_o_arg1); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR4, 0, ch_o_str4, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[CM_SEQ_STAMP] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/cm/svc/CM_SEQ_TYPED.pgc b/app/src/cm/svc/CM_SEQ_TYPED.pgc index 325dea2..4453a82 100644 --- a/app/src/cm/svc/CM_SEQ_TYPED.pgc +++ b/app/src/cm/svc/CM_SEQ_TYPED.pgc @@ -156,5 +156,57 @@ void CM_SEQ_TYPED(TPSVCINFO *p) setl(b, T_ARG6, grade); userlog("CM_SEQ_TYPED 완료: aud_id=%ld grade=%ld agg=%ld", aud_id, grade, agg); + + /* ---- 업무 체인: CM_SEQ_TYPED -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg1 = getl(b, T_ARG1); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str4[256]; gets_(b, T_STR4, ch_o_str4, sizeof(ch_o_str4)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "CM_SEQ_TYPED", 0L); + Bchg(b, T_MSG, 0, "유형별 채번 수행", 0L); + Bchg(b, T_STR1, 0, "CM_SEQ_TYPED", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[CM_SEQ_TYPED] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7304); + Bchg(b, T_MSG, 0, "유형채번 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[CM_SEQ_TYPED] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG1, ch_o_arg1); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR4, 0, ch_o_str4, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[CM_SEQ_TYPED] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/lg/svc/LG_ACCRUEREV.pgc b/app/src/lg/svc/LG_ACCRUEREV.pgc index 0d97c0e..eb0bb20 100644 --- a/app/src/lg/svc/LG_ACCRUEREV.pgc +++ b/app/src/lg/svc/LG_ACCRUEREV.pgc @@ -146,6 +146,59 @@ void LG_ACCRUEREV(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_ACCRUEREV 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_POST 연동 (발생주의 환입액 기표) ==== + * 동일 글로벌 트랜잭션이지만 LG_POST 는 별도 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, "LG_ACCRUEREV", 0L); + + userlog("[LG_ACCRUEREV] 체인 호출 -> LG_POST bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_ACCRUEREV] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9468); + Bchg(b, T_MSG, 0, "발생분 환입 기표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_ACCRUEREV] LG_POST 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_ACCRUEREV] LG_POST 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_ACCTSUM.pgc b/app/src/lg/svc/LG_ACCTSUM.pgc index 696cea9..c820b7b 100644 --- a/app/src/lg/svc/LG_ACCTSUM.pgc +++ b/app/src/lg/svc/LG_ACCTSUM.pgc @@ -119,6 +119,64 @@ void LG_ACCTSUM(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_ACCTSUM 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_RECALC 연동 (계정별 집계 후 계정잔액 재계산) ==== + * 동일 글로벌 트랜잭션이지만 LG_RECALC 는 별도 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, "LG_ACCTSUM", 0L); + /* 체인 표식: 이 서비스는 위에서 이미 같은 (acct, biz_date) 의 lg_account_bal + * 집계행을 재집계(upsert)해 이 브랜치에 잠가 두었다. 하위(LG_RECALC)가 형제 + * XA 브랜치에서 같은 행을 다시 upsert 하면 미커밋 행락으로 교착되므로, + * 하위에서는 재집계를 생략하고 소유자인 이 브랜치에 위임하게 한다. */ + Bchg(b, T_STR8, 0, "CHAIN", 0L); + + userlog("[LG_ACCTSUM] 체인 호출 -> LG_RECALC bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_RECALC", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_ACCTSUM] tpcall(LG_RECALC) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9442); + Bchg(b, T_MSG, 0, "계정집계 재계산 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_ACCTSUM] LG_RECALC 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_ACCTSUM] LG_RECALC 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_ACQPOST.pgc b/app/src/lg/svc/LG_ACQPOST.pgc index c498221..55e73f8 100644 --- a/app/src/lg/svc/LG_ACQPOST.pgc +++ b/app/src/lg/svc/LG_ACQPOST.pgc @@ -129,6 +129,59 @@ void LG_ACQPOST(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_ACQPOST 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (매입 기표 후 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_ACQPOST", 0L); + + userlog("[LG_ACQPOST] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_ACQPOST] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9412); + Bchg(b, T_MSG, 0, "매입기표 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_ACQPOST] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_ACQPOST] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_ADJUST.pgc b/app/src/lg/svc/LG_ADJUST.pgc index 999a83b..ac325bc 100644 --- a/app/src/lg/svc/LG_ADJUST.pgc +++ b/app/src/lg/svc/LG_ADJUST.pgc @@ -118,6 +118,59 @@ void LG_ADJUST(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_ADJUST 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (조정 분개 후 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_ADJUST", 0L); + + userlog("[LG_ADJUST] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_ADJUST] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9422); + Bchg(b, T_MSG, 0, "조정분개 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_ADJUST] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_ADJUST] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_ALLOWANCE.pgc b/app/src/lg/svc/LG_ALLOWANCE.pgc index b9ac9db..224d236 100644 --- a/app/src/lg/svc/LG_ALLOWANCE.pgc +++ b/app/src/lg/svc/LG_ALLOWANCE.pgc @@ -125,6 +125,59 @@ void LG_ALLOWANCE(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_ALLOWANCE 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_POST 연동 (대손충당금 설정액 기표) ==== + * 동일 글로벌 트랜잭션이지만 LG_POST 는 별도 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, "LG_ALLOWANCE", 0L); + + userlog("[LG_ALLOWANCE] 체인 호출 -> LG_POST bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_ALLOWANCE] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9462); + Bchg(b, T_MSG, 0, "대손충당 기표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_ALLOWANCE] LG_POST 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_ALLOWANCE] LG_POST 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_ALLOWRECALC.pgc b/app/src/lg/svc/LG_ALLOWRECALC.pgc index f493dd6..1b69633 100644 --- a/app/src/lg/svc/LG_ALLOWRECALC.pgc +++ b/app/src/lg/svc/LG_ALLOWRECALC.pgc @@ -135,6 +135,59 @@ void LG_ALLOWRECALC(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_ALLOWRECALC 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_ACCTSUM 연동 (충당금 재산정 후 계정집계 갱신) ==== + * 동일 글로벌 트랜잭션이지만 LG_ACCTSUM 는 별도 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, "LG_ALLOWRECALC", 0L); + + userlog("[LG_ALLOWRECALC] 체인 호출 -> LG_ACCTSUM bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_ACCTSUM", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_ALLOWRECALC] tpcall(LG_ACCTSUM) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9473); + Bchg(b, T_MSG, 0, "충당금 재산정 집계 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_ALLOWRECALC] LG_ACCTSUM 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_ALLOWRECALC] LG_ACCTSUM 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_BADDEBT.pgc b/app/src/lg/svc/LG_BADDEBT.pgc index 7669134..8d2432d 100644 --- a/app/src/lg/svc/LG_BADDEBT.pgc +++ b/app/src/lg/svc/LG_BADDEBT.pgc @@ -129,6 +129,59 @@ void LG_BADDEBT(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_BADDEBT 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_POST 연동 (부실채권 인식액 기표) ==== + * 동일 글로벌 트랜잭션이지만 LG_POST 는 별도 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, "LG_BADDEBT", 0L); + + userlog("[LG_BADDEBT] 체인 호출 -> LG_POST bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_BADDEBT] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9466); + Bchg(b, T_MSG, 0, "부실채권 기표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_BADDEBT] LG_POST 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_BADDEBT] LG_POST 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_BADDEBTRCV.pgc b/app/src/lg/svc/LG_BADDEBTRCV.pgc index 10a4223..96a8867 100644 --- a/app/src/lg/svc/LG_BADDEBTRCV.pgc +++ b/app/src/lg/svc/LG_BADDEBTRCV.pgc @@ -136,6 +136,59 @@ void LG_BADDEBTRCV(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_BADDEBTRCV 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_POST 연동 (부실채권 회수액 기표) ==== + * 동일 글로벌 트랜잭션이지만 LG_POST 는 별도 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, "LG_BADDEBTRCV", 0L); + + userlog("[LG_BADDEBTRCV] 체인 호출 -> LG_POST bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_BADDEBTRCV] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9467); + Bchg(b, T_MSG, 0, "부실채권회수 기표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_BADDEBTRCV] LG_POST 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_BADDEBTRCV] LG_POST 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_BALCERT.pgc b/app/src/lg/svc/LG_BALCERT.pgc index 76b0163..516ebae 100644 --- a/app/src/lg/svc/LG_BALCERT.pgc +++ b/app/src/lg/svc/LG_BALCERT.pgc @@ -129,6 +129,59 @@ void LG_BALCERT(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_BALCERT 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (잔액확인서 발급 전 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_BALCERT", 0L); + + userlog("[LG_BALCERT] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_BALCERT] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9427); + Bchg(b, T_MSG, 0, "잔액확인서 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_BALCERT] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_BALCERT] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_BALPROOF.pgc b/app/src/lg/svc/LG_BALPROOF.pgc index 53cdf05..c8a5a6b 100644 --- a/app/src/lg/svc/LG_BALPROOF.pgc +++ b/app/src/lg/svc/LG_BALPROOF.pgc @@ -139,6 +139,59 @@ void LG_BALPROOF(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_BALPROOF 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (잔액 증명 산출 근거의 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_BALPROOF", 0L); + + userlog("[LG_BALPROOF] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_BALPROOF] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9426); + Bchg(b, T_MSG, 0, "잔액증명 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_BALPROOF] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_BALPROOF] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_BLACKENTRY.pgc b/app/src/lg/svc/LG_BLACKENTRY.pgc index ea1e60c..cc7a0b9 100644 --- a/app/src/lg/svc/LG_BLACKENTRY.pgc +++ b/app/src/lg/svc/LG_BLACKENTRY.pgc @@ -157,6 +157,59 @@ void LG_BLACKENTRY(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_BLACKENTRY 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (흑자(정상) 분개 후 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_BLACKENTRY", 0L); + + userlog("[LG_BLACKENTRY] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_BLACKENTRY] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9420); + Bchg(b, T_MSG, 0, "흑자분개 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_BLACKENTRY] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_BLACKENTRY] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_BSSUMMARY.pgc b/app/src/lg/svc/LG_BSSUMMARY.pgc index 37c3ddc..a8d3080 100644 --- a/app/src/lg/svc/LG_BSSUMMARY.pgc +++ b/app/src/lg/svc/LG_BSSUMMARY.pgc @@ -119,6 +119,59 @@ void LG_BSSUMMARY(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_BSSUMMARY 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: VL_LEDGER 연동 (재무상태표 집계 전 원장 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_LEDGER 는 별도 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, "LG_BSSUMMARY", 0L); + + userlog("[LG_BSSUMMARY] 체인 호출 -> VL_LEDGER bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_LEDGER", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_BSSUMMARY] tpcall(VL_LEDGER) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9432); + Bchg(b, T_MSG, 0, "재무상태표 원장검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_BSSUMMARY] VL_LEDGER 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_BSSUMMARY] VL_LEDGER 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_CLOSE_LINK.pgc b/app/src/lg/svc/LG_CLOSE_LINK.pgc index 6ba3bd7..d2e9d5e 100644 --- a/app/src/lg/svc/LG_CLOSE_LINK.pgc +++ b/app/src/lg/svc/LG_CLOSE_LINK.pgc @@ -114,6 +114,59 @@ void LG_CLOSE_LINK(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_CLOSE_LINK 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: CL_LOCK 연동 (원장 마감연계 확정 후 마감기간 잠금) ==== + * 동일 글로벌 트랜잭션이지만 CL_LOCK 는 별도 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, "LG_CLOSE_LINK", 0L); + + userlog("[LG_CLOSE_LINK] 체인 호출 -> CL_LOCK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("CL_LOCK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_CLOSE_LINK] tpcall(CL_LOCK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9451); + Bchg(b, T_MSG, 0, "마감 잠금 연계 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_CLOSE_LINK] CL_LOCK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_CLOSE_LINK] CL_LOCK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_CORPSUM.pgc b/app/src/lg/svc/LG_CORPSUM.pgc index 00994ce..bc5d7f5 100644 --- a/app/src/lg/svc/LG_CORPSUM.pgc +++ b/app/src/lg/svc/LG_CORPSUM.pgc @@ -144,6 +144,59 @@ void LG_CORPSUM(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_CORPSUM 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_RECALC 연동 (법인별 집계 후 계정잔액 재계산) ==== + * 동일 글로벌 트랜잭션이지만 LG_RECALC 는 별도 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, "LG_CORPSUM", 0L); + + userlog("[LG_CORPSUM] 체인 호출 -> LG_RECALC bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_RECALC", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_CORPSUM] tpcall(LG_RECALC) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9444); + Bchg(b, T_MSG, 0, "법인집계 재계산 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_CORPSUM] LG_RECALC 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_CORPSUM] LG_RECALC 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_CORRECT.pgc b/app/src/lg/svc/LG_CORRECT.pgc index 5a20c3f..ff203d8 100644 --- a/app/src/lg/svc/LG_CORRECT.pgc +++ b/app/src/lg/svc/LG_CORRECT.pgc @@ -114,6 +114,59 @@ void LG_CORRECT(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_CORRECT 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (정정 분개 후 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_CORRECT", 0L); + + userlog("[LG_CORRECT] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_CORRECT] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9424); + Bchg(b, T_MSG, 0, "정정분개 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_CORRECT] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_CORRECT] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_DEPTSUM.pgc b/app/src/lg/svc/LG_DEPTSUM.pgc index 45c40ff..c52641c 100644 --- a/app/src/lg/svc/LG_DEPTSUM.pgc +++ b/app/src/lg/svc/LG_DEPTSUM.pgc @@ -129,6 +129,59 @@ void LG_DEPTSUM(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_DEPTSUM 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_RECALC 연동 (부서별 집계 후 계정잔액 재계산) ==== + * 동일 글로벌 트랜잭션이지만 LG_RECALC 는 별도 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, "LG_DEPTSUM", 0L); + + userlog("[LG_DEPTSUM] 체인 호출 -> LG_RECALC bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_RECALC", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_DEPTSUM] tpcall(LG_RECALC) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9443); + Bchg(b, T_MSG, 0, "부서집계 재계산 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_DEPTSUM] LG_RECALC 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_DEPTSUM] LG_RECALC 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_DOUBLE.pgc b/app/src/lg/svc/LG_DOUBLE.pgc index 38ba5fc..25a719d 100644 --- a/app/src/lg/svc/LG_DOUBLE.pgc +++ b/app/src/lg/svc/LG_DOUBLE.pgc @@ -123,6 +123,59 @@ void LG_DOUBLE(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_DOUBLE 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (복식 분개 직후 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_DOUBLE", 0L); + + userlog("[LG_DOUBLE] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_DOUBLE] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9414); + Bchg(b, T_MSG, 0, "복식분개 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_DOUBLE] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_DOUBLE] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_FEEACCRUE.pgc b/app/src/lg/svc/LG_FEEACCRUE.pgc index 33070f6..fb70d15 100644 --- a/app/src/lg/svc/LG_FEEACCRUE.pgc +++ b/app/src/lg/svc/LG_FEEACCRUE.pgc @@ -131,6 +131,59 @@ void LG_FEEACCRUE(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_FEEACCRUE 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_FEEPOST 연동 (수수료 발생분 기표) ==== + * 동일 글로벌 트랜잭션이지만 LG_FEEPOST 는 별도 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, "LG_FEEACCRUE", 0L); + + userlog("[LG_FEEACCRUE] 체인 호출 -> LG_FEEPOST bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_FEEPOST", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_FEEACCRUE] tpcall(LG_FEEPOST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9471); + Bchg(b, T_MSG, 0, "수수료발생 기표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_FEEACCRUE] LG_FEEPOST 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_FEEACCRUE] LG_FEEPOST 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_FEEPOST.pgc b/app/src/lg/svc/LG_FEEPOST.pgc index a3bdf37..ecf3377 100644 --- a/app/src/lg/svc/LG_FEEPOST.pgc +++ b/app/src/lg/svc/LG_FEEPOST.pgc @@ -124,6 +124,59 @@ void LG_FEEPOST(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_FEEPOST 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (수수료 기표 후 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_FEEPOST", 0L); + + userlog("[LG_FEEPOST] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_FEEPOST] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9416); + Bchg(b, T_MSG, 0, "수수료기표 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_FEEPOST] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_FEEPOST] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_HALFCLOSE.pgc b/app/src/lg/svc/LG_HALFCLOSE.pgc index a68e42e..16c286c 100644 --- a/app/src/lg/svc/LG_HALFCLOSE.pgc +++ b/app/src/lg/svc/LG_HALFCLOSE.pgc @@ -133,6 +133,59 @@ void LG_HALFCLOSE(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_HALFCLOSE 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_TRIALBAL 연동 (반기마감 확정 전 시산표 산출) ==== + * 동일 글로벌 트랜잭션이지만 LG_TRIALBAL 는 별도 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, "LG_HALFCLOSE", 0L); + + userlog("[LG_HALFCLOSE] 체인 호출 -> LG_TRIALBAL bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_TRIALBAL", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_HALFCLOSE] tpcall(LG_TRIALBAL) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9484); + Bchg(b, T_MSG, 0, "반기마감 시산표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_HALFCLOSE] LG_TRIALBAL 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_HALFCLOSE] LG_TRIALBAL 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_MERCHBAL.pgc b/app/src/lg/svc/LG_MERCHBAL.pgc index a0dd9f0..810ec43 100644 --- a/app/src/lg/svc/LG_MERCHBAL.pgc +++ b/app/src/lg/svc/LG_MERCHBAL.pgc @@ -127,6 +127,59 @@ void LG_MERCHBAL(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_MERCHBAL 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_RECALC 연동 (가맹점 잔액 집계 후 계정잔액 재계산) ==== + * 동일 글로벌 트랜잭션이지만 LG_RECALC 는 별도 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, "LG_MERCHBAL", 0L); + + userlog("[LG_MERCHBAL] 체인 호출 -> LG_RECALC bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_RECALC", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_MERCHBAL] tpcall(LG_RECALC) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9441); + Bchg(b, T_MSG, 0, "가맹점잔액 재계산 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_MERCHBAL] LG_RECALC 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_MERCHBAL] LG_RECALC 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_MERCHPROOF.pgc b/app/src/lg/svc/LG_MERCHPROOF.pgc index 4481fba..31a0c28 100644 --- a/app/src/lg/svc/LG_MERCHPROOF.pgc +++ b/app/src/lg/svc/LG_MERCHPROOF.pgc @@ -153,6 +153,59 @@ void LG_MERCHPROOF(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_MERCHPROOF 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_RECALC 연동 (가맹점 증명 산출 전 계정잔액 재계산) ==== + * 동일 글로벌 트랜잭션이지만 LG_RECALC 는 별도 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, "LG_MERCHPROOF", 0L); + + userlog("[LG_MERCHPROOF] 체인 호출 -> LG_RECALC bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_RECALC", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_MERCHPROOF] tpcall(LG_RECALC) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9446); + Bchg(b, T_MSG, 0, "가맹점증명 재계산 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_MERCHPROOF] LG_RECALC 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_MERCHPROOF] LG_RECALC 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_MONTHCLOSE.pgc b/app/src/lg/svc/LG_MONTHCLOSE.pgc index ad0715a..2f47f45 100644 --- a/app/src/lg/svc/LG_MONTHCLOSE.pgc +++ b/app/src/lg/svc/LG_MONTHCLOSE.pgc @@ -140,6 +140,59 @@ void LG_MONTHCLOSE(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_MONTHCLOSE 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_TRIALBAL 연동 (월마감 확정 전 시산표 산출) ==== + * 동일 글로벌 트랜잭션이지만 LG_TRIALBAL 는 별도 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, "LG_MONTHCLOSE", 0L); + + userlog("[LG_MONTHCLOSE] 체인 호출 -> LG_TRIALBAL bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_TRIALBAL", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_MONTHCLOSE] tpcall(LG_TRIALBAL) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9481); + Bchg(b, T_MSG, 0, "월마감 시산표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_MONTHCLOSE] LG_TRIALBAL 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_MONTHCLOSE] LG_TRIALBAL 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_MONTHLYSUM.pgc b/app/src/lg/svc/LG_MONTHLYSUM.pgc index 23c7d39..c5f7fee 100644 --- a/app/src/lg/svc/LG_MONTHLYSUM.pgc +++ b/app/src/lg/svc/LG_MONTHLYSUM.pgc @@ -119,6 +119,59 @@ void LG_MONTHLYSUM(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_MONTHLYSUM 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_RECALC 연동 (월별 집계 후 계정잔액 재계산) ==== + * 동일 글로벌 트랜잭션이지만 LG_RECALC 는 별도 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, "LG_MONTHLYSUM", 0L); + + userlog("[LG_MONTHLYSUM] 체인 호출 -> LG_RECALC bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_RECALC", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_MONTHLYSUM] tpcall(LG_RECALC) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9445); + Bchg(b, T_MSG, 0, "월집계 재계산 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_MONTHLYSUM] LG_RECALC 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_MONTHLYSUM] LG_RECALC 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_PARTREVERSE.pgc b/app/src/lg/svc/LG_PARTREVERSE.pgc index 5d87801..06568b9 100644 --- a/app/src/lg/svc/LG_PARTREVERSE.pgc +++ b/app/src/lg/svc/LG_PARTREVERSE.pgc @@ -137,6 +137,59 @@ void LG_PARTREVERSE(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_PARTREVERSE 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_POST 연동 (부분 역분개 잔액에 대한 재기표) ==== + * 동일 글로벌 트랜잭션이지만 LG_POST 는 별도 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, "LG_PARTREVERSE", 0L); + + userlog("[LG_PARTREVERSE] 체인 호출 -> LG_POST bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_PARTREVERSE] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9465); + Bchg(b, T_MSG, 0, "부분역분개 재기표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_PARTREVERSE] LG_POST 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_PARTREVERSE] LG_POST 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_PERIODTB.pgc b/app/src/lg/svc/LG_PERIODTB.pgc index 767cdbd..3b3505d 100644 --- a/app/src/lg/svc/LG_PERIODTB.pgc +++ b/app/src/lg/svc/LG_PERIODTB.pgc @@ -150,6 +150,59 @@ void LG_PERIODTB(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_PERIODTB 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: VL_LEDGER 연동 (기간 시산표 산출 전 원장 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_LEDGER 는 별도 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, "LG_PERIODTB", 0L); + + userlog("[LG_PERIODTB] 체인 호출 -> VL_LEDGER bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_LEDGER", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_PERIODTB] tpcall(VL_LEDGER) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9434); + Bchg(b, T_MSG, 0, "기간시산 원장검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_PERIODTB] VL_LEDGER 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_PERIODTB] VL_LEDGER 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_PLSUMMARY.pgc b/app/src/lg/svc/LG_PLSUMMARY.pgc index 5469ace..b2d72bd 100644 --- a/app/src/lg/svc/LG_PLSUMMARY.pgc +++ b/app/src/lg/svc/LG_PLSUMMARY.pgc @@ -123,6 +123,59 @@ void LG_PLSUMMARY(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_PLSUMMARY 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: VL_LEDGER 연동 (손익 집계 전 원장 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_LEDGER 는 별도 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, "LG_PLSUMMARY", 0L); + + userlog("[LG_PLSUMMARY] 체인 호출 -> VL_LEDGER bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_LEDGER", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_PLSUMMARY] tpcall(VL_LEDGER) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9433); + Bchg(b, T_MSG, 0, "손익계산서 원장검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_PLSUMMARY] VL_LEDGER 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_PLSUMMARY] VL_LEDGER 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_POST.pgc b/app/src/lg/svc/LG_POST.pgc index 0e7c242..2148e25 100644 --- a/app/src/lg/svc/LG_POST.pgc +++ b/app/src/lg/svc/LG_POST.pgc @@ -132,6 +132,59 @@ void LG_POST(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_POST 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (전표 기표 후 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_POST", 0L); + + userlog("[LG_POST] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_POST] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9411); + Bchg(b, T_MSG, 0, "전표 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_POST] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_POST] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_PREPAIDAMORT.pgc b/app/src/lg/svc/LG_PREPAIDAMORT.pgc index 7dc6e8b..225b182 100644 --- a/app/src/lg/svc/LG_PREPAIDAMORT.pgc +++ b/app/src/lg/svc/LG_PREPAIDAMORT.pgc @@ -118,6 +118,59 @@ void LG_PREPAIDAMORT(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_PREPAIDAMORT 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_PREPAIDPOST 연동 (선급비용 상각분 기표) ==== + * 동일 글로벌 트랜잭션이지만 LG_PREPAIDPOST 는 별도 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, "LG_PREPAIDAMORT", 0L); + + userlog("[LG_PREPAIDAMORT] 체인 호출 -> LG_PREPAIDPOST bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_PREPAIDPOST", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_PREPAIDAMORT] tpcall(LG_PREPAIDPOST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9469); + Bchg(b, T_MSG, 0, "선급상각 기표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_PREPAIDAMORT] LG_PREPAIDPOST 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_PREPAIDAMORT] LG_PREPAIDPOST 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_PREPAIDPOST.pgc b/app/src/lg/svc/LG_PREPAIDPOST.pgc index 78b4a37..ed8765c 100644 --- a/app/src/lg/svc/LG_PREPAIDPOST.pgc +++ b/app/src/lg/svc/LG_PREPAIDPOST.pgc @@ -125,6 +125,59 @@ void LG_PREPAIDPOST(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_PREPAIDPOST 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (선급비용 기표 후 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_PREPAIDPOST", 0L); + + userlog("[LG_PREPAIDPOST] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_PREPAIDPOST] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9418); + Bchg(b, T_MSG, 0, "선급기표 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_PREPAIDPOST] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_PREPAIDPOST] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_QTRCLOSE.pgc b/app/src/lg/svc/LG_QTRCLOSE.pgc index d8d1ce9..500531d 100644 --- a/app/src/lg/svc/LG_QTRCLOSE.pgc +++ b/app/src/lg/svc/LG_QTRCLOSE.pgc @@ -137,6 +137,59 @@ void LG_QTRCLOSE(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_QTRCLOSE 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_TRIALBAL 연동 (분기마감 확정 전 시산표 산출) ==== + * 동일 글로벌 트랜잭션이지만 LG_TRIALBAL 는 별도 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, "LG_QTRCLOSE", 0L); + + userlog("[LG_QTRCLOSE] 체인 호출 -> LG_TRIALBAL bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_TRIALBAL", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_QTRCLOSE] tpcall(LG_TRIALBAL) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9482); + Bchg(b, T_MSG, 0, "분기마감 시산표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_QTRCLOSE] LG_TRIALBAL 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_QTRCLOSE] LG_TRIALBAL 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_RECALC.pgc b/app/src/lg/svc/LG_RECALC.pgc index 4f6ca36..388c3ce 100644 --- a/app/src/lg/svc/LG_RECALC.pgc +++ b/app/src/lg/svc/LG_RECALC.pgc @@ -84,7 +84,24 @@ void LG_RECALC(TPSVCINFO *p) userlog("LG_RECALC 본처리 진입 bd=%s id=%ld amt=%ld", gx_bd, gx_in_id, gx_in_amt); gets_(b, T_KEY1, acct, sizeof(acct)); if (acct[0] == 0) strcpy(acct, "RECV"); gets_(b, T_BIZDATE, bizdate, sizeof(bizdate)); - if (lgdb_recalc_acct_bal(acct, bizdate) < 0) FAIL(b); + /* 체인 하위 호출 판별 (T_STR8 = "CHAIN"): 상위 서비스가 이미 자기 XA 브랜치에서 + * 같은 (acct, biz_date) 의 lg_account_bal 집계행을 upsert 해 잠근 채 이 서비스를 + * 부른 상태다. 같은 글로벌 트랜잭션의 다른 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) { + userlog("LG_RECALC 체인 하위 호출 - lg_account_bal(%s,%s) 재집계는 상위 브랜치에 위임", + acct, bizdate); + } else { + if (lgdb_recalc_acct_bal(acct, bizdate) < 0) FAIL(b); + } + } /* ============ 5) 이력/감사 적재부 (cm_log, advisory) ============ */ if (gx_ok) { diff --git a/app/src/lg/svc/LG_REDADJUST.pgc b/app/src/lg/svc/LG_REDADJUST.pgc index ef96157..d803958 100644 --- a/app/src/lg/svc/LG_REDADJUST.pgc +++ b/app/src/lg/svc/LG_REDADJUST.pgc @@ -129,6 +129,59 @@ void LG_REDADJUST(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_REDADJUST 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_POST 연동 (적색 조정 후 정정 전표 재기표) ==== + * 동일 글로벌 트랜잭션이지만 LG_POST 는 별도 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, "LG_REDADJUST", 0L); + + userlog("[LG_REDADJUST] 체인 호출 -> LG_POST bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_REDADJUST] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9461); + Bchg(b, T_MSG, 0, "적색조정 재기표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_REDADJUST] LG_POST 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_REDADJUST] LG_POST 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_REDBLACKNET.pgc b/app/src/lg/svc/LG_REDBLACKNET.pgc index 0893fe8..ad3a25e 100644 --- a/app/src/lg/svc/LG_REDBLACKNET.pgc +++ b/app/src/lg/svc/LG_REDBLACKNET.pgc @@ -130,6 +130,59 @@ void LG_REDBLACKNET(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_REDBLACKNET 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_REDENTRY 연동 (적/흑 상계 잔액의 적색 분개) ==== + * 동일 글로벌 트랜잭션이지만 LG_REDENTRY 는 별도 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, "LG_REDBLACKNET", 0L); + + userlog("[LG_REDBLACKNET] 체인 호출 -> LG_REDENTRY bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_REDENTRY", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_REDBLACKNET] tpcall(LG_REDENTRY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9472); + Bchg(b, T_MSG, 0, "적흑상계 분개 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_REDBLACKNET] LG_REDENTRY 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_REDBLACKNET] LG_REDENTRY 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_REDENTRY.pgc b/app/src/lg/svc/LG_REDENTRY.pgc index 24f5367..2425515 100644 --- a/app/src/lg/svc/LG_REDENTRY.pgc +++ b/app/src/lg/svc/LG_REDENTRY.pgc @@ -144,6 +144,59 @@ void LG_REDENTRY(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_REDENTRY 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (적색(역) 분개 후 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_REDENTRY", 0L); + + userlog("[LG_REDENTRY] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_REDENTRY] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9421); + Bchg(b, T_MSG, 0, "적자분개 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_REDENTRY] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_REDENTRY] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_REPOST.pgc b/app/src/lg/svc/LG_REPOST.pgc index f30997d..4ea413d 100644 --- a/app/src/lg/svc/LG_REPOST.pgc +++ b/app/src/lg/svc/LG_REPOST.pgc @@ -138,6 +138,59 @@ void LG_REPOST(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_REPOST 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_POST 연동 (취소 전표에 대한 재기표) ==== + * 동일 글로벌 트랜잭션이지만 LG_POST 는 별도 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, "LG_REPOST", 0L); + + userlog("[LG_REPOST] 체인 호출 -> LG_POST bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_REPOST] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9464); + Bchg(b, T_MSG, 0, "재기표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_REPOST] LG_POST 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_REPOST] LG_POST 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_REVERSE.pgc b/app/src/lg/svc/LG_REVERSE.pgc index 88fda29..c3b5417 100644 --- a/app/src/lg/svc/LG_REVERSE.pgc +++ b/app/src/lg/svc/LG_REVERSE.pgc @@ -136,6 +136,59 @@ void LG_REVERSE(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_REVERSE 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (역분개 전표의 차대 균형 검증(재기표는 LG_REDADJUST 경유)) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_REVERSE", 0L); + + userlog("[LG_REVERSE] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_REVERSE] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9428); + Bchg(b, T_MSG, 0, "역분개 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_REVERSE] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_REVERSE] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_ROLLTB.pgc b/app/src/lg/svc/LG_ROLLTB.pgc index 4671bbb..b455793 100644 --- a/app/src/lg/svc/LG_ROLLTB.pgc +++ b/app/src/lg/svc/LG_ROLLTB.pgc @@ -139,6 +139,59 @@ void LG_ROLLTB(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_ROLLTB 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: VL_LEDGER 연동 (이월 시산표 산출 전 원장 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_LEDGER 는 별도 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, "LG_ROLLTB", 0L); + + userlog("[LG_ROLLTB] 체인 호출 -> VL_LEDGER bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_LEDGER", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_ROLLTB] tpcall(VL_LEDGER) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9435); + Bchg(b, T_MSG, 0, "이월시산 원장검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_ROLLTB] VL_LEDGER 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_ROLLTB] VL_LEDGER 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_SETTLEPOST.pgc b/app/src/lg/svc/LG_SETTLEPOST.pgc index 30c1652..60385dc 100644 --- a/app/src/lg/svc/LG_SETTLEPOST.pgc +++ b/app/src/lg/svc/LG_SETTLEPOST.pgc @@ -135,6 +135,59 @@ void LG_SETTLEPOST(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_SETTLEPOST 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (정산 기표 후 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_SETTLEPOST", 0L); + + userlog("[LG_SETTLEPOST] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_SETTLEPOST] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9413); + Bchg(b, T_MSG, 0, "정산기표 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_SETTLEPOST] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_SETTLEPOST] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_SPANTB.pgc b/app/src/lg/svc/LG_SPANTB.pgc index c252e44..b6b7e82 100644 --- a/app/src/lg/svc/LG_SPANTB.pgc +++ b/app/src/lg/svc/LG_SPANTB.pgc @@ -133,6 +133,59 @@ void LG_SPANTB(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_SPANTB 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: VL_LEDGER 연동 (구간 시산표 산출 전 원장 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_LEDGER 는 별도 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, "LG_SPANTB", 0L); + + userlog("[LG_SPANTB] 체인 호출 -> VL_LEDGER bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_LEDGER", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_SPANTB] tpcall(VL_LEDGER) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9436); + Bchg(b, T_MSG, 0, "구간시산 원장검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_SPANTB] VL_LEDGER 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_SPANTB] VL_LEDGER 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_SUSPENSE.pgc b/app/src/lg/svc/LG_SUSPENSE.pgc index 31598f4..5566f42 100644 --- a/app/src/lg/svc/LG_SUSPENSE.pgc +++ b/app/src/lg/svc/LG_SUSPENSE.pgc @@ -140,6 +140,59 @@ void LG_SUSPENSE(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_SUSPENSE 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (가계정 대체 후 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_SUSPENSE", 0L); + + userlog("[LG_SUSPENSE] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_SUSPENSE] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9425); + Bchg(b, T_MSG, 0, "가계정 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_SUSPENSE] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_SUSPENSE] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_TRANSFER.pgc b/app/src/lg/svc/LG_TRANSFER.pgc index 34b661c..3ac2f80 100644 --- a/app/src/lg/svc/LG_TRANSFER.pgc +++ b/app/src/lg/svc/LG_TRANSFER.pgc @@ -117,6 +117,59 @@ void LG_TRANSFER(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_TRANSFER 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (계정 대체 후 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_TRANSFER", 0L); + + userlog("[LG_TRANSFER] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_TRANSFER] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9423); + Bchg(b, T_MSG, 0, "계정대체 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_TRANSFER] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_TRANSFER] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_TRIALBAL.pgc b/app/src/lg/svc/LG_TRIALBAL.pgc index 4d0ef24..8aa9920 100644 --- a/app/src/lg/svc/LG_TRIALBAL.pgc +++ b/app/src/lg/svc/LG_TRIALBAL.pgc @@ -131,6 +131,59 @@ void LG_TRIALBAL(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_TRIALBAL 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: VL_LEDGER 연동 (시산표 확정 전 원장 정합성 검증) ==== + * 동일 글로벌 트랜잭션이지만 VL_LEDGER 는 별도 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, "LG_TRIALBAL", 0L); + + userlog("[LG_TRIALBAL] 체인 호출 -> VL_LEDGER bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("VL_LEDGER", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_TRIALBAL] tpcall(VL_LEDGER) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9431); + Bchg(b, T_MSG, 0, "시산표 원장검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_TRIALBAL] VL_LEDGER 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_TRIALBAL] VL_LEDGER 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_UNEARNPOST.pgc b/app/src/lg/svc/LG_UNEARNPOST.pgc index a94b82f..84fbc8f 100644 --- a/app/src/lg/svc/LG_UNEARNPOST.pgc +++ b/app/src/lg/svc/LG_UNEARNPOST.pgc @@ -126,6 +126,59 @@ void LG_UNEARNPOST(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_UNEARNPOST 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (선수수익 기표 후 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_UNEARNPOST", 0L); + + userlog("[LG_UNEARNPOST] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_UNEARNPOST] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9419); + Bchg(b, T_MSG, 0, "선수기표 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_UNEARNPOST] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_UNEARNPOST] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_UNEARNRECOG.pgc b/app/src/lg/svc/LG_UNEARNRECOG.pgc index af3eb71..f70c8ac 100644 --- a/app/src/lg/svc/LG_UNEARNRECOG.pgc +++ b/app/src/lg/svc/LG_UNEARNRECOG.pgc @@ -121,6 +121,59 @@ void LG_UNEARNRECOG(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_UNEARNRECOG 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_UNEARNPOST 연동 (선수수익 인식분 기표) ==== + * 동일 글로벌 트랜잭션이지만 LG_UNEARNPOST 는 별도 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, "LG_UNEARNRECOG", 0L); + + userlog("[LG_UNEARNRECOG] 체인 호출 -> LG_UNEARNPOST bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_UNEARNPOST", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_UNEARNRECOG] tpcall(LG_UNEARNPOST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9470); + Bchg(b, T_MSG, 0, "선수인식 기표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_UNEARNRECOG] LG_UNEARNPOST 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_UNEARNRECOG] LG_UNEARNPOST 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_VOUCHER.pgc b/app/src/lg/svc/LG_VOUCHER.pgc index 4fcb0c6..2e00f9b 100644 --- a/app/src/lg/svc/LG_VOUCHER.pgc +++ b/app/src/lg/svc/LG_VOUCHER.pgc @@ -123,6 +123,59 @@ void LG_VOUCHER(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_VOUCHER 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (전표 발행 후 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_VOUCHER", 0L); + + userlog("[LG_VOUCHER] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_VOUCHER] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9415); + Bchg(b, T_MSG, 0, "전표발행 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_VOUCHER] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_VOUCHER] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_WEEKCLOSE.pgc b/app/src/lg/svc/LG_WEEKCLOSE.pgc index d85508b..603a4ca 100644 --- a/app/src/lg/svc/LG_WEEKCLOSE.pgc +++ b/app/src/lg/svc/LG_WEEKCLOSE.pgc @@ -130,6 +130,59 @@ void LG_WEEKCLOSE(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_WEEKCLOSE 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_TRIALBAL 연동 (주마감 확정 전 시산표 산출) ==== + * 동일 글로벌 트랜잭션이지만 LG_TRIALBAL 는 별도 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, "LG_WEEKCLOSE", 0L); + + userlog("[LG_WEEKCLOSE] 체인 호출 -> LG_TRIALBAL bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_TRIALBAL", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_WEEKCLOSE] tpcall(LG_TRIALBAL) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9485); + Bchg(b, T_MSG, 0, "주마감 시산표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_WEEKCLOSE] LG_TRIALBAL 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_WEEKCLOSE] LG_TRIALBAL 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_WRITEOFF.pgc b/app/src/lg/svc/LG_WRITEOFF.pgc index 2f87439..c87f3dd 100644 --- a/app/src/lg/svc/LG_WRITEOFF.pgc +++ b/app/src/lg/svc/LG_WRITEOFF.pgc @@ -117,6 +117,59 @@ void LG_WRITEOFF(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_WRITEOFF 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_POST 연동 (대손 상각액 기표) ==== + * 동일 글로벌 트랜잭션이지만 LG_POST 는 별도 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, "LG_WRITEOFF", 0L); + + userlog("[LG_WRITEOFF] 체인 호출 -> LG_POST bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_WRITEOFF] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9463); + Bchg(b, T_MSG, 0, "대손상각 기표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_WRITEOFF] LG_POST 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_WRITEOFF] LG_POST 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_XFERPOST.pgc b/app/src/lg/svc/LG_XFERPOST.pgc index d9c08a3..f70fcc7 100644 --- a/app/src/lg/svc/LG_XFERPOST.pgc +++ b/app/src/lg/svc/LG_XFERPOST.pgc @@ -128,6 +128,59 @@ void LG_XFERPOST(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_XFERPOST 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_BALCHK 연동 (대체 기표 후 차대 균형 검증) ==== + * 동일 글로벌 트랜잭션이지만 LG_BALCHK 는 별도 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, "LG_XFERPOST", 0L); + + userlog("[LG_XFERPOST] 체인 호출 -> LG_BALCHK bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_XFERPOST] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9417); + Bchg(b, T_MSG, 0, "대체기표 대차검증 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_XFERPOST] LG_BALCHK 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_XFERPOST] LG_BALCHK 체인 정상 완료 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); } diff --git a/app/src/lg/svc/LG_YEARCLOSE.pgc b/app/src/lg/svc/LG_YEARCLOSE.pgc index 8307a4e..8fe9a6a 100644 --- a/app/src/lg/svc/LG_YEARCLOSE.pgc +++ b/app/src/lg/svc/LG_YEARCLOSE.pgc @@ -145,6 +145,59 @@ void LG_YEARCLOSE(TPSVCINFO *p) setl(b, T_ARG6, gx_diff); /* ==== 9) 로깅(완료 요약) ==== */ userlog("LG_YEARCLOSE 완료 bd=%s 차=%ld 대=%ld cnt=%ld rc=%ld", gx_bd, gx_dr, gx_cr, gx_cnt, gx_rc); + + /* ==== 10) 업무흐름 체인: LG_TRIALBAL 연동 (연마감 확정 전 시산표 산출) ==== + * 동일 글로벌 트랜잭션이지만 LG_TRIALBAL 는 별도 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, "LG_YEARCLOSE", 0L); + + userlog("[LG_YEARCLOSE] 체인 호출 -> LG_TRIALBAL bd=%s id=%ld amt=%ld", + cx0_bd, cx0_id1, cx0_amt); + if (tpcall("LG_TRIALBAL", (char *)b, 0L, (char **)&b, &cx0_rlen, 0L) < 0) { + userlog("[LG_YEARCLOSE] tpcall(LG_TRIALBAL) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9483); + Bchg(b, T_MSG, 0, "연마감 시산표 체인 실패", 0L); + FAIL(b); + } + cx0_sub = getl(b, T_RC); + if (cx0_sub != 0) + userlog("[LG_YEARCLOSE] LG_TRIALBAL 경고 통보 rc=%ld — 상위 판단 계속", cx0_sub); + else + userlog("[LG_YEARCLOSE] LG_TRIALBAL 체인 정상 완료 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); } diff --git a/app/src/mg/dbio/mg_bump_stan_dbio.pgc b/app/src/mg/dbio/mg_bump_stan_dbio.pgc index 3e61d9f..590a0ac 100644 --- a/app/src/mg/dbio/mg_bump_stan_dbio.pgc +++ b/app/src/mg/dbio/mg_bump_stan_dbio.pgc @@ -7,14 +7,47 @@ #include #include "mg_bump_stan_dbio.h" +/* + * 해당 영업일에 전문이 오간 활동 채널 수를 세고, STAN 은 시퀀스에서 채번한다. + * + * 과거 구현은 mg_channel 을 다중행 UPDATE(last_stan = last_stan + 1) 했었다. + * 그 방식은 크로스브랜치 핫로우 교착의 원인이다: 한 글로벌 트랜잭션 안에서 + * 형제 XA 브랜치 둘이 같은 채널 행을 잠그면 같은 트랜잭션이라 락이 풀리지 않아 + * 트랜잭션 타임아웃까지 그대로 멈춘다(AUTH→LIMIT_DEC/FRAUD_DETECT→MG_LOG 사례). + * 다중행 UPDATE 라 활동 채널 전체를 한 번에 잠가 파급도 가장 넓었다. + * + * 실제 전문 스위치도 STAN 을 채널 상태행이 아니라 카운터에서 뽑는다. + * 시퀀스 채번은 행락을 잡지 않아 형제 브랜치끼리 충돌하지 않는다. + * mg_channel 쓰기는 채널 생애주기 소유자(MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/ + * RESET/SIGNON/SIGNOFF)에게만 남긴다. + * + * 반환: 해당 영업일 활동 채널 수 (실패 시 -1). + */ long mgdb_channel_bump_stan(const char *bizdate) { EXEC SQL BEGIN DECLARE SECTION; char h_bizdate[16]; + long h_chan_cnt = 0; + long h_stan = 0; EXEC SQL END DECLARE SECTION; strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0; - EXEC SQL UPDATE mg_channel SET last_stan = last_stan + 1 - WHERE channel IN (SELECT channel FROM mg_msg_log WHERE biz_date = :h_bizdate); - if (sqlca.sqlcode < 0) { userlog("mgdb_channel_bump_stan FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); return -1; } - return sqlca.sqlerrd[2]; + + EXEC SQL SELECT count(DISTINCT channel) INTO :h_chan_cnt + FROM mg_msg_log WHERE biz_date = :h_bizdate; + if (sqlca.sqlcode < 0) { + userlog("mgdb_channel_bump_stan 활동채널 집계 FAIL [%d] %s", + sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); + return -1; + } + + EXEC SQL SELECT nextval('mg_stan_seq') INTO :h_stan; + if (sqlca.sqlcode < 0) { + userlog("mgdb_channel_bump_stan STAN 채번 FAIL [%d] %s", + sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); + return -1; + } + + userlog("mgdb_channel_bump_stan 영업일=%s 활동채널=%ld STAN=%ld", + h_bizdate, h_chan_cnt, h_stan); + return h_chan_cnt; } diff --git a/app/src/mg/svc/MG_ACK.pgc b/app/src/mg/svc/MG_ACK.pgc index e8aa6ac..92ac88d 100644 --- a/app/src/mg/svc/MG_ACK.pgc +++ b/app/src/mg/svc/MG_ACK.pgc @@ -19,11 +19,12 @@ void MG_ACK(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_ACK(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_ACK 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_ACK 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_ACK", "S", gw_bizdate) < 0) { + userlog("MG_ACK 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -161,5 +183,61 @@ void MG_ACK(TPSVCINFO *p) long msg_id = getl(b, T_ID1); if (mgdb_update_msg_rc(msg_id, "00", "A") < 0) FAIL(b); sets_(b, T_STATUS, "A"); + + /* ---- 업무 체인: MG_ACK -> MG_SEND (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_status[256]; gets_(b, T_STATUS, ch_o_status, sizeof(ch_o_status)); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0810"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_ACK] tpcall(MG_SEND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7228); + Bchg(b, T_MSG, 0, "ACK 응답 송신 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_ACK] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STATUS, 0, ch_o_status, 0L); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_ACK] 체인 대상 컨텍스트 없음 - MG_SEND 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_ADVICE.pgc b/app/src/mg/svc/MG_ADVICE.pgc index 35bb9d3..b59f21e 100644 --- a/app/src/mg/svc/MG_ADVICE.pgc +++ b/app/src/mg/svc/MG_ADVICE.pgc @@ -20,11 +20,12 @@ void MG_ADVICE(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_ADVICE(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_ADVICE 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_ADVICE 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_ADVICE", "S", gw_bizdate) < 0) { + userlog("MG_ADVICE 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_AMTCHECK.pgc b/app/src/mg/svc/MG_AMTCHECK.pgc index f9e219e..adb5dcd 100644 --- a/app/src/mg/svc/MG_AMTCHECK.pgc +++ b/app/src/mg/svc/MG_AMTCHECK.pgc @@ -20,11 +20,12 @@ void MG_AMTCHECK(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_AMTCHECK(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_AMTCHECK 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_AMTCHECK 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_AMTCHECK", "S", gw_bizdate) < 0) { + userlog("MG_AMTCHECK 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_AUTHREQ.pgc b/app/src/mg/svc/MG_AUTHREQ.pgc index ccb63bd..d08e9c5 100644 --- a/app/src/mg/svc/MG_AUTHREQ.pgc +++ b/app/src/mg/svc/MG_AUTHREQ.pgc @@ -31,11 +31,12 @@ void MG_AUTHREQ(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -114,19 +115,40 @@ void MG_AUTHREQ(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_AUTHREQ 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_AUTHREQ 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_AUTHREQ", "S", gw_bizdate) < 0) { + userlog("MG_AUTHREQ 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_AUTHRSP.pgc b/app/src/mg/svc/MG_AUTHRSP.pgc index d3419f6..1e339ea 100644 --- a/app/src/mg/svc/MG_AUTHRSP.pgc +++ b/app/src/mg/svc/MG_AUTHRSP.pgc @@ -20,11 +20,12 @@ void MG_AUTHRSP(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_AUTHRSP(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_AUTHRSP 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_AUTHRSP 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_AUTHRSP", "S", gw_bizdate) < 0) { + userlog("MG_AUTHRSP 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_BITMAP.pgc b/app/src/mg/svc/MG_BITMAP.pgc index 7a6d285..4561858 100644 --- a/app/src/mg/svc/MG_BITMAP.pgc +++ b/app/src/mg/svc/MG_BITMAP.pgc @@ -27,11 +27,12 @@ void MG_BITMAP(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -110,19 +111,40 @@ void MG_BITMAP(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_BITMAP 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_BITMAP 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_BITMAP", "S", gw_bizdate) < 0) { + userlog("MG_BITMAP 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -182,5 +204,61 @@ void MG_BITMAP(TPSVCINFO *p) EXEC SQL UPDATE mg_msg_log SET bitmap = :h_bitmap WHERE msg_id = :h_id; if (sqlca.sqlcode < 0) { userlog("MG_BITMAP UPDATE FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); } } + + /* ---- 업무 체인: MG_BITMAP -> MG_PARSE (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str6[256]; gets_(b, T_STR6, ch_o_str6, sizeof(ch_o_str6)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0200"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_PARSE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_BITMAP] tpcall(MG_PARSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7214); + Bchg(b, T_MSG, 0, "비트맵 파싱 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_BITMAP] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR6, 0, ch_o_str6, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_BITMAP] 체인 대상 컨텍스트 없음 - MG_PARSE 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_BMPPARSE.pgc b/app/src/mg/svc/MG_BMPPARSE.pgc index 9d2505c..e5038c0 100644 --- a/app/src/mg/svc/MG_BMPPARSE.pgc +++ b/app/src/mg/svc/MG_BMPPARSE.pgc @@ -119,5 +119,63 @@ void MG_BMPPARSE(TPSVCINFO *p) sets_(b, T_STR3, list); setl(b, T_COUNT, cnt); setl(b, T_RC, 0); + + /* ---- 업무 체인: MG_BMPPARSE -> MG_PARSE (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str3[256]; gets_(b, T_STR3, ch_o_str3, sizeof(ch_o_str3)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0200"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_PARSE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_BMPPARSE] tpcall(MG_PARSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7215); + Bchg(b, T_MSG, 0, "비트맵 해석 파싱 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_BMPPARSE] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR3, 0, ch_o_str3, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_BMPPARSE] 체인 대상 컨텍스트 없음 - MG_PARSE 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_CAPRSP.pgc b/app/src/mg/svc/MG_CAPRSP.pgc index 7e19735..7a065ca 100644 --- a/app/src/mg/svc/MG_CAPRSP.pgc +++ b/app/src/mg/svc/MG_CAPRSP.pgc @@ -20,11 +20,12 @@ void MG_CAPRSP(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_CAPRSP(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_CAPRSP 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_CAPRSP 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_CAPRSP", "S", gw_bizdate) < 0) { + userlog("MG_CAPRSP 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_CAPTURE.pgc b/app/src/mg/svc/MG_CAPTURE.pgc index ed13ca1..4d608ca 100644 --- a/app/src/mg/svc/MG_CAPTURE.pgc +++ b/app/src/mg/svc/MG_CAPTURE.pgc @@ -20,11 +20,12 @@ void MG_CAPTURE(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_CAPTURE(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_CAPTURE 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_CAPTURE 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_CAPTURE", "S", gw_bizdate) < 0) { + userlog("MG_CAPTURE 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_CHANAUTH.pgc b/app/src/mg/svc/MG_CHANAUTH.pgc index 4554ee7..e9a5dc3 100644 --- a/app/src/mg/svc/MG_CHANAUTH.pgc +++ b/app/src/mg/svc/MG_CHANAUTH.pgc @@ -19,11 +19,12 @@ void MG_CHANAUTH(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_CHANAUTH(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_CHANAUTH 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_CHANAUTH 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_CHANAUTH", "S", gw_bizdate) < 0) { + userlog("MG_CHANAUTH 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_CHANFAILOVER.pgc b/app/src/mg/svc/MG_CHANFAILOVER.pgc index e1bb22d..338201e 100644 --- a/app/src/mg/svc/MG_CHANFAILOVER.pgc +++ b/app/src/mg/svc/MG_CHANFAILOVER.pgc @@ -187,5 +187,63 @@ void MG_CHANFAILOVER(TPSVCINFO *p) sets_(b, T_STATUS, "FAILOVER"); sets_(b, T_STR5, backup); setl(b, T_RC, 0); + + /* ---- 업무 체인: MG_CHANFAILOVER -> MG_ROUTE (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_status[256]; gets_(b, T_STATUS, ch_o_status, sizeof(ch_o_status)); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str5[256]; gets_(b, T_STR5, ch_o_str5, sizeof(ch_o_str5)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0800"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_ROUTE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_CHANFAILOVER] tpcall(MG_ROUTE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7233); + Bchg(b, T_MSG, 0, "채널 페일오버 라우팅 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_CHANFAILOVER] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STATUS, 0, ch_o_status, 0L); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR5, 0, ch_o_str5, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_CHANFAILOVER] 체인 대상 컨텍스트 없음 - MG_ROUTE 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_CHANHEALTH.pgc b/app/src/mg/svc/MG_CHANHEALTH.pgc index e869c1b..72e0a44 100644 --- a/app/src/mg/svc/MG_CHANHEALTH.pgc +++ b/app/src/mg/svc/MG_CHANHEALTH.pgc @@ -20,11 +20,12 @@ void MG_CHANHEALTH(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_CHANHEALTH(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_CHANHEALTH 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_CHANHEALTH 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_CHANHEALTH", "S", gw_bizdate) < 0) { + userlog("MG_CHANHEALTH 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -196,5 +218,63 @@ void MG_CHANHEALTH(TPSVCINFO *p) setl(b, T_ARG7, h_backlog); setl(b, T_ARG8, score); setl(b, T_RC, (score < 60) ? 1 : 0); + + /* ---- 업무 체인: MG_CHANHEALTH -> MG_CHANPING (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg3 = getl(b, T_ARG3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_status[256]; gets_(b, T_STATUS, ch_o_status, sizeof(ch_o_status)); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0800"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_CHANPING", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_CHANHEALTH] tpcall(MG_CHANPING) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7242); + Bchg(b, T_MSG, 0, "채널 헬스체크 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_CHANHEALTH] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG3, ch_o_arg3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STATUS, 0, ch_o_status, 0L); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_CHANHEALTH] 체인 대상 컨텍스트 없음 - MG_CHANPING 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_CHANLIST.pgc b/app/src/mg/svc/MG_CHANLIST.pgc index 704806e..bd4e545 100644 --- a/app/src/mg/svc/MG_CHANLIST.pgc +++ b/app/src/mg/svc/MG_CHANLIST.pgc @@ -19,11 +19,12 @@ void MG_CHANLIST(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_CHANLIST(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_CHANLIST 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_CHANLIST 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_CHANLIST", "S", gw_bizdate) < 0) { + userlog("MG_CHANLIST 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_CHANOPEN.pgc b/app/src/mg/svc/MG_CHANOPEN.pgc index e192ed0..861e7e6 100644 --- a/app/src/mg/svc/MG_CHANOPEN.pgc +++ b/app/src/mg/svc/MG_CHANOPEN.pgc @@ -178,5 +178,63 @@ void MG_CHANOPEN(TPSVCINFO *p) sets_(b, T_STATUS, "UP"); sets_(b, T_STR5, cur); /* 개통 전 상태 */ setl(b, T_RC, 0); + + /* ---- 업무 체인: MG_CHANOPEN -> MG_ROUTE (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_status[256]; gets_(b, T_STATUS, ch_o_status, sizeof(ch_o_status)); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str5[256]; gets_(b, T_STR5, ch_o_str5, sizeof(ch_o_str5)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0800"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_ROUTE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_CHANOPEN] tpcall(MG_ROUTE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7231); + Bchg(b, T_MSG, 0, "채널개통 라우팅 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_CHANOPEN] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STATUS, 0, ch_o_status, 0L); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR5, 0, ch_o_str5, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_CHANOPEN] 체인 대상 컨텍스트 없음 - MG_ROUTE 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_CHANPING.pgc b/app/src/mg/svc/MG_CHANPING.pgc index e84ea10..2fd3dcf 100644 --- a/app/src/mg/svc/MG_CHANPING.pgc +++ b/app/src/mg/svc/MG_CHANPING.pgc @@ -19,11 +19,12 @@ void MG_CHANPING(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_CHANPING(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_CHANPING 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_CHANPING 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_CHANPING", "S", gw_bizdate) < 0) { + userlog("MG_CHANPING 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -158,9 +180,11 @@ void MG_CHANPING(TPSVCINFO *p) userlog("MG_CHANPING 심화완료 chan=%s daysum=%ld fee=%ld score=%ld aff=%ld", gw_chan, gw_daysum, gw_fee, gw_score, gw_aff); } - char chan[16], cur[16]; + char chan[16], cur[16], ping_bizdate[16]; + long ping_stan, ping_msgid; EXEC SQL BEGIN DECLARE SECTION; char h_chan[16]; + long h_last, h_idle; EXEC SQL END DECLARE SECTION; gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01"); @@ -173,9 +197,35 @@ void MG_CHANPING(TPSVCINFO *p) } strncpy(h_chan, chan, sizeof(h_chan)-1); h_chan[sizeof(h_chan)-1] = 0; - EXEC SQL UPDATE mg_channel SET updated_at = now() WHERE channel = :h_chan; + /* 채널행(mg_channel)은 생애주기 소유자(MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/ + * RESET/STAT, MG_SIGNON/SIGNOFF)만 UPDATE 한다. PING 은 하트비트일 뿐이라 + * 채널행을 SELECT 로만 읽고, 하트비트 사실은 자기 이력(mg_msg_log)에 + * 0800 네트워크관리 전문으로 적재한다(형제 XA 브랜치 간 행락 회피). */ + EXEC SQL SELECT coalesce(last_stan, 0), + coalesce(EXTRACT(epoch FROM now() - updated_at)::bigint, 0) + INTO :h_last, :h_idle + FROM mg_channel WHERE channel = :h_chan; + if (sqlca.sqlcode == 100) { setl(b, T_RC, 25); FAIL(b); } if (sqlca.sqlcode < 0) FAIL(b); + ping_stan = mgdb_next_stan(); + if (ping_stan < 0) FAIL(b); + gets_(b, T_BIZDATE, ping_bizdate, sizeof(ping_bizdate)); + if (ping_bizdate[0] == 0) strcpy(ping_bizdate, "2026-07-19"); + ping_msgid = mgdb_next_msg_id(); + if (ping_msgid > 0) { + if (mgdb_insert_msg(ping_msgid, ping_stan, "0800", chan, "OUT", + "301000", "", 0, "", "00", + "GW-PING-MG_CHANPING", "S", ping_bizdate) < 0) { + userlog("MG_CHANPING 하트비트 이력 적재경고 chan=%s stan=%ld", + chan, ping_stan); + } + } + userlog("MG_CHANPING 하트비트 chan=%s last_stan=%ld idle=%lds stan=%ld", + chan, h_last, h_idle, ping_stan); + setl(b, T_ARG2, h_idle); + setl(b, T_ARG3, h_last); + sets_(b, T_STATUS, "UP"); setl(b, T_RC, 0); OK(b); diff --git a/app/src/mg/svc/MG_CHANSTAT.pgc b/app/src/mg/svc/MG_CHANSTAT.pgc index 293dcf3..6cf58b7 100644 --- a/app/src/mg/svc/MG_CHANSTAT.pgc +++ b/app/src/mg/svc/MG_CHANSTAT.pgc @@ -19,11 +19,12 @@ void MG_CHANSTAT(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_CHANSTAT(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_CHANSTAT 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_CHANSTAT 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_CHANSTAT", "S", gw_bizdate) < 0) { + userlog("MG_CHANSTAT 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_CHANSWITCH.pgc b/app/src/mg/svc/MG_CHANSWITCH.pgc index 04c85e1..1612ff7 100644 --- a/app/src/mg/svc/MG_CHANSWITCH.pgc +++ b/app/src/mg/svc/MG_CHANSWITCH.pgc @@ -193,5 +193,65 @@ void MG_CHANSWITCH(TPSVCINFO *p) sets_(b, T_STR2, bak); setl(b, T_COUNT, moved); setl(b, T_RC, 0); + + /* ---- 업무 체인: MG_CHANSWITCH -> MG_ROUTE (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str2[256]; gets_(b, T_STR2, ch_o_str2, sizeof(ch_o_str2)); + char ch_o_str5[256]; gets_(b, T_STR5, ch_o_str5, sizeof(ch_o_str5)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0800"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_ROUTE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_CHANSWITCH] tpcall(MG_ROUTE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7232); + Bchg(b, T_MSG, 0, "채널전환 라우팅 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_CHANSWITCH] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR2, 0, ch_o_str2, 0L); + Bchg(b, T_STR5, 0, ch_o_str5, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_CHANSWITCH] 체인 대상 컨텍스트 없음 - MG_ROUTE 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_CONFIRM.pgc b/app/src/mg/svc/MG_CONFIRM.pgc index a14a841..18243bf 100644 --- a/app/src/mg/svc/MG_CONFIRM.pgc +++ b/app/src/mg/svc/MG_CONFIRM.pgc @@ -19,11 +19,12 @@ void MG_CONFIRM(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_CONFIRM(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_CONFIRM 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_CONFIRM 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_CONFIRM", "S", gw_bizdate) < 0) { + userlog("MG_CONFIRM 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_CONVERT.pgc b/app/src/mg/svc/MG_CONVERT.pgc index 3fc66ba..253a9fa 100644 --- a/app/src/mg/svc/MG_CONVERT.pgc +++ b/app/src/mg/svc/MG_CONVERT.pgc @@ -19,11 +19,12 @@ void MG_CONVERT(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_CONVERT(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_CONVERT 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_CONVERT 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_CONVERT", "S", gw_bizdate) < 0) { + userlog("MG_CONVERT 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_DECODE.pgc b/app/src/mg/svc/MG_DECODE.pgc index 54ecaa7..f1470b1 100644 --- a/app/src/mg/svc/MG_DECODE.pgc +++ b/app/src/mg/svc/MG_DECODE.pgc @@ -118,5 +118,63 @@ void MG_DECODE(TPSVCINFO *p) setl(b, T_ARG1, stan); sets_(b, T_CHANNEL, chan); setl(b, T_RC, 0); + + /* ---- 업무 체인: MG_DECODE -> MG_PARSE (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg1 = getl(b, T_ARG1); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str4[256]; gets_(b, T_STR4, ch_o_str4, sizeof(ch_o_str4)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0200"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_PARSE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_DECODE] tpcall(MG_PARSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7217); + Bchg(b, T_MSG, 0, "전문 디코딩 파싱 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_DECODE] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG1, ch_o_arg1); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR4, 0, ch_o_str4, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_DECODE] 체인 대상 컨텍스트 없음 - MG_PARSE 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_DEQUEUE.pgc b/app/src/mg/svc/MG_DEQUEUE.pgc index b8c3088..c1e4d9f 100644 --- a/app/src/mg/svc/MG_DEQUEUE.pgc +++ b/app/src/mg/svc/MG_DEQUEUE.pgc @@ -19,11 +19,12 @@ void MG_DEQUEUE(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_DEQUEUE(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_DEQUEUE 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_DEQUEUE 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_DEQUEUE", "S", gw_bizdate) < 0) { + userlog("MG_DEQUEUE 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_DIRECTADPT.pgc b/app/src/mg/svc/MG_DIRECTADPT.pgc index 52f0622..ab35371 100644 --- a/app/src/mg/svc/MG_DIRECTADPT.pgc +++ b/app/src/mg/svc/MG_DIRECTADPT.pgc @@ -31,11 +31,12 @@ void MG_DIRECTADPT(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -114,19 +115,40 @@ void MG_DIRECTADPT(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_DIRECTADPT 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_DIRECTADPT 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_DIRECTADPT", "S", gw_bizdate) < 0) { + userlog("MG_DIRECTADPT 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_DUPCHK.pgc b/app/src/mg/svc/MG_DUPCHK.pgc index d80aacf..76d77e7 100644 --- a/app/src/mg/svc/MG_DUPCHK.pgc +++ b/app/src/mg/svc/MG_DUPCHK.pgc @@ -20,11 +20,12 @@ void MG_DUPCHK(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_DUPCHK(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_DUPCHK 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_DUPCHK 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_DUPCHK", "S", gw_bizdate) < 0) { + userlog("MG_DUPCHK 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_DUPPURGE.pgc b/app/src/mg/svc/MG_DUPPURGE.pgc index c9083d0..64e3df2 100644 --- a/app/src/mg/svc/MG_DUPPURGE.pgc +++ b/app/src/mg/svc/MG_DUPPURGE.pgc @@ -19,11 +19,12 @@ void MG_DUPPURGE(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_DUPPURGE(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_DUPPURGE 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_DUPPURGE 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_DUPPURGE", "S", gw_bizdate) < 0) { + userlog("MG_DUPPURGE 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_ECHO.pgc b/app/src/mg/svc/MG_ECHO.pgc index 2831f1b..956ece5 100644 --- a/app/src/mg/svc/MG_ECHO.pgc +++ b/app/src/mg/svc/MG_ECHO.pgc @@ -19,11 +19,12 @@ void MG_ECHO(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_ECHO(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_ECHO 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_ECHO 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_ECHO", "S", gw_bizdate) < 0) { + userlog("MG_ECHO 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_ENCODE.pgc b/app/src/mg/svc/MG_ENCODE.pgc index f269edb..20b9385 100644 --- a/app/src/mg/svc/MG_ENCODE.pgc +++ b/app/src/mg/svc/MG_ENCODE.pgc @@ -111,5 +111,63 @@ void MG_ENCODE(TPSVCINFO *p) sets_(b, T_STR3, raw); setl(b, T_COUNT, (long)strlen(raw)); setl(b, T_RC, 0); + + /* ---- 업무 체인: MG_ENCODE -> MG_SEND (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str3[256]; gets_(b, T_STR3, ch_o_str3, sizeof(ch_o_str3)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0210"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_ENCODE] tpcall(MG_SEND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7227); + Bchg(b, T_MSG, 0, "전문 인코딩 후 송신 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_ENCODE] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR3, 0, ch_o_str3, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_ENCODE] 체인 대상 컨텍스트 없음 - MG_SEND 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_ERRESCAL.pgc b/app/src/mg/svc/MG_ERRESCAL.pgc index f4c63a6..4175c36 100644 --- a/app/src/mg/svc/MG_ERRESCAL.pgc +++ b/app/src/mg/svc/MG_ERRESCAL.pgc @@ -19,11 +19,12 @@ void MG_ERRESCAL(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_ERRESCAL(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_ERRESCAL 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_ERRESCAL 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_ERRESCAL", "S", gw_bizdate) < 0) { + userlog("MG_ERRESCAL 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_ERRLIST.pgc b/app/src/mg/svc/MG_ERRLIST.pgc index de42b11..0a8e01f 100644 --- a/app/src/mg/svc/MG_ERRLIST.pgc +++ b/app/src/mg/svc/MG_ERRLIST.pgc @@ -20,11 +20,12 @@ void MG_ERRLIST(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_ERRLIST(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_ERRLIST 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_ERRLIST 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_ERRLIST", "S", gw_bizdate) < 0) { + userlog("MG_ERRLIST 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_ERRMSG.pgc b/app/src/mg/svc/MG_ERRMSG.pgc index 7aee1ad..1b485e3 100644 --- a/app/src/mg/svc/MG_ERRMSG.pgc +++ b/app/src/mg/svc/MG_ERRMSG.pgc @@ -19,11 +19,12 @@ void MG_ERRMSG(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_ERRMSG(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_ERRMSG 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_ERRMSG 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_ERRMSG", "S", gw_bizdate) < 0) { + userlog("MG_ERRMSG 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_ERRPURGE.pgc b/app/src/mg/svc/MG_ERRPURGE.pgc index 03a7e51..01af7f6 100644 --- a/app/src/mg/svc/MG_ERRPURGE.pgc +++ b/app/src/mg/svc/MG_ERRPURGE.pgc @@ -20,11 +20,12 @@ void MG_ERRPURGE(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_ERRPURGE(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_ERRPURGE 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_ERRPURGE 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_ERRPURGE", "S", gw_bizdate) < 0) { + userlog("MG_ERRPURGE 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_ERRREQUEUE.pgc b/app/src/mg/svc/MG_ERRREQUEUE.pgc index d74c9a2..4a01830 100644 --- a/app/src/mg/svc/MG_ERRREQUEUE.pgc +++ b/app/src/mg/svc/MG_ERRREQUEUE.pgc @@ -19,11 +19,12 @@ void MG_ERRREQUEUE(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_ERRREQUEUE(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_ERRREQUEUE 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_ERRREQUEUE 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_ERRREQUEUE", "S", gw_bizdate) < 0) { + userlog("MG_ERRREQUEUE 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -183,5 +205,63 @@ void MG_ERRREQUEUE(TPSVCINFO *p) setl(b, T_ID2, qid); setl(b, T_ARG1, h_stan); setl(b, T_RC, 0); + + /* ---- 업무 체인: MG_ERRREQUEUE -> MG_SEND (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg1 = getl(b, T_ARG1); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + long ch_o_id2 = getl(b, T_ID2); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0200"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_ERRREQUEUE] tpcall(MG_SEND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7221); + Bchg(b, T_MSG, 0, "오류전문 재큐잉 송신 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_ERRREQUEUE] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG1, ch_o_arg1); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + setl(b, T_ID2, ch_o_id2); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_ERRREQUEUE] 체인 대상 컨텍스트 없음 - MG_SEND 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_ERRRETRY.pgc b/app/src/mg/svc/MG_ERRRETRY.pgc index 1fee934..a27ba9e 100644 --- a/app/src/mg/svc/MG_ERRRETRY.pgc +++ b/app/src/mg/svc/MG_ERRRETRY.pgc @@ -20,11 +20,12 @@ void MG_ERRRETRY(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_ERRRETRY(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_ERRRETRY 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_ERRRETRY 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_ERRRETRY", "S", gw_bizdate) < 0) { + userlog("MG_ERRRETRY 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -186,5 +208,61 @@ void MG_ERRRETRY(TPSVCINFO *p) userlog("MG_ERRRETRY 재처리 msg_id=%ld -> queue_id=%ld", msg_id, qid); setl(b, T_ID2, qid); setl(b, T_RC, 0); + + /* ---- 업무 체인: MG_ERRRETRY -> MG_SEND (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + long ch_o_id2 = getl(b, T_ID2); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0200"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_ERRRETRY] tpcall(MG_SEND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7222); + Bchg(b, T_MSG, 0, "오류전문 재시도 송신 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_ERRRETRY] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + setl(b, T_ID2, ch_o_id2); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_ERRRETRY] 체인 대상 컨텍스트 없음 - MG_SEND 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_FROMISO.pgc b/app/src/mg/svc/MG_FROMISO.pgc index e60674a..c988f78 100644 --- a/app/src/mg/svc/MG_FROMISO.pgc +++ b/app/src/mg/svc/MG_FROMISO.pgc @@ -20,11 +20,12 @@ void MG_FROMISO(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_FROMISO(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_FROMISO 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_FROMISO 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_FROMISO", "S", gw_bizdate) < 0) { + userlog("MG_FROMISO 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -178,5 +200,65 @@ void MG_FROMISO(TPSVCINFO *p) setl(b, T_AMOUNT, amount); setl(b, T_COUNT, (long)strlen(internal)); setl(b, T_RC, 0); + + /* ---- 업무 체인: MG_FROMISO -> MG_PARSE (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str3[256]; gets_(b, T_STR3, ch_o_str3, sizeof(ch_o_str3)); + char ch_o_str4[256]; gets_(b, T_STR4, ch_o_str4, sizeof(ch_o_str4)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0210"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_PARSE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_FROMISO] tpcall(MG_PARSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7216); + Bchg(b, T_MSG, 0, "ISO 역변환 파싱 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_FROMISO] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR3, 0, ch_o_str3, 0L); + Bchg(b, T_STR4, 0, ch_o_str4, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_FROMISO] 체인 대상 컨텍스트 없음 - MG_PARSE 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_GAPSCAN.pgc b/app/src/mg/svc/MG_GAPSCAN.pgc index 63e89ee..ae1529a 100644 --- a/app/src/mg/svc/MG_GAPSCAN.pgc +++ b/app/src/mg/svc/MG_GAPSCAN.pgc @@ -20,11 +20,12 @@ void MG_GAPSCAN(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_GAPSCAN(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_GAPSCAN 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_GAPSCAN 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_GAPSCAN", "S", gw_bizdate) < 0) { + userlog("MG_GAPSCAN 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_HEALTH.pgc b/app/src/mg/svc/MG_HEALTH.pgc index 070f0f7..6e875f5 100644 --- a/app/src/mg/svc/MG_HEALTH.pgc +++ b/app/src/mg/svc/MG_HEALTH.pgc @@ -19,11 +19,12 @@ void MG_HEALTH(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_HEALTH(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_HEALTH 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_HEALTH 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_HEALTH", "S", gw_bizdate) < 0) { + userlog("MG_HEALTH 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_INFLIGHT.pgc b/app/src/mg/svc/MG_INFLIGHT.pgc index 7b2eec1..ef4e8f1 100644 --- a/app/src/mg/svc/MG_INFLIGHT.pgc +++ b/app/src/mg/svc/MG_INFLIGHT.pgc @@ -19,11 +19,12 @@ void MG_INFLIGHT(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_INFLIGHT(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_INFLIGHT 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_INFLIGHT 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_INFLIGHT", "S", gw_bizdate) < 0) { + userlog("MG_INFLIGHT 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_ISO8583.pgc b/app/src/mg/svc/MG_ISO8583.pgc index 4d9111d..f76ad6b 100644 --- a/app/src/mg/svc/MG_ISO8583.pgc +++ b/app/src/mg/svc/MG_ISO8583.pgc @@ -19,11 +19,12 @@ void MG_ISO8583(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_ISO8583(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_ISO8583 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_ISO8583 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_ISO8583", "S", gw_bizdate) < 0) { + userlog("MG_ISO8583 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -181,5 +203,63 @@ void MG_ISO8583(TPSVCINFO *p) sets_(b, T_STR4, proc); setl(b, T_AMOUNT, amount); setl(b, T_ID1, msg_id); + + /* ---- 업무 체인: MG_ISO8583 -> MG_PARSE (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + long ch_o_id1 = getl(b, T_ID1); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str4[256]; gets_(b, T_STR4, ch_o_str4, sizeof(ch_o_str4)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0200"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_PARSE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_ISO8583] tpcall(MG_PARSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7213); + Bchg(b, T_MSG, 0, "ISO8583 파싱 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_ISO8583] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + setl(b, T_ID1, ch_o_id1); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR4, 0, ch_o_str4, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_ISO8583] 체인 대상 컨텍스트 없음 - MG_PARSE 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_KEYCHECK.pgc b/app/src/mg/svc/MG_KEYCHECK.pgc index b1365da..5df7ba0 100644 --- a/app/src/mg/svc/MG_KEYCHECK.pgc +++ b/app/src/mg/svc/MG_KEYCHECK.pgc @@ -29,11 +29,12 @@ void MG_KEYCHECK(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -112,19 +113,40 @@ void MG_KEYCHECK(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_KEYCHECK 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_KEYCHECK 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_KEYCHECK", "S", gw_bizdate) < 0) { + userlog("MG_KEYCHECK 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -194,5 +216,61 @@ void MG_KEYCHECK(TPSVCINFO *p) sets_(b, T_KEY1, kcv); setl(b, T_ARG3, keyver); setl(b, T_RC, mismatch ? 1 : 0); + + /* ---- 업무 체인: MG_KEYCHECK -> CM_HASH_DJB2 (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg3 = getl(b, T_ARG3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_key1[256]; gets_(b, T_KEY1, ch_o_key1, sizeof(ch_o_key1)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_sd[128]; gets_(b, T_STR2, ch_sd, sizeof(ch_sd)); + if (ch_sd[0] == 0) strcpy(ch_sd, "MG_KEYCHECK"); + Bchg(b, T_STR1, 0, ch_sd, 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_HASH_DJB2", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_KEYCHECK] tpcall(CM_HASH_DJB2) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7255); + Bchg(b, T_MSG, 0, "키 체크값 산출 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_KEYCHECK] 검사값 연동 완료 val=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG3, ch_o_arg3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_KEY1, 0, ch_o_key1, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_KEYCHECK] 체인 대상 컨텍스트 없음 - CM_HASH_DJB2 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_KEYEXCH.pgc b/app/src/mg/svc/MG_KEYEXCH.pgc index 1cd0e1d..cc82fdf 100644 --- a/app/src/mg/svc/MG_KEYEXCH.pgc +++ b/app/src/mg/svc/MG_KEYEXCH.pgc @@ -19,11 +19,12 @@ void MG_KEYEXCH(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_KEYEXCH(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_KEYEXCH 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_KEYEXCH 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_KEYEXCH", "S", gw_bizdate) < 0) { + userlog("MG_KEYEXCH 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_KEYEXPIRE.pgc b/app/src/mg/svc/MG_KEYEXPIRE.pgc index 109e9c1..46844d7 100644 --- a/app/src/mg/svc/MG_KEYEXPIRE.pgc +++ b/app/src/mg/svc/MG_KEYEXPIRE.pgc @@ -19,11 +19,12 @@ void MG_KEYEXPIRE(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_KEYEXPIRE(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_KEYEXPIRE 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_KEYEXPIRE 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_KEYEXPIRE", "S", gw_bizdate) < 0) { + userlog("MG_KEYEXPIRE 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_KEYLOAD.pgc b/app/src/mg/svc/MG_KEYLOAD.pgc index 3e146ed..a252d84 100644 --- a/app/src/mg/svc/MG_KEYLOAD.pgc +++ b/app/src/mg/svc/MG_KEYLOAD.pgc @@ -19,11 +19,12 @@ void MG_KEYLOAD(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_KEYLOAD(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_KEYLOAD 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_KEYLOAD 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_KEYLOAD", "S", gw_bizdate) < 0) { + userlog("MG_KEYLOAD 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -186,5 +208,61 @@ void MG_KEYLOAD(TPSVCINFO *p) sets_(b, T_KEY1, newkey); setl(b, T_ARG3, h_kv); setl(b, T_RC, 0); + + /* ---- 업무 체인: MG_KEYLOAD -> CM_HASH_FNV (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg3 = getl(b, T_ARG3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_key1[256]; gets_(b, T_KEY1, ch_o_key1, sizeof(ch_o_key1)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_sd[128]; gets_(b, T_STR2, ch_sd, sizeof(ch_sd)); + if (ch_sd[0] == 0) strcpy(ch_sd, "MG_KEYLOAD"); + Bchg(b, T_STR1, 0, ch_sd, 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_HASH_FNV", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_KEYLOAD] tpcall(CM_HASH_FNV) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7256); + Bchg(b, T_MSG, 0, "키 적재검증 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_KEYLOAD] 검사값 연동 완료 val=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG3, ch_o_arg3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_KEY1, 0, ch_o_key1, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_KEYLOAD] 체인 대상 컨텍스트 없음 - CM_HASH_FNV 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_KEYROTATE.pgc b/app/src/mg/svc/MG_KEYROTATE.pgc index 81a3faa..4fc59c5 100644 --- a/app/src/mg/svc/MG_KEYROTATE.pgc +++ b/app/src/mg/svc/MG_KEYROTATE.pgc @@ -20,11 +20,12 @@ void MG_KEYROTATE(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_KEYROTATE(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_KEYROTATE 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_KEYROTATE 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_KEYROTATE", "S", gw_bizdate) < 0) { + userlog("MG_KEYROTATE 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_KEYSTATUS.pgc b/app/src/mg/svc/MG_KEYSTATUS.pgc index ab2f9b2..a1c012d 100644 --- a/app/src/mg/svc/MG_KEYSTATUS.pgc +++ b/app/src/mg/svc/MG_KEYSTATUS.pgc @@ -20,11 +20,12 @@ void MG_KEYSTATUS(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_KEYSTATUS(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_KEYSTATUS 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_KEYSTATUS 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_KEYSTATUS", "S", gw_bizdate) < 0) { + userlog("MG_KEYSTATUS 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_LOADBAL.pgc b/app/src/mg/svc/MG_LOADBAL.pgc index 067d2b1..edc4f61 100644 --- a/app/src/mg/svc/MG_LOADBAL.pgc +++ b/app/src/mg/svc/MG_LOADBAL.pgc @@ -19,11 +19,12 @@ void MG_LOADBAL(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_LOADBAL(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_LOADBAL 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_LOADBAL 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_LOADBAL", "S", gw_bizdate) < 0) { + userlog("MG_LOADBAL 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -189,5 +211,63 @@ void MG_LOADBAL(TPSVCINFO *p) setl(b, T_COUNT, best_load); setl(b, T_ARG3, considered); setl(b, T_RC, 0); + + /* ---- 업무 체인: MG_LOADBAL -> MG_CHANPING (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg3 = getl(b, T_ARG3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0800"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_CHANPING", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_LOADBAL] tpcall(MG_CHANPING) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7241); + Bchg(b, T_MSG, 0, "부하분산 채널점검 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_LOADBAL] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG3, ch_o_arg3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_LOADBAL] 체인 대상 컨텍스트 없음 - MG_CHANPING 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_LOG.pgc b/app/src/mg/svc/MG_LOG.pgc index 9058ae0..e353fc9 100644 --- a/app/src/mg/svc/MG_LOG.pgc +++ b/app/src/mg/svc/MG_LOG.pgc @@ -19,11 +19,12 @@ void MG_LOG(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_LOG(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_LOG 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_LOG 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_LOG", "S", gw_bizdate) < 0) { + userlog("MG_LOG 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_MAC.pgc b/app/src/mg/svc/MG_MAC.pgc index fd503f9..32e4478 100644 --- a/app/src/mg/svc/MG_MAC.pgc +++ b/app/src/mg/svc/MG_MAC.pgc @@ -29,11 +29,12 @@ void MG_MAC(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -112,19 +113,40 @@ void MG_MAC(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_MAC 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_MAC 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_MAC", "S", gw_bizdate) < 0) { + userlog("MG_MAC 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -184,5 +206,59 @@ void MG_MAC(TPSVCINFO *p) EXEC SQL UPDATE mg_msg_log SET mac = :h_mac WHERE msg_id = :h_id; if (sqlca.sqlcode < 0) { userlog("MG_MAC UPDATE FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); } } + + /* ---- 업무 체인: MG_MAC -> CM_CRC (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_key1[256]; gets_(b, T_KEY1, ch_o_key1, sizeof(ch_o_key1)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_sd[128]; gets_(b, T_STR2, ch_sd, sizeof(ch_sd)); + if (ch_sd[0] == 0) strcpy(ch_sd, "MG_MAC"); + Bchg(b, T_STR1, 0, ch_sd, 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_CRC", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_MAC] tpcall(CM_CRC) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7251); + Bchg(b, T_MSG, 0, "MAC 검사값 산출 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_MAC] 검사값 연동 완료 val=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_KEY1, 0, ch_o_key1, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_MAC] 체인 대상 컨텍스트 없음 - CM_CRC 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_MACGEN.pgc b/app/src/mg/svc/MG_MACGEN.pgc index ec04475..6fe0f64 100644 --- a/app/src/mg/svc/MG_MACGEN.pgc +++ b/app/src/mg/svc/MG_MACGEN.pgc @@ -34,11 +34,12 @@ void MG_MACGEN(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -117,19 +118,40 @@ void MG_MACGEN(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_MACGEN 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_MACGEN 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_MACGEN", "S", gw_bizdate) < 0) { + userlog("MG_MACGEN 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -190,5 +212,61 @@ void MG_MACGEN(TPSVCINFO *p) sets_(b, T_KEY1, mac); setl(b, T_ARG3, keyver); setl(b, T_RC, 0); + + /* ---- 업무 체인: MG_MACGEN -> CM_HASH_SUM (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg3 = getl(b, T_ARG3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_key1[256]; gets_(b, T_KEY1, ch_o_key1, sizeof(ch_o_key1)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_sd[128]; gets_(b, T_STR2, ch_sd, sizeof(ch_sd)); + if (ch_sd[0] == 0) strcpy(ch_sd, "MG_MACGEN"); + Bchg(b, T_STR1, 0, ch_sd, 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_HASH_SUM", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_MACGEN] tpcall(CM_HASH_SUM) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7253); + Bchg(b, T_MSG, 0, "MAC 생성 해시 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_MACGEN] 검사값 연동 완료 val=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG3, ch_o_arg3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_KEY1, 0, ch_o_key1, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_MACGEN] 체인 대상 컨텍스트 없음 - CM_HASH_SUM 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_MACSESSION.pgc b/app/src/mg/svc/MG_MACSESSION.pgc index 49936a2..45f681e 100644 --- a/app/src/mg/svc/MG_MACSESSION.pgc +++ b/app/src/mg/svc/MG_MACSESSION.pgc @@ -33,11 +33,12 @@ void MG_MACSESSION(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -116,19 +117,40 @@ void MG_MACSESSION(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_MACSESSION 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_MACSESSION 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_MACSESSION", "S", gw_bizdate) < 0) { + userlog("MG_MACSESSION 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -191,5 +213,59 @@ void MG_MACSESSION(TPSVCINFO *p) mg_macsession_calc(h_sk, raw, mac); sets_(b, T_KEY1, mac); setl(b, T_RC, 0); + + /* ---- 업무 체인: MG_MACSESSION -> CM_HASH_SUM (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_key1[256]; gets_(b, T_KEY1, ch_o_key1, sizeof(ch_o_key1)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_sd[128]; gets_(b, T_STR2, ch_sd, sizeof(ch_sd)); + if (ch_sd[0] == 0) strcpy(ch_sd, "MG_MACSESSION"); + Bchg(b, T_STR1, 0, ch_sd, 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_HASH_SUM", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_MACSESSION] tpcall(CM_HASH_SUM) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7254); + Bchg(b, T_MSG, 0, "세션MAC 해시 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_MACSESSION] 검사값 연동 완료 val=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_KEY1, 0, ch_o_key1, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_MACSESSION] 체인 대상 컨텍스트 없음 - CM_HASH_SUM 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_MACVERIFY.pgc b/app/src/mg/svc/MG_MACVERIFY.pgc index 92a487a..e9fa85c 100644 --- a/app/src/mg/svc/MG_MACVERIFY.pgc +++ b/app/src/mg/svc/MG_MACVERIFY.pgc @@ -30,11 +30,12 @@ void MG_MACVERIFY(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -113,19 +114,40 @@ void MG_MACVERIFY(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_MACVERIFY 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_MACVERIFY 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_MACVERIFY", "S", gw_bizdate) < 0) { + userlog("MG_MACVERIFY 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -195,5 +217,59 @@ void MG_MACVERIFY(TPSVCINFO *p) setl(b, T_RC, 96); } sets_(b, T_KEY2, calc); + + /* ---- 업무 체인: MG_MACVERIFY -> CM_CRC (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_key2[256]; gets_(b, T_KEY2, ch_o_key2, sizeof(ch_o_key2)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_sd[128]; gets_(b, T_STR2, ch_sd, sizeof(ch_sd)); + if (ch_sd[0] == 0) strcpy(ch_sd, "MG_MACVERIFY"); + Bchg(b, T_STR1, 0, ch_sd, 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_CRC", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_MACVERIFY] tpcall(CM_CRC) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7252); + Bchg(b, T_MSG, 0, "MAC 검증 체크섬 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_MACVERIFY] 검사값 연동 완료 val=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_KEY2, 0, ch_o_key2, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_MACVERIFY] 체인 대상 컨텍스트 없음 - CM_CRC 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_NACK.pgc b/app/src/mg/svc/MG_NACK.pgc index 36afd97..86856c8 100644 --- a/app/src/mg/svc/MG_NACK.pgc +++ b/app/src/mg/svc/MG_NACK.pgc @@ -19,11 +19,12 @@ void MG_NACK(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_NACK(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_NACK 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_NACK 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_NACK", "S", gw_bizdate) < 0) { + userlog("MG_NACK 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -164,5 +186,61 @@ void MG_NACK(TPSVCINFO *p) sprintf(rc, "%02ld", rcnum % 100); if (mgdb_update_msg_rc(msg_id, rc, "N") < 0) FAIL(b); sets_(b, T_STATUS, "N"); + + /* ---- 업무 체인: MG_NACK -> MG_SEND (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_status[256]; gets_(b, T_STATUS, ch_o_status, sizeof(ch_o_status)); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0810"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_NACK] tpcall(MG_SEND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7229); + Bchg(b, T_MSG, 0, "NACK 응답 송신 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_NACK] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STATUS, 0, ch_o_status, 0L); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_NACK] 체인 대상 컨텍스트 없음 - MG_SEND 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_NETMGMT.pgc b/app/src/mg/svc/MG_NETMGMT.pgc index 78e60fe..88d05ed 100644 --- a/app/src/mg/svc/MG_NETMGMT.pgc +++ b/app/src/mg/svc/MG_NETMGMT.pgc @@ -20,11 +20,12 @@ void MG_NETMGMT(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_NETMGMT(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_NETMGMT 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_NETMGMT 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_NETMGMT", "S", gw_bizdate) < 0) { + userlog("MG_NETMGMT 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_PACK.pgc b/app/src/mg/svc/MG_PACK.pgc index f1c3021..46aee40 100644 --- a/app/src/mg/svc/MG_PACK.pgc +++ b/app/src/mg/svc/MG_PACK.pgc @@ -19,11 +19,12 @@ void MG_PACK(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_PACK(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_PACK 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_PACK 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_PACK", "S", gw_bizdate) < 0) { + userlog("MG_PACK 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -166,5 +188,63 @@ void MG_PACK(TPSVCINFO *p) sprintf(raw, "%.4s%.6s%012ld", mti, proc, amount); sets_(b, T_STR3, raw); setl(b, T_COUNT, (long)strlen(raw)); + + /* ---- 업무 체인: MG_PACK -> MG_SEND (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str3[256]; gets_(b, T_STR3, ch_o_str3, sizeof(ch_o_str3)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0210"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_PACK] tpcall(MG_SEND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7225); + Bchg(b, T_MSG, 0, "전문 팩 후 송신 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_PACK] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR3, 0, ch_o_str3, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_PACK] 체인 대상 컨텍스트 없음 - MG_SEND 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_PANMASK.pgc b/app/src/mg/svc/MG_PANMASK.pgc index bae1b08..60bb768 100644 --- a/app/src/mg/svc/MG_PANMASK.pgc +++ b/app/src/mg/svc/MG_PANMASK.pgc @@ -38,11 +38,12 @@ void MG_PANMASK(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -121,19 +122,40 @@ void MG_PANMASK(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_PANMASK 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_PANMASK 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_PANMASK", "S", gw_bizdate) < 0) { + userlog("MG_PANMASK 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_PARSE.pgc b/app/src/mg/svc/MG_PARSE.pgc index d1d5974..6306d53 100644 --- a/app/src/mg/svc/MG_PARSE.pgc +++ b/app/src/mg/svc/MG_PARSE.pgc @@ -19,11 +19,12 @@ void MG_PARSE(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_PARSE(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_PARSE 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_PARSE 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_PARSE", "S", gw_bizdate) < 0) { + userlog("MG_PARSE 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -168,5 +190,67 @@ void MG_PARSE(TPSVCINFO *p) sets_(b, T_STR1, mti); sets_(b, T_STR4, proc); setl(b, T_COUNT, n); + + /* ---- 업무 체인: MG_PARSE -> AUTH (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_key1[256]; gets_(b, T_KEY1, ch_o_key1, sizeof(ch_o_key1)); + char ch_o_merchant[256]; gets_(b, T_MERCHANT, ch_o_merchant, sizeof(ch_o_merchant)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str4[256]; gets_(b, T_STR4, ch_o_str4, sizeof(ch_o_str4)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_cd[24]; gets_(b, T_KEY1, ch_cd, sizeof(ch_cd)); + if (ch_cd[0] == 0) sets_(b, T_KEY1, "0000000000000000"); } + { char ch_mc[64]; gets_(b, T_MERCHANT, ch_mc, sizeof(ch_mc)); + if (ch_mc[0] == 0) sets_(b, T_MERCHANT, "M0001"); } + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("AUTH", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_PARSE] tpcall(AUTH) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7201); + Bchg(b, T_MSG, 0, "전문 파싱 후 승인전달 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + { char ch_st[16]; gets_(b, T_STATUS, ch_st, sizeof(ch_st)); + userlog("[MG_PARSE] 승인 연동 완료 상태=%s", ch_st); } + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_KEY1, 0, ch_o_key1, 0L); + Bchg(b, T_MERCHANT, 0, ch_o_merchant, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR4, 0, ch_o_str4, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_PARSE] 체인 대상 컨텍스트 없음 - AUTH 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_QDEPTH.pgc b/app/src/mg/svc/MG_QDEPTH.pgc index d04f392..a473161 100644 --- a/app/src/mg/svc/MG_QDEPTH.pgc +++ b/app/src/mg/svc/MG_QDEPTH.pgc @@ -20,11 +20,12 @@ void MG_QDEPTH(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_QDEPTH(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_QDEPTH 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_QDEPTH 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_QDEPTH", "S", gw_bizdate) < 0) { + userlog("MG_QDEPTH 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_QUEUE.pgc b/app/src/mg/svc/MG_QUEUE.pgc index fd865a1..66a4bf1 100644 --- a/app/src/mg/svc/MG_QUEUE.pgc +++ b/app/src/mg/svc/MG_QUEUE.pgc @@ -19,11 +19,12 @@ void MG_QUEUE(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_QUEUE(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_QUEUE 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_QUEUE 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_QUEUE", "S", gw_bizdate) < 0) { + userlog("MG_QUEUE 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_RATELIMIT.pgc b/app/src/mg/svc/MG_RATELIMIT.pgc index bfbaf9e..03ab871 100644 --- a/app/src/mg/svc/MG_RATELIMIT.pgc +++ b/app/src/mg/svc/MG_RATELIMIT.pgc @@ -19,11 +19,12 @@ void MG_RATELIMIT(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_RATELIMIT(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_RATELIMIT 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_RATELIMIT 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_RATELIMIT", "S", gw_bizdate) < 0) { + userlog("MG_RATELIMIT 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_READYZ.pgc b/app/src/mg/svc/MG_READYZ.pgc index 6c566cd..5cbd4f6 100644 --- a/app/src/mg/svc/MG_READYZ.pgc +++ b/app/src/mg/svc/MG_READYZ.pgc @@ -19,11 +19,12 @@ void MG_READYZ(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_READYZ(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_READYZ 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_READYZ 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_READYZ", "S", gw_bizdate) < 0) { + userlog("MG_READYZ 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_REASM.pgc b/app/src/mg/svc/MG_REASM.pgc index dd1b8d2..ee00433 100644 --- a/app/src/mg/svc/MG_REASM.pgc +++ b/app/src/mg/svc/MG_REASM.pgc @@ -20,11 +20,12 @@ void MG_REASM(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_REASM(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_REASM 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_REASM 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_REASM", "S", gw_bizdate) < 0) { + userlog("MG_REASM 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -185,5 +207,65 @@ void MG_REASM(TPSVCINFO *p) setl(b, T_COUNT, got); setl(b, T_ARG2, total); setl(b, T_RC, 0); + + /* ---- 업무 체인: MG_REASM -> MG_PARSE (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg2 = getl(b, T_ARG2); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str3[256]; gets_(b, T_STR3, ch_o_str3, sizeof(ch_o_str3)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0200"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_PARSE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_REASM] tpcall(MG_PARSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7218); + Bchg(b, T_MSG, 0, "분할전문 재조립 파싱 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_REASM] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG2, ch_o_arg2); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR3, 0, ch_o_str3, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_REASM] 체인 대상 컨텍스트 없음 - MG_PARSE 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_RECV.pgc b/app/src/mg/svc/MG_RECV.pgc index 66d4f3f..3ebe4bb 100644 --- a/app/src/mg/svc/MG_RECV.pgc +++ b/app/src/mg/svc/MG_RECV.pgc @@ -19,11 +19,12 @@ void MG_RECV(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_RECV(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_RECV 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_RECV 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_RECV", "S", gw_bizdate) < 0) { + userlog("MG_RECV 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -176,5 +198,63 @@ void MG_RECV(TPSVCINFO *p) setl(b, T_ARG1, stan); setl(b, T_ID1, msg_id); userlog("MG_RECV 수신 stan=%ld msg_id=%ld chan=%s mti=%s amt=%ld", stan, msg_id, chan, mti, amount); + + /* ---- 업무 체인: MG_RECV -> MG_PARSE (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg1 = getl(b, T_ARG1); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + long ch_o_id1 = getl(b, T_ID1); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0200"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_PARSE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_RECV] tpcall(MG_PARSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7211); + Bchg(b, T_MSG, 0, "수신전문 파싱 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_RECV] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG1, ch_o_arg1); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + setl(b, T_ID1, ch_o_id1); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_RECV] 체인 대상 컨텍스트 없음 - MG_PARSE 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_RESEND.pgc b/app/src/mg/svc/MG_RESEND.pgc index c0ec8eb..1d9b498 100644 --- a/app/src/mg/svc/MG_RESEND.pgc +++ b/app/src/mg/svc/MG_RESEND.pgc @@ -19,11 +19,12 @@ void MG_RESEND(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_RESEND(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_RESEND 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_RESEND 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_RESEND", "S", gw_bizdate) < 0) { + userlog("MG_RESEND 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -174,5 +196,61 @@ void MG_RESEND(TPSVCINFO *p) if (mgdb_enqueue(qid, stan, chan, mti, raw, bizdate) < 0) FAIL(b); setl(b, T_ID2, qid); userlog("MG_RESEND 재전송 큐적재 stan=%ld qid=%ld", stan, qid); + + /* ---- 업무 체인: MG_RESEND -> MG_SEND (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + long ch_o_id2 = getl(b, T_ID2); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0200"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_RESEND] tpcall(MG_SEND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7223); + Bchg(b, T_MSG, 0, "전문 재전송 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_RESEND] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + setl(b, T_ID2, ch_o_id2); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_RESEND] 체인 대상 컨텍스트 없음 - MG_SEND 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_RESNDONE.pgc b/app/src/mg/svc/MG_RESNDONE.pgc index 12ea3a4..2d8df13 100644 --- a/app/src/mg/svc/MG_RESNDONE.pgc +++ b/app/src/mg/svc/MG_RESNDONE.pgc @@ -19,11 +19,12 @@ void MG_RESNDONE(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_RESNDONE(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_RESNDONE 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_RESNDONE 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_RESNDONE", "S", gw_bizdate) < 0) { + userlog("MG_RESNDONE 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -177,5 +199,61 @@ void MG_RESNDONE(TPSVCINFO *p) if (h_retry > limit) late = 1; setl(b, T_COUNT, h_retry); setl(b, T_RC, late ? 1 : 0); + + /* ---- 업무 체인: MG_RESNDONE -> MG_SEND (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0200"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_RESNDONE] tpcall(MG_SEND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7224); + Bchg(b, T_MSG, 0, "단건 재전송 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_RESNDONE] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_RESNDONE] 체인 대상 컨텍스트 없음 - MG_SEND 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_RETRY.pgc b/app/src/mg/svc/MG_RETRY.pgc index 8aec058..dcbcd4b 100644 --- a/app/src/mg/svc/MG_RETRY.pgc +++ b/app/src/mg/svc/MG_RETRY.pgc @@ -19,11 +19,12 @@ void MG_RETRY(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_RETRY(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_RETRY 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_RETRY 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_RETRY", "S", gw_bizdate) < 0) { + userlog("MG_RETRY 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_REVADVICE.pgc b/app/src/mg/svc/MG_REVADVICE.pgc index 950a768..a04b403 100644 --- a/app/src/mg/svc/MG_REVADVICE.pgc +++ b/app/src/mg/svc/MG_REVADVICE.pgc @@ -20,11 +20,12 @@ void MG_REVADVICE(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_REVADVICE(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_REVADVICE 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_REVADVICE 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_REVADVICE", "S", gw_bizdate) < 0) { + userlog("MG_REVADVICE 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -162,7 +184,7 @@ void MG_REVADVICE(TPSVCINFO *p) char chan[16], bizdate[16], raw[512]; long stan, msg_id, amount; EXEC SQL BEGIN DECLARE SECTION; - long h_stan; + long h_stan, h_chanlast; char h_chan[16]; EXEC SQL END DECLARE SECTION; @@ -179,10 +201,18 @@ void MG_REVADVICE(TPSVCINFO *p) h_stan = stan; strncpy(h_chan, chan, sizeof(h_chan)-1); h_chan[sizeof(h_chan)-1] = 0; - EXEC SQL UPDATE mg_channel - SET last_stan = greatest(last_stan, :h_stan), updated_at = now() - WHERE channel = :h_chan; - if (sqlca.sqlcode < 0) { userlog("MG_REVADVICE 순번동기 FAIL [%d]", sqlca.sqlcode); FAIL(b); } + /* 순번 동기: 채널행은 소유자 서비스만 UPDATE 한다. MG_REVADVICE 는 + * 비소유자이므로 채널 기록순번을 SELECT 로 대조만 하고, 실제 STAN 권위는 + * mg_stan_seq 채번값이다. 역전 시에는 이력에만 남기고 진행한다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :h_chanlast + FROM mg_channel WHERE channel = :h_chan; + if (sqlca.sqlcode == 100) h_chanlast = 0; + else if (sqlca.sqlcode < 0) { userlog("MG_REVADVICE 순번조회 FAIL [%d]", sqlca.sqlcode); FAIL(b); } + if (h_stan <= h_chanlast) { + userlog("MG_REVADVICE 순번역전 chan=%s stan=%ld chan_last=%ld", + chan, h_stan, h_chanlast); + } + setl(b, T_ARG4, h_chanlast); setl(b, T_ID1, msg_id); setl(b, T_ARG1, stan); diff --git a/app/src/mg/svc/MG_REVERSAL.pgc b/app/src/mg/svc/MG_REVERSAL.pgc index 896f5c8..2ce6f09 100644 --- a/app/src/mg/svc/MG_REVERSAL.pgc +++ b/app/src/mg/svc/MG_REVERSAL.pgc @@ -20,11 +20,12 @@ void MG_REVERSAL(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_REVERSAL(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_REVERSAL 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_REVERSAL 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_REVERSAL", "S", gw_bizdate) < 0) { + userlog("MG_REVERSAL 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_ROUTE.pgc b/app/src/mg/svc/MG_ROUTE.pgc index 09688bd..e4cf2a2 100644 --- a/app/src/mg/svc/MG_ROUTE.pgc +++ b/app/src/mg/svc/MG_ROUTE.pgc @@ -19,11 +19,12 @@ void MG_ROUTE(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_ROUTE(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_ROUTE 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_ROUTE 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_ROUTE", "S", gw_bizdate) < 0) { + userlog("MG_ROUTE 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -168,5 +190,61 @@ void MG_ROUTE(TPSVCINFO *p) } sets_(b, T_STR3, dest); setl(b, T_RC, 0); + + /* ---- 업무 체인: MG_ROUTE -> MG_CHANSTAT (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str3[256]; gets_(b, T_STR3, ch_o_str3, sizeof(ch_o_str3)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0800"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_CHANSTAT", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_ROUTE] tpcall(MG_CHANSTAT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7203); + Bchg(b, T_MSG, 0, "라우팅 채널상태 확인 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_ROUTE] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR3, 0, ch_o_str3, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_ROUTE] 체인 대상 컨텍스트 없음 - MG_CHANSTAT 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_RTADD.pgc b/app/src/mg/svc/MG_RTADD.pgc index 48e11bf..adc7933 100644 --- a/app/src/mg/svc/MG_RTADD.pgc +++ b/app/src/mg/svc/MG_RTADD.pgc @@ -20,11 +20,12 @@ void MG_RTADD(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_RTADD(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_RTADD 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_RTADD 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_RTADD", "S", gw_bizdate) < 0) { + userlog("MG_RTADD 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_RTCOUNT.pgc b/app/src/mg/svc/MG_RTCOUNT.pgc index 2590ce5..d2f7595 100644 --- a/app/src/mg/svc/MG_RTCOUNT.pgc +++ b/app/src/mg/svc/MG_RTCOUNT.pgc @@ -19,11 +19,12 @@ void MG_RTCOUNT(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_RTCOUNT(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_RTCOUNT 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_RTCOUNT 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_RTCOUNT", "S", gw_bizdate) < 0) { + userlog("MG_RTCOUNT 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_RTDISABLE.pgc b/app/src/mg/svc/MG_RTDISABLE.pgc index 3e7d4a7..8cb30d4 100644 --- a/app/src/mg/svc/MG_RTDISABLE.pgc +++ b/app/src/mg/svc/MG_RTDISABLE.pgc @@ -19,11 +19,12 @@ void MG_RTDISABLE(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_RTDISABLE(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_RTDISABLE 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_RTDISABLE 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_RTDISABLE", "S", gw_bizdate) < 0) { + userlog("MG_RTDISABLE 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_RTDROP.pgc b/app/src/mg/svc/MG_RTDROP.pgc index 6547972..1182956 100644 --- a/app/src/mg/svc/MG_RTDROP.pgc +++ b/app/src/mg/svc/MG_RTDROP.pgc @@ -20,11 +20,12 @@ void MG_RTDROP(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_RTDROP(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_RTDROP 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_RTDROP 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_RTDROP", "S", gw_bizdate) < 0) { + userlog("MG_RTDROP 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_RTENABLE.pgc b/app/src/mg/svc/MG_RTENABLE.pgc index 74edd35..afef082 100644 --- a/app/src/mg/svc/MG_RTENABLE.pgc +++ b/app/src/mg/svc/MG_RTENABLE.pgc @@ -19,11 +19,12 @@ void MG_RTENABLE(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_RTENABLE(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_RTENABLE 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_RTENABLE 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_RTENABLE", "S", gw_bizdate) < 0) { + userlog("MG_RTENABLE 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_RTFIND.pgc b/app/src/mg/svc/MG_RTFIND.pgc index 24109a4..1efdb2c 100644 --- a/app/src/mg/svc/MG_RTFIND.pgc +++ b/app/src/mg/svc/MG_RTFIND.pgc @@ -19,11 +19,12 @@ void MG_RTFIND(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_RTFIND(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_RTFIND 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_RTFIND 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_RTFIND", "S", gw_bizdate) < 0) { + userlog("MG_RTFIND 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_RTLIST.pgc b/app/src/mg/svc/MG_RTLIST.pgc index a40c392..7516d10 100644 --- a/app/src/mg/svc/MG_RTLIST.pgc +++ b/app/src/mg/svc/MG_RTLIST.pgc @@ -20,11 +20,12 @@ void MG_RTLIST(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_RTLIST(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_RTLIST 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_RTLIST 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_RTLIST", "S", gw_bizdate) < 0) { + userlog("MG_RTLIST 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_RTSWITCH.pgc b/app/src/mg/svc/MG_RTSWITCH.pgc index 11ce1f2..da07740 100644 --- a/app/src/mg/svc/MG_RTSWITCH.pgc +++ b/app/src/mg/svc/MG_RTSWITCH.pgc @@ -20,11 +20,12 @@ void MG_RTSWITCH(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_RTSWITCH(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_RTSWITCH 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_RTSWITCH 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_RTSWITCH", "S", gw_bizdate) < 0) { + userlog("MG_RTSWITCH 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_SEND.pgc b/app/src/mg/svc/MG_SEND.pgc index efe79b5..74f92c1 100644 --- a/app/src/mg/svc/MG_SEND.pgc +++ b/app/src/mg/svc/MG_SEND.pgc @@ -19,11 +19,12 @@ void MG_SEND(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_SEND(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_SEND 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_SEND 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_SEND", "S", gw_bizdate) < 0) { + userlog("MG_SEND 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -173,5 +195,63 @@ void MG_SEND(TPSVCINFO *p) "", "00", raw, "S", bizdate) < 0) FAIL(b); setl(b, T_ARG1, stan); setl(b, T_ID1, msg_id); + + /* ---- 업무 체인: MG_SEND -> MG_STAN (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg1 = getl(b, T_ARG1); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + long ch_o_id1 = getl(b, T_ID1); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0200"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_STAN", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_SEND] tpcall(MG_STAN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7202); + Bchg(b, T_MSG, 0, "송신 STAN 채번 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_SEND] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG1, ch_o_arg1); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + setl(b, T_ID1, ch_o_id1); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_SEND] 체인 대상 컨텍스트 없음 - MG_STAN 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_SEQAUDIT.pgc b/app/src/mg/svc/MG_SEQAUDIT.pgc index ec93871..2b5479e 100644 --- a/app/src/mg/svc/MG_SEQAUDIT.pgc +++ b/app/src/mg/svc/MG_SEQAUDIT.pgc @@ -20,11 +20,12 @@ void MG_SEQAUDIT(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_SEQAUDIT(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_SEQAUDIT 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_SEQAUDIT 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_SEQAUDIT", "S", gw_bizdate) < 0) { + userlog("MG_SEQAUDIT 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_SEQFILL.pgc b/app/src/mg/svc/MG_SEQFILL.pgc index c66f265..d036dd1 100644 --- a/app/src/mg/svc/MG_SEQFILL.pgc +++ b/app/src/mg/svc/MG_SEQFILL.pgc @@ -19,11 +19,12 @@ void MG_SEQFILL(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_SEQFILL(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_SEQFILL 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_SEQFILL 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_SEQFILL", "S", gw_bizdate) < 0) { + userlog("MG_SEQFILL 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -162,7 +184,7 @@ void MG_SEQFILL(TPSVCINFO *p) long recv, s, filled = 0, msg_id; EXEC SQL BEGIN DECLARE SECTION; char h_chan[16]; - long h_last, h_new; + long h_last, h_new, h_seqset; EXEC SQL END DECLARE SECTION; gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01"); @@ -184,12 +206,76 @@ void MG_SEQFILL(TPSVCINFO *p) if (recv > h_last) { h_new = recv; - EXEC SQL UPDATE mg_channel SET last_stan = :h_new, updated_at = now() - WHERE channel = :h_chan; + /* 결번을 메운 뒤 순번 수위를 올린다. 채널행(mg_channel)은 생애주기 + * 소유자만 UPDATE 하므로, STAN 권위인 mg_stan_seq 를 앞으로만 당긴다. + * setval 은 행락을 잡지 않아 형제 XA 브랜치와 교착하지 않는다. */ + EXEC SQL SELECT last_value INTO :h_seqset FROM mg_stan_seq; if (sqlca.sqlcode < 0) FAIL(b); + if (h_new > h_seqset) { + EXEC SQL SELECT setval('mg_stan_seq', :h_new) INTO :h_seqset; + if (sqlca.sqlcode < 0) FAIL(b); + } + userlog("MG_SEQFILL 순번수위 chan=%s %ld -> %ld (seq=%ld, filled=%ld)", + chan, h_last, h_new, h_seqset, filled); } setl(b, T_COUNT, filled); setl(b, T_RC, (filled > 0) ? 1 : 0); + + /* ---- 업무 체인: MG_SEQFILL -> MG_STAN (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0200"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_STAN", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_SEQFILL] tpcall(MG_STAN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7244); + Bchg(b, T_MSG, 0, "일련번호 결번보충 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_SEQFILL] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_SEQFILL] 체인 대상 컨텍스트 없음 - MG_STAN 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_SEQNEXT.pgc b/app/src/mg/svc/MG_SEQNEXT.pgc index 758949e..d1dd118 100644 --- a/app/src/mg/svc/MG_SEQNEXT.pgc +++ b/app/src/mg/svc/MG_SEQNEXT.pgc @@ -19,11 +19,12 @@ void MG_SEQNEXT(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_SEQNEXT(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_SEQNEXT 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_SEQNEXT 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_SEQNEXT", "S", gw_bizdate) < 0) { + userlog("MG_SEQNEXT 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -177,5 +199,61 @@ void MG_SEQNEXT(TPSVCINFO *p) setl(b, T_ARG2, expect); /* 기대순번 */ setl(b, T_ARG6, gap); /* 갭폭 (0=정상) */ setl(b, T_RC, (recv > 0 && gap != 0) ? 1 : 0); + + /* ---- 업무 체인: MG_SEQNEXT -> MG_STAN (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg2 = getl(b, T_ARG2); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0200"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_STAN", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_SEQNEXT] tpcall(MG_STAN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7243); + Bchg(b, T_MSG, 0, "전문일련번호 채번 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_SEQNEXT] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG2, ch_o_arg2); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_SEQNEXT] 체인 대상 컨텍스트 없음 - MG_STAN 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_SEQRESET.pgc b/app/src/mg/svc/MG_SEQRESET.pgc index 8a54ec5..406ecc5 100644 --- a/app/src/mg/svc/MG_SEQRESET.pgc +++ b/app/src/mg/svc/MG_SEQRESET.pgc @@ -19,11 +19,12 @@ void MG_SEQRESET(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_SEQRESET(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_SEQRESET 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_SEQRESET 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_SEQRESET", "S", gw_bizdate) < 0) { + userlog("MG_SEQRESET 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -158,10 +180,11 @@ void MG_SEQRESET(TPSVCINFO *p) userlog("MG_SEQRESET 심화완료 chan=%s daysum=%ld fee=%ld score=%ld aff=%ld", gw_chan, gw_daysum, gw_fee, gw_score, gw_aff); } - long newval; + long newval, rs_msgid; + char rs_bizdate[16], rs_raw[128]; EXEC SQL BEGIN DECLARE SECTION; char h_chan[16]; - long h_old, h_new; + long h_old, h_new, h_seqset; EXEC SQL END DECLARE SECTION; gets_(b, T_CHANNEL, h_chan, sizeof(h_chan)); if (h_chan[0] == 0) strcpy(h_chan, "CH01"); @@ -172,11 +195,25 @@ void MG_SEQRESET(TPSVCINFO *p) if (sqlca.sqlcode == 100) { setl(b, T_RC, 25); FAIL(b); } if (sqlca.sqlcode < 0) FAIL(b); - EXEC SQL UPDATE mg_channel SET last_stan = :h_new, updated_at = now() - WHERE channel = :h_chan; + /* STAN 권위는 채널행(mg_channel.last_stan)이 아니라 mg_stan_seq 시퀀스다. + * 채널행은 소유자 서비스만 UPDATE 하므로, 순번 리셋은 시퀀스 setval 로 + * 수행한다. setval 은 행락을 잡지 않아 형제 XA 브랜치와 교착하지 않는다. */ + EXEC SQL SELECT setval('mg_stan_seq', GREATEST(:h_new, 1)) INTO :h_seqset; if (sqlca.sqlcode < 0) FAIL(b); - userlog("MG_SEQRESET 채널=%s 순번 %ld -> %ld", h_chan, h_old, h_new); + /* 리셋 사실을 자기 이력(mg_msg_log)에 0800 관리전문으로 남긴다. */ + gets_(b, T_BIZDATE, rs_bizdate, sizeof(rs_bizdate)); + if (rs_bizdate[0] == 0) strcpy(rs_bizdate, "2026-07-19"); + snprintf(rs_raw, sizeof(rs_raw), "GW-SEQRESET chan=%s %ld->%ld", h_chan, h_old, h_new); + rs_msgid = mgdb_next_msg_id(); + if (rs_msgid > 0) { + if (mgdb_insert_msg(rs_msgid, h_seqset, "0800", h_chan, "OUT", + "302000", "", 0, "", "00", rs_raw, "C", rs_bizdate) < 0) { + userlog("MG_SEQRESET 리셋이력 적재경고 chan=%s", h_chan); + } + } + + userlog("MG_SEQRESET 채널=%s 순번 %ld -> %ld (seq=%ld)", h_chan, h_old, h_new, h_seqset); setl(b, T_ARG2, h_old); /* 리셋 전 순번 */ setl(b, T_ARG3, h_new); setl(b, T_RC, 0); diff --git a/app/src/mg/svc/MG_SESSION.pgc b/app/src/mg/svc/MG_SESSION.pgc index 6500a8a..4544e30 100644 --- a/app/src/mg/svc/MG_SESSION.pgc +++ b/app/src/mg/svc/MG_SESSION.pgc @@ -19,11 +19,12 @@ void MG_SESSION(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_SESSION(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_SESSION 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_SESSION 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_SESSION", "S", gw_bizdate) < 0) { + userlog("MG_SESSION 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_SETTLEREQ.pgc b/app/src/mg/svc/MG_SETTLEREQ.pgc index 9497046..5f45a26 100644 --- a/app/src/mg/svc/MG_SETTLEREQ.pgc +++ b/app/src/mg/svc/MG_SETTLEREQ.pgc @@ -20,11 +20,12 @@ void MG_SETTLEREQ(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_SETTLEREQ(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_SETTLEREQ 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_SETTLEREQ 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_SETTLEREQ", "S", gw_bizdate) < 0) { + userlog("MG_SETTLEREQ 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_SETTLERSP.pgc b/app/src/mg/svc/MG_SETTLERSP.pgc index 9043a42..623d67b 100644 --- a/app/src/mg/svc/MG_SETTLERSP.pgc +++ b/app/src/mg/svc/MG_SETTLERSP.pgc @@ -20,11 +20,12 @@ void MG_SETTLERSP(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_SETTLERSP(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_SETTLERSP 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_SETTLERSP 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_SETTLERSP", "S", gw_bizdate) < 0) { + userlog("MG_SETTLERSP 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_STALEMARK.pgc b/app/src/mg/svc/MG_STALEMARK.pgc index 376aebf..19ae849 100644 --- a/app/src/mg/svc/MG_STALEMARK.pgc +++ b/app/src/mg/svc/MG_STALEMARK.pgc @@ -19,11 +19,12 @@ void MG_STALEMARK(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_STALEMARK(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_STALEMARK 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_STALEMARK 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_STALEMARK", "S", gw_bizdate) < 0) { + userlog("MG_STALEMARK 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_STAN.pgc b/app/src/mg/svc/MG_STAN.pgc index d5e80e8..68edff0 100644 --- a/app/src/mg/svc/MG_STAN.pgc +++ b/app/src/mg/svc/MG_STAN.pgc @@ -19,11 +19,12 @@ void MG_STAN(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_STAN(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_STAN 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_STAN 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_STAN", "S", gw_bizdate) < 0) { + userlog("MG_STAN 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_STATAMT.pgc b/app/src/mg/svc/MG_STATAMT.pgc index fcf26f4..2a1b739 100644 --- a/app/src/mg/svc/MG_STATAMT.pgc +++ b/app/src/mg/svc/MG_STATAMT.pgc @@ -19,11 +19,12 @@ void MG_STATAMT(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_STATAMT(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_STATAMT 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_STATAMT 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_STATAMT", "S", gw_bizdate) < 0) { + userlog("MG_STATAMT 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_STATCHAN.pgc b/app/src/mg/svc/MG_STATCHAN.pgc index e582e6a..f49d487 100644 --- a/app/src/mg/svc/MG_STATCHAN.pgc +++ b/app/src/mg/svc/MG_STATCHAN.pgc @@ -19,11 +19,12 @@ void MG_STATCHAN(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_STATCHAN(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_STATCHAN 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_STATCHAN 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_STATCHAN", "S", gw_bizdate) < 0) { + userlog("MG_STATCHAN 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_STATDIR.pgc b/app/src/mg/svc/MG_STATDIR.pgc index a2920ab..60cf3f5 100644 --- a/app/src/mg/svc/MG_STATDIR.pgc +++ b/app/src/mg/svc/MG_STATDIR.pgc @@ -20,11 +20,12 @@ void MG_STATDIR(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_STATDIR(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_STATDIR 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_STATDIR 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_STATDIR", "S", gw_bizdate) < 0) { + userlog("MG_STATDIR 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_STATERR.pgc b/app/src/mg/svc/MG_STATERR.pgc index 6c79384..5c45923 100644 --- a/app/src/mg/svc/MG_STATERR.pgc +++ b/app/src/mg/svc/MG_STATERR.pgc @@ -19,11 +19,12 @@ void MG_STATERR(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_STATERR(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_STATERR 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_STATERR 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_STATERR", "S", gw_bizdate) < 0) { + userlog("MG_STATERR 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_STATHOUR.pgc b/app/src/mg/svc/MG_STATHOUR.pgc index 25379c7..82bdb95 100644 --- a/app/src/mg/svc/MG_STATHOUR.pgc +++ b/app/src/mg/svc/MG_STATHOUR.pgc @@ -20,11 +20,12 @@ void MG_STATHOUR(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_STATHOUR(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_STATHOUR 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_STATHOUR 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_STATHOUR", "S", gw_bizdate) < 0) { + userlog("MG_STATHOUR 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_STATMTI.pgc b/app/src/mg/svc/MG_STATMTI.pgc index 3785b98..28fbca8 100644 --- a/app/src/mg/svc/MG_STATMTI.pgc +++ b/app/src/mg/svc/MG_STATMTI.pgc @@ -20,11 +20,12 @@ void MG_STATMTI(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_STATMTI(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_STATMTI 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_STATMTI 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_STATMTI", "S", gw_bizdate) < 0) { + userlog("MG_STATMTI 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_STATPEAK.pgc b/app/src/mg/svc/MG_STATPEAK.pgc index c09eaa5..3ef0649 100644 --- a/app/src/mg/svc/MG_STATPEAK.pgc +++ b/app/src/mg/svc/MG_STATPEAK.pgc @@ -19,11 +19,12 @@ void MG_STATPEAK(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_STATPEAK(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_STATPEAK 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_STATPEAK 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_STATPEAK", "S", gw_bizdate) < 0) { + userlog("MG_STATPEAK 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_STATRC.pgc b/app/src/mg/svc/MG_STATRC.pgc index 95d5a1f..42ddc59 100644 --- a/app/src/mg/svc/MG_STATRC.pgc +++ b/app/src/mg/svc/MG_STATRC.pgc @@ -20,11 +20,12 @@ void MG_STATRC(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_STATRC(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_STATRC 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_STATRC 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_STATRC", "S", gw_bizdate) < 0) { + userlog("MG_STATRC 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_STATS.pgc b/app/src/mg/svc/MG_STATS.pgc index ff96589..9081b90 100644 --- a/app/src/mg/svc/MG_STATS.pgc +++ b/app/src/mg/svc/MG_STATS.pgc @@ -19,11 +19,12 @@ void MG_STATS(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_STATS(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_STATS 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_STATS 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_STATS", "S", gw_bizdate) < 0) { + userlog("MG_STATS 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_STATSUM.pgc b/app/src/mg/svc/MG_STATSUM.pgc index 16235f8..6c6388f 100644 --- a/app/src/mg/svc/MG_STATSUM.pgc +++ b/app/src/mg/svc/MG_STATSUM.pgc @@ -19,11 +19,12 @@ void MG_STATSUM(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_STATSUM(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_STATSUM 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_STATSUM 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_STATSUM", "S", gw_bizdate) < 0) { + userlog("MG_STATSUM 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_STATUS.pgc b/app/src/mg/svc/MG_STATUS.pgc index 65dbce8..578354e 100644 --- a/app/src/mg/svc/MG_STATUS.pgc +++ b/app/src/mg/svc/MG_STATUS.pgc @@ -19,11 +19,12 @@ void MG_STATUS(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_STATUS(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_STATUS 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_STATUS 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_STATUS", "S", gw_bizdate) < 0) { + userlog("MG_STATUS 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_THROTTLE.pgc b/app/src/mg/svc/MG_THROTTLE.pgc index cedf958..d8464e6 100644 --- a/app/src/mg/svc/MG_THROTTLE.pgc +++ b/app/src/mg/svc/MG_THROTTLE.pgc @@ -20,11 +20,12 @@ void MG_THROTTLE(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_THROTTLE(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_THROTTLE 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_THROTTLE 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_THROTTLE", "S", gw_bizdate) < 0) { + userlog("MG_THROTTLE 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_TIMEOUT.pgc b/app/src/mg/svc/MG_TIMEOUT.pgc index abb0ee3..62b8891 100644 --- a/app/src/mg/svc/MG_TIMEOUT.pgc +++ b/app/src/mg/svc/MG_TIMEOUT.pgc @@ -20,11 +20,12 @@ void MG_TIMEOUT(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_TIMEOUT(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_TIMEOUT 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_TIMEOUT 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_TIMEOUT", "S", gw_bizdate) < 0) { + userlog("MG_TIMEOUT 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_TIMEOUTSET.pgc b/app/src/mg/svc/MG_TIMEOUTSET.pgc index b8d8fd5..bc086aa 100644 --- a/app/src/mg/svc/MG_TIMEOUTSET.pgc +++ b/app/src/mg/svc/MG_TIMEOUTSET.pgc @@ -20,11 +20,12 @@ void MG_TIMEOUTSET(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_TIMEOUTSET(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_TIMEOUTSET 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_TIMEOUTSET 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_TIMEOUTSET", "S", gw_bizdate) < 0) { + userlog("MG_TIMEOUTSET 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_TOISO.pgc b/app/src/mg/svc/MG_TOISO.pgc index dfe7f00..a36f33d 100644 --- a/app/src/mg/svc/MG_TOISO.pgc +++ b/app/src/mg/svc/MG_TOISO.pgc @@ -20,11 +20,12 @@ void MG_TOISO(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_TOISO(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_TOISO 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_TOISO 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_TOISO", "S", gw_bizdate) < 0) { + userlog("MG_TOISO 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -189,5 +211,63 @@ void MG_TOISO(TPSVCINFO *p) sets_(b, T_STR1, mti); setl(b, T_AMOUNT, amount); setl(b, T_RC, 0); + + /* ---- 업무 체인: MG_TOISO -> MG_SEND (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str3[256]; gets_(b, T_STR3, ch_o_str3, sizeof(ch_o_str3)); + char ch_o_str6[256]; gets_(b, T_STR6, ch_o_str6, sizeof(ch_o_str6)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0210"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_TOISO] tpcall(MG_SEND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7226); + Bchg(b, T_MSG, 0, "ISO 변환 후 송신 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_TOISO] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR3, 0, ch_o_str3, 0L); + Bchg(b, T_STR6, 0, ch_o_str6, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_TOISO] 체인 대상 컨텍스트 없음 - MG_SEND 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_TPSCHECK.pgc b/app/src/mg/svc/MG_TPSCHECK.pgc index 15bb5cf..4a13cff 100644 --- a/app/src/mg/svc/MG_TPSCHECK.pgc +++ b/app/src/mg/svc/MG_TPSCHECK.pgc @@ -20,11 +20,12 @@ void MG_TPSCHECK(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_TPSCHECK(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_TPSCHECK 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_TPSCHECK 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_TPSCHECK", "S", gw_bizdate) < 0) { + userlog("MG_TPSCHECK 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_UNPACK.pgc b/app/src/mg/svc/MG_UNPACK.pgc index 94e7d00..a37faa6 100644 --- a/app/src/mg/svc/MG_UNPACK.pgc +++ b/app/src/mg/svc/MG_UNPACK.pgc @@ -19,11 +19,12 @@ void MG_UNPACK(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -102,19 +103,40 @@ void MG_UNPACK(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_UNPACK 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_UNPACK 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_UNPACK", "S", gw_bizdate) < 0) { + userlog("MG_UNPACK 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); @@ -169,5 +191,61 @@ void MG_UNPACK(TPSVCINFO *p) sets_(b, T_STR1, mti); sets_(b, T_STR4, proc); setl(b, T_AMOUNT, amount); + + /* ---- 업무 체인: MG_UNPACK -> MG_PARSE (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt2 = getl(b, T_AMT2); + long ch_o_amt3 = getl(b, T_AMT3); + long ch_o_arg6 = getl(b, T_ARG6); + long ch_o_arg7 = getl(b, T_ARG7); + long ch_o_arg8 = getl(b, T_ARG8); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_channel[256]; gets_(b, T_CHANNEL, ch_o_channel, sizeof(ch_o_channel)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str4[256]; gets_(b, T_STR4, ch_o_str4, sizeof(ch_o_str4)); + char ch_o_str8[256]; gets_(b, T_STR8, ch_o_str8, sizeof(ch_o_str8)); + if (ch_do) { + { char ch_ch[16]; gets_(b, T_CHANNEL, ch_ch, sizeof(ch_ch)); + if (strlen(ch_ch) < 2) sets_(b, T_CHANNEL, "CH01"); } + sets_(b, T_STR1, "0200"); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("MG_PARSE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MG_UNPACK] tpcall(MG_PARSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7212); + Bchg(b, T_MSG, 0, "전문 언팩 파싱 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MG_UNPACK] 게이트웨이 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT2, ch_o_amt2); + setl(b, T_AMT3, ch_o_amt3); + setl(b, T_ARG6, ch_o_arg6); + setl(b, T_ARG7, ch_o_arg7); + setl(b, T_ARG8, ch_o_arg8); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_CHANNEL, 0, ch_o_channel, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR4, 0, ch_o_str4, 0L); + Bchg(b, T_STR8, 0, ch_o_str8, 0L); + } else { + userlog("[MG_UNPACK] 체인 대상 컨텍스트 없음 - MG_PARSE 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mg/svc/MG_VAN1ADPT.pgc b/app/src/mg/svc/MG_VAN1ADPT.pgc index b9e129d..6197a53 100644 --- a/app/src/mg/svc/MG_VAN1ADPT.pgc +++ b/app/src/mg/svc/MG_VAN1ADPT.pgc @@ -20,11 +20,12 @@ void MG_VAN1ADPT(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_VAN1ADPT(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_VAN1ADPT 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_VAN1ADPT 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_VAN1ADPT", "S", gw_bizdate) < 0) { + userlog("MG_VAN1ADPT 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mg/svc/MG_VAN2ADPT.pgc b/app/src/mg/svc/MG_VAN2ADPT.pgc index b540718..7682765 100644 --- a/app/src/mg/svc/MG_VAN2ADPT.pgc +++ b/app/src/mg/svc/MG_VAN2ADPT.pgc @@ -20,11 +20,12 @@ void MG_VAN2ADPT(TPSVCINFO *p) EXEC SQL BEGIN DECLARE SECTION; char gw_chan[16], gw_bizdate[16], gw_mti[8], gw_merch[16]; long gw_stan, gw_last, gw_total, gw_err, gw_backlog; + long gw_chanlast; long gw_limit, gw_mdr, gw_daysum; EXEC SQL END DECLARE SECTION; char gw_cstat[16], gw_reason[64]; long gw_amount, gw_band, gw_grade, gw_reject, gw_score, gw_fee; - long gw_msgid, gw_thr, gw_aff; + long gw_msgid, gw_thr, gw_aff, gw_stanmsg; /* --- 1) 입력 검증부: 필수/형식/범위 ------------------------------ */ gets_(b, T_CHANNEL, gw_chan, sizeof(gw_chan)); @@ -103,19 +104,40 @@ void MG_VAN2ADPT(TPSVCINFO *p) strcpy(gw_reason, "정상 수용"); } - /* --- 4) 본처리부: 채번/수수료 산출 + 채널 순번 반영 ------------- */ + /* --- 4) 본처리부: 시퀀스 채번/수수료 산출 + 채널 순번 대조(읽기) --- */ gw_fee = acq_fee(gw_amount, gw_mdr); gw_stan = mgdb_next_stan(); if (gw_stan < 0) { setl(b, T_RC, 9320); sets_(b, T_MSG, "STAN 채번 실패"); FAIL(b); } - EXEC SQL UPDATE mg_channel - SET last_stan = GREATEST(last_stan, :gw_stan), updated_at = now() - WHERE channel = :gw_chan; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번갱신 실패"); FAIL(b); + /* 채널 마스터(mg_channel) 행을 UPDATE 하는 것은 채널 생애주기 소유자 + * (MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/RESET/STAT, MG_SIGNON/SIGNOFF)만이다. + * 비소유자인 MG_VAN2ADPT 은 하나의 글로벌 트랜잭션 안에서 형제 XA + * 브랜치와 같은 행을 물어 교착하지 않도록 mg_channel 을 SELECT 만 하고, + * 전문 순번(STAN)은 mg_stan_seq 채번값을 권위로 삼는다. */ + EXEC SQL SELECT coalesce(last_stan, 0) INTO :gw_chanlast + FROM mg_channel WHERE channel = :gw_chan; + if (sqlca.sqlcode == 100) gw_chanlast = 0; + else if (sqlca.sqlcode < 0) { + setl(b, T_RC, 9321); sets_(b, T_MSG, "채널 순번조회 실패"); FAIL(b); + } + if (gw_stan > gw_chanlast) { + gw_aff = 1; /* 정상: 채번값이 채널 기록순번보다 앞선다 */ + } else { + gw_aff = 0; /* 순번 역전: 채널 재개통/시퀀스 리셋 흔적 */ + userlog("MG_VAN2ADPT 순번역전 감지 chan=%s seq=%ld chan_last=%ld", + gw_chan, gw_stan, gw_chanlast); + } + /* 채널행 갱신 대신 자기 이력(mg_msg_log)에 채번 사실을 적재한다. + * 채널별 최종 순번은 조회 시점에 max(stan) 으로 난다. */ + gw_stanmsg = mgdb_next_msg_id(); + if (gw_stanmsg > 0) { + if (mgdb_insert_msg(gw_stanmsg, gw_stan, gw_mti, gw_chan, "OUT", + "000000", "", gw_amount, "", "00", + "GW-STAN-MG_VAN2ADPT", "S", gw_bizdate) < 0) { + userlog("MG_VAN2ADPT 순번이력 적재경고 stan=%ld", gw_stan); + } } - gw_aff = sqlca.sqlerrd[2]; /* --- 5) 이력/감사 적재부: 전문원장에 감사행 기록 --------------- */ gw_msgid = mgdb_next_msg_id(); diff --git a/app/src/mm/svc/MM_ACCT_REG.pgc b/app/src/mm/svc/MM_ACCT_REG.pgc index f80ffd6..f1bff37 100644 --- a/app/src/mm/svc/MM_ACCT_REG.pgc +++ b/app/src/mm/svc/MM_ACCT_REG.pgc @@ -148,5 +148,42 @@ void MM_ACCT_REG(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_ACCT_REG -> CM_LUHN (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str5[256]; gets_(b, T_STR5, ch_o_str5, sizeof(ch_o_str5)); + if (ch_do) { + { char ch_pn[32]; gets_(b, T_STR3, ch_pn, sizeof(ch_pn)); + Bchg(b, T_STR5, 0, ch_pn, 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LUHN", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_ACCT_REG] tpcall(CM_LUHN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7161); + Bchg(b, T_MSG, 0, "정산계좌 체크섬 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_ACCT_REG] 계좌 체크섬 연동 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR5, 0, ch_o_str5, 0L); + } else { + userlog("[MM_ACCT_REG] 체인 대상 컨텍스트 없음 - CM_LUHN 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_ACCT_VERIFY.pgc b/app/src/mm/svc/MM_ACCT_VERIFY.pgc index 37c962b..714faa9 100644 --- a/app/src/mm/svc/MM_ACCT_VERIFY.pgc +++ b/app/src/mm/svc/MM_ACCT_VERIFY.pgc @@ -152,5 +152,44 @@ void MM_ACCT_VERIFY(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_ACCT_VERIFY -> CM_LUHN (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str5[256]; gets_(b, T_STR5, ch_o_str5, sizeof(ch_o_str5)); + if (ch_do) { + { char ch_pn[32]; gets_(b, T_STR3, ch_pn, sizeof(ch_pn)); + Bchg(b, T_STR5, 0, ch_pn, 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LUHN", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_ACCT_VERIFY] tpcall(CM_LUHN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7162); + Bchg(b, T_MSG, 0, "계좌검증 체크섬 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_ACCT_VERIFY] 계좌 체크섬 연동 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR5, 0, ch_o_str5, 0L); + } else { + userlog("[MM_ACCT_VERIFY] 체인 대상 컨텍스트 없음 - CM_LUHN 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_APPLY_APPROVE.pgc b/app/src/mm/svc/MM_APPLY_APPROVE.pgc index 0eb6b5c..9d7b0ff 100644 --- a/app/src/mm/svc/MM_APPLY_APPROVE.pgc +++ b/app/src/mm/svc/MM_APPLY_APPROVE.pgc @@ -153,5 +153,36 @@ void MM_APPLY_APPROVE(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_APPLY_APPROVE -> MM_VALIDATE (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + char ch_o_merchant[256]; gets_(b, T_MERCHANT, ch_o_merchant, sizeof(ch_o_merchant)); + long ch_o_rc = getl(b, T_RC); + if (ch_do) { + { char ch_mc[64]; gets_(b, T_MERCHANT, ch_mc, sizeof(ch_mc)); + if (ch_mc[0] == 0) { gets_(b, T_KEY1, ch_mc, sizeof(ch_mc)); + Bchg(b, T_MERCHANT, 0, ch_mc, 0L); } } + if (tpcall("MM_VALIDATE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_APPLY_APPROVE] tpcall(MM_VALIDATE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7104); + Bchg(b, T_MSG, 0, "가맹 신청승인 검증 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_APPLY_APPROVE] 마스터 검증 연동 완료 rc=%ld", getl(b, T_RC)); + Bchg(b, T_MERCHANT, 0, ch_o_merchant, 0L); + setl(b, T_RC, ch_o_rc); + } else { + userlog("[MM_APPLY_APPROVE] 체인 대상 컨텍스트 없음 - MM_VALIDATE 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_APPLY_REG.pgc b/app/src/mm/svc/MM_APPLY_REG.pgc index 67f7f3a..90db883 100644 --- a/app/src/mm/svc/MM_APPLY_REG.pgc +++ b/app/src/mm/svc/MM_APPLY_REG.pgc @@ -155,5 +155,44 @@ void MM_APPLY_REG(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_APPLY_REG -> CM_SEQ (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_key1[256]; gets_(b, T_KEY1, ch_o_key1, sizeof(ch_o_key1)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + Bchg(b, T_KEY1, 0, "MM_APPLY", 0L); + Bchg(b, T_STR1, 0, "MM_APPLY_REG", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_SEQ", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_APPLY_REG] tpcall(CM_SEQ) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7156); + Bchg(b, T_MSG, 0, "가맹신청 채번 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_APPLY_REG] 채번 연동 완료 seq=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_KEY1, 0, ch_o_key1, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[MM_APPLY_REG] 체인 대상 컨텍스트 없음 - CM_SEQ 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_BIN_REG.pgc b/app/src/mm/svc/MM_BIN_REG.pgc index c2c2d26..28969f5 100644 --- a/app/src/mm/svc/MM_BIN_REG.pgc +++ b/app/src/mm/svc/MM_BIN_REG.pgc @@ -119,5 +119,33 @@ void MM_BIN_REG(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_BIN_REG -> VL_BIN (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + char ch_o_merchant[256]; gets_(b, T_MERCHANT, ch_o_merchant, sizeof(ch_o_merchant)); + if (ch_do) { + { char ch_mc[64]; gets_(b, T_MERCHANT, ch_mc, sizeof(ch_mc)); + if (strlen(ch_mc) > 32) { ch_mc[32] = 0; Bchg(b, T_MERCHANT, 0, ch_mc, 0L); } } + if (tpcall("VL_BIN", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_BIN_REG] tpcall(VL_BIN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7141); + Bchg(b, T_MSG, 0, "BIN 정합검증 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_BIN_REG] 정합검증 연동 완료 rc=%ld", getl(b, T_RC)); + Bchg(b, T_MERCHANT, 0, ch_o_merchant, 0L); + } else { + userlog("[MM_BIN_REG] 체인 대상 컨텍스트 없음 - VL_BIN 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_BIZNO_CHECK.pgc b/app/src/mm/svc/MM_BIZNO_CHECK.pgc index 48c0851..e5bb2de 100644 --- a/app/src/mm/svc/MM_BIZNO_CHECK.pgc +++ b/app/src/mm/svc/MM_BIZNO_CHECK.pgc @@ -154,5 +154,45 @@ void MM_BIZNO_CHECK(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_BIZNO_CHECK -> CM_CHECKDIGIT (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_count = getl(b, T_COUNT); + long ch_o_rc = getl(b, T_RC); + char ch_o_str2[256]; gets_(b, T_STR2, ch_o_str2, sizeof(ch_o_str2)); + if (ch_do) { + { char ch_bs[32]; gets_(b, T_STR2, ch_bs, sizeof(ch_bs)); + if (ch_bs[0] == 0) strcpy(ch_bs, "0000000000"); + Bchg(b, T_STR2, 0, ch_bs, 0L); } + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_CHECKDIGIT", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_BIZNO_CHECK] tpcall(CM_CHECKDIGIT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7163); + Bchg(b, T_MSG, 0, "사업자번호 검증 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_BIZNO_CHECK] 검증번호 연동 d=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_COUNT, ch_o_count); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR2, 0, ch_o_str2, 0L); + } else { + userlog("[MM_BIZNO_CHECK] 체인 대상 컨텍스트 없음 - CM_CHECKDIGIT 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_CHK_LIMIT.pgc b/app/src/mm/svc/MM_CHK_LIMIT.pgc index b1c4c43..100f1fa 100644 --- a/app/src/mm/svc/MM_CHK_LIMIT.pgc +++ b/app/src/mm/svc/MM_CHK_LIMIT.pgc @@ -141,5 +141,39 @@ void MM_CHK_LIMIT(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_CHK_LIMIT -> LIMIT_CHK (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg1 = getl(b, T_ARG1); + long ch_o_count = getl(b, T_COUNT); + long ch_o_rc = getl(b, T_RC); + { char ch_cd[24]; gets_(b, T_KEY1, ch_cd, sizeof(ch_cd)); ch_do = (ch_cd[0] != 0); } + if (ch_do) { + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("LIMIT_CHK", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_CHK_LIMIT] tpcall(LIMIT_CHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7132); + Bchg(b, T_MSG, 0, "승인한도 점검 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_CHK_LIMIT] 승인한도 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG1, ch_o_arg1); + setl(b, T_COUNT, ch_o_count); + setl(b, T_RC, ch_o_rc); + } else { + userlog("[MM_CHK_LIMIT] 체인 대상 컨텍스트 없음 - LIMIT_CHK 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_CODE_REG.pgc b/app/src/mm/svc/MM_CODE_REG.pgc index 8f6a736..f14bd02 100644 --- a/app/src/mm/svc/MM_CODE_REG.pgc +++ b/app/src/mm/svc/MM_CODE_REG.pgc @@ -119,5 +119,36 @@ void MM_CODE_REG(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_CODE_REG -> VL_CODEVAL (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + char ch_o_merchant[256]; gets_(b, T_MERCHANT, ch_o_merchant, sizeof(ch_o_merchant)); + char ch_o_str3[256]; gets_(b, T_STR3, ch_o_str3, sizeof(ch_o_str3)); + if (ch_do) { + { char ch_mc[64]; gets_(b, T_MERCHANT, ch_mc, sizeof(ch_mc)); + if (strlen(ch_mc) > 32) { ch_mc[32] = 0; Bchg(b, T_MERCHANT, 0, ch_mc, 0L); } } + Bchg(b, T_STR3, 0, "CODE_VALID", 0L); + if (tpcall("VL_CODEVAL", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_CODE_REG] tpcall(VL_CODEVAL) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7145); + Bchg(b, T_MSG, 0, "공통코드 검증 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_CODE_REG] 정합검증 연동 완료 rc=%ld", getl(b, T_RC)); + Bchg(b, T_MERCHANT, 0, ch_o_merchant, 0L); + Bchg(b, T_STR3, 0, ch_o_str3, 0L); + } else { + userlog("[MM_CODE_REG] 체인 대상 컨텍스트 없음 - VL_CODEVAL 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_CONTRACT_AMEND.pgc b/app/src/mm/svc/MM_CONTRACT_AMEND.pgc index f3b8a76..76f78eb 100644 --- a/app/src/mm/svc/MM_CONTRACT_AMEND.pgc +++ b/app/src/mm/svc/MM_CONTRACT_AMEND.pgc @@ -155,5 +155,44 @@ void MM_CONTRACT_AMEND(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_CONTRACT_AMEND -> CM_SEQ (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_key1[256]; gets_(b, T_KEY1, ch_o_key1, sizeof(ch_o_key1)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + Bchg(b, T_KEY1, 0, "MM_CONTRACT", 0L); + Bchg(b, T_STR1, 0, "MM_CONTRACT_AMEND", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_SEQ", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_CONTRACT_AMEND] tpcall(CM_SEQ) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7155); + Bchg(b, T_MSG, 0, "계약변경 채번 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_CONTRACT_AMEND] 채번 연동 완료 seq=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_KEY1, 0, ch_o_key1, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[MM_CONTRACT_AMEND] 체인 대상 컨텍스트 없음 - CM_SEQ 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_CONTRACT_NEW.pgc b/app/src/mm/svc/MM_CONTRACT_NEW.pgc index 9390bb7..c9a1c99 100644 --- a/app/src/mm/svc/MM_CONTRACT_NEW.pgc +++ b/app/src/mm/svc/MM_CONTRACT_NEW.pgc @@ -154,5 +154,44 @@ void MM_CONTRACT_NEW(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_CONTRACT_NEW -> CM_SEQ (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_key1[256]; gets_(b, T_KEY1, ch_o_key1, sizeof(ch_o_key1)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + Bchg(b, T_KEY1, 0, "MM_CONTRACT", 0L); + Bchg(b, T_STR1, 0, "MM_CONTRACT_NEW", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_SEQ", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_CONTRACT_NEW] tpcall(CM_SEQ) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7153); + Bchg(b, T_MSG, 0, "계약 채번 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_CONTRACT_NEW] 채번 연동 완료 seq=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_KEY1, 0, ch_o_key1, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[MM_CONTRACT_NEW] 체인 대상 컨텍스트 없음 - CM_SEQ 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_CONTRACT_RENEW.pgc b/app/src/mm/svc/MM_CONTRACT_RENEW.pgc index 266b157..85e2ae1 100644 --- a/app/src/mm/svc/MM_CONTRACT_RENEW.pgc +++ b/app/src/mm/svc/MM_CONTRACT_RENEW.pgc @@ -157,5 +157,46 @@ void MM_CONTRACT_RENEW(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_CONTRACT_RENEW -> CM_SEQ (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_key1[256]; gets_(b, T_KEY1, ch_o_key1, sizeof(ch_o_key1)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_str2[256]; gets_(b, T_STR2, ch_o_str2, sizeof(ch_o_str2)); + if (ch_do) { + Bchg(b, T_KEY1, 0, "MM_CONTRACT", 0L); + Bchg(b, T_STR1, 0, "MM_CONTRACT_RENEW", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_SEQ", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_CONTRACT_RENEW] tpcall(CM_SEQ) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7154); + Bchg(b, T_MSG, 0, "계약갱신 채번 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_CONTRACT_RENEW] 채번 연동 완료 seq=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_KEY1, 0, ch_o_key1, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_STR2, 0, ch_o_str2, 0L); + } else { + userlog("[MM_CONTRACT_RENEW] 체인 대상 컨텍스트 없음 - CM_SEQ 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_FEERATE_SET.pgc b/app/src/mm/svc/MM_FEERATE_SET.pgc index 8b06dcb..da908df 100644 --- a/app/src/mm/svc/MM_FEERATE_SET.pgc +++ b/app/src/mm/svc/MM_FEERATE_SET.pgc @@ -130,5 +130,36 @@ void MM_FEERATE_SET(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_FEERATE_SET -> ST_MDR (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_fee = getl(b, T_FEE); + if (ch_do) { + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_FEE) < 0) setl(b, T_FEE, 0); + if (tpcall("ST_MDR", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_FEERATE_SET] tpcall(ST_MDR) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7121); + Bchg(b, T_MSG, 0, "요율 원장반영 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_FEERATE_SET] 요율 원장반영 연동 완료 pid=%ld", getl(b, T_PURCHASE_ID)); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_FEE, ch_o_fee); + } else { + userlog("[MM_FEERATE_SET] 체인 대상 컨텍스트 없음 - ST_MDR 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_GRADE_ADJUST.pgc b/app/src/mm/svc/MM_GRADE_ADJUST.pgc index 72ebcc9..1896e4d 100644 --- a/app/src/mm/svc/MM_GRADE_ADJUST.pgc +++ b/app/src/mm/svc/MM_GRADE_ADJUST.pgc @@ -148,5 +148,37 @@ void MM_GRADE_ADJUST(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_GRADE_ADJUST -> VL_MERCH (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + char ch_o_merchant[256]; gets_(b, T_MERCHANT, ch_o_merchant, sizeof(ch_o_merchant)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + { char ch_mc[64]; gets_(b, T_MERCHANT, ch_mc, sizeof(ch_mc)); + if (strlen(ch_mc) > 32) { ch_mc[32] = 0; Bchg(b, T_MERCHANT, 0, ch_mc, 0L); } } + if (tpcall("VL_MERCH", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_GRADE_ADJUST] tpcall(VL_MERCH) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7147); + Bchg(b, T_MSG, 0, "등급조정 가맹점검증 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_GRADE_ADJUST] 정합검증 연동 완료 rc=%ld", getl(b, T_RC)); + Bchg(b, T_MERCHANT, 0, ch_o_merchant, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[MM_GRADE_ADJUST] 체인 대상 컨텍스트 없음 - VL_MERCH 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_ISSUER_REG.pgc b/app/src/mm/svc/MM_ISSUER_REG.pgc index 092c807..9d76858 100644 --- a/app/src/mm/svc/MM_ISSUER_REG.pgc +++ b/app/src/mm/svc/MM_ISSUER_REG.pgc @@ -118,5 +118,33 @@ void MM_ISSUER_REG(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_ISSUER_REG -> VL_BIN (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + char ch_o_merchant[256]; gets_(b, T_MERCHANT, ch_o_merchant, sizeof(ch_o_merchant)); + if (ch_do) { + { char ch_mc[64]; gets_(b, T_MERCHANT, ch_mc, sizeof(ch_mc)); + if (strlen(ch_mc) > 32) { ch_mc[32] = 0; Bchg(b, T_MERCHANT, 0, ch_mc, 0L); } } + if (tpcall("VL_BIN", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_ISSUER_REG] tpcall(VL_BIN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7142); + Bchg(b, T_MSG, 0, "발급사 BIN 정합검증 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_ISSUER_REG] 정합검증 연동 완료 rc=%ld", getl(b, T_RC)); + Bchg(b, T_MERCHANT, 0, ch_o_merchant, 0L); + } else { + userlog("[MM_ISSUER_REG] 체인 대상 컨텍스트 없음 - VL_BIN 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_LIMIT_SET.pgc b/app/src/mm/svc/MM_LIMIT_SET.pgc index 8e2e564..0aea9a8 100644 --- a/app/src/mm/svc/MM_LIMIT_SET.pgc +++ b/app/src/mm/svc/MM_LIMIT_SET.pgc @@ -141,5 +141,33 @@ void MM_LIMIT_SET(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_LIMIT_SET -> LIMIT_CHK (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + { char ch_cd[24]; gets_(b, T_KEY1, ch_cd, sizeof(ch_cd)); ch_do = (ch_cd[0] != 0); } + if (ch_do) { + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + if (tpcall("LIMIT_CHK", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_LIMIT_SET] tpcall(LIMIT_CHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7131); + Bchg(b, T_MSG, 0, "승인한도 연동 점검 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_LIMIT_SET] 승인한도 연동 완료 rc=%ld", getl(b, T_RC)); + setl(b, T_AMOUNT, ch_o_amount); + } else { + userlog("[MM_LIMIT_SET] 체인 대상 컨텍스트 없음 - LIMIT_CHK 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_MCC_REG.pgc b/app/src/mm/svc/MM_MCC_REG.pgc index 89c8354..fbb4391 100644 --- a/app/src/mm/svc/MM_MCC_REG.pgc +++ b/app/src/mm/svc/MM_MCC_REG.pgc @@ -123,5 +123,36 @@ void MM_MCC_REG(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_MCC_REG -> VL_CODEVAL (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + char ch_o_merchant[256]; gets_(b, T_MERCHANT, ch_o_merchant, sizeof(ch_o_merchant)); + char ch_o_str3[256]; gets_(b, T_STR3, ch_o_str3, sizeof(ch_o_str3)); + if (ch_do) { + { char ch_mc[64]; gets_(b, T_MERCHANT, ch_mc, sizeof(ch_mc)); + if (strlen(ch_mc) > 32) { ch_mc[32] = 0; Bchg(b, T_MERCHANT, 0, ch_mc, 0L); } } + Bchg(b, T_STR3, 0, "MCC_VALID", 0L); + if (tpcall("VL_CODEVAL", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_MCC_REG] tpcall(VL_CODEVAL) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7143); + Bchg(b, T_MSG, 0, "MCC 코드검증 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_MCC_REG] 정합검증 연동 완료 rc=%ld", getl(b, T_RC)); + Bchg(b, T_MERCHANT, 0, ch_o_merchant, 0L); + Bchg(b, T_STR3, 0, ch_o_str3, 0L); + } else { + userlog("[MM_MCC_REG] 체인 대상 컨텍스트 없음 - VL_CODEVAL 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_MCC_UPD.pgc b/app/src/mm/svc/MM_MCC_UPD.pgc index f1ad9f5..2745a03 100644 --- a/app/src/mm/svc/MM_MCC_UPD.pgc +++ b/app/src/mm/svc/MM_MCC_UPD.pgc @@ -131,5 +131,38 @@ void MM_MCC_UPD(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_MCC_UPD -> VL_CODEVAL (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + char ch_o_merchant[256]; gets_(b, T_MERCHANT, ch_o_merchant, sizeof(ch_o_merchant)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str3[256]; gets_(b, T_STR3, ch_o_str3, sizeof(ch_o_str3)); + if (ch_do) { + { char ch_mc[64]; gets_(b, T_MERCHANT, ch_mc, sizeof(ch_mc)); + if (strlen(ch_mc) > 32) { ch_mc[32] = 0; Bchg(b, T_MERCHANT, 0, ch_mc, 0L); } } + Bchg(b, T_STR3, 0, "MCC_VALID", 0L); + if (tpcall("VL_CODEVAL", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_MCC_UPD] tpcall(VL_CODEVAL) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7144); + Bchg(b, T_MSG, 0, "MCC 변경검증 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_MCC_UPD] 정합검증 연동 완료 rc=%ld", getl(b, T_RC)); + Bchg(b, T_MERCHANT, 0, ch_o_merchant, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR3, 0, ch_o_str3, 0L); + } else { + userlog("[MM_MCC_UPD] 체인 대상 컨텍스트 없음 - VL_CODEVAL 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_MERCH_CLOSE.pgc b/app/src/mm/svc/MM_MERCH_CLOSE.pgc index 8d98d62..30d79f5 100644 --- a/app/src/mm/svc/MM_MERCH_CLOSE.pgc +++ b/app/src/mm/svc/MM_MERCH_CLOSE.pgc @@ -156,5 +156,49 @@ void MM_MERCH_CLOSE(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_MERCH_CLOSE -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "MM_MERCH_CLOSE", 0L); + Bchg(b, T_MSG, 0, "가맹점 해지 처리", 0L); + Bchg(b, T_STR1, 0, "MM_MERCH_CLOSE", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_MERCH_CLOSE] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7112); + Bchg(b, T_MSG, 0, "해지 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_MERCH_CLOSE] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[MM_MERCH_CLOSE] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_MERCH_DORMANT.pgc b/app/src/mm/svc/MM_MERCH_DORMANT.pgc index dcff9c6..16e78c2 100644 --- a/app/src/mm/svc/MM_MERCH_DORMANT.pgc +++ b/app/src/mm/svc/MM_MERCH_DORMANT.pgc @@ -152,5 +152,49 @@ void MM_MERCH_DORMANT(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_MERCH_DORMANT -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_gross = getl(b, T_GROSS); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "MM_MERCH_DORMANT", 0L); + Bchg(b, T_MSG, 0, "가맹점 휴면 전환", 0L); + Bchg(b, T_STR1, 0, "MM_MERCH_DORMANT", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_MERCH_DORMANT] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7115); + Bchg(b, T_MSG, 0, "휴면전환 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_MERCH_DORMANT] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_GROSS, ch_o_gross); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[MM_MERCH_DORMANT] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_MERCH_GRADE.pgc b/app/src/mm/svc/MM_MERCH_GRADE.pgc index d140599..fd67429 100644 --- a/app/src/mm/svc/MM_MERCH_GRADE.pgc +++ b/app/src/mm/svc/MM_MERCH_GRADE.pgc @@ -129,5 +129,35 @@ void MM_MERCH_GRADE(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_MERCH_GRADE -> VL_MERCH (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + char ch_o_merchant[256]; gets_(b, T_MERCHANT, ch_o_merchant, sizeof(ch_o_merchant)); + char ch_o_str2[256]; gets_(b, T_STR2, ch_o_str2, sizeof(ch_o_str2)); + if (ch_do) { + { char ch_mc[64]; gets_(b, T_MERCHANT, ch_mc, sizeof(ch_mc)); + if (strlen(ch_mc) > 32) { ch_mc[32] = 0; Bchg(b, T_MERCHANT, 0, ch_mc, 0L); } } + if (tpcall("VL_MERCH", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_MERCH_GRADE] tpcall(VL_MERCH) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7146); + Bchg(b, T_MSG, 0, "등급변경 가맹점검증 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_MERCH_GRADE] 정합검증 연동 완료 rc=%ld", getl(b, T_RC)); + Bchg(b, T_MERCHANT, 0, ch_o_merchant, 0L); + Bchg(b, T_STR2, 0, ch_o_str2, 0L); + } else { + userlog("[MM_MERCH_GRADE] 체인 대상 컨텍스트 없음 - VL_MERCH 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_MERCH_PAUSE.pgc b/app/src/mm/svc/MM_MERCH_PAUSE.pgc index 4a39ef6..b99eb83 100644 --- a/app/src/mm/svc/MM_MERCH_PAUSE.pgc +++ b/app/src/mm/svc/MM_MERCH_PAUSE.pgc @@ -150,5 +150,49 @@ void MM_MERCH_PAUSE(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_MERCH_PAUSE -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "MM_MERCH_PAUSE", 0L); + Bchg(b, T_MSG, 0, "가맹점 일시정지 처리", 0L); + Bchg(b, T_STR1, 0, "MM_MERCH_PAUSE", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_MERCH_PAUSE] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7113); + Bchg(b, T_MSG, 0, "일시정지 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_MERCH_PAUSE] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[MM_MERCH_PAUSE] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_MERCH_REG.pgc b/app/src/mm/svc/MM_MERCH_REG.pgc index 28a7949..388d77b 100644 --- a/app/src/mm/svc/MM_MERCH_REG.pgc +++ b/app/src/mm/svc/MM_MERCH_REG.pgc @@ -136,5 +136,36 @@ void MM_MERCH_REG(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_MERCH_REG -> MM_VALIDATE (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + char ch_o_merchant[256]; gets_(b, T_MERCHANT, ch_o_merchant, sizeof(ch_o_merchant)); + char ch_o_status[256]; gets_(b, T_STATUS, ch_o_status, sizeof(ch_o_status)); + if (ch_do) { + { char ch_mc[64]; gets_(b, T_MERCHANT, ch_mc, sizeof(ch_mc)); + if (ch_mc[0] == 0) { gets_(b, T_KEY1, ch_mc, sizeof(ch_mc)); + Bchg(b, T_MERCHANT, 0, ch_mc, 0L); } } + if (tpcall("MM_VALIDATE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_MERCH_REG] tpcall(MM_VALIDATE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7101); + Bchg(b, T_MSG, 0, "가맹점 등록 검증 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_MERCH_REG] 마스터 검증 연동 완료 rc=%ld", getl(b, T_RC)); + Bchg(b, T_MERCHANT, 0, ch_o_merchant, 0L); + Bchg(b, T_STATUS, 0, ch_o_status, 0L); + } else { + userlog("[MM_MERCH_REG] 체인 대상 컨텍스트 없음 - MM_VALIDATE 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_MERCH_RESUME.pgc b/app/src/mm/svc/MM_MERCH_RESUME.pgc index 4995f05..aef91aa 100644 --- a/app/src/mm/svc/MM_MERCH_RESUME.pgc +++ b/app/src/mm/svc/MM_MERCH_RESUME.pgc @@ -148,5 +148,49 @@ void MM_MERCH_RESUME(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_MERCH_RESUME -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_count = getl(b, T_COUNT); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "MM_MERCH_RESUME", 0L); + Bchg(b, T_MSG, 0, "가맹점 거래재개 처리", 0L); + Bchg(b, T_STR1, 0, "MM_MERCH_RESUME", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_MERCH_RESUME] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7114); + Bchg(b, T_MSG, 0, "재개 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_MERCH_RESUME] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_COUNT, ch_o_count); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[MM_MERCH_RESUME] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_MERCH_STATUS.pgc b/app/src/mm/svc/MM_MERCH_STATUS.pgc index ed4409a..57f2110 100644 --- a/app/src/mm/svc/MM_MERCH_STATUS.pgc +++ b/app/src/mm/svc/MM_MERCH_STATUS.pgc @@ -128,5 +128,34 @@ void MM_MERCH_STATUS(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_MERCH_STATUS -> MM_VALIDATE (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + char ch_o_merchant[256]; gets_(b, T_MERCHANT, ch_o_merchant, sizeof(ch_o_merchant)); + if (ch_do) { + { char ch_mc[64]; gets_(b, T_MERCHANT, ch_mc, sizeof(ch_mc)); + if (ch_mc[0] == 0) { gets_(b, T_KEY1, ch_mc, sizeof(ch_mc)); + Bchg(b, T_MERCHANT, 0, ch_mc, 0L); } } + if (tpcall("MM_VALIDATE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_MERCH_STATUS] tpcall(MM_VALIDATE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7103); + Bchg(b, T_MSG, 0, "가맹점 상태변경 검증 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_MERCH_STATUS] 마스터 검증 연동 완료 rc=%ld", getl(b, T_RC)); + Bchg(b, T_MERCHANT, 0, ch_o_merchant, 0L); + } else { + userlog("[MM_MERCH_STATUS] 체인 대상 컨텍스트 없음 - MM_VALIDATE 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_MERCH_UPD.pgc b/app/src/mm/svc/MM_MERCH_UPD.pgc index 810f9f9..1bd332b 100644 --- a/app/src/mm/svc/MM_MERCH_UPD.pgc +++ b/app/src/mm/svc/MM_MERCH_UPD.pgc @@ -142,5 +142,34 @@ void MM_MERCH_UPD(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_MERCH_UPD -> MM_VALIDATE (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + char ch_o_merchant[256]; gets_(b, T_MERCHANT, ch_o_merchant, sizeof(ch_o_merchant)); + if (ch_do) { + { char ch_mc[64]; gets_(b, T_MERCHANT, ch_mc, sizeof(ch_mc)); + if (ch_mc[0] == 0) { gets_(b, T_KEY1, ch_mc, sizeof(ch_mc)); + Bchg(b, T_MERCHANT, 0, ch_mc, 0L); } } + if (tpcall("MM_VALIDATE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_MERCH_UPD] tpcall(MM_VALIDATE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7102); + Bchg(b, T_MSG, 0, "가맹점 변경 검증 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_MERCH_UPD] 마스터 검증 연동 완료 rc=%ld", getl(b, T_RC)); + Bchg(b, T_MERCHANT, 0, ch_o_merchant, 0L); + } else { + userlog("[MM_MERCH_UPD] 체인 대상 컨텍스트 없음 - MM_VALIDATE 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_RATE_APPROVE.pgc b/app/src/mm/svc/MM_RATE_APPROVE.pgc index d8dedcb..1f35adf 100644 --- a/app/src/mm/svc/MM_RATE_APPROVE.pgc +++ b/app/src/mm/svc/MM_RATE_APPROVE.pgc @@ -157,5 +157,42 @@ void MM_RATE_APPROVE(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_RATE_APPROVE -> ST_MDR (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amt1 = getl(b, T_AMT1); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + long ch_o_fee = getl(b, T_FEE); + long ch_o_rc = getl(b, T_RC); + char ch_o_str2[256]; gets_(b, T_STR2, ch_o_str2, sizeof(ch_o_str2)); + if (ch_do) { + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (getl(b, T_FEE) < 0) setl(b, T_FEE, 0); + if (tpcall("ST_MDR", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_RATE_APPROVE] tpcall(ST_MDR) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7122); + Bchg(b, T_MSG, 0, "승인요율 원장반영 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_RATE_APPROVE] 요율 원장반영 연동 완료 pid=%ld", getl(b, T_PURCHASE_ID)); + setl(b, T_AMT1, ch_o_amt1); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + setl(b, T_FEE, ch_o_fee); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR2, 0, ch_o_str2, 0L); + } else { + userlog("[MM_RATE_APPROVE] 체인 대상 컨텍스트 없음 - ST_MDR 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_RATE_REQ.pgc b/app/src/mm/svc/MM_RATE_REQ.pgc index 13c5b79..8e0f965 100644 --- a/app/src/mm/svc/MM_RATE_REQ.pgc +++ b/app/src/mm/svc/MM_RATE_REQ.pgc @@ -161,5 +161,49 @@ void MM_RATE_REQ(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_RATE_REQ -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_amt1 = getl(b, T_AMT1); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "MM_RATE_REQ", 0L); + Bchg(b, T_MSG, 0, "가맹점 요율변경 신청", 0L); + Bchg(b, T_STR1, 0, "MM_RATE_REQ", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_RATE_REQ] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7117); + Bchg(b, T_MSG, 0, "요율신청 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_RATE_REQ] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_AMT1, ch_o_amt1); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[MM_RATE_REQ] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_RISK_SCORE.pgc b/app/src/mm/svc/MM_RISK_SCORE.pgc index 24a1477..b621cc1 100644 --- a/app/src/mm/svc/MM_RISK_SCORE.pgc +++ b/app/src/mm/svc/MM_RISK_SCORE.pgc @@ -156,5 +156,49 @@ void MM_RISK_SCORE(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_RISK_SCORE -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + long ch_o_arg1 = getl(b, T_ARG1); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "MM_RISK_SCORE", 0L); + Bchg(b, T_MSG, 0, "가맹점 위험점수 산정", 0L); + Bchg(b, T_STR1, 0, "MM_RISK_SCORE", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_RISK_SCORE] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7116); + Bchg(b, T_MSG, 0, "위험점수 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_RISK_SCORE] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + setl(b, T_ARG1, ch_o_arg1); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[MM_RISK_SCORE] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_RISK_SET.pgc b/app/src/mm/svc/MM_RISK_SET.pgc index 36b6704..5a92fec 100644 --- a/app/src/mm/svc/MM_RISK_SET.pgc +++ b/app/src/mm/svc/MM_RISK_SET.pgc @@ -142,5 +142,35 @@ void MM_RISK_SET(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_RISK_SET -> VL_MERCH (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + char ch_o_merchant[256]; gets_(b, T_MERCHANT, ch_o_merchant, sizeof(ch_o_merchant)); + long ch_o_rc = getl(b, T_RC); + if (ch_do) { + { char ch_mc[64]; gets_(b, T_MERCHANT, ch_mc, sizeof(ch_mc)); + if (strlen(ch_mc) > 32) { ch_mc[32] = 0; Bchg(b, T_MERCHANT, 0, ch_mc, 0L); } } + if (tpcall("VL_MERCH", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_RISK_SET] tpcall(VL_MERCH) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7148); + Bchg(b, T_MSG, 0, "위험등급 가맹점검증 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_RISK_SET] 정합검증 연동 완료 rc=%ld", getl(b, T_RC)); + Bchg(b, T_MERCHANT, 0, ch_o_merchant, 0L); + setl(b, T_RC, ch_o_rc); + } else { + userlog("[MM_RISK_SET] 체인 대상 컨텍스트 없음 - VL_MERCH 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_TERMINAL_REG.pgc b/app/src/mm/svc/MM_TERMINAL_REG.pgc index 1a41f77..0d0f3c9 100644 --- a/app/src/mm/svc/MM_TERMINAL_REG.pgc +++ b/app/src/mm/svc/MM_TERMINAL_REG.pgc @@ -131,5 +131,42 @@ void MM_TERMINAL_REG(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_TERMINAL_REG -> CM_SEQ (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_key1[256]; gets_(b, T_KEY1, ch_o_key1, sizeof(ch_o_key1)); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + Bchg(b, T_KEY1, 0, "MM_TERMINAL", 0L); + Bchg(b, T_STR1, 0, "MM_TERMINAL_REG", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_SEQ", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_TERMINAL_REG] tpcall(CM_SEQ) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7151); + Bchg(b, T_MSG, 0, "단말 채번 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_TERMINAL_REG] 채번 연동 완료 seq=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_KEY1, 0, ch_o_key1, 0L); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[MM_TERMINAL_REG] 체인 대상 컨텍스트 없음 - CM_SEQ 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_TERM_INSTALL.pgc b/app/src/mm/svc/MM_TERM_INSTALL.pgc index db0d10e..46bb6f6 100644 --- a/app/src/mm/svc/MM_TERM_INSTALL.pgc +++ b/app/src/mm/svc/MM_TERM_INSTALL.pgc @@ -142,5 +142,44 @@ void MM_TERM_INSTALL(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_TERM_INSTALL -> CM_SEQ (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_key1[256]; gets_(b, T_KEY1, ch_o_key1, sizeof(ch_o_key1)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + if (ch_do) { + Bchg(b, T_KEY1, 0, "MM_TERMINAL", 0L); + Bchg(b, T_STR1, 0, "MM_TERM_INSTALL", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_SEQ", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_TERM_INSTALL] tpcall(CM_SEQ) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7152); + Bchg(b, T_MSG, 0, "단말설치 채번 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_TERM_INSTALL] 채번 연동 완료 seq=%ld", getl(b, T_ARG1)); + setl(b, T_AMOUNT, ch_o_amount); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_KEY1, 0, ch_o_key1, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + } else { + userlog("[MM_TERM_INSTALL] 체인 대상 컨텍스트 없음 - CM_SEQ 호출 생략"); + } + } + OK(b); } diff --git a/app/src/mm/svc/MM_VALIDATE.pgc b/app/src/mm/svc/MM_VALIDATE.pgc index 8fa9d12..df0d166 100644 --- a/app/src/mm/svc/MM_VALIDATE.pgc +++ b/app/src/mm/svc/MM_VALIDATE.pgc @@ -139,5 +139,47 @@ void MM_VALIDATE(TPSVCINFO *p) (void)zx_vat; (void)zx_wht; (void)zx_n3; } + + /* ---- 업무 체인: MM_VALIDATE -> CM_LOG (동일 글로벌 트랜잭션 / 별도 XA 브랜치) ---- + * 하위 서비스는 별도 XA 브랜치라 상위가 방금 갱신한 미커밋 행이 보이지 않는다. + * 판정에 필요한 값은 전문(T_*)에 실어 전달하고, 상위의 입출력 계약 필드는 + * 호출 전 보존 -> 호출 후 복원하여 기존 응답 계약을 그대로 유지한다. + * 체인 실패는 T_RC/T_MSG 설정 후 FAIL 하여 같은 글로벌 트랜잭션을 + * 통째로 롤백한다(별도 보상 트랜잭션 불필요). */ + { + long ch_rlen = 0; + int ch_do = 1; + long ch_o_amount = getl(b, T_AMOUNT); + char ch_o_bizdate[256]; gets_(b, T_BIZDATE, ch_o_bizdate, sizeof(ch_o_bizdate)); + char ch_o_msg[256]; gets_(b, T_MSG, ch_o_msg, sizeof(ch_o_msg)); + long ch_o_rc = getl(b, T_RC); + char ch_o_str1[256]; gets_(b, T_STR1, ch_o_str1, sizeof(ch_o_str1)); + char ch_o_svcname[256]; gets_(b, T_SVCNAME, ch_o_svcname, sizeof(ch_o_svcname)); + if (ch_do) { + Bchg(b, T_SVCNAME, 0, "MM_VALIDATE", 0L); + Bchg(b, T_MSG, 0, "가맹점 마스터 검증 수행", 0L); + Bchg(b, T_STR1, 0, "MM_VALIDATE", 0L); + if (getl(b, T_AMOUNT) < 0) setl(b, T_AMOUNT, 0); + { char ch_bd[16]; gets_(b, T_BIZDATE, ch_bd, sizeof(ch_bd)); + if (strlen(ch_bd) != 10) Bchg(b, T_BIZDATE, 0, "2026-07-19", 0L); } + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[MM_VALIDATE] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 7111); + Bchg(b, T_MSG, 0, "검증 이력 적재 체인 실패", 0L); + FAIL(b); + } + /* 하위 결과 반영(참조 로깅) 후 상위 응답 계약 필드 복원 */ + userlog("[MM_VALIDATE] 이력 연동 완료 log_id=%ld", getl(b, T_ID1)); + setl(b, T_AMOUNT, ch_o_amount); + Bchg(b, T_BIZDATE, 0, ch_o_bizdate, 0L); + Bchg(b, T_MSG, 0, ch_o_msg, 0L); + setl(b, T_RC, ch_o_rc); + Bchg(b, T_STR1, 0, ch_o_str1, 0L); + Bchg(b, T_SVCNAME, 0, ch_o_svcname, 0L); + } else { + userlog("[MM_VALIDATE] 체인 대상 컨텍스트 없음 - CM_LOG 호출 생략"); + } + } + OK(b); } diff --git a/app/src/py/dbio/py_payout_reject_dbio.pgc b/app/src/py/dbio/py_payout_reject_dbio.pgc index f4739f3..c3fb9d3 100644 --- a/app/src/py/dbio/py_payout_reject_dbio.pgc +++ b/app/src/py/dbio/py_payout_reject_dbio.pgc @@ -28,6 +28,13 @@ int pydb_payout_reject_reason(long payout_id, char *out) EXEC SQL END DECLARE SECTION; EXEC SQL SELECT coalesce(reject_reason,'') INTO :h_reason FROM py_payout WHERE payout_id = :h_pay; if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) { userlog("pydb_payout_reject_reason FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); return -1; } - strncpy(out, h_reason, 127); out[127] = 0; + /* 실제 값 길이만 복사 (strncpy 의 NUL 패딩으로 호출자 스택을 넘어 쓰는 것 방지). + * 상세 사유는 cm_param_dbio.pgc 의 cmdb_get_param 주석 참조. */ + { + size_t vn = strlen(h_reason); + if (vn > 127) vn = 127; + memcpy(out, h_reason, vn); + out[vn] = 0; + } return 0; } diff --git a/app/src/py/svc/PAY_ACCTCHK.pgc b/app/src/py/svc/PAY_ACCTCHK.pgc index f2ae501..1371410 100644 --- a/app/src/py/svc/PAY_ACCTCHK.pgc +++ b/app/src/py/svc/PAY_ACCTCHK.pgc @@ -132,5 +132,66 @@ void PAY_ACCTCHK(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_ACCTCHK -> LG_POST (계좌검증-원장반영) ===== + * XA 규율: tpcall 로 부르는 LG_POST 는 별도 XA 브랜치라 PAY_ACCTCHK 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_ACCTCHK", 0L); + Bchg(b, T_REASON, 0, "계좌검증-원장반영", 0L); + userlog("[PAY_ACCTCHK] 계좌검증-원장반영: 체인 호출 -> LG_POST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_ACCTCHK] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8811); + Bchg(b, T_MSG, 0, "계좌검증 원장반영(LG_POST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_ACCTCHK 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_ACCTCHK", 0L); + setl(b, T_RC, 0); + userlog("[PAY_ACCTCHK] 계좌검증-원장반영: 체인 완료 <- LG_POST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_ACCTVERIFY.pgc b/app/src/py/svc/PAY_ACCTVERIFY.pgc index 031f1bf..8ad6e27 100644 --- a/app/src/py/svc/PAY_ACCTVERIFY.pgc +++ b/app/src/py/svc/PAY_ACCTVERIFY.pgc @@ -145,5 +145,75 @@ void PAY_ACCTVERIFY(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_ACCTVERIFY -> PAY_ACCTCHK (계좌실명-계좌검증) ===== + * XA 규율: tpcall 로 부르는 PAY_ACCTCHK 는 별도 XA 브랜치라 PAY_ACCTVERIFY 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_ACCTVERIFY", 0L); + Bchg(b, T_REASON, 0, "계좌실명-계좌검증", 0L); + + { + char cx_k1[64]; + gets_(b, T_KEY1, cx_k1, sizeof(cx_k1)); + if (strlen(cx_k1) < 3) { + if (strlen(cx_mid) >= 3) Bchg(b, T_KEY1, 0, cx_mid, 0L); + else Bchg(b, T_KEY1, 0, "ACCT00000001", 0L); + } + } + userlog("[PAY_ACCTVERIFY] 계좌실명-계좌검증: 체인 호출 -> PAY_ACCTCHK pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_ACCTCHK", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_ACCTVERIFY] tpcall(PAY_ACCTCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8828); + Bchg(b, T_MSG, 0, "계좌실명 검증 체인 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_ACCTVERIFY 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_ACCTVERIFY", 0L); + setl(b, T_RC, 0); + userlog("[PAY_ACCTVERIFY] 계좌실명-계좌검증: 체인 완료 <- PAY_ACCTCHK pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_ADJUST.pgc b/app/src/py/svc/PAY_ADJUST.pgc index 19792b6..a0ff9cd 100644 --- a/app/src/py/svc/PAY_ADJUST.pgc +++ b/app/src/py/svc/PAY_ADJUST.pgc @@ -181,5 +181,71 @@ void PAY_ADJUST(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_ADJUST -> ST_ADJUST (지급조정-정산조정) ===== + * XA 규율: tpcall 로 부르는 ST_ADJUST 는 별도 XA 브랜치라 PAY_ADJUST 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_ADJUST", 0L); + Bchg(b, T_REASON, 0, "지급조정-정산조정", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[PAY_ADJUST] 지급조정-정산조정: 체인 호출 -> ST_ADJUST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("ST_ADJUST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_ADJUST] tpcall(ST_ADJUST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8820); + Bchg(b, T_MSG, 0, "지급조정 정산조정(ST_ADJUST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_ADJUST 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_ADJUST", 0L); + setl(b, T_RC, 0); + userlog("[PAY_ADJUST] 지급조정-정산조정: 체인 완료 <- ST_ADJUST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_APPRBULK.pgc b/app/src/py/svc/PAY_APPRBULK.pgc index 7d97242..e7c8d64 100644 --- a/app/src/py/svc/PAY_APPRBULK.pgc +++ b/app/src/py/svc/PAY_APPRBULK.pgc @@ -20,6 +20,7 @@ void PAY_APPRBULK(TPSVCINFO *p) long h_wlim; long h_wused; long h_waff; + long h_wfid; long h_wval; long h_wrate; char h_wst[8]; @@ -123,5 +124,102 @@ void PAY_APPRBULK(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_APPRBULK -> PAY_FILEGEN (일괄승인-지급파일생성) ===== + * XA 규율: tpcall 로 부르는 PAY_FILEGEN 는 별도 XA 브랜치라 PAY_APPRBULK 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_APPRBULK", 0L); + Bchg(b, T_REASON, 0, "일괄승인-지급파일생성", 0L); + /* 체인 표식 + 위임 편성분 전달: 방금 이 브랜치에서 'A' 로 일괄 전이한 지급건은 + * 하위(PAY_FILEGEN)의 스냅샷에 보이지 않고, 하위가 그 행들을 다시 UPDATE 하면 + * 형제 XA 브랜치끼리 미커밋 행락으로 교착된다. 따라서 승인 건수/금액만 넘기고 + * py_payout 편성 UPDATE 는 행 소유자인 이 브랜치가 복귀 후 수행한다. */ + Bchg(b, T_STR8, 0, "CHAIN", 0L); + setl(b, T_ARG7, h_waff); + setl(b, T_ARG8, h_wsum > 0 ? h_wsum : 0); + Bdel(b, T_STR7, 0); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[PAY_APPRBULK] 일괄승인-지급파일생성: 체인 호출 -> PAY_FILEGEN pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_FILEGEN", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_APPRBULK] tpcall(PAY_FILEGEN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8843); + Bchg(b, T_MSG, 0, "일괄승인 파일생성 체인 실패", 0L); + FAIL(b); + } + /* --- 위임 편성 반영부: 하위가 채번한 지급파일로의 편성을, 행 소유자인 + * 이 브랜치에서 자신이 일괄 승인한 건에 대해 단 한 번만 반영한다. --- */ + { + char dg_mk[16]; + dg_mk[0] = 0; + gets_(b, T_STR7, dg_mk, sizeof(dg_mk)); + if (strcmp(dg_mk, "FILEASSIGN") == 0) { + h_wfid = getl(b, T_ID2); + if (h_wfid > 0) { + EXEC SQL UPDATE py_payout SET file_id = :h_wfid, status = 'F', + updated_at = now() + WHERE biz_date = :h_bizdate AND status = 'A' AND net <= :h_amt1; + if (sqlca.sqlcode < 0) { + setl(b, T_RC, 53); + Bchg(b, T_MSG, 0, "일괄 지급건 파일 편성(위임) 실패", 0L); + FAIL(b); + } + userlog("[PAY_APPRBULK] 위임 편성 반영 완료 file=%ld aff=%ld", + h_wfid, (long)sqlca.sqlerrd[2]); + } + Bdel(b, T_STR7, 0); + } + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_APPRBULK 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_APPRBULK", 0L); + setl(b, T_RC, 0); + userlog("[PAY_APPRBULK] 일괄승인-지급파일생성: 체인 완료 <- PAY_FILEGEN pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_APPROVE.pgc b/app/src/py/svc/PAY_APPROVE.pgc index d69c787..46847f0 100644 --- a/app/src/py/svc/PAY_APPROVE.pgc +++ b/app/src/py/svc/PAY_APPROVE.pgc @@ -19,6 +19,7 @@ void PAY_APPROVE(TPSVCINFO *p) char h_wchan[16]; long h_wretry; long h_waff; + long h_wfid; char h_wmerch[64]; char h_wacct[64]; long h_wcnt; @@ -151,5 +152,102 @@ void PAY_APPROVE(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_APPROVE -> PAY_FILEGEN (지급승인-지급파일생성) ===== + * XA 규율: tpcall 로 부르는 PAY_FILEGEN 는 별도 XA 브랜치라 PAY_APPROVE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_APPROVE", 0L); + Bchg(b, T_REASON, 0, "지급승인-지급파일생성", 0L); + /* 체인 표식 + 위임 편성분 전달: 방금 이 브랜치에서 'A' 로 전이한 지급건은 + * 하위(PAY_FILEGEN)의 스냅샷에 보이지 않고, 하위가 그 행을 다시 UPDATE 하면 + * 형제 XA 브랜치끼리 미커밋 행락으로 교착된다. 따라서 승인 건수/금액만 넘기고 + * py_payout 편성 UPDATE 는 행 소유자인 이 브랜치가 복귀 후 수행한다. */ + Bchg(b, T_STR8, 0, "CHAIN", 0L); + setl(b, T_ARG7, h_waff); + setl(b, T_ARG8, h_wnet > 0 ? h_wnet : 0); + Bdel(b, T_STR7, 0); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[PAY_APPROVE] 지급승인-지급파일생성: 체인 호출 -> PAY_FILEGEN pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_FILEGEN", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_APPROVE] tpcall(PAY_FILEGEN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8842); + Bchg(b, T_MSG, 0, "지급승인 파일생성 체인 실패", 0L); + FAIL(b); + } + /* --- 위임 편성 반영부: 하위가 채번한 지급파일로의 편성을, 행 소유자인 + * 이 브랜치에서 자신이 승인한 건에 대해 단 한 번만 반영한다. --- */ + { + char dg_mk[16]; + dg_mk[0] = 0; + gets_(b, T_STR7, dg_mk, sizeof(dg_mk)); + if (strcmp(dg_mk, "FILEASSIGN") == 0) { + h_wfid = getl(b, T_ID2); + if (h_wfid > 0) { + EXEC SQL UPDATE py_payout SET file_id = :h_wfid, status = 'F', + updated_at = now() + WHERE payout_id = :h_id1 AND status = 'A'; + if (sqlca.sqlcode < 0) { + setl(b, T_RC, 53); + Bchg(b, T_MSG, 0, "지급건 파일 편성(위임) 실패", 0L); + FAIL(b); + } + userlog("[PAY_APPROVE] 위임 편성 반영 완료 payout=%ld file=%ld aff=%ld", + h_id1, h_wfid, (long)sqlca.sqlerrd[2]); + } + Bdel(b, T_STR7, 0); + } + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_APPROVE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_APPROVE", 0L); + setl(b, T_RC, 0); + userlog("[PAY_APPROVE] 지급승인-지급파일생성: 체인 완료 <- PAY_FILEGEN pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_BANKFILE.pgc b/app/src/py/svc/PAY_BANKFILE.pgc index 1099d99..c2673b8 100644 --- a/app/src/py/svc/PAY_BANKFILE.pgc +++ b/app/src/py/svc/PAY_BANKFILE.pgc @@ -166,5 +166,73 @@ void PAY_BANKFILE(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_BANKFILE -> MG_SEND (은행파일-이체전문송신) ===== + * XA 규율: tpcall 로 부르는 MG_SEND 는 별도 XA 브랜치라 PAY_BANKFILE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_BANKFILE", 0L); + Bchg(b, T_REASON, 0, "은행파일-이체전문송신", 0L); + + { + char cx_ch[16]; + gets_(b, T_CHANNEL, cx_ch, sizeof(cx_ch)); + if (strlen(cx_ch) < 2) Bchg(b, T_CHANNEL, 0, "CH01", 0L); + } + Bchg(b, T_STR1, 0, "0200", 0L); + userlog("[PAY_BANKFILE] 은행파일-이체전문송신: 체인 호출 -> MG_SEND pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_BANKFILE] tpcall(MG_SEND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8837); + Bchg(b, T_MSG, 0, "은행파일 전문송신(MG_SEND) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_BANKFILE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_BANKFILE", 0L); + setl(b, T_RC, 0); + userlog("[PAY_BANKFILE] 은행파일-이체전문송신: 체인 완료 <- MG_SEND pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_BANKVERIFY.pgc b/app/src/py/svc/PAY_BANKVERIFY.pgc index 6b30f5b..966f861 100644 --- a/app/src/py/svc/PAY_BANKVERIFY.pgc +++ b/app/src/py/svc/PAY_BANKVERIFY.pgc @@ -124,5 +124,75 @@ void PAY_BANKVERIFY(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_BANKVERIFY -> PAY_ACCTCHK (은행검증-계좌검증) ===== + * XA 규율: tpcall 로 부르는 PAY_ACCTCHK 는 별도 XA 브랜치라 PAY_BANKVERIFY 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_BANKVERIFY", 0L); + Bchg(b, T_REASON, 0, "은행검증-계좌검증", 0L); + + { + char cx_k1[64]; + gets_(b, T_KEY1, cx_k1, sizeof(cx_k1)); + if (strlen(cx_k1) < 3) { + if (strlen(cx_mid) >= 3) Bchg(b, T_KEY1, 0, cx_mid, 0L); + else Bchg(b, T_KEY1, 0, "ACCT00000001", 0L); + } + } + userlog("[PAY_BANKVERIFY] 은행검증-계좌검증: 체인 호출 -> PAY_ACCTCHK pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_ACCTCHK", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_BANKVERIFY] tpcall(PAY_ACCTCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8829); + Bchg(b, T_MSG, 0, "은행검증 체인 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_BANKVERIFY 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_BANKVERIFY", 0L); + setl(b, T_RC, 0); + userlog("[PAY_BANKVERIFY] 은행검증-계좌검증: 체인 완료 <- PAY_ACCTCHK pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_CANCEL.pgc b/app/src/py/svc/PAY_CANCEL.pgc index b59c995..5aa4dd5 100644 --- a/app/src/py/svc/PAY_CANCEL.pgc +++ b/app/src/py/svc/PAY_CANCEL.pgc @@ -173,5 +173,131 @@ void PAY_CANCEL(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_CANCEL -> LG_REVERSE (지급취소-원장역분개) ===== + * XA 규율: tpcall 로 부르는 LG_REVERSE 는 별도 XA 브랜치라 PAY_CANCEL 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_CANCEL", 0L); + Bchg(b, T_REASON, 0, "지급취소-원장역분개", 0L); + userlog("[PAY_CANCEL] 지급취소-원장역분개: 체인 호출 -> LG_REVERSE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_REVERSE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_CANCEL] tpcall(LG_REVERSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8814); + Bchg(b, T_MSG, 0, "지급취소 역분개(LG_REVERSE) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_CANCEL 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_CANCEL", 0L); + setl(b, T_RC, 0); + userlog("[PAY_CANCEL] 지급취소-원장역분개: 체인 완료 <- LG_REVERSE pid=%ld", cx_pid); + } + + /* ===== 8c) 업무 체인 호출부: PAY_CANCEL -> ST_ADJUST (지급취소-정산조정) ===== + * XA 규율: tpcall 로 부르는 ST_ADJUST 는 별도 XA 브랜치라 PAY_CANCEL 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_CANCEL", 0L); + Bchg(b, T_REASON, 0, "지급취소-정산조정", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[PAY_CANCEL] 지급취소-정산조정: 체인 호출 -> ST_ADJUST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("ST_ADJUST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_CANCEL] tpcall(ST_ADJUST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8815); + Bchg(b, T_MSG, 0, "지급취소 정산조정(ST_ADJUST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_CANCEL 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_CANCEL", 0L); + setl(b, T_RC, 0); + userlog("[PAY_CANCEL] 지급취소-정산조정: 체인 완료 <- ST_ADJUST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_CHARGEBACK.pgc b/app/src/py/svc/PAY_CHARGEBACK.pgc index 92776d4..fb59b6f 100644 --- a/app/src/py/svc/PAY_CHARGEBACK.pgc +++ b/app/src/py/svc/PAY_CHARGEBACK.pgc @@ -178,5 +178,66 @@ void PAY_CHARGEBACK(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_CHARGEBACK -> LG_REVERSE (지급차지백-원장역분개) ===== + * XA 규율: tpcall 로 부르는 LG_REVERSE 는 별도 XA 브랜치라 PAY_CHARGEBACK 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_CHARGEBACK", 0L); + Bchg(b, T_REASON, 0, "지급차지백-원장역분개", 0L); + userlog("[PAY_CHARGEBACK] 지급차지백-원장역분개: 체인 호출 -> LG_REVERSE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_REVERSE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_CHARGEBACK] tpcall(LG_REVERSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8845); + Bchg(b, T_MSG, 0, "지급차지백 역분개 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_CHARGEBACK 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_CHARGEBACK", 0L); + setl(b, T_RC, 0); + userlog("[PAY_CHARGEBACK] 지급차지백-원장역분개: 체인 완료 <- LG_REVERSE pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_CLOSE.pgc b/app/src/py/svc/PAY_CLOSE.pgc index 5d60f17..1f1eca8 100644 --- a/app/src/py/svc/PAY_CLOSE.pgc +++ b/app/src/py/svc/PAY_CLOSE.pgc @@ -135,5 +135,66 @@ void PAY_CLOSE(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_CLOSE -> LG_POST (지급마감-원장반영) ===== + * XA 규율: tpcall 로 부르는 LG_POST 는 별도 XA 브랜치라 PAY_CLOSE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_CLOSE", 0L); + Bchg(b, T_REASON, 0, "지급마감-원장반영", 0L); + userlog("[PAY_CLOSE] 지급마감-원장반영: 체인 호출 -> LG_POST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_CLOSE] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8848); + Bchg(b, T_MSG, 0, "지급마감 원장반영(LG_POST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_CLOSE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_CLOSE", 0L); + setl(b, T_RC, 0); + userlog("[PAY_CLOSE] 지급마감-원장반영: 체인 완료 <- LG_POST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_COMBINE.pgc b/app/src/py/svc/PAY_COMBINE.pgc index dd832d5..f942e47 100644 --- a/app/src/py/svc/PAY_COMBINE.pgc +++ b/app/src/py/svc/PAY_COMBINE.pgc @@ -180,5 +180,75 @@ void PAY_COMBINE(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_COMBINE -> PAY_ACCTCHK (지급합산-계좌검증) ===== + * XA 규율: tpcall 로 부르는 PAY_ACCTCHK 는 별도 XA 브랜치라 PAY_COMBINE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_COMBINE", 0L); + Bchg(b, T_REASON, 0, "지급합산-계좌검증", 0L); + + { + char cx_k1[64]; + gets_(b, T_KEY1, cx_k1, sizeof(cx_k1)); + if (strlen(cx_k1) < 3) { + if (strlen(cx_mid) >= 3) Bchg(b, T_KEY1, 0, cx_mid, 0L); + else Bchg(b, T_KEY1, 0, "ACCT00000001", 0L); + } + } + userlog("[PAY_COMBINE] 지급합산-계좌검증: 체인 호출 -> PAY_ACCTCHK pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_ACCTCHK", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_COMBINE] tpcall(PAY_ACCTCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8826); + Bchg(b, T_MSG, 0, "지급합산 계좌검증 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_COMBINE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_COMBINE", 0L); + setl(b, T_RC, 0); + userlog("[PAY_COMBINE] 지급합산-계좌검증: 체인 완료 <- PAY_ACCTCHK pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_CONFIRM.pgc b/app/src/py/svc/PAY_CONFIRM.pgc index 574b289..20caf99 100644 --- a/app/src/py/svc/PAY_CONFIRM.pgc +++ b/app/src/py/svc/PAY_CONFIRM.pgc @@ -144,5 +144,66 @@ void PAY_CONFIRM(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_CONFIRM -> LG_POST (지급확정-원장반영) ===== + * XA 규율: tpcall 로 부르는 LG_POST 는 별도 XA 브랜치라 PAY_CONFIRM 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_CONFIRM", 0L); + Bchg(b, T_REASON, 0, "지급확정-원장반영", 0L); + userlog("[PAY_CONFIRM] 지급확정-원장반영: 체인 호출 -> LG_POST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_CONFIRM] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8813); + Bchg(b, T_MSG, 0, "지급확정 원장반영(LG_POST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_CONFIRM 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_CONFIRM", 0L); + setl(b, T_RC, 0); + userlog("[PAY_CONFIRM] 지급확정-원장반영: 체인 완료 <- LG_POST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_FILEGEN.pgc b/app/src/py/svc/PAY_FILEGEN.pgc index e85d081..f45248c 100644 --- a/app/src/py/svc/PAY_FILEGEN.pgc +++ b/app/src/py/svc/PAY_FILEGEN.pgc @@ -33,6 +33,10 @@ void PAY_FILEGEN(TPSVCINFO *p) long h_wz2; long h_wz3; EXEC SQL END DECLARE SECTION; + /* 체인 하위 호출 표식 / 상위가 자기 브랜치에서 이미 승인(A)한 위임 편성분 */ + char ch_mark[16]; + int in_chain = 0; + long ch_pcnt = 0, ch_pamt = 0; /* 1) 입력 검증부 - 모든 입력 필드의 필수/범위/형식 검사 */ gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate)); @@ -51,6 +55,26 @@ void PAY_FILEGEN(TPSVCINFO *p) Bchg(b, T_MSG, 0, "편성 대상 집계 오류", 0L); FAIL(b); } + /* 체인 하위 호출 판별 (T_STR8 = "CHAIN"): 상위(PAY_APPROVE/PAY_APPRBULK)가 이미 + * 자기 XA 브랜치에서 py_payout 행을 'A' 로 전이해 잠근 채 이 서비스를 부른 상태다. + * 같은 글로벌 트랜잭션의 다른 XA 브랜치가 그 행을 다시 UPDATE 하면 미커밋 행락을 + * 서로 기다려 트랜잭션 타임아웃까지 교착된다. 게다가 상위의 승인분은 이 브랜치의 + * 스냅샷에 보이지 않아 위 집계에서 누락되므로 파일 헤더 수치까지 틀어진다. + * 따라서 체인 하위에서는 (1) 상위가 전문(T_ARG7/T_ARG8)으로 넘긴 승인분을 편성 + * 대상에 합산하고, (2) py_payout 행 편성 UPDATE 는 소유자(상위)에게 위임한다. + * 파일 채번/헤더 생성/정책 판정/이력 적재는 그대로 이 서비스가 수행한다. */ + gets_(b, T_STR8, ch_mark, sizeof(ch_mark)); + if (strcmp(ch_mark, "CHAIN") == 0) { + in_chain = 1; + ch_pcnt = getl(b, T_ARG7); + ch_pamt = getl(b, T_ARG8); + if (ch_pcnt < 0) ch_pcnt = 0; + if (ch_pamt < 0) ch_pamt = 0; + h_wrcnt += ch_pcnt; + h_wramt += ch_pamt; + userlog("PAY_FILEGEN 체인 하위 호출 - 상위 승인분 %ld건 %ld원 합산, py_payout 편성은 상위에 위임", + ch_pcnt, ch_pamt); + } h_whcnt = h_wrcnt; h_whamt = h_wramt; strcpy(h_wfst, "G"); strncpy(h_wfdate, h_bizdate, sizeof(h_wfdate)-1); @@ -99,15 +123,27 @@ void PAY_FILEGEN(TPSVCINFO *p) Bchg(b, T_MSG, 0, "지급파일 헤더 생성 실패", 0L); FAIL(b); } - EXEC SQL UPDATE py_payout SET file_id = :h_wnew, status = 'F', - updated_at = now() - WHERE biz_date = :h_bizdate AND status = 'A'; - if (sqlca.sqlcode < 0) { - setl(b, T_RC, 52); - Bchg(b, T_MSG, 0, "지급건 파일 편성 실패", 0L); - FAIL(b); + if (!in_chain) { + /* 행 소유자 브랜치: 당일 승인(A) 지급건을 직접 이 파일로 편성한다 */ + EXEC SQL UPDATE py_payout SET file_id = :h_wnew, status = 'F', + updated_at = now() + WHERE biz_date = :h_bizdate AND status = 'A'; + if (sqlca.sqlcode < 0) { + setl(b, T_RC, 52); + Bchg(b, T_MSG, 0, "지급건 파일 편성 실패", 0L); + FAIL(b); + } + h_waff = sqlca.sqlerrd[2]; + } else { + /* 체인 하위 브랜치: py_payout 편성 UPDATE 를 하지 않고, 채번된 파일번호를 + * 전문에 실어 소유자(상위)에게 위임한다. 상위가 tpcall 복귀 후 자기 브랜치에서 + * 자신이 승인한 행에 대해 한 번만 file_id/status='F' 를 반영한다. */ + Bchg(b, T_STR7, 0, "FILEASSIGN", 0L); + setl(b, T_ID2, h_wnew); + h_waff = ch_pcnt; + userlog("PAY_FILEGEN 체인 하위 - 파일편성(file=%ld %ld건)을 상위 소유자에 위임", + h_wnew, ch_pcnt); } - h_waff = sqlca.sqlerrd[2]; strcpy(h_lvl, "I"); snprintf(h_amsg, sizeof(h_amsg), "%s file=%ld 상세=%ld건 %ld원 반영=%ld", "PAY_FILEGEN", h_wnew, h_wrcnt, h_wramt, h_waff); EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) @@ -154,5 +190,75 @@ void PAY_FILEGEN(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_FILEGEN -> PAY_ACCTCHK (지급파일생성-계좌검증) ===== + * XA 규율: tpcall 로 부르는 PAY_ACCTCHK 는 별도 XA 브랜치라 PAY_FILEGEN 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_FILEGEN", 0L); + Bchg(b, T_REASON, 0, "지급파일생성-계좌검증", 0L); + + { + char cx_k1[64]; + gets_(b, T_KEY1, cx_k1, sizeof(cx_k1)); + if (strlen(cx_k1) < 3) { + if (strlen(cx_mid) >= 3) Bchg(b, T_KEY1, 0, cx_mid, 0L); + else Bchg(b, T_KEY1, 0, "ACCT00000001", 0L); + } + } + userlog("[PAY_FILEGEN] 지급파일생성-계좌검증: 체인 호출 -> PAY_ACCTCHK pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_ACCTCHK", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_FILEGEN] tpcall(PAY_ACCTCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8810); + Bchg(b, T_MSG, 0, "계좌검증(PAY_ACCTCHK) 체인 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_FILEGEN 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_FILEGEN", 0L); + setl(b, T_RC, 0); + userlog("[PAY_FILEGEN] 지급파일생성-계좌검증: 체인 완료 <- PAY_ACCTCHK pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_FILEREBUILD.pgc b/app/src/py/svc/PAY_FILEREBUILD.pgc index 0ca129e..fd13d29 100644 --- a/app/src/py/svc/PAY_FILEREBUILD.pgc +++ b/app/src/py/svc/PAY_FILEREBUILD.pgc @@ -136,5 +136,75 @@ void PAY_FILEREBUILD(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_FILEREBUILD -> PAY_ACCTCHK (파일재생성-계좌검증) ===== + * XA 규율: tpcall 로 부르는 PAY_ACCTCHK 는 별도 XA 브랜치라 PAY_FILEREBUILD 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_FILEREBUILD", 0L); + Bchg(b, T_REASON, 0, "파일재생성-계좌검증", 0L); + + { + char cx_k1[64]; + gets_(b, T_KEY1, cx_k1, sizeof(cx_k1)); + if (strlen(cx_k1) < 3) { + if (strlen(cx_mid) >= 3) Bchg(b, T_KEY1, 0, cx_mid, 0L); + else Bchg(b, T_KEY1, 0, "ACCT00000001", 0L); + } + } + userlog("[PAY_FILEREBUILD] 파일재생성-계좌검증: 체인 호출 -> PAY_ACCTCHK pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_ACCTCHK", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_FILEREBUILD] tpcall(PAY_ACCTCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8831); + Bchg(b, T_MSG, 0, "파일 재생성 계좌검증 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_FILEREBUILD 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_FILEREBUILD", 0L); + setl(b, T_RC, 0); + userlog("[PAY_FILEREBUILD] 파일재생성-계좌검증: 체인 완료 <- PAY_ACCTCHK pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_HOLD.pgc b/app/src/py/svc/PAY_HOLD.pgc index aeb0b1c..e62f777 100644 --- a/app/src/py/svc/PAY_HOLD.pgc +++ b/app/src/py/svc/PAY_HOLD.pgc @@ -150,5 +150,71 @@ void PAY_HOLD(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_HOLD -> ST_HOLD (지급보류-정산보류연동) ===== + * XA 규율: tpcall 로 부르는 ST_HOLD 는 별도 XA 브랜치라 PAY_HOLD 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_HOLD", 0L); + Bchg(b, T_REASON, 0, "지급보류-정산보류연동", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[PAY_HOLD] 지급보류-정산보류연동: 체인 호출 -> ST_HOLD pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("ST_HOLD", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_HOLD] tpcall(ST_HOLD) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8821); + Bchg(b, T_MSG, 0, "지급보류 정산연동(ST_HOLD) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_HOLD 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_HOLD", 0L); + setl(b, T_RC, 0); + userlog("[PAY_HOLD] 지급보류-정산보류연동: 체인 완료 <- ST_HOLD pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_MERGE.pgc b/app/src/py/svc/PAY_MERGE.pgc index ee4b40b..27961f4 100644 --- a/app/src/py/svc/PAY_MERGE.pgc +++ b/app/src/py/svc/PAY_MERGE.pgc @@ -181,5 +181,75 @@ void PAY_MERGE(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_MERGE -> PAY_ACCTCHK (지급병합-계좌검증) ===== + * XA 규율: tpcall 로 부르는 PAY_ACCTCHK 는 별도 XA 브랜치라 PAY_MERGE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_MERGE", 0L); + Bchg(b, T_REASON, 0, "지급병합-계좌검증", 0L); + + { + char cx_k1[64]; + gets_(b, T_KEY1, cx_k1, sizeof(cx_k1)); + if (strlen(cx_k1) < 3) { + if (strlen(cx_mid) >= 3) Bchg(b, T_KEY1, 0, cx_mid, 0L); + else Bchg(b, T_KEY1, 0, "ACCT00000001", 0L); + } + } + userlog("[PAY_MERGE] 지급병합-계좌검증: 체인 호출 -> PAY_ACCTCHK pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_ACCTCHK", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_MERGE] tpcall(PAY_ACCTCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8827); + Bchg(b, T_MSG, 0, "지급병합 계좌검증 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_MERGE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_MERGE", 0L); + setl(b, T_RC, 0); + userlog("[PAY_MERGE] 지급병합-계좌검증: 체인 완료 <- PAY_ACCTCHK pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_NETOFF.pgc b/app/src/py/svc/PAY_NETOFF.pgc index 7625f4e..c60ff84 100644 --- a/app/src/py/svc/PAY_NETOFF.pgc +++ b/app/src/py/svc/PAY_NETOFF.pgc @@ -172,5 +172,66 @@ void PAY_NETOFF(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_NETOFF -> LG_POST (지급상계-원장반영) ===== + * XA 규율: tpcall 로 부르는 LG_POST 는 별도 XA 브랜치라 PAY_NETOFF 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_NETOFF", 0L); + Bchg(b, T_REASON, 0, "지급상계-원장반영", 0L); + userlog("[PAY_NETOFF] 지급상계-원장반영: 체인 호출 -> LG_POST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_NETOFF] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8847); + Bchg(b, T_MSG, 0, "지급상계 원장반영(LG_POST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_NETOFF 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_NETOFF", 0L); + setl(b, T_RC, 0); + userlog("[PAY_NETOFF] 지급상계-원장반영: 체인 완료 <- LG_POST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_RECLAIM.pgc b/app/src/py/svc/PAY_RECLAIM.pgc index 1bf1827..a0e4174 100644 --- a/app/src/py/svc/PAY_RECLAIM.pgc +++ b/app/src/py/svc/PAY_RECLAIM.pgc @@ -174,5 +174,131 @@ void PAY_RECLAIM(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_RECLAIM -> LG_REVERSE (지급환수-원장역분개) ===== + * XA 규율: tpcall 로 부르는 LG_REVERSE 는 별도 XA 브랜치라 PAY_RECLAIM 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_RECLAIM", 0L); + Bchg(b, T_REASON, 0, "지급환수-원장역분개", 0L); + userlog("[PAY_RECLAIM] 지급환수-원장역분개: 체인 호출 -> LG_REVERSE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_REVERSE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_RECLAIM] tpcall(LG_REVERSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8818); + Bchg(b, T_MSG, 0, "지급환수 역분개(LG_REVERSE) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_RECLAIM 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_RECLAIM", 0L); + setl(b, T_RC, 0); + userlog("[PAY_RECLAIM] 지급환수-원장역분개: 체인 완료 <- LG_REVERSE pid=%ld", cx_pid); + } + + /* ===== 8c) 업무 체인 호출부: PAY_RECLAIM -> ST_ADJUST (지급환수-정산조정) ===== + * XA 규율: tpcall 로 부르는 ST_ADJUST 는 별도 XA 브랜치라 PAY_RECLAIM 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_RECLAIM", 0L); + Bchg(b, T_REASON, 0, "지급환수-정산조정", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[PAY_RECLAIM] 지급환수-정산조정: 체인 호출 -> ST_ADJUST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("ST_ADJUST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_RECLAIM] tpcall(ST_ADJUST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8819); + Bchg(b, T_MSG, 0, "지급환수 정산조정(ST_ADJUST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_RECLAIM 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_RECLAIM", 0L); + setl(b, T_RC, 0); + userlog("[PAY_RECLAIM] 지급환수-정산조정: 체인 완료 <- ST_ADJUST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_REFUND.pgc b/app/src/py/svc/PAY_REFUND.pgc index b6fe144..e6962d0 100644 --- a/app/src/py/svc/PAY_REFUND.pgc +++ b/app/src/py/svc/PAY_REFUND.pgc @@ -169,5 +169,66 @@ void PAY_REFUND(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_REFUND -> LG_REVERSE (지급환불-원장역분개) ===== + * XA 규율: tpcall 로 부르는 LG_REVERSE 는 별도 XA 브랜치라 PAY_REFUND 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_REFUND", 0L); + Bchg(b, T_REASON, 0, "지급환불-원장역분개", 0L); + userlog("[PAY_REFUND] 지급환불-원장역분개: 체인 호출 -> LG_REVERSE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_REVERSE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_REFUND] tpcall(LG_REVERSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8844); + Bchg(b, T_MSG, 0, "지급환불 역분개(LG_REVERSE) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_REFUND 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_REFUND", 0L); + setl(b, T_RC, 0); + userlog("[PAY_REFUND] 지급환불-원장역분개: 체인 완료 <- LG_REVERSE pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_RELEASE.pgc b/app/src/py/svc/PAY_RELEASE.pgc index a6a8862..a0f6919 100644 --- a/app/src/py/svc/PAY_RELEASE.pgc +++ b/app/src/py/svc/PAY_RELEASE.pgc @@ -151,5 +151,71 @@ void PAY_RELEASE(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_RELEASE -> ST_RELEASE (지급해제-정산해제연동) ===== + * XA 규율: tpcall 로 부르는 ST_RELEASE 는 별도 XA 브랜치라 PAY_RELEASE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_RELEASE", 0L); + Bchg(b, T_REASON, 0, "지급해제-정산해제연동", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[PAY_RELEASE] 지급해제-정산해제연동: 체인 호출 -> ST_RELEASE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("ST_RELEASE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_RELEASE] tpcall(ST_RELEASE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8822); + Bchg(b, T_MSG, 0, "지급해제 정산연동(ST_RELEASE) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_RELEASE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_RELEASE", 0L); + setl(b, T_RC, 0); + userlog("[PAY_RELEASE] 지급해제-정산해제연동: 체인 완료 <- ST_RELEASE pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_REMIT.pgc b/app/src/py/svc/PAY_REMIT.pgc index ac61eb9..4772243 100644 --- a/app/src/py/svc/PAY_REMIT.pgc +++ b/app/src/py/svc/PAY_REMIT.pgc @@ -140,5 +140,73 @@ void PAY_REMIT(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_REMIT -> MG_SEND (송금-이체전문송신) ===== + * XA 규율: tpcall 로 부르는 MG_SEND 는 별도 XA 브랜치라 PAY_REMIT 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_REMIT", 0L); + Bchg(b, T_REASON, 0, "송금-이체전문송신", 0L); + + { + char cx_ch[16]; + gets_(b, T_CHANNEL, cx_ch, sizeof(cx_ch)); + if (strlen(cx_ch) < 2) Bchg(b, T_CHANNEL, 0, "CH01", 0L); + } + Bchg(b, T_STR1, 0, "0200", 0L); + userlog("[PAY_REMIT] 송금-이체전문송신: 체인 호출 -> MG_SEND pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_REMIT] tpcall(MG_SEND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8836); + Bchg(b, T_MSG, 0, "송금 전문송신(MG_SEND) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_REMIT 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_REMIT", 0L); + setl(b, T_RC, 0); + userlog("[PAY_REMIT] 송금-이체전문송신: 체인 완료 <- MG_SEND pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_REPROC.pgc b/app/src/py/svc/PAY_REPROC.pgc index 6a9dd87..d1961e4 100644 --- a/app/src/py/svc/PAY_REPROC.pgc +++ b/app/src/py/svc/PAY_REPROC.pgc @@ -153,5 +153,71 @@ void PAY_REPROC(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_REPROC -> PAY_FAILRSN (지급재처리-실패사유확인) ===== + * XA 규율: tpcall 로 부르는 PAY_FAILRSN 는 별도 XA 브랜치라 PAY_REPROC 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_REPROC", 0L); + Bchg(b, T_REASON, 0, "지급재처리-실패사유확인", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[PAY_REPROC] 지급재처리-실패사유확인: 체인 호출 -> PAY_FAILRSN pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_FAILRSN", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_REPROC] tpcall(PAY_FAILRSN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8841); + Bchg(b, T_MSG, 0, "재처리 실패사유 확인 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_REPROC 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_REPROC", 0L); + setl(b, T_RC, 0); + userlog("[PAY_REPROC] 지급재처리-실패사유확인: 체인 완료 <- PAY_FAILRSN pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_REQUEUE.pgc b/app/src/py/svc/PAY_REQUEUE.pgc index 668a5a3..c522bbe 100644 --- a/app/src/py/svc/PAY_REQUEUE.pgc +++ b/app/src/py/svc/PAY_REQUEUE.pgc @@ -137,5 +137,73 @@ void PAY_REQUEUE(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_REQUEUE -> MG_SEND (재큐잉-이체전문재송신) ===== + * XA 규율: tpcall 로 부르는 MG_SEND 는 별도 XA 브랜치라 PAY_REQUEUE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_REQUEUE", 0L); + Bchg(b, T_REASON, 0, "재큐잉-이체전문재송신", 0L); + + { + char cx_ch[16]; + gets_(b, T_CHANNEL, cx_ch, sizeof(cx_ch)); + if (strlen(cx_ch) < 2) Bchg(b, T_CHANNEL, 0, "CH01", 0L); + } + Bchg(b, T_STR1, 0, "0200", 0L); + userlog("[PAY_REQUEUE] 재큐잉-이체전문재송신: 체인 호출 -> MG_SEND pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_REQUEUE] tpcall(MG_SEND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8838); + Bchg(b, T_MSG, 0, "재큐잉 전문 재송신(MG_SEND) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_REQUEUE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_REQUEUE", 0L); + setl(b, T_RC, 0); + userlog("[PAY_REQUEUE] 재큐잉-이체전문재송신: 체인 완료 <- MG_SEND pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_RESULT.pgc b/app/src/py/svc/PAY_RESULT.pgc index 1b8c657..926aab9 100644 --- a/app/src/py/svc/PAY_RESULT.pgc +++ b/app/src/py/svc/PAY_RESULT.pgc @@ -150,5 +150,66 @@ void PAY_RESULT(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_RESULT -> LG_POST (지급결과-원장반영) ===== + * XA 규율: tpcall 로 부르는 LG_POST 는 별도 XA 브랜치라 PAY_RESULT 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_RESULT", 0L); + Bchg(b, T_REASON, 0, "지급결과-원장반영", 0L); + userlog("[PAY_RESULT] 지급결과-원장반영: 체인 호출 -> LG_POST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_RESULT] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8812); + Bchg(b, T_MSG, 0, "지급결과 원장반영(LG_POST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_RESULT 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_RESULT", 0L); + setl(b, T_RC, 0); + userlog("[PAY_RESULT] 지급결과-원장반영: 체인 완료 <- LG_POST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_RESVMODIFY.pgc b/app/src/py/svc/PAY_RESVMODIFY.pgc index 6925e13..5988d86 100644 --- a/app/src/py/svc/PAY_RESVMODIFY.pgc +++ b/app/src/py/svc/PAY_RESVMODIFY.pgc @@ -138,5 +138,69 @@ void PAY_RESVMODIFY(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_RESVMODIFY -> CM_BIZDAY (예약변경-영업일계산) ===== + * XA 규율: tpcall 로 부르는 CM_BIZDAY 는 별도 XA 브랜치라 PAY_RESVMODIFY 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_RESVMODIFY", 0L); + Bchg(b, T_REASON, 0, "예약변경-영업일계산", 0L); + + Bchg(b, T_STR1, 0, "BIZDAY", 0L); + if (getl(b, T_ARG1) <= 0) setl(b, T_ARG1, 1); + userlog("[PAY_RESVMODIFY] 예약변경-영업일계산: 체인 호출 -> CM_BIZDAY pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("CM_BIZDAY", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_RESVMODIFY] tpcall(CM_BIZDAY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8833); + Bchg(b, T_MSG, 0, "예약변경 영업일계산 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_RESVMODIFY 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_RESVMODIFY", 0L); + setl(b, T_RC, 0); + userlog("[PAY_RESVMODIFY] 예약변경-영업일계산: 체인 완료 <- CM_BIZDAY pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_RETRY.pgc b/app/src/py/svc/PAY_RETRY.pgc index a350cfd..aaad385 100644 --- a/app/src/py/svc/PAY_RETRY.pgc +++ b/app/src/py/svc/PAY_RETRY.pgc @@ -152,5 +152,71 @@ void PAY_RETRY(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_RETRY -> PAY_FAILRSN (지급재시도-실패사유확인) ===== + * XA 규율: tpcall 로 부르는 PAY_FAILRSN 는 별도 XA 브랜치라 PAY_RETRY 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_RETRY", 0L); + Bchg(b, T_REASON, 0, "지급재시도-실패사유확인", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[PAY_RETRY] 지급재시도-실패사유확인: 체인 호출 -> PAY_FAILRSN pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_FAILRSN", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_RETRY] tpcall(PAY_FAILRSN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8839); + Bchg(b, T_MSG, 0, "실패사유 확인(PAY_FAILRSN) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_RETRY 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_RETRY", 0L); + setl(b, T_RC, 0); + userlog("[PAY_RETRY] 지급재시도-실패사유확인: 체인 완료 <- PAY_FAILRSN pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_RETRYONE.pgc b/app/src/py/svc/PAY_RETRYONE.pgc index 8805995..8ccfc1f 100644 --- a/app/src/py/svc/PAY_RETRYONE.pgc +++ b/app/src/py/svc/PAY_RETRYONE.pgc @@ -154,5 +154,71 @@ void PAY_RETRYONE(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_RETRYONE -> PAY_FAILRSN (단건재시도-실패사유확인) ===== + * XA 규율: tpcall 로 부르는 PAY_FAILRSN 는 별도 XA 브랜치라 PAY_RETRYONE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_RETRYONE", 0L); + Bchg(b, T_REASON, 0, "단건재시도-실패사유확인", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[PAY_RETRYONE] 단건재시도-실패사유확인: 체인 호출 -> PAY_FAILRSN pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_FAILRSN", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_RETRYONE] tpcall(PAY_FAILRSN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8840); + Bchg(b, T_MSG, 0, "단건 실패사유 확인 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_RETRYONE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_RETRYONE", 0L); + setl(b, T_RC, 0); + userlog("[PAY_RETRYONE] 단건재시도-실패사유확인: 체인 완료 <- PAY_FAILRSN pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_REVERSE.pgc b/app/src/py/svc/PAY_REVERSE.pgc index c2de00b..936240b 100644 --- a/app/src/py/svc/PAY_REVERSE.pgc +++ b/app/src/py/svc/PAY_REVERSE.pgc @@ -171,5 +171,131 @@ void PAY_REVERSE(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_REVERSE -> LG_REVERSE (지급반환-원장역분개) ===== + * XA 규율: tpcall 로 부르는 LG_REVERSE 는 별도 XA 브랜치라 PAY_REVERSE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_REVERSE", 0L); + Bchg(b, T_REASON, 0, "지급반환-원장역분개", 0L); + userlog("[PAY_REVERSE] 지급반환-원장역분개: 체인 호출 -> LG_REVERSE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_REVERSE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_REVERSE] tpcall(LG_REVERSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8816); + Bchg(b, T_MSG, 0, "지급반환 역분개(LG_REVERSE) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_REVERSE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_REVERSE", 0L); + setl(b, T_RC, 0); + userlog("[PAY_REVERSE] 지급반환-원장역분개: 체인 완료 <- LG_REVERSE pid=%ld", cx_pid); + } + + /* ===== 8c) 업무 체인 호출부: PAY_REVERSE -> ST_ADJUST (지급반환-정산조정) ===== + * XA 규율: tpcall 로 부르는 ST_ADJUST 는 별도 XA 브랜치라 PAY_REVERSE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_REVERSE", 0L); + Bchg(b, T_REASON, 0, "지급반환-정산조정", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[PAY_REVERSE] 지급반환-정산조정: 체인 호출 -> ST_ADJUST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("ST_ADJUST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_REVERSE] tpcall(ST_ADJUST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8817); + Bchg(b, T_MSG, 0, "지급반환 정산조정(ST_ADJUST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_REVERSE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_REVERSE", 0L); + setl(b, T_RC, 0); + userlog("[PAY_REVERSE] 지급반환-정산조정: 체인 완료 <- ST_ADJUST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_ROLLFWD.pgc b/app/src/py/svc/PAY_ROLLFWD.pgc index bba2499..4c414c4 100644 --- a/app/src/py/svc/PAY_ROLLFWD.pgc +++ b/app/src/py/svc/PAY_ROLLFWD.pgc @@ -155,5 +155,69 @@ void PAY_ROLLFWD(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_ROLLFWD -> CM_BIZDAY (지급이월-영업일계산) ===== + * XA 규율: tpcall 로 부르는 CM_BIZDAY 는 별도 XA 브랜치라 PAY_ROLLFWD 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_ROLLFWD", 0L); + Bchg(b, T_REASON, 0, "지급이월-영업일계산", 0L); + + Bchg(b, T_STR1, 0, "BIZDAY", 0L); + if (getl(b, T_ARG1) <= 0) setl(b, T_ARG1, 1); + userlog("[PAY_ROLLFWD] 지급이월-영업일계산: 체인 호출 -> CM_BIZDAY pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("CM_BIZDAY", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_ROLLFWD] tpcall(CM_BIZDAY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8834); + Bchg(b, T_MSG, 0, "지급이월 영업일계산 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_ROLLFWD 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_ROLLFWD", 0L); + setl(b, T_RC, 0); + userlog("[PAY_ROLLFWD] 지급이월-영업일계산: 체인 완료 <- CM_BIZDAY pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_SCHEDULE.pgc b/app/src/py/svc/PAY_SCHEDULE.pgc index 3cd8803..5168dff 100644 --- a/app/src/py/svc/PAY_SCHEDULE.pgc +++ b/app/src/py/svc/PAY_SCHEDULE.pgc @@ -141,5 +141,69 @@ void PAY_SCHEDULE(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_SCHEDULE -> CM_BIZDAY (지급예약-영업일계산) ===== + * XA 규율: tpcall 로 부르는 CM_BIZDAY 는 별도 XA 브랜치라 PAY_SCHEDULE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_SCHEDULE", 0L); + Bchg(b, T_REASON, 0, "지급예약-영업일계산", 0L); + + Bchg(b, T_STR1, 0, "BIZDAY", 0L); + if (getl(b, T_ARG1) <= 0) setl(b, T_ARG1, 1); + userlog("[PAY_SCHEDULE] 지급예약-영업일계산: 체인 호출 -> CM_BIZDAY pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("CM_BIZDAY", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_SCHEDULE] tpcall(CM_BIZDAY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8832); + Bchg(b, T_MSG, 0, "지급예약 영업일계산(CM_BIZDAY) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_SCHEDULE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_SCHEDULE", 0L); + setl(b, T_RC, 0); + userlog("[PAY_SCHEDULE] 지급예약-영업일계산: 체인 완료 <- CM_BIZDAY pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_SPLIT.pgc b/app/src/py/svc/PAY_SPLIT.pgc index 2991070..2649e92 100644 --- a/app/src/py/svc/PAY_SPLIT.pgc +++ b/app/src/py/svc/PAY_SPLIT.pgc @@ -226,5 +226,75 @@ void PAY_SPLIT(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_SPLIT -> PAY_ACCTCHK (분할지급-계좌검증) ===== + * XA 규율: tpcall 로 부르는 PAY_ACCTCHK 는 별도 XA 브랜치라 PAY_SPLIT 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_SPLIT", 0L); + Bchg(b, T_REASON, 0, "분할지급-계좌검증", 0L); + + { + char cx_k1[64]; + gets_(b, T_KEY1, cx_k1, sizeof(cx_k1)); + if (strlen(cx_k1) < 3) { + if (strlen(cx_mid) >= 3) Bchg(b, T_KEY1, 0, cx_mid, 0L); + else Bchg(b, T_KEY1, 0, "ACCT00000001", 0L); + } + } + userlog("[PAY_SPLIT] 분할지급-계좌검증: 체인 호출 -> PAY_ACCTCHK pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_ACCTCHK", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_SPLIT] tpcall(PAY_ACCTCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8823); + Bchg(b, T_MSG, 0, "분할지급 계좌검증 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_SPLIT 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_SPLIT", 0L); + setl(b, T_RC, 0); + userlog("[PAY_SPLIT] 분할지급-계좌검증: 체인 완료 <- PAY_ACCTCHK pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_SPLITEVEN.pgc b/app/src/py/svc/PAY_SPLITEVEN.pgc index d35c827..a1fc768 100644 --- a/app/src/py/svc/PAY_SPLITEVEN.pgc +++ b/app/src/py/svc/PAY_SPLITEVEN.pgc @@ -186,5 +186,75 @@ void PAY_SPLITEVEN(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_SPLITEVEN -> PAY_ACCTCHK (균등분할-계좌검증) ===== + * XA 규율: tpcall 로 부르는 PAY_ACCTCHK 는 별도 XA 브랜치라 PAY_SPLITEVEN 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_SPLITEVEN", 0L); + Bchg(b, T_REASON, 0, "균등분할-계좌검증", 0L); + + { + char cx_k1[64]; + gets_(b, T_KEY1, cx_k1, sizeof(cx_k1)); + if (strlen(cx_k1) < 3) { + if (strlen(cx_mid) >= 3) Bchg(b, T_KEY1, 0, cx_mid, 0L); + else Bchg(b, T_KEY1, 0, "ACCT00000001", 0L); + } + } + userlog("[PAY_SPLITEVEN] 균등분할-계좌검증: 체인 호출 -> PAY_ACCTCHK pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_ACCTCHK", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_SPLITEVEN] tpcall(PAY_ACCTCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8824); + Bchg(b, T_MSG, 0, "균등분할 계좌검증 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_SPLITEVEN 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_SPLITEVEN", 0L); + setl(b, T_RC, 0); + userlog("[PAY_SPLITEVEN] 균등분할-계좌검증: 체인 완료 <- PAY_ACCTCHK pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_SPLITRATIO.pgc b/app/src/py/svc/PAY_SPLITRATIO.pgc index 2dbd0b7..eacfebd 100644 --- a/app/src/py/svc/PAY_SPLITRATIO.pgc +++ b/app/src/py/svc/PAY_SPLITRATIO.pgc @@ -177,5 +177,75 @@ void PAY_SPLITRATIO(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_SPLITRATIO -> PAY_ACCTCHK (비율분할-계좌검증) ===== + * XA 규율: tpcall 로 부르는 PAY_ACCTCHK 는 별도 XA 브랜치라 PAY_SPLITRATIO 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_SPLITRATIO", 0L); + Bchg(b, T_REASON, 0, "비율분할-계좌검증", 0L); + + { + char cx_k1[64]; + gets_(b, T_KEY1, cx_k1, sizeof(cx_k1)); + if (strlen(cx_k1) < 3) { + if (strlen(cx_mid) >= 3) Bchg(b, T_KEY1, 0, cx_mid, 0L); + else Bchg(b, T_KEY1, 0, "ACCT00000001", 0L); + } + } + userlog("[PAY_SPLITRATIO] 비율분할-계좌검증: 체인 호출 -> PAY_ACCTCHK pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_ACCTCHK", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_SPLITRATIO] tpcall(PAY_ACCTCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8825); + Bchg(b, T_MSG, 0, "비율분할 계좌검증 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_SPLITRATIO 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_SPLITRATIO", 0L); + setl(b, T_RC, 0); + userlog("[PAY_SPLITRATIO] 비율분할-계좌검증: 체인 완료 <- PAY_ACCTCHK pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_URGENT.pgc b/app/src/py/svc/PAY_URGENT.pgc index 03305b0..5ecf98c 100644 --- a/app/src/py/svc/PAY_URGENT.pgc +++ b/app/src/py/svc/PAY_URGENT.pgc @@ -227,5 +227,75 @@ void PAY_URGENT(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_URGENT -> PAY_ACCTCHK (긴급지급-계좌검증) ===== + * XA 규율: tpcall 로 부르는 PAY_ACCTCHK 는 별도 XA 브랜치라 PAY_URGENT 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_URGENT", 0L); + Bchg(b, T_REASON, 0, "긴급지급-계좌검증", 0L); + + { + char cx_k1[64]; + gets_(b, T_KEY1, cx_k1, sizeof(cx_k1)); + if (strlen(cx_k1) < 3) { + if (strlen(cx_mid) >= 3) Bchg(b, T_KEY1, 0, cx_mid, 0L); + else Bchg(b, T_KEY1, 0, "ACCT00000001", 0L); + } + } + userlog("[PAY_URGENT] 긴급지급-계좌검증: 체인 호출 -> PAY_ACCTCHK pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_ACCTCHK", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_URGENT] tpcall(PAY_ACCTCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8830); + Bchg(b, T_MSG, 0, "긴급지급 계좌검증 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_URGENT 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_URGENT", 0L); + setl(b, T_RC, 0); + userlog("[PAY_URGENT] 긴급지급-계좌검증: 체인 완료 <- PAY_ACCTCHK pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_VOIDONE.pgc b/app/src/py/svc/PAY_VOIDONE.pgc index 4fb5866..681b38a 100644 --- a/app/src/py/svc/PAY_VOIDONE.pgc +++ b/app/src/py/svc/PAY_VOIDONE.pgc @@ -161,5 +161,66 @@ void PAY_VOIDONE(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_VOIDONE -> LG_REVERSE (지급무효-원장역분개) ===== + * XA 규율: tpcall 로 부르는 LG_REVERSE 는 별도 XA 브랜치라 PAY_VOIDONE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_VOIDONE", 0L); + Bchg(b, T_REASON, 0, "지급무효-원장역분개", 0L); + userlog("[PAY_VOIDONE] 지급무효-원장역분개: 체인 호출 -> LG_REVERSE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_REVERSE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_VOIDONE] tpcall(LG_REVERSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8846); + Bchg(b, T_MSG, 0, "지급무효 역분개(LG_REVERSE) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_VOIDONE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_VOIDONE", 0L); + setl(b, T_RC, 0); + userlog("[PAY_VOIDONE] 지급무효-원장역분개: 체인 완료 <- LG_REVERSE pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/py/svc/PAY_XFERLINK.pgc b/app/src/py/svc/PAY_XFERLINK.pgc index 550fd4e..3b83553 100644 --- a/app/src/py/svc/PAY_XFERLINK.pgc +++ b/app/src/py/svc/PAY_XFERLINK.pgc @@ -150,5 +150,73 @@ void PAY_XFERLINK(TPSVCINFO *p) Bchg(b, T_MSG, 0, "당일 지급 순액 합계가 음수 - 원장 정합 오류", 0L); FAIL(b); } + + /* ===== 8b) 업무 체인 호출부: PAY_XFERLINK -> MG_SEND (이체연계-이체전문송신) ===== + * XA 규율: tpcall 로 부르는 MG_SEND 는 별도 XA 브랜치라 PAY_XFERLINK 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "PAY_XFERLINK", 0L); + Bchg(b, T_REASON, 0, "이체연계-이체전문송신", 0L); + + { + char cx_ch[16]; + gets_(b, T_CHANNEL, cx_ch, sizeof(cx_ch)); + if (strlen(cx_ch) < 2) Bchg(b, T_CHANNEL, 0, "CH01", 0L); + } + Bchg(b, T_STR1, 0, "0200", 0L); + userlog("[PAY_XFERLINK] 이체연계-이체전문송신: 체인 호출 -> MG_SEND pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("MG_SEND", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[PAY_XFERLINK] tpcall(MG_SEND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8835); + Bchg(b, T_MSG, 0, "이체 전문송신(MG_SEND) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * PAY_XFERLINK 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "PAY_XFERLINK", 0L); + setl(b, T_RC, 0); + userlog("[PAY_XFERLINK] 이체연계-이체전문송신: 체인 완료 <- MG_SEND pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/rc/svc/RC_3WAY.pgc b/app/src/rc/svc/RC_3WAY.pgc index 4e0d965..5e3d25e 100644 --- a/app/src/rc/svc/RC_3WAY.pgc +++ b/app/src/rc/svc/RC_3WAY.pgc @@ -149,6 +149,39 @@ void RC_3WAY(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_3WAY] 승인-매입 정합성 검증 연계 -> VL_APPR_ACQ pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_APPR_ACQ", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_3WAY] tpcall(VL_APPR_ACQ) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8811); Bchg(b, T_MSG, 0, "승인-매입 정합성 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_3WAY] VL_APPR_ACQ 이상 회신 rc=%ld", ch_sub); + userlog("[RC_3WAY] 원장 3-way 대조 연계 -> LG_THREEWAY pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("LG_THREEWAY", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_3WAY] tpcall(LG_THREEWAY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8812); Bchg(b, T_MSG, 0, "원장 3-way 대조 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_3WAY] LG_THREEWAY 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_RC, rc_code); diff --git a/app/src/rc/svc/RC_4WAY.pgc b/app/src/rc/svc/RC_4WAY.pgc index 6ebbb33..e05cf25 100644 --- a/app/src/rc/svc/RC_4WAY.pgc +++ b/app/src/rc/svc/RC_4WAY.pgc @@ -149,6 +149,31 @@ void RC_4WAY(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_4WAY] 승인-매입-정산-원장 교차검증 연계 -> VL_CROSSCHK pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_CROSSCHK", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_4WAY] tpcall(VL_CROSSCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8813); Bchg(b, T_MSG, 0, "승인-매입-정산-원장 교차검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_4WAY] VL_CROSSCHK 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ID1, h_id); setl(b, T_RC, rc_code); diff --git a/app/src/rc/svc/RC_ACQMATCH.pgc b/app/src/rc/svc/RC_ACQMATCH.pgc index 905669d..88138d5 100644 --- a/app/src/rc/svc/RC_ACQMATCH.pgc +++ b/app/src/rc/svc/RC_ACQMATCH.pgc @@ -120,6 +120,31 @@ void RC_ACQMATCH(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_ACQMATCH] 매입-승인 축 교차검증 연계 -> VL_AXPURAPPR pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_AXPURAPPR", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_ACQMATCH] tpcall(VL_AXPURAPPR) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8817); Bchg(b, T_MSG, 0, "매입-승인 축 교차검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_ACQMATCH] VL_AXPURAPPR 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ARG1, matched_rows); setl(b, T_ARG2, unmatched_rows); diff --git a/app/src/rc/svc/RC_ACQ_DEP.pgc b/app/src/rc/svc/RC_ACQ_DEP.pgc index f6b54d6..ff5dc8b 100644 --- a/app/src/rc/svc/RC_ACQ_DEP.pgc +++ b/app/src/rc/svc/RC_ACQ_DEP.pgc @@ -149,6 +149,31 @@ void RC_ACQ_DEP(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_ACQ_DEP] 원장 정합성 검증 연계 -> VL_LEDGER pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_LEDGER", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_ACQ_DEP] tpcall(VL_LEDGER) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8818); Bchg(b, T_MSG, 0, "원장 정합성 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_ACQ_DEP] VL_LEDGER 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_GROSS, h_gross); setl(b, T_RC, rc_code); diff --git a/app/src/rc/svc/RC_ALERT.pgc b/app/src/rc/svc/RC_ALERT.pgc index 071b0a1..5129965 100644 --- a/app/src/rc/svc/RC_ALERT.pgc +++ b/app/src/rc/svc/RC_ALERT.pgc @@ -60,8 +60,17 @@ void RC_ALERT(TPSVCINFO *p) INTO :h_amt, :h_fee, :h_net, :h_pstat, :h_merch, :h_channel, :h_issuer, :h_category, :h_bizdate FROM purchase WHERE purchase_id = :h_pid; if (sqlca.sqlcode == 100) { - setl(b, T_RC, 8003); Bchg(b, T_MSG, 0, "매입 원장 미존재", 0L); - userlog("[RC_ALERT] 매입 원장 미존재 pid=%ld", h_pid); FAIL(b); + /* XA 브랜치 격리: 상위(호출측) 브랜치가 방금 INSERT 한 매입 원장은 + * 아직 미커밋이라 이 브랜치에서 보이지 않는다(owner-writes 규율). + * 미존재는 정상 흐름으로 보고 요청 전문(UBF) 값으로 대사경보 등록 를 진행한다. + * 여기서 FAIL 하면 체인 전체가 롤백되므로 실패 처리하지 않는다. */ + h_amt = getl(b, T_AMOUNT); + h_fee = getl(b, T_FEE); + h_net = getl(b, T_NET); + gets_(b, T_MERCHANT, h_merch, sizeof(h_merch)); + gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate)); + strncpy(h_pstat, "A", sizeof(h_pstat) - 1); h_pstat[sizeof(h_pstat) - 1] = 0; + userlog("[RC_ALERT] 체인 신규매입(미커밋) pid=%ld — 전문값으로 진행", h_pid); } else if (sqlca.sqlcode < 0) { userlog("[RC_ALERT] 매입 조회 오류 [%d]", sqlca.sqlcode); FAIL(b); } @@ -153,6 +162,31 @@ void RC_ALERT(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_ALERT] 대사경보 통지 발송 연계 -> CM_NOTI_SEND pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("CM_NOTI_SEND", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_ALERT] tpcall(CM_NOTI_SEND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8832); Bchg(b, T_MSG, 0, "대사경보 통지 발송 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_ALERT] CM_NOTI_SEND 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ID1, h_id); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_AMTDIFF.pgc b/app/src/rc/svc/RC_AMTDIFF.pgc index ea0aa18..ee5dea1 100644 --- a/app/src/rc/svc/RC_AMTDIFF.pgc +++ b/app/src/rc/svc/RC_AMTDIFF.pgc @@ -152,6 +152,31 @@ void RC_AMTDIFF(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_AMTDIFF] 대사 금액차 검증 연계 -> VL_AMOUNT pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_AMOUNT", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_AMTDIFF] tpcall(VL_AMOUNT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8862); Bchg(b, T_MSG, 0, "대사 금액차 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_AMTDIFF] VL_AMOUNT 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_DELTA, h_diff); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_APPRGAP.pgc b/app/src/rc/svc/RC_APPRGAP.pgc index dfbf0ab..3147eea 100644 --- a/app/src/rc/svc/RC_APPRGAP.pgc +++ b/app/src/rc/svc/RC_APPRGAP.pgc @@ -124,6 +124,35 @@ void RC_APPRGAP(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + if (unmatched_rows <= 0) { + userlog("[RC_APPRGAP] 불일치 없음 — 후속 체인 생략 scan=%ld", scan_rows); + } else { + userlog("[RC_APPRGAP] 승인만 존재(매입누락) 검증 연계 -> VL_APPRNOPUR pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_APPRNOPUR", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_APPRGAP] tpcall(VL_APPRNOPUR) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8816); Bchg(b, T_MSG, 0, "승인만 존재(매입누락) 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_APPRGAP] VL_APPRNOPUR 이상 회신 rc=%ld", ch_sub); + } + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_COUNT, out_cnt); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_APPRMATCH.pgc b/app/src/rc/svc/RC_APPRMATCH.pgc index fe48f50..3584e22 100644 --- a/app/src/rc/svc/RC_APPRMATCH.pgc +++ b/app/src/rc/svc/RC_APPRMATCH.pgc @@ -120,6 +120,31 @@ void RC_APPRMATCH(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_APPRMATCH] 승인 참조무결성 검증 연계 -> VL_RIAPPR pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_RIAPPR", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_APPRMATCH] tpcall(VL_RIAPPR) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8815); Bchg(b, T_MSG, 0, "승인 참조무결성 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_APPRMATCH] VL_RIAPPR 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ARG1, matched_rows); setl(b, T_ARG2, unmatched_rows); diff --git a/app/src/rc/svc/RC_APPR_ACQ.pgc b/app/src/rc/svc/RC_APPR_ACQ.pgc index 645b30e..357071c 100644 --- a/app/src/rc/svc/RC_APPR_ACQ.pgc +++ b/app/src/rc/svc/RC_APPR_ACQ.pgc @@ -149,6 +149,31 @@ void RC_APPR_ACQ(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_APPR_ACQ] 승인금액 대 매입금액 검증 연계 -> VL_APPRAMT pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_APPRAMT", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_APPR_ACQ] tpcall(VL_APPRAMT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8814); Bchg(b, T_MSG, 0, "승인금액 대 매입금액 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_APPR_ACQ] VL_APPRAMT 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ID1, h_id); setl(b, T_RC, rc_code); diff --git a/app/src/rc/svc/RC_AUTOFIX.pgc b/app/src/rc/svc/RC_AUTOFIX.pgc index 2f6ac30..574cfe1 100644 --- a/app/src/rc/svc/RC_AUTOFIX.pgc +++ b/app/src/rc/svc/RC_AUTOFIX.pgc @@ -149,6 +149,35 @@ void RC_AUTOFIX(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + if (unmatched_rows <= 0) { + userlog("[RC_AUTOFIX] 불일치 없음 — 후속 체인 생략 scan=%ld", scan_rows); + } else { + userlog("[RC_AUTOFIX] 자동보정 결과 원장 전기 연계 -> LG_POST pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_AUTOFIX] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8821); Bchg(b, T_MSG, 0, "자동보정 결과 원장 전기 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_AUTOFIX] LG_POST 이상 회신 rc=%ld", ch_sub); + } + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_CLOSEDAY.pgc b/app/src/rc/svc/RC_CLOSEDAY.pgc index d36b4c5..320df94 100644 --- a/app/src/rc/svc/RC_CLOSEDAY.pgc +++ b/app/src/rc/svc/RC_CLOSEDAY.pgc @@ -123,6 +123,31 @@ void RC_CLOSEDAY(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_CLOSEDAY] 일마감 정산배치 잠금 연계 -> ST_LOCKBATCH pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("ST_LOCKBATCH", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_CLOSEDAY] tpcall(ST_LOCKBATCH) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8872); Bchg(b, T_MSG, 0, "일마감 정산배치 잠금 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_CLOSEDAY] ST_LOCKBATCH 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ARG1, matched_rows); setl(b, T_ARG2, unmatched_rows); diff --git a/app/src/rc/svc/RC_CNTDIFF.pgc b/app/src/rc/svc/RC_CNTDIFF.pgc index 6fe4099..a931043 100644 --- a/app/src/rc/svc/RC_CNTDIFF.pgc +++ b/app/src/rc/svc/RC_CNTDIFF.pgc @@ -126,6 +126,31 @@ void RC_CNTDIFF(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_CNTDIFF] 건수 합계 검증 연계 -> VL_SUMTXNCNT pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_SUMTXNCNT", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_CNTDIFF] tpcall(VL_SUMTXNCNT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8887); Bchg(b, T_MSG, 0, "건수 합계 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_CNTDIFF] VL_SUMTXNCNT 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_COUNT, out_cnt); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_CONFIRM.pgc b/app/src/rc/svc/RC_CONFIRM.pgc index fa0debc..7bde479 100644 --- a/app/src/rc/svc/RC_CONFIRM.pgc +++ b/app/src/rc/svc/RC_CONFIRM.pgc @@ -126,6 +126,31 @@ void RC_CONFIRM(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_CONFIRM] 대사확정에 따른 정산 상태 확정 연계 -> ST_STATUS pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("ST_STATUS", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_CONFIRM] tpcall(ST_STATUS) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8871); Bchg(b, T_MSG, 0, "대사확정에 따른 정산 상태 확정 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_CONFIRM] ST_STATUS 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ Bchg(b, T_STATUS, 0, h_status, 0L); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_DEPGAP.pgc b/app/src/rc/svc/RC_DEPGAP.pgc index 373aa82..0371b2c 100644 --- a/app/src/rc/svc/RC_DEPGAP.pgc +++ b/app/src/rc/svc/RC_DEPGAP.pgc @@ -124,6 +124,35 @@ void RC_DEPGAP(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + if (unmatched_rows <= 0) { + userlog("[RC_DEPGAP] 불일치 없음 — 후속 체인 생략 scan=%ld", scan_rows); + } else { + userlog("[RC_DEPGAP] 입금 미도래 구간 검증 연계 -> VL_AXSETTPAY pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_AXSETTPAY", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_DEPGAP] tpcall(VL_AXSETTPAY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8893); Bchg(b, T_MSG, 0, "입금 미도래 구간 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_DEPGAP] VL_AXSETTPAY 이상 회신 rc=%ld", ch_sub); + } + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_COUNT, out_cnt); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_DEPMATCH.pgc b/app/src/rc/svc/RC_DEPMATCH.pgc index dbe1048..7a0d541 100644 --- a/app/src/rc/svc/RC_DEPMATCH.pgc +++ b/app/src/rc/svc/RC_DEPMATCH.pgc @@ -147,6 +147,31 @@ void RC_DEPMATCH(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_DEPMATCH] 정산-지급 축 대사 검증 연계 -> VL_AXSETTPAY pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_AXSETTPAY", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_DEPMATCH] tpcall(VL_AXSETTPAY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8891); Bchg(b, T_MSG, 0, "정산-지급 축 대사 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_DEPMATCH] VL_AXSETTPAY 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_AMT1, h_gross); setl(b, T_AMT2, h_net); diff --git a/app/src/rc/svc/RC_DUPCHK.pgc b/app/src/rc/svc/RC_DUPCHK.pgc index 9c69f43..5204b4d 100644 --- a/app/src/rc/svc/RC_DUPCHK.pgc +++ b/app/src/rc/svc/RC_DUPCHK.pgc @@ -129,6 +129,31 @@ void RC_DUPCHK(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_DUPCHK] 중복대사 감사적재 연계 -> CM_LOG pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_DUPCHK] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8837); Bchg(b, T_MSG, 0, "중복대사 감사적재 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_DUPCHK] CM_LOG 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_COUNT, out_cnt); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_ESCALATE.pgc b/app/src/rc/svc/RC_ESCALATE.pgc index 5d9659a..acd1b58 100644 --- a/app/src/rc/svc/RC_ESCALATE.pgc +++ b/app/src/rc/svc/RC_ESCALATE.pgc @@ -129,6 +129,31 @@ void RC_ESCALATE(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_ESCALATE] 예외 상향 통지이력 적재 연계 -> CM_NOTI_HIST pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("CM_NOTI_HIST", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_ESCALATE] tpcall(CM_NOTI_HIST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8833); Bchg(b, T_MSG, 0, "예외 상향 통지이력 적재 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_ESCALATE] CM_NOTI_HIST 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_COUNT, out_cnt); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_EXCEPTION.pgc b/app/src/rc/svc/RC_EXCEPTION.pgc index c175062..6407183 100644 --- a/app/src/rc/svc/RC_EXCEPTION.pgc +++ b/app/src/rc/svc/RC_EXCEPTION.pgc @@ -58,8 +58,17 @@ void RC_EXCEPTION(TPSVCINFO *p) INTO :h_amt, :h_fee, :h_net, :h_pstat, :h_merch, :h_channel, :h_issuer, :h_category, :h_bizdate FROM purchase WHERE purchase_id = :h_pid; if (sqlca.sqlcode == 100) { - setl(b, T_RC, 8003); Bchg(b, T_MSG, 0, "매입 원장 미존재", 0L); - userlog("[RC_EXCEPTION] 매입 원장 미존재 pid=%ld", h_pid); FAIL(b); + /* XA 브랜치 격리: 상위(호출측) 브랜치가 방금 INSERT 한 매입 원장은 + * 아직 미커밋이라 이 브랜치에서 보이지 않는다(owner-writes 규율). + * 미존재는 정상 흐름으로 보고 요청 전문(UBF) 값으로 대사예외 등록 를 진행한다. + * 여기서 FAIL 하면 체인 전체가 롤백되므로 실패 처리하지 않는다. */ + h_amt = getl(b, T_AMOUNT); + h_fee = getl(b, T_FEE); + h_net = getl(b, T_NET); + gets_(b, T_MERCHANT, h_merch, sizeof(h_merch)); + gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate)); + strncpy(h_pstat, "A", sizeof(h_pstat) - 1); h_pstat[sizeof(h_pstat) - 1] = 0; + userlog("[RC_EXCEPTION] 체인 신규매입(미커밋) pid=%ld — 전문값으로 진행", h_pid); } else if (sqlca.sqlcode < 0) { userlog("[RC_EXCEPTION] 매입 조회 오류 [%d]", sqlca.sqlcode); FAIL(b); } @@ -146,6 +155,31 @@ void RC_EXCEPTION(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_EXCEPTION] 대사예외 공통 감사적재 연계 -> CM_LOG pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_EXCEPTION] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8831); Bchg(b, T_MSG, 0, "대사예외 공통 감사적재 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_EXCEPTION] CM_LOG 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ID1, h_id); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_EXCNOTIFY.pgc b/app/src/rc/svc/RC_EXCNOTIFY.pgc index f9da1e2..ab5500a 100644 --- a/app/src/rc/svc/RC_EXCNOTIFY.pgc +++ b/app/src/rc/svc/RC_EXCNOTIFY.pgc @@ -129,6 +129,31 @@ void RC_EXCNOTIFY(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_EXCNOTIFY] 예외 통지 발송 연계 -> CM_NOTI_SEND pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("CM_NOTI_SEND", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_EXCNOTIFY] tpcall(CM_NOTI_SEND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8834); Bchg(b, T_MSG, 0, "예외 통지 발송 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_EXCNOTIFY] CM_NOTI_SEND 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_COUNT, out_cnt); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_FEEDIFF.pgc b/app/src/rc/svc/RC_FEEDIFF.pgc index f3b6bd1..cb1f751 100644 --- a/app/src/rc/svc/RC_FEEDIFF.pgc +++ b/app/src/rc/svc/RC_FEEDIFF.pgc @@ -126,6 +126,31 @@ void RC_FEEDIFF(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_FEEDIFF] 수수료 정합성 검증 연계 -> VL_FEE pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_FEE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_FEEDIFF] tpcall(VL_FEE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8881); Bchg(b, T_MSG, 0, "수수료 정합성 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_FEEDIFF] VL_FEE 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_COUNT, out_cnt); setl(b, T_DELTA, h_diff); diff --git a/app/src/rc/svc/RC_FEERECON.pgc b/app/src/rc/svc/RC_FEERECON.pgc index 8af462e..010c445 100644 --- a/app/src/rc/svc/RC_FEERECON.pgc +++ b/app/src/rc/svc/RC_FEERECON.pgc @@ -147,6 +147,31 @@ void RC_FEERECON(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_FEERECON] 수수료 합계 검증 연계 -> VL_SUMFEECHK pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_SUMFEECHK", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_FEERECON] tpcall(VL_SUMFEECHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8882); Bchg(b, T_MSG, 0, "수수료 합계 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_FEERECON] VL_SUMFEECHK 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_DELTA, h_diff); setl(b, T_FEE, h_fee); diff --git a/app/src/rc/svc/RC_FIXFEE.pgc b/app/src/rc/svc/RC_FIXFEE.pgc index a594f15..5c66bb1 100644 --- a/app/src/rc/svc/RC_FIXFEE.pgc +++ b/app/src/rc/svc/RC_FIXFEE.pgc @@ -141,6 +141,35 @@ void RC_FIXFEE(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + if (unmatched_rows <= 0) { + userlog("[RC_FIXFEE] 불일치 없음 — 후속 체인 생략 scan=%ld", scan_rows); + } else { + userlog("[RC_FIXFEE] 보정 후 가맹점 요율 재확인 연계 -> ST_MERCHRATE pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("ST_MERCHRATE", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_FIXFEE] tpcall(ST_MERCHRATE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8824); Bchg(b, T_MSG, 0, "보정 후 가맹점 요율 재확인 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_FIXFEE] ST_MERCHRATE 이상 회신 rc=%ld", ch_sub); + } + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ARG1, matched_rows); setl(b, T_DELTA, h_diff); diff --git a/app/src/rc/svc/RC_FIXFX.pgc b/app/src/rc/svc/RC_FIXFX.pgc index 793f0ef..6272848 100644 --- a/app/src/rc/svc/RC_FIXFX.pgc +++ b/app/src/rc/svc/RC_FIXFX.pgc @@ -141,6 +141,35 @@ void RC_FIXFX(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + if (unmatched_rows <= 0) { + userlog("[RC_FIXFX] 불일치 없음 — 후속 체인 생략 scan=%ld", scan_rows); + } else { + userlog("[RC_FIXFX] 환산 재계산 연계 -> CM_FX_CONV pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("CM_FX_CONV", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_FIXFX] tpcall(CM_FX_CONV) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8826); Bchg(b, T_MSG, 0, "환산 재계산 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_FIXFX] CM_FX_CONV 이상 회신 rc=%ld", ch_sub); + } + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ARG1, matched_rows); setl(b, T_ARG2, unmatched_rows); diff --git a/app/src/rc/svc/RC_FIXROUND.pgc b/app/src/rc/svc/RC_FIXROUND.pgc index c992c2b..1eb5e8b 100644 --- a/app/src/rc/svc/RC_FIXROUND.pgc +++ b/app/src/rc/svc/RC_FIXROUND.pgc @@ -120,6 +120,35 @@ void RC_FIXROUND(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + if (unmatched_rows <= 0) { + userlog("[RC_FIXROUND] 불일치 없음 — 후속 체인 생략 scan=%ld", scan_rows); + } else { + userlog("[RC_FIXROUND] 라운딩 규칙 재적용 연계 -> CM_AMT_ROUND pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("CM_AMT_ROUND", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_FIXROUND] tpcall(CM_AMT_ROUND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8825); Bchg(b, T_MSG, 0, "라운딩 규칙 재적용 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_FIXROUND] CM_AMT_ROUND 이상 회신 rc=%ld", ch_sub); + } + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_COUNT, out_cnt); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_FXDIFF.pgc b/app/src/rc/svc/RC_FXDIFF.pgc index 8d14801..8339d68 100644 --- a/app/src/rc/svc/RC_FXDIFF.pgc +++ b/app/src/rc/svc/RC_FXDIFF.pgc @@ -126,6 +126,31 @@ void RC_FXDIFF(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_FXDIFF] 환율 적용 검증 연계 -> VL_FXCHK pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_FXCHK", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_FXDIFF] tpcall(VL_FXCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8883); Bchg(b, T_MSG, 0, "환율 적용 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_FXDIFF] VL_FXCHK 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ARG1, matched_rows); setl(b, T_ARG2, unmatched_rows); diff --git a/app/src/rc/svc/RC_FXRECON.pgc b/app/src/rc/svc/RC_FXRECON.pgc index eb98e38..77157dc 100644 --- a/app/src/rc/svc/RC_FXRECON.pgc +++ b/app/src/rc/svc/RC_FXRECON.pgc @@ -147,6 +147,31 @@ void RC_FXRECON(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_FXRECON] 환산금액 재계산 대조 연계 -> CM_FX_CONV pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("CM_FX_CONV", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_FXRECON] tpcall(CM_FX_CONV) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8884); Bchg(b, T_MSG, 0, "환산금액 재계산 대조 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_FXRECON] CM_FX_CONV 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_AMT1, h_gross); setl(b, T_AMT2, h_net); diff --git a/app/src/rc/svc/RC_HOLDCLR.pgc b/app/src/rc/svc/RC_HOLDCLR.pgc index 323163e..b7eed61 100644 --- a/app/src/rc/svc/RC_HOLDCLR.pgc +++ b/app/src/rc/svc/RC_HOLDCLR.pgc @@ -145,6 +145,31 @@ void RC_HOLDCLR(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_HOLDCLR] 보류해제 정산 잠금해제 연계 -> ST_UNLOCK pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("ST_UNLOCK", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_HOLDCLR] tpcall(ST_UNLOCK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8874); Bchg(b, T_MSG, 0, "보류해제 정산 잠금해제 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_HOLDCLR] ST_UNLOCK 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_COUNT, out_cnt); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_HOLDSET.pgc b/app/src/rc/svc/RC_HOLDSET.pgc index dd488fb..3ed818d 100644 --- a/app/src/rc/svc/RC_HOLDSET.pgc +++ b/app/src/rc/svc/RC_HOLDSET.pgc @@ -146,6 +146,31 @@ void RC_HOLDSET(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_HOLDSET] 대사보류 정산 보류금액 반영 연계 -> ST_HOLDAMT pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("ST_HOLDAMT", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_HOLDSET] tpcall(ST_HOLDAMT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8873); Bchg(b, T_MSG, 0, "대사보류 정산 보류금액 반영 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_HOLDSET] ST_HOLDAMT 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ID1, h_id); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_LEDGERBAL.pgc b/app/src/rc/svc/RC_LEDGERBAL.pgc index 4af5c1a..e34390a 100644 --- a/app/src/rc/svc/RC_LEDGERBAL.pgc +++ b/app/src/rc/svc/RC_LEDGERBAL.pgc @@ -120,6 +120,31 @@ void RC_LEDGERBAL(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_LEDGERBAL] 원장 잔액 검증 연계 -> LG_BALCHK pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_LEDGERBAL] tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8842); Bchg(b, T_MSG, 0, "원장 잔액 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_LEDGERBAL] LG_BALCHK 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ARG1, matched_rows); setl(b, T_ARG2, unmatched_rows); diff --git a/app/src/rc/svc/RC_LEDGERLINK.pgc b/app/src/rc/svc/RC_LEDGERLINK.pgc index 05ad160..7b30c7a 100644 --- a/app/src/rc/svc/RC_LEDGERLINK.pgc +++ b/app/src/rc/svc/RC_LEDGERLINK.pgc @@ -146,6 +146,31 @@ void RC_LEDGERLINK(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_LEDGERLINK] 대사확정 원장 전기 연계 -> LG_POST pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_LEDGERLINK] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8841); Bchg(b, T_MSG, 0, "대사확정 원장 전기 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_LEDGERLINK] LG_POST 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_LIMITCHK.pgc b/app/src/rc/svc/RC_LIMITCHK.pgc index b0ec65c..c089e1f 100644 --- a/app/src/rc/svc/RC_LIMITCHK.pgc +++ b/app/src/rc/svc/RC_LIMITCHK.pgc @@ -133,6 +133,31 @@ void RC_LIMITCHK(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_LIMITCHK] 가맹점 한도 확인 연계 -> LIMIT_CHK pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("LIMIT_CHK", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_LIMITCHK] tpcall(LIMIT_CHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8896); Bchg(b, T_MSG, 0, "가맹점 한도 확인 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_LIMITCHK] LIMIT_CHK 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_AMT1, h_gross); setl(b, T_AMT2, h_net); diff --git a/app/src/rc/svc/RC_MANUAL.pgc b/app/src/rc/svc/RC_MANUAL.pgc index 0159ee6..ecffe3c 100644 --- a/app/src/rc/svc/RC_MANUAL.pgc +++ b/app/src/rc/svc/RC_MANUAL.pgc @@ -149,6 +149,31 @@ void RC_MANUAL(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_MANUAL] 수동대사 결과 원장 전기 연계 -> LG_POST pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_MANUAL] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8822); Bchg(b, T_MSG, 0, "수동대사 결과 원장 전기 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_MANUAL] LG_POST 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ID1, h_id); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_NOTIFY.pgc b/app/src/rc/svc/RC_NOTIFY.pgc index 4733710..56691f7 100644 --- a/app/src/rc/svc/RC_NOTIFY.pgc +++ b/app/src/rc/svc/RC_NOTIFY.pgc @@ -129,6 +129,31 @@ void RC_NOTIFY(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_NOTIFY] 대사결과 통지 연계 -> CM_NOTI_SEND pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("CM_NOTI_SEND", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_NOTIFY] tpcall(CM_NOTI_SEND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8835); Bchg(b, T_MSG, 0, "대사결과 통지 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_NOTIFY] CM_NOTI_SEND 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ARG1, matched_rows); setl(b, T_ARG2, unmatched_rows); diff --git a/app/src/rc/svc/RC_ORPHAN.pgc b/app/src/rc/svc/RC_ORPHAN.pgc index c9f29b1..a6cf563 100644 --- a/app/src/rc/svc/RC_ORPHAN.pgc +++ b/app/src/rc/svc/RC_ORPHAN.pgc @@ -124,6 +124,35 @@ void RC_ORPHAN(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + if (unmatched_rows <= 0) { + userlog("[RC_ORPHAN] 불일치 없음 — 후속 체인 생략 scan=%ld", scan_rows); + } else { + userlog("[RC_ORPHAN] 무승인 매입(고아거래) 검증 연계 -> VL_PURNOAPPR pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_PURNOAPPR", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_ORPHAN] tpcall(VL_PURNOAPPR) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8895); Bchg(b, T_MSG, 0, "무승인 매입(고아거래) 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_ORPHAN] VL_PURNOAPPR 이상 회신 rc=%ld", ch_sub); + } + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_COUNT, out_cnt); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_OVERAMT.pgc b/app/src/rc/svc/RC_OVERAMT.pgc index 39487eb..52b852e 100644 --- a/app/src/rc/svc/RC_OVERAMT.pgc +++ b/app/src/rc/svc/RC_OVERAMT.pgc @@ -120,6 +120,35 @@ void RC_OVERAMT(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + if (unmatched_rows <= 0) { + userlog("[RC_OVERAMT] 불일치 없음 — 후속 체인 생략 scan=%ld", scan_rows); + } else { + userlog("[RC_OVERAMT] 초과금액 검증 연계 -> VL_AMOUNT pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_AMOUNT", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_OVERAMT] tpcall(VL_AMOUNT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8863); Bchg(b, T_MSG, 0, "초과금액 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_OVERAMT] VL_AMOUNT 이상 회신 rc=%ld", ch_sub); + } + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_COUNT, out_cnt); setl(b, T_DELTA, h_diff); diff --git a/app/src/rc/svc/RC_PAYLEDGER.pgc b/app/src/rc/svc/RC_PAYLEDGER.pgc index dea67e4..caa82be 100644 --- a/app/src/rc/svc/RC_PAYLEDGER.pgc +++ b/app/src/rc/svc/RC_PAYLEDGER.pgc @@ -120,6 +120,31 @@ void RC_PAYLEDGER(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_PAYLEDGER] 지급대사 원장 전기 연계 -> LG_POST pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_PAYLEDGER] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8843); Bchg(b, T_MSG, 0, "지급대사 원장 전기 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_PAYLEDGER] LG_POST 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ARG1, matched_rows); setl(b, T_DELTA, h_diff); diff --git a/app/src/rc/svc/RC_PAYMATCH.pgc b/app/src/rc/svc/RC_PAYMATCH.pgc index 55b612d..45b65d3 100644 --- a/app/src/rc/svc/RC_PAYMATCH.pgc +++ b/app/src/rc/svc/RC_PAYMATCH.pgc @@ -147,6 +147,31 @@ void RC_PAYMATCH(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_PAYMATCH] 지급 참조무결성 검증 연계 -> VL_RIPAY pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_RIPAY", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_PAYMATCH] tpcall(VL_RIPAY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8892); Bchg(b, T_MSG, 0, "지급 참조무결성 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_PAYMATCH] VL_RIPAY 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_DELTA, h_diff); setl(b, T_ID1, h_id); diff --git a/app/src/rc/svc/RC_PROGRESS.pgc b/app/src/rc/svc/RC_PROGRESS.pgc index f895ebe..cc1de9f 100644 --- a/app/src/rc/svc/RC_PROGRESS.pgc +++ b/app/src/rc/svc/RC_PROGRESS.pgc @@ -120,6 +120,31 @@ void RC_PROGRESS(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_PROGRESS] 대사 진행상태 조회 연계 -> CM_STATUS pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("CM_STATUS", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_PROGRESS] tpcall(CM_STATUS) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8898); Bchg(b, T_MSG, 0, "대사 진행상태 조회 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_PROGRESS] CM_STATUS 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_RC, rc_code); diff --git a/app/src/rc/svc/RC_RECORR.pgc b/app/src/rc/svc/RC_RECORR.pgc index 000cbcf..b285884 100644 --- a/app/src/rc/svc/RC_RECORR.pgc +++ b/app/src/rc/svc/RC_RECORR.pgc @@ -144,6 +144,35 @@ void RC_RECORR(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + if (unmatched_rows <= 0) { + userlog("[RC_RECORR] 불일치 없음 — 후속 체인 생략 scan=%ld", scan_rows); + } else { + userlog("[RC_RECORR] 재보정 원장 조정 전기 연계 -> LG_ADJUST pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("LG_ADJUST", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_RECORR] tpcall(LG_ADJUST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8823); Bchg(b, T_MSG, 0, "재보정 원장 조정 전기 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_RECORR] LG_ADJUST 이상 회신 rc=%ld", ch_sub); + } + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_NET, h_net); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_REDIFF.pgc b/app/src/rc/svc/RC_REDIFF.pgc index db75cb6..00dde1a 100644 --- a/app/src/rc/svc/RC_REDIFF.pgc +++ b/app/src/rc/svc/RC_REDIFF.pgc @@ -147,6 +147,35 @@ void RC_REDIFF(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + if (unmatched_rows <= 0) { + userlog("[RC_REDIFF] 불일치 없음 — 후속 체인 생략 scan=%ld", scan_rows); + } else { + userlog("[RC_REDIFF] 재산출 차액 금액 검증 연계 -> VL_AMOUNT pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_AMOUNT", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_REDIFF] tpcall(VL_AMOUNT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8854); Bchg(b, T_MSG, 0, "재산출 차액 금액 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_REDIFF] VL_AMOUNT 이상 회신 rc=%ld", ch_sub); + } + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_DELTA, h_diff); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_REFULL.pgc b/app/src/rc/svc/RC_REFULL.pgc index aa7ef19..aa689a2 100644 --- a/app/src/rc/svc/RC_REFULL.pgc +++ b/app/src/rc/svc/RC_REFULL.pgc @@ -120,6 +120,31 @@ void RC_REFULL(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_REFULL] 전량 재대사 합계 검증 연계 -> VL_SUMRECON pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_SUMRECON", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_REFULL] tpcall(VL_SUMRECON) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8855); Bchg(b, T_MSG, 0, "전량 재대사 합계 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_REFULL] VL_SUMRECON 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ARG1, matched_rows); setl(b, T_COUNT, out_cnt); diff --git a/app/src/rc/svc/RC_RELEASE.pgc b/app/src/rc/svc/RC_RELEASE.pgc index e947555..2d401c5 100644 --- a/app/src/rc/svc/RC_RELEASE.pgc +++ b/app/src/rc/svc/RC_RELEASE.pgc @@ -126,6 +126,31 @@ void RC_RELEASE(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_RELEASE] 대사해제 후 지급상태 확인 연계 -> ST_PAYSTATUS pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("ST_PAYSTATUS", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_RELEASE] tpcall(ST_PAYSTATUS) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8875); Bchg(b, T_MSG, 0, "대사해제 후 지급상태 확인 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_RELEASE] ST_PAYSTATUS 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ Bchg(b, T_STATUS, 0, h_status, 0L); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_REMATCH.pgc b/app/src/rc/svc/RC_REMATCH.pgc index 693b6d8..e531c1c 100644 --- a/app/src/rc/svc/RC_REMATCH.pgc +++ b/app/src/rc/svc/RC_REMATCH.pgc @@ -62,8 +62,17 @@ void RC_REMATCH(TPSVCINFO *p) INTO :h_amt, :h_fee, :h_net, :h_pstat, :h_merch, :h_channel, :h_issuer, :h_category, :h_bizdate FROM purchase WHERE purchase_id = :h_pid; if (sqlca.sqlcode == 100) { - setl(b, T_RC, 8004); Bchg(b, T_MSG, 0, "매입 원장 미존재", 0L); - userlog("[RC_REMATCH] 매입 원장 미존재 pid=%ld", h_pid); FAIL(b); + /* XA 브랜치 격리: 상위(호출측) 브랜치가 방금 INSERT 한 매입 원장은 + * 아직 미커밋이라 이 브랜치에서 보이지 않는다(owner-writes 규율). + * 미존재는 정상 흐름으로 보고 요청 전문(UBF) 값으로 재대사 를 진행한다. + * 여기서 FAIL 하면 체인 전체가 롤백되므로 실패 처리하지 않는다. */ + h_amt = getl(b, T_AMOUNT); + h_fee = getl(b, T_FEE); + h_net = getl(b, T_NET); + gets_(b, T_MERCHANT, h_merch, sizeof(h_merch)); + gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate)); + strncpy(h_pstat, "A", sizeof(h_pstat) - 1); h_pstat[sizeof(h_pstat) - 1] = 0; + userlog("[RC_REMATCH] 체인 신규매입(미커밋) pid=%ld — 전문값으로 진행", h_pid); } else if (sqlca.sqlcode < 0) { userlog("[RC_REMATCH] 매입 조회 오류 [%d]", sqlca.sqlcode); FAIL(b); } @@ -148,6 +157,31 @@ void RC_REMATCH(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_REMATCH] 재대사 전 중복매입 검증 연계 -> VL_DUPPURCH pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_DUPPURCH", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_REMATCH] tpcall(VL_DUPPURCH) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8851); Bchg(b, T_MSG, 0, "재대사 전 중복매입 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_REMATCH] VL_DUPPURCH 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_REPROC.pgc b/app/src/rc/svc/RC_REPROC.pgc index 989fb92..68e576f 100644 --- a/app/src/rc/svc/RC_REPROC.pgc +++ b/app/src/rc/svc/RC_REPROC.pgc @@ -51,8 +51,17 @@ void RC_REPROC(TPSVCINFO *p) INTO :h_amt, :h_fee, :h_net, :h_pstat, :h_merch, :h_channel, :h_issuer, :h_category, :h_bizdate FROM purchase WHERE purchase_id = :h_pid; if (sqlca.sqlcode == 100) { - setl(b, T_RC, 8002); Bchg(b, T_MSG, 0, "매입 원장 미존재", 0L); - userlog("[RC_REPROC] 매입 원장 미존재 pid=%ld", h_pid); FAIL(b); + /* XA 브랜치 격리: 상위(호출측) 브랜치가 방금 INSERT 한 매입 원장은 + * 아직 미커밋이라 이 브랜치에서 보이지 않는다(owner-writes 규율). + * 미존재는 정상 흐름으로 보고 요청 전문(UBF) 값으로 재처리 를 진행한다. + * 여기서 FAIL 하면 체인 전체가 롤백되므로 실패 처리하지 않는다. */ + h_amt = getl(b, T_AMOUNT); + h_fee = getl(b, T_FEE); + h_net = getl(b, T_NET); + gets_(b, T_MERCHANT, h_merch, sizeof(h_merch)); + gets_(b, T_BIZDATE, h_bizdate, sizeof(h_bizdate)); + strncpy(h_pstat, "A", sizeof(h_pstat) - 1); h_pstat[sizeof(h_pstat) - 1] = 0; + userlog("[RC_REPROC] 체인 신규매입(미커밋) pid=%ld — 전문값으로 진행", h_pid); } else if (sqlca.sqlcode < 0) { userlog("[RC_REPROC] 매입 조회 오류 [%d]", sqlca.sqlcode); FAIL(b); } @@ -126,6 +135,31 @@ void RC_REPROC(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_REPROC] 재처리 대상 상태 검증 연계 -> VL_STATUS_CHK pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_STATUS_CHK", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_REPROC] tpcall(VL_STATUS_CHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8852); Bchg(b, T_MSG, 0, "재처리 대상 상태 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_REPROC] VL_STATUS_CHK 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ Bchg(b, T_STATUS, 0, h_status, 0L); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_RERUN.pgc b/app/src/rc/svc/RC_RERUN.pgc index 55d6ca3..0f57a11 100644 --- a/app/src/rc/svc/RC_RERUN.pgc +++ b/app/src/rc/svc/RC_RERUN.pgc @@ -121,6 +121,31 @@ void RC_RERUN(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_RERUN] 재수행 배치 정합성 검증 연계 -> VL_BATCH_CHK pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_BATCH_CHK", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_RERUN] tpcall(VL_BATCH_CHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8853); Bchg(b, T_MSG, 0, "재수행 배치 정합성 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_RERUN] VL_BATCH_CHK 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_COUNT, out_cnt); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_ROUNDDIFF.pgc b/app/src/rc/svc/RC_ROUNDDIFF.pgc index 81efebb..036de38 100644 --- a/app/src/rc/svc/RC_ROUNDDIFF.pgc +++ b/app/src/rc/svc/RC_ROUNDDIFF.pgc @@ -120,6 +120,35 @@ void RC_ROUNDDIFF(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + if (unmatched_rows <= 0) { + userlog("[RC_ROUNDDIFF] 불일치 없음 — 후속 체인 생략 scan=%ld", scan_rows); + } else { + userlog("[RC_ROUNDDIFF] 라운딩 차액 재산출 연계 -> CM_AMT_ROUND pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("CM_AMT_ROUND", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_ROUNDDIFF] tpcall(CM_AMT_ROUND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8885); Bchg(b, T_MSG, 0, "라운딩 차액 재산출 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_ROUNDDIFF] CM_AMT_ROUND 이상 회신 rc=%ld", ch_sub); + } + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_COUNT, out_cnt); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_SNAPSHOT.pgc b/app/src/rc/svc/RC_SNAPSHOT.pgc index a9ebab3..1659eb1 100644 --- a/app/src/rc/svc/RC_SNAPSHOT.pgc +++ b/app/src/rc/svc/RC_SNAPSHOT.pgc @@ -123,6 +123,31 @@ void RC_SNAPSHOT(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_SNAPSHOT] 대사 시점 분개 스냅샷 연계 -> LG_JOURNAL pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("LG_JOURNAL", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_SNAPSHOT] tpcall(LG_JOURNAL) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8844); Bchg(b, T_MSG, 0, "대사 시점 분개 스냅샷 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_SNAPSHOT] LG_JOURNAL 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ARG1, matched_rows); setl(b, T_ARG2, unmatched_rows); diff --git a/app/src/rc/svc/RC_STATUS.pgc b/app/src/rc/svc/RC_STATUS.pgc index b9558ec..3bc0f10 100644 --- a/app/src/rc/svc/RC_STATUS.pgc +++ b/app/src/rc/svc/RC_STATUS.pgc @@ -122,6 +122,31 @@ void RC_STATUS(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_STATUS] 공통 상태코드 조회 연계 -> CM_STATUS pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("CM_STATUS", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_STATUS] tpcall(CM_STATUS) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8897); Bchg(b, T_MSG, 0, "공통 상태코드 조회 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_STATUS] CM_STATUS 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ Bchg(b, T_STATUS, 0, h_status, 0L); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/rc/svc/RC_SUMCHK.pgc b/app/src/rc/svc/RC_SUMCHK.pgc index 08f774f..752931a 100644 --- a/app/src/rc/svc/RC_SUMCHK.pgc +++ b/app/src/rc/svc/RC_SUMCHK.pgc @@ -123,6 +123,31 @@ void RC_SUMCHK(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_SUMCHK] 총액 합계 검증 연계 -> VL_SUMGROSS pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_SUMGROSS", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_SUMCHK] tpcall(VL_SUMGROSS) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8886); Bchg(b, T_MSG, 0, "총액 합계 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_SUMCHK] VL_SUMGROSS 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_ARG1, matched_rows); setl(b, T_ARG2, unmatched_rows); diff --git a/app/src/rc/svc/RC_TOLERANCE.pgc b/app/src/rc/svc/RC_TOLERANCE.pgc index 2517815..53842f4 100644 --- a/app/src/rc/svc/RC_TOLERANCE.pgc +++ b/app/src/rc/svc/RC_TOLERANCE.pgc @@ -146,6 +146,31 @@ void RC_TOLERANCE(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_TOLERANCE] 허용오차 금액 검증 연계 -> VL_AMOUNT pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_AMOUNT", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_TOLERANCE] tpcall(VL_AMOUNT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8861); Bchg(b, T_MSG, 0, "허용오차 금액 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_TOLERANCE] VL_AMOUNT 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_RC, rc_code); diff --git a/app/src/rc/svc/RC_UNDERAMT.pgc b/app/src/rc/svc/RC_UNDERAMT.pgc index 9cac2a6..f6aabc7 100644 --- a/app/src/rc/svc/RC_UNDERAMT.pgc +++ b/app/src/rc/svc/RC_UNDERAMT.pgc @@ -120,6 +120,35 @@ void RC_UNDERAMT(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + if (unmatched_rows <= 0) { + userlog("[RC_UNDERAMT] 불일치 없음 — 후속 체인 생략 scan=%ld", scan_rows); + } else { + userlog("[RC_UNDERAMT] 부족금액 검증 연계 -> VL_AMOUNT pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("VL_AMOUNT", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_UNDERAMT] tpcall(VL_AMOUNT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8864); Bchg(b, T_MSG, 0, "부족금액 검증 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_UNDERAMT] VL_AMOUNT 이상 회신 rc=%ld", ch_sub); + } + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_COUNT, out_cnt); setl(b, T_DELTA, h_diff); diff --git a/app/src/rc/svc/RC_UNMATCH.pgc b/app/src/rc/svc/RC_UNMATCH.pgc index 94e0fb0..a0660a1 100644 --- a/app/src/rc/svc/RC_UNMATCH.pgc +++ b/app/src/rc/svc/RC_UNMATCH.pgc @@ -124,6 +124,31 @@ void RC_UNMATCH(TPSVCINFO *p) if (h_n1 == 0) h_n1 = matched_rows; if (h_n2 == 0) h_n2 = unmatched_rows; + /* [7-1] 후속 업무 체인 (tpcall) — CHAIN-BEGIN ----------------------- + * 하위 서비스는 별도 XA 브랜치라 이 브랜치의 미커밋 행이 보이지 않는다. + * 판단에 필요한 값은 전문(T_*)에 실어 전달하고, 응답 계약은 [8] 응답부가 + * 뒤에서 재확정한다(하위 결과코드가 기존 계약을 덮지 않도록 복원). */ + { + long ch_rlen = 0, ch_sub = 0, ch_keep = getl(b, T_RC); + long ch_pid = getl(b, T_PURCHASE_ID); + setl(b, T_AMOUNT, h_amt); setl(b, T_FEE, h_fee); setl(b, T_NET, h_net); + setl(b, T_GROSS, h_gross); setl(b, T_COUNT, scan_rows); + setl(b, T_ARG3, unmatched_rows); setl(b, T_AMT2, unmatched_amt); + setl(b, T_ARG4, rc_code); + Bchg(b, T_BIZDATE, 0, h_bizdate, 0L); + if (h_merch[0]) Bchg(b, T_MERCHANT, 0, h_merch, 0L); + Bchg(b, T_SVCNAME, 0, h_svc, 0L); + userlog("[RC_UNMATCH] 미매칭 내역 감사적재 연계 -> CM_LOG pid=%ld date=[%s]", ch_pid, h_bizdate); + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &ch_rlen, 0L) < 0) { + userlog("[RC_UNMATCH] tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8836); Bchg(b, T_MSG, 0, "미매칭 내역 감사적재 연계 실패", 0L); + FAIL(b); + } + ch_sub = getl(b, T_RC); + if (ch_sub != 0) userlog("[RC_UNMATCH] CM_LOG 이상 회신 rc=%ld", ch_sub); + setl(b, T_RC, ch_keep); /* 기존 응답 계약 복원 — [8]에서 최종 확정 */ + } + /* [8] 응답부 (출력 필드 설정) ------------------------------------- */ setl(b, T_COUNT, out_cnt); /* T_RC 미계약 서비스: 결과코드는 감사로그로만 기록 */ diff --git a/app/src/st/svc/SETTLE.pgc b/app/src/st/svc/SETTLE.pgc index ba7931c..abe99e1 100644 --- a/app/src/st/svc/SETTLE.pgc +++ b/app/src/st/svc/SETTLE.pgc @@ -34,6 +34,72 @@ void SETTLE(TPSVCINFO *p) setl(b, T_SETTLE_ID, h_sid); Bchg(b, T_STATUS, 0, "S", 0L); userlog("SETTLE pid=%ld settlement_id=%ld net=%ld", h_pid, h_sid, h_net); + + /* ===== 8b) 업무 체인 호출부: SETTLE -> ST_MDR (정산확정-수수료산출) ===== + * XA 규율: tpcall 로 부르는 ST_MDR 는 별도 XA 브랜치라 SETTLE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "SETTLE", 0L); + Bchg(b, T_REASON, 0, "정산확정-수수료산출", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[SETTLE] 정산확정-수수료산출: 체인 호출 -> ST_MDR pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("ST_MDR", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[SETTLE] tpcall(ST_MDR) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8710); + Bchg(b, T_MSG, 0, "수수료 산출 체인(ST_MDR) 호출 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * SETTLE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "SETTLE", 0L); + setl(b, T_RC, 0); + userlog("[SETTLE] 정산확정-수수료산출: 체인 완료 <- ST_MDR pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_ADJHIST.pgc b/app/src/st/svc/ST_ADJHIST.pgc index d0e496f..1f46f54 100644 --- a/app/src/st/svc/ST_ADJHIST.pgc +++ b/app/src/st/svc/ST_ADJHIST.pgc @@ -107,7 +107,7 @@ void ST_ADJHIST(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "매입별 조정 이력 요약. (심화판) [ST_ADJHIST] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_ADJREVERSE.pgc b/app/src/st/svc/ST_ADJREVERSE.pgc index 271c443..666da31 100644 --- a/app/src/st/svc/ST_ADJREVERSE.pgc +++ b/app/src/st/svc/ST_ADJREVERSE.pgc @@ -105,7 +105,7 @@ void ST_ADJREVERSE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "기존 조정을 반대부호로 상쇄. (심화판) [ST_ADJREVERSE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -130,6 +130,67 @@ void ST_ADJREVERSE(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 기존 조정을 반대부호로 상쇄. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_ADJREVERSE -> LG_REVERSE (조정취소-원장역분개) ===== + * XA 규율: tpcall 로 부르는 LG_REVERSE 는 별도 XA 브랜치라 ST_ADJREVERSE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_ADJREVERSE", 0L); + Bchg(b, T_REASON, 0, "조정취소-원장역분개", 0L); + userlog("[ST_ADJREVERSE] 조정취소-원장역분개: 체인 호출 -> LG_REVERSE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_REVERSE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_ADJREVERSE] tpcall(LG_REVERSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8720); + Bchg(b, T_MSG, 0, "조정취소 역분개(LG_REVERSE) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_ADJREVERSE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_ADJREVERSE", 0L); + setl(b, T_RC, 0); + userlog("[ST_ADJREVERSE] 조정취소-원장역분개: 체인 완료 <- LG_REVERSE pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_ADJUST.pgc b/app/src/st/svc/ST_ADJUST.pgc index fc6a776..8804d91 100644 --- a/app/src/st/svc/ST_ADJUST.pgc +++ b/app/src/st/svc/ST_ADJUST.pgc @@ -112,7 +112,7 @@ void ST_ADJUST(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 조정 (가감) 기록. (심화판) [ST_ADJUST] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -137,6 +137,67 @@ void ST_ADJUST(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 정산 조정 (가감) 기록. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_ADJUST -> LG_POST (정산조정-원장반영) ===== + * XA 규율: tpcall 로 부르는 LG_POST 는 별도 XA 브랜치라 ST_ADJUST 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_ADJUST", 0L); + Bchg(b, T_REASON, 0, "정산조정-원장반영", 0L); + userlog("[ST_ADJUST] 정산조정-원장반영: 체인 호출 -> LG_POST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_ADJUST] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8719); + Bchg(b, T_MSG, 0, "정산조정 원장반영(LG_POST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_ADJUST 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_ADJUST", 0L); + setl(b, T_RC, 0); + userlog("[ST_ADJUST] 정산조정-원장반영: 체인 완료 <- LG_POST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_ADVANCE.pgc b/app/src/st/svc/ST_ADVANCE.pgc index d86b5c2..66365b7 100644 --- a/app/src/st/svc/ST_ADVANCE.pgc +++ b/app/src/st/svc/ST_ADVANCE.pgc @@ -108,7 +108,7 @@ void ST_ADVANCE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "선지급 예약: 지급 레코드(SCHEDULED) 생성. (심화판) [ST_ADVANCE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_APPEALSTAT.pgc b/app/src/st/svc/ST_APPEALSTAT.pgc index c3304cf..39d3539 100644 --- a/app/src/st/svc/ST_APPEALSTAT.pgc +++ b/app/src/st/svc/ST_APPEALSTAT.pgc @@ -107,7 +107,7 @@ void ST_APPEALSTAT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "이의신청 조정 건수/금액 통계. (심화판) [ST_APPEALSTAT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_APPROVE.pgc b/app/src/st/svc/ST_APPROVE.pgc index 541fdb6..3b29fa8 100644 --- a/app/src/st/svc/ST_APPROVE.pgc +++ b/app/src/st/svc/ST_APPROVE.pgc @@ -118,7 +118,7 @@ void ST_APPROVE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 승인 (CONFIRMED -> APPROVED). (심화판) [ST_APPROVE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -143,6 +143,72 @@ void ST_APPROVE(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 정산 승인 (CONFIRMED -> APPROVED). (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_APPROVE -> PAY_FILEGEN (정산승인-지급파일생성) ===== + * XA 규율: tpcall 로 부르는 PAY_FILEGEN 는 별도 XA 브랜치라 ST_APPROVE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_APPROVE", 0L); + Bchg(b, T_REASON, 0, "정산승인-지급파일생성", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[ST_APPROVE] 정산승인-지급파일생성: 체인 호출 -> PAY_FILEGEN pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_FILEGEN", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_APPROVE] tpcall(PAY_FILEGEN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8715); + Bchg(b, T_MSG, 0, "지급 파일생성(PAY_FILEGEN) 트리거 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_APPROVE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_APPROVE", 0L); + setl(b, T_RC, 0); + userlog("[ST_APPROVE] 정산승인-지급파일생성: 체인 완료 <- PAY_FILEGEN pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_APPROVEALL.pgc b/app/src/st/svc/ST_APPROVEALL.pgc index 2ea0dd5..443aa1d 100644 --- a/app/src/st/svc/ST_APPROVEALL.pgc +++ b/app/src/st/svc/ST_APPROVEALL.pgc @@ -107,7 +107,7 @@ void ST_APPROVEALL(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "당일 지급 예정 일괄 승인(->PAID). (심화판) [ST_APPROVEALL] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -137,6 +137,72 @@ void ST_APPROVEALL(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 당일 지급 예정 일괄 승인(->PAID). (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_APPROVEALL -> PAY_FILEGEN (일괄승인-지급파일생성) ===== + * XA 규율: tpcall 로 부르는 PAY_FILEGEN 는 별도 XA 브랜치라 ST_APPROVEALL 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_APPROVEALL", 0L); + Bchg(b, T_REASON, 0, "일괄승인-지급파일생성", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[ST_APPROVEALL] 일괄승인-지급파일생성: 체인 호출 -> PAY_FILEGEN pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_FILEGEN", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_APPROVEALL] tpcall(PAY_FILEGEN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8716); + Bchg(b, T_MSG, 0, "일괄 지급파일 생성 트리거 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_APPROVEALL 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_APPROVEALL", 0L); + setl(b, T_RC, 0); + userlog("[ST_APPROVEALL] 일괄승인-지급파일생성: 체인 완료 <- PAY_FILEGEN pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_BADDEBT.pgc b/app/src/st/svc/ST_BADDEBT.pgc index 635125a..62f24d9 100644 --- a/app/src/st/svc/ST_BADDEBT.pgc +++ b/app/src/st/svc/ST_BADDEBT.pgc @@ -105,7 +105,7 @@ void ST_BADDEBT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "장기 미수 대손 상각(상계+취소). (심화판) [ST_BADDEBT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_BANDRATE.pgc b/app/src/st/svc/ST_BANDRATE.pgc index 202a34f..8826fd8 100644 --- a/app/src/st/svc/ST_BANDRATE.pgc +++ b/app/src/st/svc/ST_BANDRATE.pgc @@ -109,7 +109,7 @@ void ST_BANDRATE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "금액 구간 요율(bps) 조회. (심화판) [ST_BANDRATE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_BANDSIM.pgc b/app/src/st/svc/ST_BANDSIM.pgc index be79160..78837d8 100644 --- a/app/src/st/svc/ST_BANDSIM.pgc +++ b/app/src/st/svc/ST_BANDSIM.pgc @@ -109,7 +109,7 @@ void ST_BANDSIM(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "적용가능 구간 중 최고 요율 시뮬. (심화판) [ST_BANDSIM] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_BIWEEKLY.pgc b/app/src/st/svc/ST_BIWEEKLY.pgc index ce6a0f1..0a6d4c8 100644 --- a/app/src/st/svc/ST_BIWEEKLY.pgc +++ b/app/src/st/svc/ST_BIWEEKLY.pgc @@ -109,7 +109,7 @@ void ST_BIWEEKLY(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "2주 주기 net 합계 지급 예정. (심화판) [ST_BIWEEKLY] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_BYMERCH.pgc b/app/src/st/svc/ST_BYMERCH.pgc index 1fd8c99..017d776 100644 --- a/app/src/st/svc/ST_BYMERCH.pgc +++ b/app/src/st/svc/ST_BYMERCH.pgc @@ -108,7 +108,7 @@ void ST_BYMERCH(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "가맹점별 정산 집계 upsert. (심화판) [ST_BYMERCH] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_CANCEL.pgc b/app/src/st/svc/ST_CANCEL.pgc index 76eec96..673ffc2 100644 --- a/app/src/st/svc/ST_CANCEL.pgc +++ b/app/src/st/svc/ST_CANCEL.pgc @@ -120,7 +120,7 @@ void ST_CANCEL(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 취소: 상태 CANCELLED + 취소 조정. (심화판) [ST_CANCEL] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -145,6 +145,67 @@ void ST_CANCEL(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 정산 취소: 상태 CANCELLED + 취소 조정. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_CANCEL -> LG_REVERSE (정산취소-원장역분개) ===== + * XA 규율: tpcall 로 부르는 LG_REVERSE 는 별도 XA 브랜치라 ST_CANCEL 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_CANCEL", 0L); + Bchg(b, T_REASON, 0, "정산취소-원장역분개", 0L); + userlog("[ST_CANCEL] 정산취소-원장역분개: 체인 호출 -> LG_REVERSE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_REVERSE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_CANCEL] tpcall(LG_REVERSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8718); + Bchg(b, T_MSG, 0, "정산취소 역분개(LG_REVERSE) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_CANCEL 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_CANCEL", 0L); + setl(b, T_RC, 0); + userlog("[ST_CANCEL] 정산취소-원장역분개: 체인 완료 <- LG_REVERSE pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_CAP.pgc b/app/src/st/svc/ST_CAP.pgc index 21eab16..c8e8639 100644 --- a/app/src/st/svc/ST_CAP.pgc +++ b/app/src/st/svc/ST_CAP.pgc @@ -105,7 +105,7 @@ void ST_CAP(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "수수료 상한 적용: 상한 초과분을 감액 조정. (심화판) [ST_CAP] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_CAPCHECK.pgc b/app/src/st/svc/ST_CAPCHECK.pgc index cbe9337..fb7a56c 100644 --- a/app/src/st/svc/ST_CAPCHECK.pgc +++ b/app/src/st/svc/ST_CAPCHECK.pgc @@ -110,7 +110,7 @@ void ST_CAPCHECK(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "상한 초과 여부 판정 (조정 없음). (심화판) [ST_CAPCHECK] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -135,6 +135,67 @@ void ST_CAPCHECK(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 상한 초과 여부 판정 (조정 없음). (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_CAPCHECK -> VL_SETTLE (상한검증-정산검증) ===== + * XA 규율: tpcall 로 부르는 VL_SETTLE 는 별도 XA 브랜치라 ST_CAPCHECK 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_CAPCHECK", 0L); + Bchg(b, T_REASON, 0, "상한검증-정산검증", 0L); + userlog("[ST_CAPCHECK] 상한검증-정산검증: 체인 호출 -> VL_SETTLE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("VL_SETTLE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_CAPCHECK] tpcall(VL_SETTLE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8732); + Bchg(b, T_MSG, 0, "상한검증(VL_SETTLE) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_CAPCHECK 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_CAPCHECK", 0L); + setl(b, T_RC, 0); + userlog("[ST_CAPCHECK] 상한검증-정산검증: 체인 완료 <- VL_SETTLE pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_CARRYOVER.pgc b/app/src/st/svc/ST_CARRYOVER.pgc index 6fb91ae..e4020b5 100644 --- a/app/src/st/svc/ST_CARRYOVER.pgc +++ b/app/src/st/svc/ST_CARRYOVER.pgc @@ -109,7 +109,7 @@ void ST_CARRYOVER(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "미정산분 익영업일 이월 예약. (심화판) [ST_CARRYOVER] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_CASHBACK.pgc b/app/src/st/svc/ST_CASHBACK.pgc index 37a0af3..f9c6610 100644 --- a/app/src/st/svc/ST_CASHBACK.pgc +++ b/app/src/st/svc/ST_CASHBACK.pgc @@ -108,7 +108,7 @@ void ST_CASHBACK(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "캐시백 지급 예정 등록. (심화판) [ST_CASHBACK] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_CHAINSET.pgc b/app/src/st/svc/ST_CHAINSET.pgc index c3f0878..2701850 100644 --- a/app/src/st/svc/ST_CHAINSET.pgc +++ b/app/src/st/svc/ST_CHAINSET.pgc @@ -109,7 +109,7 @@ void ST_CHAINSET(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "업종 체인 통합 net 지급. (심화판) [ST_CHAINSET] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_CHARGEBACK.pgc b/app/src/st/svc/ST_CHARGEBACK.pgc index 8477953..05aa515 100644 --- a/app/src/st/svc/ST_CHARGEBACK.pgc +++ b/app/src/st/svc/ST_CHARGEBACK.pgc @@ -109,7 +109,7 @@ void ST_CHARGEBACK(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "차지백 회수 조정 + 지급 보류. (심화판) [ST_CHARGEBACK] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -139,6 +139,67 @@ void ST_CHARGEBACK(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 차지백 회수 조정 + 지급 보류. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_CHARGEBACK -> LG_REVERSE (차지백-원장역분개) ===== + * XA 규율: tpcall 로 부르는 LG_REVERSE 는 별도 XA 브랜치라 ST_CHARGEBACK 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_CHARGEBACK", 0L); + Bchg(b, T_REASON, 0, "차지백-원장역분개", 0L); + userlog("[ST_CHARGEBACK] 차지백-원장역분개: 체인 호출 -> LG_REVERSE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_REVERSE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_CHARGEBACK] tpcall(LG_REVERSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8736); + Bchg(b, T_MSG, 0, "차지백 역분개(LG_REVERSE) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_CHARGEBACK 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_CHARGEBACK", 0L); + setl(b, T_RC, 0); + userlog("[ST_CHARGEBACK] 차지백-원장역분개: 체인 완료 <- LG_REVERSE pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_CHNLSTAT.pgc b/app/src/st/svc/ST_CHNLSTAT.pgc index 8e4b0d7..e61c41c 100644 --- a/app/src/st/svc/ST_CHNLSTAT.pgc +++ b/app/src/st/svc/ST_CHNLSTAT.pgc @@ -106,7 +106,7 @@ void ST_CHNLSTAT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "채널별 정산 net 분해 통계. (심화판) [ST_CHNLSTAT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_COLLATERAL.pgc b/app/src/st/svc/ST_COLLATERAL.pgc index 833ad0e..5cbbb11 100644 --- a/app/src/st/svc/ST_COLLATERAL.pgc +++ b/app/src/st/svc/ST_COLLATERAL.pgc @@ -108,7 +108,7 @@ void ST_COLLATERAL(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "가맹점 누적 보증금 잔액 조회. (심화판) [ST_COLLATERAL] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_CONFIRM.pgc b/app/src/st/svc/ST_CONFIRM.pgc index 1f2a073..e0ae644 100644 --- a/app/src/st/svc/ST_CONFIRM.pgc +++ b/app/src/st/svc/ST_CONFIRM.pgc @@ -118,7 +118,7 @@ void ST_CONFIRM(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 확정 (SETTLED -> CONFIRMED). (심화판) [ST_CONFIRM] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -143,6 +143,72 @@ void ST_CONFIRM(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 정산 확정 (SETTLED -> CONFIRMED). (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_CONFIRM -> PAY_FILEGEN (정산확정-지급파일생성) ===== + * XA 규율: tpcall 로 부르는 PAY_FILEGEN 는 별도 XA 브랜치라 ST_CONFIRM 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_CONFIRM", 0L); + Bchg(b, T_REASON, 0, "정산확정-지급파일생성", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[ST_CONFIRM] 정산확정-지급파일생성: 체인 호출 -> PAY_FILEGEN pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_FILEGEN", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_CONFIRM] tpcall(PAY_FILEGEN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8714); + Bchg(b, T_MSG, 0, "지급 파일생성(PAY_FILEGEN) 트리거 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_CONFIRM 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_CONFIRM", 0L); + setl(b, T_RC, 0); + userlog("[ST_CONFIRM] 정산확정-지급파일생성: 체인 완료 <- PAY_FILEGEN pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_COUPONADJ.pgc b/app/src/st/svc/ST_COUPONADJ.pgc index f8c520b..86c5350 100644 --- a/app/src/st/svc/ST_COUPONADJ.pgc +++ b/app/src/st/svc/ST_COUPONADJ.pgc @@ -105,7 +105,7 @@ void ST_COUPONADJ(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "쿠폰 사용액 정산 조정(가산). (심화판) [ST_COUPONADJ] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_CXLRECALC.pgc b/app/src/st/svc/ST_CXLRECALC.pgc index 9c6c7c8..1a99238 100644 --- a/app/src/st/svc/ST_CXLRECALC.pgc +++ b/app/src/st/svc/ST_CXLRECALC.pgc @@ -120,7 +120,7 @@ void ST_CXLRECALC(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "취소 누계 반영 정산 net 재계산. (심화판) [ST_CXLRECALC] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -145,6 +145,72 @@ void ST_CXLRECALC(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 취소 누계 반영 정산 net 재계산. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_CXLRECALC -> ST_MDR (취소재계산-수수료재산출) ===== + * XA 규율: tpcall 로 부르는 ST_MDR 는 별도 XA 브랜치라 ST_CXLRECALC 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_CXLRECALC", 0L); + Bchg(b, T_REASON, 0, "취소재계산-수수료재산출", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[ST_CXLRECALC] 취소재계산-수수료재산출: 체인 호출 -> ST_MDR pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("ST_MDR", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_CXLRECALC] tpcall(ST_MDR) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8728); + Bchg(b, T_MSG, 0, "취소 재계산 수수료 재산출 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_CXLRECALC 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_CXLRECALC", 0L); + setl(b, T_RC, 0); + userlog("[ST_CXLRECALC] 취소재계산-수수료재산출: 체인 완료 <- ST_MDR pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_CYCLED1.pgc b/app/src/st/svc/ST_CYCLED1.pgc index 92322be..7c26f85 100644 --- a/app/src/st/svc/ST_CYCLED1.pgc +++ b/app/src/st/svc/ST_CYCLED1.pgc @@ -109,7 +109,7 @@ void ST_CYCLED1(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "D+1 주기 지급 예약. (심화판) [ST_CYCLED1] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_CYCLED2.pgc b/app/src/st/svc/ST_CYCLED2.pgc index c4da6a1..79a58f0 100644 --- a/app/src/st/svc/ST_CYCLED2.pgc +++ b/app/src/st/svc/ST_CYCLED2.pgc @@ -109,7 +109,7 @@ void ST_CYCLED2(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "D+2 주기 지급 예약 (확정분만). (심화판) [ST_CYCLED2] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_CYCLED3.pgc b/app/src/st/svc/ST_CYCLED3.pgc index 2869c2c..9104b76 100644 --- a/app/src/st/svc/ST_CYCLED3.pgc +++ b/app/src/st/svc/ST_CYCLED3.pgc @@ -109,7 +109,7 @@ void ST_CYCLED3(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "D+3 영업일 지급 예정 등록. (심화판) [ST_CYCLED3] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_CYCLEMON.pgc b/app/src/st/svc/ST_CYCLEMON.pgc index b082a4a..25f652d 100644 --- a/app/src/st/svc/ST_CYCLEMON.pgc +++ b/app/src/st/svc/ST_CYCLEMON.pgc @@ -109,7 +109,7 @@ void ST_CYCLEMON(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "월간 통합 지급 예약 (직접 INSERT). (심화판) [ST_CYCLEMON] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_CYCLEQTR.pgc b/app/src/st/svc/ST_CYCLEQTR.pgc index 3dfc9ff..0064ab6 100644 --- a/app/src/st/svc/ST_CYCLEQTR.pgc +++ b/app/src/st/svc/ST_CYCLEQTR.pgc @@ -109,7 +109,7 @@ void ST_CYCLEQTR(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "기준일까지 누적 net 분기 지급. (심화판) [ST_CYCLEQTR] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_CYCLESET.pgc b/app/src/st/svc/ST_CYCLESET.pgc index 5d11d08..8e2fd1f 100644 --- a/app/src/st/svc/ST_CYCLESET.pgc +++ b/app/src/st/svc/ST_CYCLESET.pgc @@ -109,7 +109,7 @@ void ST_CYCLESET(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "가맹점 한도 기반 정산주기 코드 파생. (심화판) [ST_CYCLESET] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_CYCLEWEEK.pgc b/app/src/st/svc/ST_CYCLEWEEK.pgc index e557a8b..7173e36 100644 --- a/app/src/st/svc/ST_CYCLEWEEK.pgc +++ b/app/src/st/svc/ST_CYCLEWEEK.pgc @@ -109,7 +109,7 @@ void ST_CYCLEWEEK(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "주간(7일 윈도) 통합 지급 예약. (심화판) [ST_CYCLEWEEK] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_DAILYCLOSE.pgc b/app/src/st/svc/ST_DAILYCLOSE.pgc index c6a4bd3..16c14ca 100644 --- a/app/src/st/svc/ST_DAILYCLOSE.pgc +++ b/app/src/st/svc/ST_DAILYCLOSE.pgc @@ -109,7 +109,7 @@ void ST_DAILYCLOSE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 일마감 선언 (3원 집계 + 마감 원장). (심화판) [ST_DAILYCLOSE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -134,6 +134,67 @@ void ST_DAILYCLOSE(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 정산 일마감 선언 (3원 집계 + 마감 원장). (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_DAILYCLOSE -> LG_POST (일마감-원장반영) ===== + * XA 규율: tpcall 로 부르는 LG_POST 는 별도 XA 브랜치라 ST_DAILYCLOSE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_DAILYCLOSE", 0L); + Bchg(b, T_REASON, 0, "일마감-원장반영", 0L); + userlog("[ST_DAILYCLOSE] 일마감-원장반영: 체인 호출 -> LG_POST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_DAILYCLOSE] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8741); + Bchg(b, T_MSG, 0, "일마감 원장반영(LG_POST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_DAILYCLOSE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_DAILYCLOSE", 0L); + setl(b, T_RC, 0); + userlog("[ST_DAILYCLOSE] 일마감-원장반영: 체인 완료 <- LG_POST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_DEBTCOLLECT.pgc b/app/src/st/svc/ST_DEBTCOLLECT.pgc index 020de3f..cf03f95 100644 --- a/app/src/st/svc/ST_DEBTCOLLECT.pgc +++ b/app/src/st/svc/ST_DEBTCOLLECT.pgc @@ -109,7 +109,7 @@ void ST_DEBTCOLLECT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "채권 회수 입금 정산. (심화판) [ST_DEBTCOLLECT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_DEBTNET.pgc b/app/src/st/svc/ST_DEBTNET.pgc index 6552017..082c16f 100644 --- a/app/src/st/svc/ST_DEBTNET.pgc +++ b/app/src/st/svc/ST_DEBTNET.pgc @@ -105,7 +105,7 @@ void ST_DEBTNET(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "지급 채무 대 미수 채권 상계. (심화판) [ST_DEBTNET] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_DELAYINT.pgc b/app/src/st/svc/ST_DELAYINT.pgc index e518c0b..1ef2b69 100644 --- a/app/src/st/svc/ST_DELAYINT.pgc +++ b/app/src/st/svc/ST_DELAYINT.pgc @@ -117,7 +117,7 @@ void ST_DELAYINT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "지연이자(net * bps/10000 * 일수) 정산 상세 기록. (심화판) [ST_DELAYINT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_DEPOSITCUT.pgc b/app/src/st/svc/ST_DEPOSITCUT.pgc index a41e310..73350d0 100644 --- a/app/src/st/svc/ST_DEPOSITCUT.pgc +++ b/app/src/st/svc/ST_DEPOSITCUT.pgc @@ -105,7 +105,7 @@ void ST_DEPOSITCUT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "지급액 보증금 원천 차감. (심화판) [ST_DEPOSITCUT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_DEPOSITSET.pgc b/app/src/st/svc/ST_DEPOSITSET.pgc index 57d85e2..56da050 100644 --- a/app/src/st/svc/ST_DEPOSITSET.pgc +++ b/app/src/st/svc/ST_DEPOSITSET.pgc @@ -105,7 +105,7 @@ void ST_DEPOSITSET(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "보증금 예치 기록 + net 차감. (심화판) [ST_DEPOSITSET] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_DIFFCHK.pgc b/app/src/st/svc/ST_DIFFCHK.pgc index 11057f1..65b5223 100644 --- a/app/src/st/svc/ST_DIFFCHK.pgc +++ b/app/src/st/svc/ST_DIFFCHK.pgc @@ -119,7 +119,7 @@ void ST_DIFFCHK(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 net vs 매입 net 차이 점검. (심화판) [ST_DIFFCHK] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -144,6 +144,67 @@ void ST_DIFFCHK(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 정산 net vs 매입 net 차이 점검. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_DIFFCHK -> VL_SETTLE (차액검증-정산검증) ===== + * XA 규율: tpcall 로 부르는 VL_SETTLE 는 별도 XA 브랜치라 ST_DIFFCHK 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_DIFFCHK", 0L); + Bchg(b, T_REASON, 0, "차액검증-정산검증", 0L); + userlog("[ST_DIFFCHK] 차액검증-정산검증: 체인 호출 -> VL_SETTLE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("VL_SETTLE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_DIFFCHK] tpcall(VL_SETTLE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8730); + Bchg(b, T_MSG, 0, "차액검증(VL_SETTLE) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_DIFFCHK 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_DIFFCHK", 0L); + setl(b, T_RC, 0); + userlog("[ST_DIFFCHK] 차액검증-정산검증: 체인 완료 <- VL_SETTLE pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_DISPUTE.pgc b/app/src/st/svc/ST_DISPUTE.pgc index 60a3c39..8f82acb 100644 --- a/app/src/st/svc/ST_DISPUTE.pgc +++ b/app/src/st/svc/ST_DISPUTE.pgc @@ -117,7 +117,7 @@ void ST_DISPUTE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 이의신청 접수 (지급 보류 + 조정). (심화판) [ST_DISPUTE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_DISPUTERSV.pgc b/app/src/st/svc/ST_DISPUTERSV.pgc index 71e556d..5415436 100644 --- a/app/src/st/svc/ST_DISPUTERSV.pgc +++ b/app/src/st/svc/ST_DISPUTERSV.pgc @@ -117,7 +117,7 @@ void ST_DISPUTERSV(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "이의신청 인용/기각 후속 처리. (심화판) [ST_DISPUTERSV] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_DTLSUM.pgc b/app/src/st/svc/ST_DTLSUM.pgc index 94ae3c9..8d59478 100644 --- a/app/src/st/svc/ST_DTLSUM.pgc +++ b/app/src/st/svc/ST_DTLSUM.pgc @@ -108,7 +108,7 @@ void ST_DTLSUM(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 상세 다중 집계 (건수/합/min/max/평균). (심화판) [ST_DTLSUM] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_EDIRECON.pgc b/app/src/st/svc/ST_EDIRECON.pgc index 7993c3e..303081f 100644 --- a/app/src/st/svc/ST_EDIRECON.pgc +++ b/app/src/st/svc/ST_EDIRECON.pgc @@ -107,7 +107,7 @@ void ST_EDIRECON(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "EDI 청구 vs 정산 집계 대사. (심화판) [ST_EDIRECON] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_EVENTFEE.pgc b/app/src/st/svc/ST_EVENTFEE.pgc index 97f6934..6e4201e 100644 --- a/app/src/st/svc/ST_EVENTFEE.pgc +++ b/app/src/st/svc/ST_EVENTFEE.pgc @@ -117,7 +117,7 @@ void ST_EVENTFEE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "이벤트 반값 수수료 감면 기록. (심화판) [ST_EVENTFEE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_FEEPREVIEW.pgc b/app/src/st/svc/ST_FEEPREVIEW.pgc index 5f8e987..decf403 100644 --- a/app/src/st/svc/ST_FEEPREVIEW.pgc +++ b/app/src/st/svc/ST_FEEPREVIEW.pgc @@ -109,7 +109,7 @@ void ST_FEEPREVIEW(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 실수령 예상 견적. (심화판) [ST_FEEPREVIEW] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_FEERATIO.pgc b/app/src/st/svc/ST_FEERATIO.pgc index 4ed498d..4feee54 100644 --- a/app/src/st/svc/ST_FEERATIO.pgc +++ b/app/src/st/svc/ST_FEERATIO.pgc @@ -109,7 +109,7 @@ void ST_FEERATIO(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "실효 수수료율 vs 계약 요율 편차 검증. (심화판) [ST_FEERATIO] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_FLATFEE.pgc b/app/src/st/svc/ST_FLATFEE.pgc index fa6d5ba..b36e8f0 100644 --- a/app/src/st/svc/ST_FLATFEE.pgc +++ b/app/src/st/svc/ST_FLATFEE.pgc @@ -117,7 +117,7 @@ void ST_FLATFEE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정액 수수료 적용 (고정액 정산 상세 기록). (심화판) [ST_FLATFEE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_FLATVSPCT.pgc b/app/src/st/svc/ST_FLATVSPCT.pgc index e21e6f4..5318f25 100644 --- a/app/src/st/svc/ST_FLATVSPCT.pgc +++ b/app/src/st/svc/ST_FLATVSPCT.pgc @@ -117,7 +117,7 @@ void ST_FLATVSPCT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정액/정률 중 저가 방식 선택. (심화판) [ST_FLATVSPCT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_FXCONV.pgc b/app/src/st/svc/ST_FXCONV.pgc index 09a6c9d..dda1b75 100644 --- a/app/src/st/svc/ST_FXCONV.pgc +++ b/app/src/st/svc/ST_FXCONV.pgc @@ -117,7 +117,7 @@ void ST_FXCONV(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "외화 환산: fx * rate/100 = KRW. (심화판) [ST_FXCONV] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_FXSETTLE.pgc b/app/src/st/svc/ST_FXSETTLE.pgc index ac6d74b..2a93cc5 100644 --- a/app/src/st/svc/ST_FXSETTLE.pgc +++ b/app/src/st/svc/ST_FXSETTLE.pgc @@ -117,7 +117,7 @@ void ST_FXSETTLE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "외화 환산액 정산 상세 기록. (심화판) [ST_FXSETTLE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_GRADESTAT.pgc b/app/src/st/svc/ST_GRADESTAT.pgc index 15b5ad2..e25eb33 100644 --- a/app/src/st/svc/ST_GRADESTAT.pgc +++ b/app/src/st/svc/ST_GRADESTAT.pgc @@ -106,7 +106,7 @@ void ST_GRADESTAT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "mdr_bps 등급별 가맹점 분포. (심화판) [ST_GRADESTAT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_GROWTHINC.pgc b/app/src/st/svc/ST_GROWTHINC.pgc index 8325967..e6d1cd2 100644 --- a/app/src/st/svc/ST_GROWTHINC.pgc +++ b/app/src/st/svc/ST_GROWTHINC.pgc @@ -105,7 +105,7 @@ void ST_GROWTHINC(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "전기 대비 매출 성장분 인센티브. (심화판) [ST_GROWTHINC] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_GRPALLOC.pgc b/app/src/st/svc/ST_GRPALLOC.pgc index 1c3b937..7818926 100644 --- a/app/src/st/svc/ST_GRPALLOC.pgc +++ b/app/src/st/svc/ST_GRPALLOC.pgc @@ -109,7 +109,7 @@ void ST_GRPALLOC(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "net 비중 안분 후 구성원별 지급 등록. (심화판) [ST_GRPALLOC] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_GRPROLLUP.pgc b/app/src/st/svc/ST_GRPROLLUP.pgc index 2aef472..7190659 100644 --- a/app/src/st/svc/ST_GRPROLLUP.pgc +++ b/app/src/st/svc/ST_GRPROLLUP.pgc @@ -106,7 +106,7 @@ void ST_GRPROLLUP(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "그룹 구성원 매출/수수료/net rollup. (심화판) [ST_GRPROLLUP] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_GRPSETTLE.pgc b/app/src/st/svc/ST_GRPSETTLE.pgc index 4310fd3..211569c 100644 --- a/app/src/st/svc/ST_GRPSETTLE.pgc +++ b/app/src/st/svc/ST_GRPSETTLE.pgc @@ -109,7 +109,7 @@ void ST_GRPSETTLE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "그룹 prefix 통합정산 지급. (심화판) [ST_GRPSETTLE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -139,6 +139,67 @@ void ST_GRPSETTLE(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 그룹 prefix 통합정산 지급. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_GRPSETTLE -> LG_POST (그룹정산-원장반영) ===== + * XA 규율: tpcall 로 부르는 LG_POST 는 별도 XA 브랜치라 ST_GRPSETTLE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_GRPSETTLE", 0L); + Bchg(b, T_REASON, 0, "그룹정산-원장반영", 0L); + userlog("[ST_GRPSETTLE] 그룹정산-원장반영: 체인 호출 -> LG_POST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_GRPSETTLE] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8742); + Bchg(b, T_MSG, 0, "그룹정산 원장반영(LG_POST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_GRPSETTLE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_GRPSETTLE", 0L); + setl(b, T_RC, 0); + userlog("[ST_GRPSETTLE] 그룹정산-원장반영: 체인 완료 <- LG_POST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_HOLD.pgc b/app/src/st/svc/ST_HOLD.pgc index 80dbe1f..7781600 100644 --- a/app/src/st/svc/ST_HOLD.pgc +++ b/app/src/st/svc/ST_HOLD.pgc @@ -107,7 +107,7 @@ void ST_HOLD(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "가맹점 지급 보류 (SCHEDULED -> HELD). (심화판) [ST_HOLD] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -137,6 +137,67 @@ void ST_HOLD(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 가맹점 지급 보류 (SCHEDULED -> HELD). (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_HOLD -> LG_POST (정산보류-원장반영) ===== + * XA 규율: tpcall 로 부르는 LG_POST 는 별도 XA 브랜치라 ST_HOLD 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_HOLD", 0L); + Bchg(b, T_REASON, 0, "정산보류-원장반영", 0L); + userlog("[ST_HOLD] 정산보류-원장반영: 체인 호출 -> LG_POST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_HOLD] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8739); + Bchg(b, T_MSG, 0, "정산보류 원장반영(LG_POST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_HOLD 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_HOLD", 0L); + setl(b, T_RC, 0); + userlog("[ST_HOLD] 정산보류-원장반영: 체인 완료 <- LG_POST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_HOLDAMT.pgc b/app/src/st/svc/ST_HOLDAMT.pgc index c97f6fb..734c1a0 100644 --- a/app/src/st/svc/ST_HOLDAMT.pgc +++ b/app/src/st/svc/ST_HOLDAMT.pgc @@ -108,7 +108,7 @@ void ST_HOLDAMT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "임계액 이상 지급 일괄 보류. (심화판) [ST_HOLDAMT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_INSTANTPAY.pgc b/app/src/st/svc/ST_INSTANTPAY.pgc index 8d35e0e..6074fb2 100644 --- a/app/src/st/svc/ST_INSTANTPAY.pgc +++ b/app/src/st/svc/ST_INSTANTPAY.pgc @@ -108,7 +108,7 @@ void ST_INSTANTPAY(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "즉시 지급(PAID) 등록. (심화판) [ST_INSTANTPAY] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -138,6 +138,72 @@ void ST_INSTANTPAY(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 즉시 지급(PAID) 등록. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_INSTANTPAY -> PAY_FILEGEN (즉시지급-지급파일생성) ===== + * XA 규율: tpcall 로 부르는 PAY_FILEGEN 는 별도 XA 브랜치라 ST_INSTANTPAY 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_INSTANTPAY", 0L); + Bchg(b, T_REASON, 0, "즉시지급-지급파일생성", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[ST_INSTANTPAY] 즉시지급-지급파일생성: 체인 호출 -> PAY_FILEGEN pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("PAY_FILEGEN", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_INSTANTPAY] tpcall(PAY_FILEGEN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8743); + Bchg(b, T_MSG, 0, "즉시지급 파일생성 트리거 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_INSTANTPAY 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_INSTANTPAY", 0L); + setl(b, T_RC, 0); + userlog("[ST_INSTANTPAY] 즉시지급-지급파일생성: 체인 완료 <- PAY_FILEGEN pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_ISSUERSTAT.pgc b/app/src/st/svc/ST_ISSUERSTAT.pgc index 88f5372..e9084f7 100644 --- a/app/src/st/svc/ST_ISSUERSTAT.pgc +++ b/app/src/st/svc/ST_ISSUERSTAT.pgc @@ -108,7 +108,7 @@ void ST_ISSUERSTAT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "발급사별 수수료 분해 통계. (심화판) [ST_ISSUERSTAT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_LEDGERLINK.pgc b/app/src/st/svc/ST_LEDGERLINK.pgc index 3585b0e..a3af59a 100644 --- a/app/src/st/svc/ST_LEDGERLINK.pgc +++ b/app/src/st/svc/ST_LEDGERLINK.pgc @@ -105,7 +105,7 @@ void ST_LEDGERLINK(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 연계 원장 기록. (심화판) [ST_LEDGERLINK] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -130,6 +130,67 @@ void ST_LEDGERLINK(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 정산 연계 원장 기록. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_LEDGERLINK -> LG_POST (원장연계-원장반영) ===== + * XA 규율: tpcall 로 부르는 LG_POST 는 별도 XA 브랜치라 ST_LEDGERLINK 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_LEDGERLINK", 0L); + Bchg(b, T_REASON, 0, "원장연계-원장반영", 0L); + userlog("[ST_LEDGERLINK] 원장연계-원장반영: 체인 호출 -> LG_POST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_LEDGERLINK] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8734); + Bchg(b, T_MSG, 0, "원장연계 반영(LG_POST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_LEDGERLINK 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_LEDGERLINK", 0L); + setl(b, T_RC, 0); + userlog("[ST_LEDGERLINK] 원장연계-원장반영: 체인 완료 <- LG_POST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_LEDGERSNAP.pgc b/app/src/st/svc/ST_LEDGERSNAP.pgc index d8de381..a8e41a8 100644 --- a/app/src/st/svc/ST_LEDGERSNAP.pgc +++ b/app/src/st/svc/ST_LEDGERSNAP.pgc @@ -109,7 +109,7 @@ void ST_LEDGERSNAP(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "당일 정산 총액 원장 스냅샷. (심화판) [ST_LEDGERSNAP] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_LIMITCHK.pgc b/app/src/st/svc/ST_LIMITCHK.pgc index e36384c..976ec5b 100644 --- a/app/src/st/svc/ST_LIMITCHK.pgc +++ b/app/src/st/svc/ST_LIMITCHK.pgc @@ -107,7 +107,7 @@ void ST_LIMITCHK(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "일 매입 한도 잔여 점검. (심화판) [ST_LIMITCHK] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -132,6 +132,67 @@ void ST_LIMITCHK(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 일 매입 한도 잔여 점검. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_LIMITCHK -> VL_SETTLE (한도검증-정산검증) ===== + * XA 규율: tpcall 로 부르는 VL_SETTLE 는 별도 XA 브랜치라 ST_LIMITCHK 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_LIMITCHK", 0L); + Bchg(b, T_REASON, 0, "한도검증-정산검증", 0L); + userlog("[ST_LIMITCHK] 한도검증-정산검증: 체인 호출 -> VL_SETTLE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("VL_SETTLE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_LIMITCHK] tpcall(VL_SETTLE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8731); + Bchg(b, T_MSG, 0, "한도검증(VL_SETTLE) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_LIMITCHK 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_LIMITCHK", 0L); + setl(b, T_RC, 0); + userlog("[ST_LIMITCHK] 한도검증-정산검증: 체인 완료 <- VL_SETTLE pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_LOCKBATCH.pgc b/app/src/st/svc/ST_LOCKBATCH.pgc index 1b39c44..6cd7648 100644 --- a/app/src/st/svc/ST_LOCKBATCH.pgc +++ b/app/src/st/svc/ST_LOCKBATCH.pgc @@ -117,7 +117,7 @@ void ST_LOCKBATCH(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "당일 정산 일괄 잠금(SETTLED->LOCKED). (심화판) [ST_LOCKBATCH] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_LOYALTY.pgc b/app/src/st/svc/ST_LOYALTY.pgc index 3597619..96e0f49 100644 --- a/app/src/st/svc/ST_LOYALTY.pgc +++ b/app/src/st/svc/ST_LOYALTY.pgc @@ -105,7 +105,7 @@ void ST_LOYALTY(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "누적 매출 기반 로열티 보상. (심화판) [ST_LOYALTY] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_MDR.pgc b/app/src/st/svc/ST_MDR.pgc index ea3fa64..c26d32c 100644 --- a/app/src/st/svc/ST_MDR.pgc +++ b/app/src/st/svc/ST_MDR.pgc @@ -20,6 +20,67 @@ void ST_MDR(TPSVCINFO *p) EXEC SQL INSERT INTO ledger (ledger_id, purchase_id, entry_type, amount, biz_date) VALUES (nextval('ledger_seq'), :h_pid, 'MDR', :h_fee, :h_bizdate); if (sqlca.sqlcode < 0) FAIL(b); + + /* ===== 8b) 업무 체인 호출부: ST_MDR -> LG_SETTLEPOST (수수료-원장반영) ===== + * XA 규율: tpcall 로 부르는 LG_SETTLEPOST 는 별도 XA 브랜치라 ST_MDR 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_MDR", 0L); + Bchg(b, T_REASON, 0, "수수료-원장반영", 0L); + userlog("[ST_MDR] 수수료-원장반영: 체인 호출 -> LG_SETTLEPOST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_SETTLEPOST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_MDR] tpcall(LG_SETTLEPOST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8711); + Bchg(b, T_MSG, 0, "수수료 원장반영(LG_SETTLEPOST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_MDR 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_MDR", 0L); + setl(b, T_RC, 0); + userlog("[ST_MDR] 수수료-원장반영: 체인 완료 <- LG_SETTLEPOST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_MERCHRATE.pgc b/app/src/st/svc/ST_MERCHRATE.pgc index 0c21c5d..9d904e9 100644 --- a/app/src/st/svc/ST_MERCHRATE.pgc +++ b/app/src/st/svc/ST_MERCHRATE.pgc @@ -118,7 +118,7 @@ void ST_MERCHRATE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "가맹점 계약 요율 수수료 산출/기록. (심화판) [ST_MERCHRATE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_MINFEE.pgc b/app/src/st/svc/ST_MINFEE.pgc index 48dfdee..49391b2 100644 --- a/app/src/st/svc/ST_MINFEE.pgc +++ b/app/src/st/svc/ST_MINFEE.pgc @@ -117,7 +117,7 @@ void ST_MINFEE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "최저 수수료 미달분 보정. (심화판) [ST_MINFEE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_MKTGSHARE.pgc b/app/src/st/svc/ST_MKTGSHARE.pgc index 5d7d0e9..67c7449 100644 --- a/app/src/st/svc/ST_MKTGSHARE.pgc +++ b/app/src/st/svc/ST_MKTGSHARE.pgc @@ -117,7 +117,7 @@ void ST_MKTGSHARE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "매출 기반 마케팅 분담금 부과. (심화판) [ST_MKTGSHARE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_MONTHLY.pgc b/app/src/st/svc/ST_MONTHLY.pgc index c5f9695..a323da4 100644 --- a/app/src/st/svc/ST_MONTHLY.pgc +++ b/app/src/st/svc/ST_MONTHLY.pgc @@ -110,7 +110,7 @@ void ST_MONTHLY(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "월별 정산 net 합계 (biz_date LIKE 'YYYY-MM%'). (심화판) [ST_MONTHLY] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_MONTHSTAT.pgc b/app/src/st/svc/ST_MONTHSTAT.pgc index 99abb11..989109c 100644 --- a/app/src/st/svc/ST_MONTHSTAT.pgc +++ b/app/src/st/svc/ST_MONTHSTAT.pgc @@ -109,7 +109,7 @@ void ST_MONTHSTAT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "월(YYYY-MM) 정산 집계. (심화판) [ST_MONTHSTAT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_NEGSWEEP.pgc b/app/src/st/svc/ST_NEGSWEEP.pgc index a40a465..75ba62b 100644 --- a/app/src/st/svc/ST_NEGSWEEP.pgc +++ b/app/src/st/svc/ST_NEGSWEEP.pgc @@ -119,7 +119,7 @@ void ST_NEGSWEEP(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "음수 net 정산 일괄 취소. (심화판) [ST_NEGSWEEP] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_NETTING.pgc b/app/src/st/svc/ST_NETTING.pgc index 8a2e559..212fa2e 100644 --- a/app/src/st/svc/ST_NETTING.pgc +++ b/app/src/st/svc/ST_NETTING.pgc @@ -109,7 +109,7 @@ void ST_NETTING(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "당일 net 합계 조회. (심화판) [ST_NETTING] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -134,6 +134,67 @@ void ST_NETTING(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 당일 net 합계 조회. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_NETTING -> LG_POST (상계-원장반영) ===== + * XA 규율: tpcall 로 부르는 LG_POST 는 별도 XA 브랜치라 ST_NETTING 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_NETTING", 0L); + Bchg(b, T_REASON, 0, "상계-원장반영", 0L); + userlog("[ST_NETTING] 상계-원장반영: 체인 호출 -> LG_POST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_NETTING] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8712); + Bchg(b, T_MSG, 0, "상계 원장반영(LG_POST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_NETTING 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_NETTING", 0L); + setl(b, T_RC, 0); + userlog("[ST_NETTING] 상계-원장반영: 체인 완료 <- LG_POST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_NEXTPAYDT.pgc b/app/src/st/svc/ST_NEXTPAYDT.pgc index 364e5cd..9fc6e30 100644 --- a/app/src/st/svc/ST_NEXTPAYDT.pgc +++ b/app/src/st/svc/ST_NEXTPAYDT.pgc @@ -109,7 +109,7 @@ void ST_NEXTPAYDT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "다음 영업일(지급일) 계산. (심화판) [ST_NEXTPAYDT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -139,6 +139,70 @@ void ST_NEXTPAYDT(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 다음 영업일(지급일) 계산. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_NEXTPAYDT -> CM_BIZDAY (차기지급일-영업일계산) ===== + * XA 규율: tpcall 로 부르는 CM_BIZDAY 는 별도 XA 브랜치라 ST_NEXTPAYDT 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_NEXTPAYDT", 0L); + Bchg(b, T_REASON, 0, "차기지급일-영업일계산", 0L); + + Bchg(b, T_STR1, 0, "BIZDAY", 0L); + if (getl(b, T_ARG1) <= 0) setl(b, T_ARG1, 1); + userlog("[ST_NEXTPAYDT] 차기지급일-영업일계산: 체인 호출 -> CM_BIZDAY pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("CM_BIZDAY", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_NEXTPAYDT] tpcall(CM_BIZDAY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8725); + Bchg(b, T_MSG, 0, "차기지급일 영업일계산 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_NEXTPAYDT 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_NEXTPAYDT", 0L); + setl(b, T_RC, 0); + userlog("[ST_NEXTPAYDT] 차기지급일-영업일계산: 체인 완료 <- CM_BIZDAY pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_OFFSET.pgc b/app/src/st/svc/ST_OFFSET.pgc index 829cc73..b49baa3 100644 --- a/app/src/st/svc/ST_OFFSET.pgc +++ b/app/src/st/svc/ST_OFFSET.pgc @@ -105,7 +105,7 @@ void ST_OFFSET(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "상계: 음수 조정으로 채권 상계 기록. (심화판) [ST_OFFSET] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -130,6 +130,67 @@ void ST_OFFSET(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 상계: 음수 조정으로 채권 상계 기록. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_OFFSET -> LG_POST (차감-원장반영) ===== + * XA 규율: tpcall 로 부르는 LG_POST 는 별도 XA 브랜치라 ST_OFFSET 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_OFFSET", 0L); + Bchg(b, T_REASON, 0, "차감-원장반영", 0L); + userlog("[ST_OFFSET] 차감-원장반영: 체인 호출 -> LG_POST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_OFFSET] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8713); + Bchg(b, T_MSG, 0, "차감 원장반영(LG_POST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_OFFSET 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_OFFSET", 0L); + setl(b, T_RC, 0); + userlog("[ST_OFFSET] 차감-원장반영: 체인 완료 <- LG_POST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_PARTIAL.pgc b/app/src/st/svc/ST_PARTIAL.pgc index 1c3f287..2457a28 100644 --- a/app/src/st/svc/ST_PARTIAL.pgc +++ b/app/src/st/svc/ST_PARTIAL.pgc @@ -118,7 +118,7 @@ void ST_PARTIAL(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "부분정산 (잔여 한도 검증 후 PARTIAL 정산 생성). (심화판) [ST_PARTIAL] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_PARTNERSET.pgc b/app/src/st/svc/ST_PARTNERSET.pgc index c58c7c4..5ec1aa0 100644 --- a/app/src/st/svc/ST_PARTNERSET.pgc +++ b/app/src/st/svc/ST_PARTNERSET.pgc @@ -109,7 +109,7 @@ void ST_PARTNERSET(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "제휴사 지분 지급 예정 등록. (심화판) [ST_PARTNERSET] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_PARTPAY.pgc b/app/src/st/svc/ST_PARTPAY.pgc index 8bae8dc..9cf2daf 100644 --- a/app/src/st/svc/ST_PARTPAY.pgc +++ b/app/src/st/svc/ST_PARTPAY.pgc @@ -108,7 +108,7 @@ void ST_PARTPAY(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "net 일부 부분 지급(PAID). (심화판) [ST_PARTPAY] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_PAYDATE.pgc b/app/src/st/svc/ST_PAYDATE.pgc index 482aeba..148de97 100644 --- a/app/src/st/svc/ST_PAYDATE.pgc +++ b/app/src/st/svc/ST_PAYDATE.pgc @@ -109,7 +109,7 @@ void ST_PAYDATE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "지급일 산정(익영업일) 후 지급일 갱신. (심화판) [ST_PAYDATE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -139,6 +139,70 @@ void ST_PAYDATE(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 지급일 산정(익영업일) 후 지급일 갱신. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_PAYDATE -> CM_BIZDAY (지급일-영업일계산) ===== + * XA 규율: tpcall 로 부르는 CM_BIZDAY 는 별도 XA 브랜치라 ST_PAYDATE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_PAYDATE", 0L); + Bchg(b, T_REASON, 0, "지급일-영업일계산", 0L); + + Bchg(b, T_STR1, 0, "BIZDAY", 0L); + if (getl(b, T_ARG1) <= 0) setl(b, T_ARG1, 1); + userlog("[ST_PAYDATE] 지급일-영업일계산: 체인 호출 -> CM_BIZDAY pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("CM_BIZDAY", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_PAYDATE] tpcall(CM_BIZDAY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8724); + Bchg(b, T_MSG, 0, "지급일 영업일계산(CM_BIZDAY) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_PAYDATE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_PAYDATE", 0L); + setl(b, T_RC, 0); + userlog("[ST_PAYDATE] 지급일-영업일계산: 체인 완료 <- CM_BIZDAY pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_PAYRETRY.pgc b/app/src/st/svc/ST_PAYRETRY.pgc index fd7c595..c07cd2a 100644 --- a/app/src/st/svc/ST_PAYRETRY.pgc +++ b/app/src/st/svc/ST_PAYRETRY.pgc @@ -107,7 +107,7 @@ void ST_PAYRETRY(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "취소 지급 익영업일 재예약. (심화판) [ST_PAYRETRY] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_PAYSTATUS.pgc b/app/src/st/svc/ST_PAYSTATUS.pgc index 332a295..3e70740 100644 --- a/app/src/st/svc/ST_PAYSTATUS.pgc +++ b/app/src/st/svc/ST_PAYSTATUS.pgc @@ -110,7 +110,7 @@ void ST_PAYSTATUS(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "가맹점 최신 지급 상태 조회. (심화판) [ST_PAYSTATUS] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_PCTFEE.pgc b/app/src/st/svc/ST_PCTFEE.pgc index c805853..1e16720 100644 --- a/app/src/st/svc/ST_PCTFEE.pgc +++ b/app/src/st/svc/ST_PCTFEE.pgc @@ -118,7 +118,7 @@ void ST_PCTFEE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정률 수수료 계산 (금액 x bps). (심화판) [ST_PCTFEE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_PRECONFIRM.pgc b/app/src/st/svc/ST_PRECONFIRM.pgc index 567437d..da60b1c 100644 --- a/app/src/st/svc/ST_PRECONFIRM.pgc +++ b/app/src/st/svc/ST_PRECONFIRM.pgc @@ -110,7 +110,7 @@ void ST_PRECONFIRM(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "보류 잔여 여부로 확정 가능 판정. (심화판) [ST_PRECONFIRM] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -135,6 +135,67 @@ void ST_PRECONFIRM(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 보류 잔여 여부로 확정 가능 판정. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_PRECONFIRM -> VL_SETTLE (사전확정-정산검증) ===== + * XA 규율: tpcall 로 부르는 VL_SETTLE 는 별도 XA 브랜치라 ST_PRECONFIRM 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_PRECONFIRM", 0L); + Bchg(b, T_REASON, 0, "사전확정-정산검증", 0L); + userlog("[ST_PRECONFIRM] 사전확정-정산검증: 체인 호출 -> VL_SETTLE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("VL_SETTLE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_PRECONFIRM] tpcall(VL_SETTLE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8717); + Bchg(b, T_MSG, 0, "사전확정 정산검증(VL_SETTLE) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_PRECONFIRM 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_PRECONFIRM", 0L); + setl(b, T_RC, 0); + userlog("[ST_PRECONFIRM] 사전확정-정산검증: 체인 완료 <- VL_SETTLE pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_PROMOAPPLY.pgc b/app/src/st/svc/ST_PROMOAPPLY.pgc index 01d84d2..a397a4e 100644 --- a/app/src/st/svc/ST_PROMOAPPLY.pgc +++ b/app/src/st/svc/ST_PROMOAPPLY.pgc @@ -105,7 +105,7 @@ void ST_PROMOAPPLY(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "수수료 프로모션 할인(음수 조정). (심화판) [ST_PROMOAPPLY] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_PROMOCALC.pgc b/app/src/st/svc/ST_PROMOCALC.pgc index 2b50edb..3051a2c 100644 --- a/app/src/st/svc/ST_PROMOCALC.pgc +++ b/app/src/st/svc/ST_PROMOCALC.pgc @@ -117,7 +117,7 @@ void ST_PROMOCALC(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "프로모션/이벤트 수수료 할인 정산. (심화판) [ST_PROMOCALC] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_RATEAPPLY.pgc b/app/src/st/svc/ST_RATEAPPLY.pgc index 8c0c802..ca9cf2f 100644 --- a/app/src/st/svc/ST_RATEAPPLY.pgc +++ b/app/src/st/svc/ST_RATEAPPLY.pgc @@ -118,7 +118,7 @@ void ST_RATEAPPLY(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "구간요율 적용 수수료 계산 + 정산 상세 기록. (심화판) [ST_RATEAPPLY] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -148,6 +148,72 @@ void ST_RATEAPPLY(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 구간요율 적용 수수료 계산 + 정산 상세 기록. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_RATEAPPLY -> ST_MDR (요율적용-수수료재산출) ===== + * XA 규율: tpcall 로 부르는 ST_MDR 는 별도 XA 브랜치라 ST_RATEAPPLY 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_RATEAPPLY", 0L); + Bchg(b, T_REASON, 0, "요율적용-수수료재산출", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[ST_RATEAPPLY] 요율적용-수수료재산출: 체인 호출 -> ST_MDR pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("ST_MDR", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_RATEAPPLY] tpcall(ST_MDR) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8727); + Bchg(b, T_MSG, 0, "요율적용 수수료 재산출 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_RATEAPPLY 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_RATEAPPLY", 0L); + setl(b, T_RC, 0); + userlog("[ST_RATEAPPLY] 요율적용-수수료재산출: 체인 완료 <- ST_MDR pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_RATECARD.pgc b/app/src/st/svc/ST_RATECARD.pgc index 426ba27..cc6b6d2 100644 --- a/app/src/st/svc/ST_RATECARD.pgc +++ b/app/src/st/svc/ST_RATECARD.pgc @@ -109,7 +109,7 @@ void ST_RATECARD(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "요율표 요약(구간수/최소/최대 bps). (심화판) [ST_RATECARD] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_RATECMP.pgc b/app/src/st/svc/ST_RATECMP.pgc index 9a50a89..8e85c5e 100644 --- a/app/src/st/svc/ST_RATECMP.pgc +++ b/app/src/st/svc/ST_RATECMP.pgc @@ -109,7 +109,7 @@ void ST_RATECMP(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "두 요율 유형 적용 bps 비교. (심화판) [ST_RATECMP] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_RATEFLOOR.pgc b/app/src/st/svc/ST_RATEFLOOR.pgc index b0d3f6c..bd577a8 100644 --- a/app/src/st/svc/ST_RATEFLOOR.pgc +++ b/app/src/st/svc/ST_RATEFLOOR.pgc @@ -117,7 +117,7 @@ void ST_RATEFLOOR(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정률 수수료 하한 보정 후 기록. (심화판) [ST_RATEFLOOR] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_RATEMAX.pgc b/app/src/st/svc/ST_RATEMAX.pgc index a5c0bf2..67349e1 100644 --- a/app/src/st/svc/ST_RATEMAX.pgc +++ b/app/src/st/svc/ST_RATEMAX.pgc @@ -117,7 +117,7 @@ void ST_RATEMAX(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정률 수수료 상한 절삭 후 기록. (심화판) [ST_RATEMAX] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_RATESIM.pgc b/app/src/st/svc/ST_RATESIM.pgc index 1f32a3f..e255ce0 100644 --- a/app/src/st/svc/ST_RATESIM.pgc +++ b/app/src/st/svc/ST_RATESIM.pgc @@ -109,7 +109,7 @@ void ST_RATESIM(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "요율 시뮬레이션 (구간 판정 + 예상 수수료). (심화판) [ST_RATESIM] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_REBATE.pgc b/app/src/st/svc/ST_REBATE.pgc index a594d69..d929fb7 100644 --- a/app/src/st/svc/ST_REBATE.pgc +++ b/app/src/st/svc/ST_REBATE.pgc @@ -105,7 +105,7 @@ void ST_REBATE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "수수료 기반 리베이트 환급 조정. (심화판) [ST_REBATE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_RECALC.pgc b/app/src/st/svc/ST_RECALC.pgc index 78cc71b..7ae2f96 100644 --- a/app/src/st/svc/ST_RECALC.pgc +++ b/app/src/st/svc/ST_RECALC.pgc @@ -118,7 +118,7 @@ void ST_RECALC(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "매입 수수료 기준 정산 net 재계산 + 갱신. (심화판) [ST_RECALC] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -143,6 +143,72 @@ void ST_RECALC(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 매입 수수료 기준 정산 net 재계산 + 갱신. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_RECALC -> ST_MDR (정산재계산-수수료재산출) ===== + * XA 규율: tpcall 로 부르는 ST_MDR 는 별도 XA 브랜치라 ST_RECALC 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_RECALC", 0L); + Bchg(b, T_REASON, 0, "정산재계산-수수료재산출", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[ST_RECALC] 정산재계산-수수료재산출: 체인 호출 -> ST_MDR pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("ST_MDR", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_RECALC] tpcall(ST_MDR) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8726); + Bchg(b, T_MSG, 0, "수수료 재산출(ST_MDR) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_RECALC 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_RECALC", 0L); + setl(b, T_RC, 0); + userlog("[ST_RECALC] 정산재계산-수수료재산출: 체인 완료 <- ST_MDR pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_RECVAGE.pgc b/app/src/st/svc/ST_RECVAGE.pgc index b79faba..afab4b4 100644 --- a/app/src/st/svc/ST_RECVAGE.pgc +++ b/app/src/st/svc/ST_RECVAGE.pgc @@ -110,7 +110,7 @@ void ST_RECVAGE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "기준일 이전 보류 미수금 집계. (심화판) [ST_RECVAGE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_RECVOFFSET.pgc b/app/src/st/svc/ST_RECVOFFSET.pgc index 4b10954..50581dd 100644 --- a/app/src/st/svc/ST_RECVOFFSET.pgc +++ b/app/src/st/svc/ST_RECVOFFSET.pgc @@ -105,7 +105,7 @@ void ST_RECVOFFSET(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "미수금-지급 상계 처리. (심화판) [ST_RECVOFFSET] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_RECVSTAT.pgc b/app/src/st/svc/ST_RECVSTAT.pgc index 0ac6816..c57d934 100644 --- a/app/src/st/svc/ST_RECVSTAT.pgc +++ b/app/src/st/svc/ST_RECVSTAT.pgc @@ -109,7 +109,7 @@ void ST_RECVSTAT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "지급 상태별 분포 통계. (심화판) [ST_RECVSTAT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_REFERRAL.pgc b/app/src/st/svc/ST_REFERRAL.pgc index 6c17fdb..8bb87b4 100644 --- a/app/src/st/svc/ST_REFERRAL.pgc +++ b/app/src/st/svc/ST_REFERRAL.pgc @@ -105,7 +105,7 @@ void ST_REFERRAL(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "추천 유치 건당 보상 지급. (심화판) [ST_REFERRAL] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_REFUNDCALC.pgc b/app/src/st/svc/ST_REFUNDCALC.pgc index 10266a4..c331a35 100644 --- a/app/src/st/svc/ST_REFUNDCALC.pgc +++ b/app/src/st/svc/ST_REFUNDCALC.pgc @@ -105,7 +105,7 @@ void ST_REFUNDCALC(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "환불 비례 수수료 환급 기록. (심화판) [ST_REFUNDCALC] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -130,6 +130,67 @@ void ST_REFUNDCALC(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 환불 비례 수수료 환급 기록. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_REFUNDCALC -> LG_REVERSE (환불정산-원장역분개) ===== + * XA 규율: tpcall 로 부르는 LG_REVERSE 는 별도 XA 브랜치라 ST_REFUNDCALC 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_REFUNDCALC", 0L); + Bchg(b, T_REASON, 0, "환불정산-원장역분개", 0L); + userlog("[ST_REFUNDCALC] 환불정산-원장역분개: 체인 호출 -> LG_REVERSE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_REVERSE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_REFUNDCALC] tpcall(LG_REVERSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8737); + Bchg(b, T_MSG, 0, "환불정산 역분개(LG_REVERSE) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_REFUNDCALC 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_REFUNDCALC", 0L); + setl(b, T_RC, 0); + userlog("[ST_REFUNDCALC] 환불정산-원장역분개: 체인 완료 <- LG_REVERSE pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_RELAYFEE.pgc b/app/src/st/svc/ST_RELAYFEE.pgc index 29d75a6..fde8a01 100644 --- a/app/src/st/svc/ST_RELAYFEE.pgc +++ b/app/src/st/svc/ST_RELAYFEE.pgc @@ -118,7 +118,7 @@ void ST_RELAYFEE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "중계 수수료: 구간요율 조회 후 정산 상세 기록. (심화판) [ST_RELAYFEE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_RELAYSPLIT.pgc b/app/src/st/svc/ST_RELAYSPLIT.pgc index c29a015..2fc431b 100644 --- a/app/src/st/svc/ST_RELAYSPLIT.pgc +++ b/app/src/st/svc/ST_RELAYSPLIT.pgc @@ -118,7 +118,7 @@ void ST_RELAYSPLIT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "중계수수료 2자 분배 기록. (심화판) [ST_RELAYSPLIT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_RELEASE.pgc b/app/src/st/svc/ST_RELEASE.pgc index 1bf7d8b..2960036 100644 --- a/app/src/st/svc/ST_RELEASE.pgc +++ b/app/src/st/svc/ST_RELEASE.pgc @@ -107,7 +107,7 @@ void ST_RELEASE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "지급 보류 해제 (HELD -> SCHEDULED). (심화판) [ST_RELEASE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -137,6 +137,67 @@ void ST_RELEASE(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 지급 보류 해제 (HELD -> SCHEDULED). (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_RELEASE -> LG_POST (보류해제-원장반영) ===== + * XA 규율: tpcall 로 부르는 LG_POST 는 별도 XA 브랜치라 ST_RELEASE 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_RELEASE", 0L); + Bchg(b, T_REASON, 0, "보류해제-원장반영", 0L); + userlog("[ST_RELEASE] 보류해제-원장반영: 체인 호출 -> LG_POST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_RELEASE] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8740); + Bchg(b, T_MSG, 0, "보류해제 원장반영(LG_POST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_RELEASE 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_RELEASE", 0L); + setl(b, T_RC, 0); + userlog("[ST_RELEASE] 보류해제-원장반영: 체인 완료 <- LG_POST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_REOPEN.pgc b/app/src/st/svc/ST_REOPEN.pgc index 0def6e3..942bd74 100644 --- a/app/src/st/svc/ST_REOPEN.pgc +++ b/app/src/st/svc/ST_REOPEN.pgc @@ -117,7 +117,7 @@ void ST_REOPEN(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 마감 철회 (STCLOSE 삭제). (심화판) [ST_REOPEN] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_REPARTIAL.pgc b/app/src/st/svc/ST_REPARTIAL.pgc index fc86b2d..249bed3 100644 --- a/app/src/st/svc/ST_REPARTIAL.pgc +++ b/app/src/st/svc/ST_REPARTIAL.pgc @@ -112,7 +112,7 @@ void ST_REPARTIAL(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "부분취소 후 수수료 재계산 조정. (심화판) [ST_REPARTIAL] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_REPORT.pgc b/app/src/st/svc/ST_REPORT.pgc index d3cadb7..99560e0 100644 --- a/app/src/st/svc/ST_REPORT.pgc +++ b/app/src/st/svc/ST_REPORT.pgc @@ -107,7 +107,7 @@ void ST_REPORT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "당일 정산 건수/합계 리포트. (심화판) [ST_REPORT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_RERUN.pgc b/app/src/st/svc/ST_RERUN.pgc index be2acb3..01e7855 100644 --- a/app/src/st/svc/ST_RERUN.pgc +++ b/app/src/st/svc/ST_RERUN.pgc @@ -107,7 +107,7 @@ void ST_RERUN(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 재실행 (상세 삭제 + 원본 기준 재생성). (심화판) [ST_RERUN] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -132,6 +132,72 @@ void ST_RERUN(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 정산 재실행 (상세 삭제 + 원본 기준 재생성). (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_RERUN -> ST_MDR (정산재수행-수수료재산출) ===== + * XA 규율: tpcall 로 부르는 ST_MDR 는 별도 XA 브랜치라 ST_RERUN 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_RERUN", 0L); + Bchg(b, T_REASON, 0, "정산재수행-수수료재산출", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[ST_RERUN] 정산재수행-수수료재산출: 체인 호출 -> ST_MDR pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("ST_MDR", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_RERUN] tpcall(ST_MDR) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8729); + Bchg(b, T_MSG, 0, "정산 재수행 수수료 재산출 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_RERUN 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_RERUN", 0L); + setl(b, T_RC, 0); + userlog("[ST_RERUN] 정산재수행-수수료재산출: 체인 완료 <- ST_MDR pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_RETRORATE.pgc b/app/src/st/svc/ST_RETRORATE.pgc index 52b4b92..f16689a 100644 --- a/app/src/st/svc/ST_RETRORATE.pgc +++ b/app/src/st/svc/ST_RETRORATE.pgc @@ -112,7 +112,7 @@ void ST_RETRORATE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "요율 소급적용 (차액 조정 기록). (심화판) [ST_RETRORATE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_ROUNDING.pgc b/app/src/st/svc/ST_ROUNDING.pgc index 18f55dd..13fa94d 100644 --- a/app/src/st/svc/ST_ROUNDING.pgc +++ b/app/src/st/svc/ST_ROUNDING.pgc @@ -118,7 +118,7 @@ void ST_ROUNDING(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 net 원단위 절사. (심화판) [ST_ROUNDING] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_SLABFEE.pgc b/app/src/st/svc/ST_SLABFEE.pgc index 13367cd..3139547 100644 --- a/app/src/st/svc/ST_SLABFEE.pgc +++ b/app/src/st/svc/ST_SLABFEE.pgc @@ -117,7 +117,7 @@ void ST_SLABFEE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "슬라브 누진 요율 수수료 합산. (심화판) [ST_SLABFEE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_SPLIT.pgc b/app/src/st/svc/ST_SPLIT.pgc index 87292bf..5cd6ec2 100644 --- a/app/src/st/svc/ST_SPLIT.pgc +++ b/app/src/st/svc/ST_SPLIT.pgc @@ -109,7 +109,7 @@ void ST_SPLIT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "분할 지급: net 을 n 회로 나눠 지급 레코드 생성 (dbio 루프). (심화판) [ST_SPLIT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_SPLITEVEN.pgc b/app/src/st/svc/ST_SPLITEVEN.pgc index 270fdce..e9b5038 100644 --- a/app/src/st/svc/ST_SPLITEVEN.pgc +++ b/app/src/st/svc/ST_SPLITEVEN.pgc @@ -109,7 +109,7 @@ void ST_SPLITEVEN(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "끝수 보정 균등 분할 지급. (심화판) [ST_SPLITEVEN] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_STATDETAIL.pgc b/app/src/st/svc/ST_STATDETAIL.pgc index 3341415..48b7563 100644 --- a/app/src/st/svc/ST_STATDETAIL.pgc +++ b/app/src/st/svc/ST_STATDETAIL.pgc @@ -108,7 +108,7 @@ void ST_STATDETAIL(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "수수료 종류별 세분 통계. (심화판) [ST_STATDETAIL] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_STATS.pgc b/app/src/st/svc/ST_STATS.pgc index 06b84a2..8ccbc1d 100644 --- a/app/src/st/svc/ST_STATS.pgc +++ b/app/src/st/svc/ST_STATS.pgc @@ -107,7 +107,7 @@ void ST_STATS(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 통계(건수/net 합계) 조회. (심화판) [ST_STATS] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_STATUS.pgc b/app/src/st/svc/ST_STATUS.pgc index 2e37b5c..cdf86dc 100644 --- a/app/src/st/svc/ST_STATUS.pgc +++ b/app/src/st/svc/ST_STATUS.pgc @@ -108,7 +108,7 @@ void ST_STATUS(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 상태 조회. (심화판) [ST_STATUS] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_SUPPLYCALC.pgc b/app/src/st/svc/ST_SUPPLYCALC.pgc index 15de5d2..838585b 100644 --- a/app/src/st/svc/ST_SUPPLYCALC.pgc +++ b/app/src/st/svc/ST_SUPPLYCALC.pgc @@ -117,7 +117,7 @@ void ST_SUPPLYCALC(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "VAT 포함 총액에서 공급가액 역산. (심화판) [ST_SUPPLYCALC] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_TAXINVCHK.pgc b/app/src/st/svc/ST_TAXINVCHK.pgc index cd3a591..fbcb1c5 100644 --- a/app/src/st/svc/ST_TAXINVCHK.pgc +++ b/app/src/st/svc/ST_TAXINVCHK.pgc @@ -107,7 +107,7 @@ void ST_TAXINVCHK(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "세금계산서-정산 VAT 대사. (심화판) [ST_TAXINVCHK] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -132,6 +132,67 @@ void ST_TAXINVCHK(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 세금계산서-정산 VAT 대사. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_TAXINVCHK -> VL_SETTLE (세금계산서-정산검증) ===== + * XA 규율: tpcall 로 부르는 VL_SETTLE 는 별도 XA 브랜치라 ST_TAXINVCHK 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_TAXINVCHK", 0L); + Bchg(b, T_REASON, 0, "세금계산서-정산검증", 0L); + userlog("[ST_TAXINVCHK] 세금계산서-정산검증: 체인 호출 -> VL_SETTLE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("VL_SETTLE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_TAXINVCHK] tpcall(VL_SETTLE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8733); + Bchg(b, T_MSG, 0, "세금계산서 검증(VL_SETTLE) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_TAXINVCHK 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_TAXINVCHK", 0L); + setl(b, T_RC, 0); + userlog("[ST_TAXINVCHK] 세금계산서-정산검증: 체인 완료 <- VL_SETTLE pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_TAXSUMMARY.pgc b/app/src/st/svc/ST_TAXSUMMARY.pgc index 1218615..ce7195b 100644 --- a/app/src/st/svc/ST_TAXSUMMARY.pgc +++ b/app/src/st/svc/ST_TAXSUMMARY.pgc @@ -108,7 +108,7 @@ void ST_TAXSUMMARY(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "부가세+원천세 통합 요약. (심화판) [ST_TAXSUMMARY] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_TIERFEE.pgc b/app/src/st/svc/ST_TIERFEE.pgc index 1867d6b..06dad44 100644 --- a/app/src/st/svc/ST_TIERFEE.pgc +++ b/app/src/st/svc/ST_TIERFEE.pgc @@ -118,7 +118,7 @@ void ST_TIERFEE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "해당 구간 요율로 정률 수수료 산출. (심화판) [ST_TIERFEE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_TIERINCENT.pgc b/app/src/st/svc/ST_TIERINCENT.pgc index e405038..6ce52d9 100644 --- a/app/src/st/svc/ST_TIERINCENT.pgc +++ b/app/src/st/svc/ST_TIERINCENT.pgc @@ -117,7 +117,7 @@ void ST_TIERINCENT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "거래대금 구간별 인센티브 정산. (심화판) [ST_TIERINCENT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_TOPMERCH.pgc b/app/src/st/svc/ST_TOPMERCH.pgc index b0a7d1c..76f2281 100644 --- a/app/src/st/svc/ST_TOPMERCH.pgc +++ b/app/src/st/svc/ST_TOPMERCH.pgc @@ -106,7 +106,7 @@ void ST_TOPMERCH(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "당일 정산 1위 가맹점 조회. (심화판) [ST_TOPMERCH] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_UNLOCK.pgc b/app/src/st/svc/ST_UNLOCK.pgc index 9114963..b8d07cd 100644 --- a/app/src/st/svc/ST_UNLOCK.pgc +++ b/app/src/st/svc/ST_UNLOCK.pgc @@ -117,7 +117,7 @@ void ST_UNLOCK(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 잠금 해제(LOCKED->SETTLED). (심화판) [ST_UNLOCK] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_UNPAIDSUM.pgc b/app/src/st/svc/ST_UNPAIDSUM.pgc index 4eb7626..34b2c11 100644 --- a/app/src/st/svc/ST_UNPAIDSUM.pgc +++ b/app/src/st/svc/ST_UNPAIDSUM.pgc @@ -109,7 +109,7 @@ void ST_UNPAIDSUM(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "예정일 경과 미지급 집계. (심화판) [ST_UNPAIDSUM] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_VANDETAIL.pgc b/app/src/st/svc/ST_VANDETAIL.pgc index 8a3cc00..4b01e19 100644 --- a/app/src/st/svc/ST_VANDETAIL.pgc +++ b/app/src/st/svc/ST_VANDETAIL.pgc @@ -108,7 +108,7 @@ void ST_VANDETAIL(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "VAN 수수료 건수/합계/평균 명세. (심화판) [ST_VANDETAIL] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_VANFEE.pgc b/app/src/st/svc/ST_VANFEE.pgc index 3afc23f..0c1607f 100644 --- a/app/src/st/svc/ST_VANFEE.pgc +++ b/app/src/st/svc/ST_VANFEE.pgc @@ -118,7 +118,7 @@ void ST_VANFEE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "VAN 수수료: 구간요율 조회 후 정산 상세 기록. (심화판) [ST_VANFEE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_VAT.pgc b/app/src/st/svc/ST_VAT.pgc index e6f9723..c4ea23e 100644 --- a/app/src/st/svc/ST_VAT.pgc +++ b/app/src/st/svc/ST_VAT.pgc @@ -117,7 +117,7 @@ void ST_VAT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "정산 부가세 원장 기록. (심화판) [ST_VAT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -147,6 +147,72 @@ void ST_VAT(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 정산 부가세 원장 기록. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_VAT -> ST_ADJUST (부가세-정산조정) ===== + * XA 규율: tpcall 로 부르는 ST_ADJUST 는 별도 XA 브랜치라 ST_VAT 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_VAT", 0L); + Bchg(b, T_REASON, 0, "부가세-정산조정", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[ST_VAT] 부가세-정산조정: 체인 호출 -> ST_ADJUST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("ST_ADJUST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_VAT] tpcall(ST_ADJUST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8721); + Bchg(b, T_MSG, 0, "부가세 정산조정(ST_ADJUST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_VAT 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_VAT", 0L); + setl(b, T_RC, 0); + userlog("[ST_VAT] 부가세-정산조정: 체인 완료 <- ST_ADJUST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_VATADJUST.pgc b/app/src/st/svc/ST_VATADJUST.pgc index b498101..886801e 100644 --- a/app/src/st/svc/ST_VATADJUST.pgc +++ b/app/src/st/svc/ST_VATADJUST.pgc @@ -117,7 +117,7 @@ void ST_VATADJUST(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "공급가액 조정 재부가세 기록. (심화판) [ST_VATADJUST] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -147,6 +147,67 @@ void ST_VATADJUST(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 공급가액 조정 재부가세 기록. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_VATADJUST -> LG_POST (부가세조정-원장반영) ===== + * XA 규율: tpcall 로 부르는 LG_POST 는 별도 XA 브랜치라 ST_VATADJUST 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_VATADJUST", 0L); + Bchg(b, T_REASON, 0, "부가세조정-원장반영", 0L); + userlog("[ST_VATADJUST] 부가세조정-원장반영: 체인 호출 -> LG_POST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_VATADJUST] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8723); + Bchg(b, T_MSG, 0, "부가세조정 원장반영(LG_POST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_VATADJUST 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_VATADJUST", 0L); + setl(b, T_RC, 0); + userlog("[ST_VATADJUST] 부가세조정-원장반영: 체인 완료 <- LG_POST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_VATDETAIL.pgc b/app/src/st/svc/ST_VATDETAIL.pgc index b467e84..4dd6374 100644 --- a/app/src/st/svc/ST_VATDETAIL.pgc +++ b/app/src/st/svc/ST_VATDETAIL.pgc @@ -108,7 +108,7 @@ void ST_VATDETAIL(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "수수료 합계 기준 부가세 명세. (심화판) [ST_VATDETAIL] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_VATREPORT.pgc b/app/src/st/svc/ST_VATREPORT.pgc index 0d2f17f..1800e92 100644 --- a/app/src/st/svc/ST_VATREPORT.pgc +++ b/app/src/st/svc/ST_VATREPORT.pgc @@ -109,7 +109,7 @@ void ST_VATREPORT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "월별 부가세 신고자료 집계. (심화판) [ST_VATREPORT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_VOIDRECALC.pgc b/app/src/st/svc/ST_VOIDRECALC.pgc index c4d9132..4fe192d 100644 --- a/app/src/st/svc/ST_VOIDRECALC.pgc +++ b/app/src/st/svc/ST_VOIDRECALC.pgc @@ -119,7 +119,7 @@ void ST_VOIDRECALC(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "전체 취소 역분개 + 지급 취소. (심화판) [ST_VOIDRECALC] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -144,6 +144,67 @@ void ST_VOIDRECALC(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 전체 취소 역분개 + 지급 취소. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_VOIDRECALC -> LG_REVERSE (무효재계산-원장역분개) ===== + * XA 규율: tpcall 로 부르는 LG_REVERSE 는 별도 XA 브랜치라 ST_VOIDRECALC 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_VOIDRECALC", 0L); + Bchg(b, T_REASON, 0, "무효재계산-원장역분개", 0L); + userlog("[ST_VOIDRECALC] 무효재계산-원장역분개: 체인 호출 -> LG_REVERSE pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_REVERSE", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_VOIDRECALC] tpcall(LG_REVERSE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8738); + Bchg(b, T_MSG, 0, "무효 재계산 역분개(LG_REVERSE) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_VOIDRECALC 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_VOIDRECALC", 0L); + setl(b, T_RC, 0); + userlog("[ST_VOIDRECALC] 무효재계산-원장역분개: 체인 완료 <- LG_REVERSE pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_VOLREBATE.pgc b/app/src/st/svc/ST_VOLREBATE.pgc index d8a13f8..d1421e0 100644 --- a/app/src/st/svc/ST_VOLREBATE.pgc +++ b/app/src/st/svc/ST_VOLREBATE.pgc @@ -105,7 +105,7 @@ void ST_VOLREBATE(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "거래건수 구간별 리베이트. (심화판) [ST_VOLREBATE] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_WHT.pgc b/app/src/st/svc/ST_WHT.pgc index f9a15b9..3756d5e 100644 --- a/app/src/st/svc/ST_WHT.pgc +++ b/app/src/st/svc/ST_WHT.pgc @@ -117,7 +117,7 @@ void ST_WHT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "원천징수(수수료의 22%) 정산 상세 기록. (심화판) [ST_WHT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -147,6 +147,72 @@ void ST_WHT(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 원천징수(수수료의 22%) 정산 상세 기록. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_WHT -> ST_ADJUST (원천세-정산조정) ===== + * XA 규율: tpcall 로 부르는 ST_ADJUST 는 별도 XA 브랜치라 ST_WHT 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_WHT", 0L); + Bchg(b, T_REASON, 0, "원천세-정산조정", 0L); + + { + long cx_dl = getl(b, T_DELTA); + if (cx_dl > 100000000L || cx_dl < -100000000L) setl(b, T_DELTA, 0); + } + userlog("[ST_WHT] 원천세-정산조정: 체인 호출 -> ST_ADJUST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("ST_ADJUST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_WHT] tpcall(ST_ADJUST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8722); + Bchg(b, T_MSG, 0, "원천세 정산조정(ST_ADJUST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_WHT 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_WHT", 0L); + setl(b, T_RC, 0); + userlog("[ST_WHT] 원천세-정산조정: 체인 완료 <- ST_ADJUST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/st/svc/ST_WHTDETAIL.pgc b/app/src/st/svc/ST_WHTDETAIL.pgc index 40ac012..5e7fe2c 100644 --- a/app/src/st/svc/ST_WHTDETAIL.pgc +++ b/app/src/st/svc/ST_WHTDETAIL.pgc @@ -108,7 +108,7 @@ void ST_WHTDETAIL(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "수수료 합계 기준 원천세 명세. (심화판) [ST_WHTDETAIL] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_WHTREPORT.pgc b/app/src/st/svc/ST_WHTREPORT.pgc index f2527ab..a87f249 100644 --- a/app/src/st/svc/ST_WHTREPORT.pgc +++ b/app/src/st/svc/ST_WHTREPORT.pgc @@ -109,7 +109,7 @@ void ST_WHTREPORT(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "가맹점 월별 원천세 명세 대사. (심화판) [ST_WHTREPORT] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_WORKFLOW.pgc b/app/src/st/svc/ST_WORKFLOW.pgc index 127e5cc..b9d7ffc 100644 --- a/app/src/st/svc/ST_WORKFLOW.pgc +++ b/app/src/st/svc/ST_WORKFLOW.pgc @@ -118,7 +118,7 @@ void ST_WORKFLOW(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "허용 전이 검증 후 정산 상태 갱신. (심화판) [ST_WORKFLOW] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; diff --git a/app/src/st/svc/ST_XFERLINK.pgc b/app/src/st/svc/ST_XFERLINK.pgc index c8786ab..86d4360 100644 --- a/app/src/st/svc/ST_XFERLINK.pgc +++ b/app/src/st/svc/ST_XFERLINK.pgc @@ -105,7 +105,7 @@ void ST_XFERLINK(TPSVCINFO *p) snprintf(msgbuf, sizeof(msgbuf), "이체 연계 원장 기록. (심화판) [ST_XFERLINK] pid=%ld fee=%ld delta=%ld net=%ld", h_pid, h_fee, h_delta, h_netsum); strncpy(h_msg, msgbuf, sizeof(h_msg)-1); h_msg[sizeof(h_msg)-1] = 0; EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date) - VALUES ((SELECT coalesce(max(log_id),0)+1 FROM cm_log), :h_svc, 'I', :h_msg, :h_bizdate); + VALUES (nextval('cm_log_seq'), :h_svc, 'I', :h_msg, :h_bizdate); if (sqlca.sqlcode < 0) { setl(b, T_RC, 91); Bchg(b, T_MSG, 0, "감사 로그 적재 실패", 0L); FAIL(b); } vstep = 5; @@ -130,6 +130,67 @@ void ST_XFERLINK(TPSVCINFO *p) setl(b, T_ARG4, (long)vstep); /* ===== 9) 완료 로깅 ===== */ userlog("[정산심화] 이체 연계 원장 기록. (심화판) 완료 rc=0 pid=%ld fee=%ld net=%ld", h_pid, h_fee, h_netsum); + + /* ===== 8b) 업무 체인 호출부: ST_XFERLINK -> LG_POST (이체연계-원장반영) ===== + * XA 규율: tpcall 로 부르는 LG_POST 는 별도 XA 브랜치라 ST_XFERLINK 가 방금 + * INSERT/UPDATE 한 미커밋 행을 볼 수 없다. 그러므로 체인에 필요한 값은 모두 + * UBF 전문(T_*)에 실어 넘기고, 하위는 전문값을 우선 사용한다(owner-writes). + * 하위 호출 실패는 같은 글로벌 트랜잭션이므로 FAIL 로 전체 롤백한다(보상 불필요). */ + { + long cx_rlen = 0; + long cx_pid = getl(b, T_PURCHASE_ID); + long cx_sid = getl(b, T_SETTLE_ID); + long cx_amt = getl(b, T_AMOUNT); + long cx_fee = getl(b, T_FEE); + long cx_net = getl(b, T_NET); + long cx_cnt = getl(b, T_COUNT); + long cx_grs = getl(b, T_GROSS); + long cx_samt, cx_sfee, cx_snet; + char cx_bd[16], cx_mid[64], cx_sts[16]; + + gets_(b, T_BIZDATE, cx_bd, sizeof(cx_bd)); + gets_(b, T_MERCHANT, cx_mid, sizeof(cx_mid)); + gets_(b, T_STATUS, cx_sts, sizeof(cx_sts)); + if (strlen(cx_bd) != 10) strcpy(cx_bd, "2026-07-20"); + if (cx_pid < 0) cx_pid = 0; + if (cx_sid < 0) cx_sid = 0; + cx_samt = (cx_amt < 0) ? -cx_amt : cx_amt; + cx_sfee = (cx_fee < 0) ? -cx_fee : cx_fee; + cx_snet = (cx_net < 0) ? 0 : cx_net; + + /* 하위가 필요로 하는 값을 전문에 적재 */ + Bchg(b, T_BIZDATE, 0, cx_bd, 0L); + if (cx_mid[0] != 0) Bchg(b, T_MERCHANT, 0, cx_mid, 0L); + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_SETTLE_ID, cx_sid); + setl(b, T_AMOUNT, cx_samt); + setl(b, T_FEE, cx_sfee); + setl(b, T_NET, cx_snet); + Bchg(b, T_SVCNAME, 0, "ST_XFERLINK", 0L); + Bchg(b, T_REASON, 0, "이체연계-원장반영", 0L); + userlog("[ST_XFERLINK] 이체연계-원장반영: 체인 호출 -> LG_POST pid=%ld sid=%ld amt=%ld biz=%s", + cx_pid, cx_sid, cx_samt, cx_bd); + if (tpcall("LG_POST", (char *)b, 0L, (char **)&b, &cx_rlen, 0L) < 0) { + userlog("[ST_XFERLINK] tpcall(LG_POST) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 8735); + Bchg(b, T_MSG, 0, "이체연계 원장반영(LG_POST) 실패", 0L); + FAIL(b); + } + /* 하위 응답 수신 — b 가 재할당될 수 있으므로 이후 Bget/Bchg 는 갱신된 b 사용. + * ST_XFERLINK 자신의 응답 계약(출력 필드)은 하위 응답에 덮이지 않도록 복원한다. */ + setl(b, T_PURCHASE_ID, cx_pid); + setl(b, T_AMOUNT, cx_amt); + setl(b, T_FEE, cx_fee); + setl(b, T_NET, cx_net); + setl(b, T_COUNT, cx_cnt); + setl(b, T_GROSS, cx_grs); + if (cx_sid > 0) setl(b, T_SETTLE_ID, cx_sid); + if (cx_sts[0] != 0) Bchg(b, T_STATUS, 0, cx_sts, 0L); + Bchg(b, T_SVCNAME, 0, "ST_XFERLINK", 0L); + setl(b, T_RC, 0); + userlog("[ST_XFERLINK] 이체연계-원장반영: 체인 완료 <- LG_POST pid=%ld", cx_pid); + } + OK(b); } diff --git a/app/src/vl/svc/VL_AMOUNT.pgc b/app/src/vl/svc/VL_AMOUNT.pgc index 6b12a89..0493961 100644 --- a/app/src/vl/svc/VL_AMOUNT.pgc +++ b/app/src/vl/svc/VL_AMOUNT.pgc @@ -118,6 +118,33 @@ void VL_AMOUNT(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_AMOUNT", 0L); + userlog("VL_AMOUNT: 금액 검증결과 감사적재 연계 -> CM_LOG pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_AMOUNT: tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9020); Bchg(b, T_MSG, 0, "금액 검증결과 감사적재 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_AMOUNT: CM_LOG 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_ANOMALY.pgc b/app/src/vl/svc/VL_ANOMALY.pgc index 0d7207d..2b4ad21 100644 --- a/app/src/vl/svc/VL_ANOMALY.pgc +++ b/app/src/vl/svc/VL_ANOMALY.pgc @@ -144,6 +144,37 @@ void VL_ANOMALY(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_ANOMALY", 0L); + if (v_metric < 3) { + userlog("VL_ANOMALY: 임계 미달 — 후속 연계 생략 base=%ld thr=%ld", v_base, v_thr); + } else { + userlog("VL_ANOMALY: 이상거래 탐지 연계 연계 -> FRAUD_DETECT pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("FRAUD_DETECT", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_ANOMALY: tpcall(FRAUD_DETECT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9051); Bchg(b, T_MSG, 0, "이상거래 탐지 연계 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_ANOMALY: FRAUD_DETECT 이상 회신 rc=%ld", c_sub); + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_APPRAMT.pgc b/app/src/vl/svc/VL_APPRAMT.pgc index 3cfe567..3b091b7 100644 --- a/app/src/vl/svc/VL_APPRAMT.pgc +++ b/app/src/vl/svc/VL_APPRAMT.pgc @@ -144,6 +144,33 @@ void VL_APPRAMT(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_APPRAMT", 0L); + userlog("VL_APPRAMT: 승인금액 검증결과 감사적재 연계 -> CM_LOG pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_APPRAMT: tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9012); Bchg(b, T_MSG, 0, "승인금액 검증결과 감사적재 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_APPRAMT: CM_LOG 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_APPRNOPUR.pgc b/app/src/vl/svc/VL_APPRNOPUR.pgc index abb90ca..4559990 100644 --- a/app/src/vl/svc/VL_APPRNOPUR.pgc +++ b/app/src/vl/svc/VL_APPRNOPUR.pgc @@ -116,6 +116,37 @@ void VL_APPRNOPUR(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_APPRNOPUR", 0L); + if (v_flag == 0) { + userlog("VL_APPRNOPUR: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + userlog("VL_APPRNOPUR: 승인이력 대조 연계 -> AUTH_HISTORY pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("AUTH_HISTORY", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_APPRNOPUR: tpcall(AUTH_HISTORY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9013); Bchg(b, T_MSG, 0, "승인이력 대조 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_APPRNOPUR: AUTH_HISTORY 이상 회신 rc=%ld", c_sub); + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_APPR_ACQ.pgc b/app/src/vl/svc/VL_APPR_ACQ.pgc index e7a8c6e..a7d701d 100644 --- a/app/src/vl/svc/VL_APPR_ACQ.pgc +++ b/app/src/vl/svc/VL_APPR_ACQ.pgc @@ -138,6 +138,33 @@ void VL_APPR_ACQ(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_APPR_ACQ", 0L); + userlog("VL_APPR_ACQ: 승인-매입 검증결과 감사적재 연계 -> CM_LOG pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_APPR_ACQ: tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9011); Bchg(b, T_MSG, 0, "승인-매입 검증결과 감사적재 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_APPR_ACQ: CM_LOG 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_AXPURAPPR.pgc b/app/src/vl/svc/VL_AXPURAPPR.pgc index b690f7a..1c2f52c 100644 --- a/app/src/vl/svc/VL_AXPURAPPR.pgc +++ b/app/src/vl/svc/VL_AXPURAPPR.pgc @@ -112,6 +112,33 @@ void VL_AXPURAPPR(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_AXPURAPPR", 0L); + userlog("VL_AXPURAPPR: 매입-승인 축 검증 감사적재 연계 -> CM_LOG pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_AXPURAPPR: tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9016); Bchg(b, T_MSG, 0, "매입-승인 축 검증 감사적재 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_AXPURAPPR: CM_LOG 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_AXSETTPAY.pgc b/app/src/vl/svc/VL_AXSETTPAY.pgc index 23edb4c..9289f58 100644 --- a/app/src/vl/svc/VL_AXSETTPAY.pgc +++ b/app/src/vl/svc/VL_AXSETTPAY.pgc @@ -112,6 +112,33 @@ void VL_AXSETTPAY(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_AXSETTPAY", 0L); + userlog("VL_AXSETTPAY: 정산-지급 축 검증 감사적재 연계 -> CM_LOG pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_AXSETTPAY: tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9024); Bchg(b, T_MSG, 0, "정산-지급 축 검증 감사적재 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_AXSETTPAY: CM_LOG 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_BALANCE.pgc b/app/src/vl/svc/VL_BALANCE.pgc index 0285457..2f1f2b7 100644 --- a/app/src/vl/svc/VL_BALANCE.pgc +++ b/app/src/vl/svc/VL_BALANCE.pgc @@ -137,6 +137,37 @@ void VL_BALANCE(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_BALANCE", 0L); + if (v_flag == 0) { + userlog("VL_BALANCE: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + userlog("VL_BALANCE: 잔액 정합성 대조 연계 -> LG_BALCHK pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_BALANCE: tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9044); Bchg(b, T_MSG, 0, "잔액 정합성 대조 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_BALANCE: LG_BALCHK 이상 회신 rc=%ld", c_sub); + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_BATCH_CHK.pgc b/app/src/vl/svc/VL_BATCH_CHK.pgc index 94f0d94..328414b 100644 --- a/app/src/vl/svc/VL_BATCH_CHK.pgc +++ b/app/src/vl/svc/VL_BATCH_CHK.pgc @@ -113,6 +113,33 @@ void VL_BATCH_CHK(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_BATCH_CHK", 0L); + userlog("VL_BATCH_CHK: 배치 검증결과 감사적재 연계 -> CM_LOG pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_BATCH_CHK: tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9019); Bchg(b, T_MSG, 0, "배치 검증결과 감사적재 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_BATCH_CHK: CM_LOG 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_BIN.pgc b/app/src/vl/svc/VL_BIN.pgc index 79fbbba..811e1dd 100644 --- a/app/src/vl/svc/VL_BIN.pgc +++ b/app/src/vl/svc/VL_BIN.pgc @@ -112,6 +112,41 @@ void VL_BIN(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_BIN", 0L); + userlog("VL_BIN: BIN 자릿수 Luhn 검증 연계 -> CM_LUHN pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LUHN", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_BIN: tpcall(CM_LUHN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9062); Bchg(b, T_MSG, 0, "BIN 자릿수 Luhn 검증 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_BIN: CM_LUHN 이상 회신 rc=%ld", c_sub); + userlog("VL_BIN: BIN 라우팅 조회 연계 -> BIN_ROUTE_INQ pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("BIN_ROUTE_INQ", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_BIN: tpcall(BIN_ROUTE_INQ) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9063); Bchg(b, T_MSG, 0, "BIN 라우팅 조회 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_BIN: BIN_ROUTE_INQ 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_CARD.pgc b/app/src/vl/svc/VL_CARD.pgc index 1ba21df..b3b334c 100644 --- a/app/src/vl/svc/VL_CARD.pgc +++ b/app/src/vl/svc/VL_CARD.pgc @@ -112,6 +112,33 @@ void VL_CARD(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_CARD", 0L); + userlog("VL_CARD: 카드번호 Luhn 검증 연계 -> CM_LUHN pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LUHN", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_CARD: tpcall(CM_LUHN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9061); Bchg(b, T_MSG, 0, "카드번호 Luhn 검증 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_CARD: CM_LUHN 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_CROSSCHK.pgc b/app/src/vl/svc/VL_CROSSCHK.pgc index 9c5e7fa..e4285f8 100644 --- a/app/src/vl/svc/VL_CROSSCHK.pgc +++ b/app/src/vl/svc/VL_CROSSCHK.pgc @@ -138,6 +138,49 @@ void VL_CROSSCHK(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_CROSSCHK", 0L); + userlog("VL_CROSSCHK: 승인 축 조회 연계 -> AUTH_STATUS pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("AUTH_STATUS", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_CROSSCHK: tpcall(AUTH_STATUS) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9030); Bchg(b, T_MSG, 0, "승인 축 조회 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_CROSSCHK: AUTH_STATUS 이상 회신 rc=%ld", c_sub); + userlog("VL_CROSSCHK: 정산 축 조회 연계 -> ST_STATUS pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("ST_STATUS", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_CROSSCHK: tpcall(ST_STATUS) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9031); Bchg(b, T_MSG, 0, "정산 축 조회 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_CROSSCHK: ST_STATUS 이상 회신 rc=%ld", c_sub); + userlog("VL_CROSSCHK: 원장 축 조회 연계 -> LG_STATUS pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("LG_STATUS", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_CROSSCHK: tpcall(LG_STATUS) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9032); Bchg(b, T_MSG, 0, "원장 축 조회 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_CROSSCHK: LG_STATUS 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_DAYLIMIT.pgc b/app/src/vl/svc/VL_DAYLIMIT.pgc index 58f5eb8..e8d9252 100644 --- a/app/src/vl/svc/VL_DAYLIMIT.pgc +++ b/app/src/vl/svc/VL_DAYLIMIT.pgc @@ -136,6 +136,37 @@ void VL_DAYLIMIT(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_DAYLIMIT", 0L); + if (v_metric < 3) { + userlog("VL_DAYLIMIT: 임계 미달 — 후속 연계 생략 base=%ld thr=%ld", v_base, v_thr); + } else { + userlog("VL_DAYLIMIT: 일한도 확인 연계 -> LIMIT_CHK pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("LIMIT_CHK", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_DAYLIMIT: tpcall(LIMIT_CHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9093); Bchg(b, T_MSG, 0, "일한도 확인 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_DAYLIMIT: LIMIT_CHK 이상 회신 rc=%ld", c_sub); + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_DUP.pgc b/app/src/vl/svc/VL_DUP.pgc index 9556587..9042d47 100644 --- a/app/src/vl/svc/VL_DUP.pgc +++ b/app/src/vl/svc/VL_DUP.pgc @@ -143,6 +143,41 @@ void VL_DUP(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_DUP", 0L); + if (v_flag == 0) { + userlog("VL_DUP: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + if (c_pid <= 0 || strlen(c_date) < 8) { + userlog("VL_DUP: 매입키 미지정 — 대사 연계 생략 pid=%ld", c_pid); + } else { + userlog("VL_DUP: 중복거래 대사 확인 연계 -> RC_DUPCHK pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("RC_DUPCHK", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_DUP: tpcall(RC_DUPCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9071); Bchg(b, T_MSG, 0, "중복거래 대사 확인 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_DUP: RC_DUPCHK 이상 회신 rc=%ld", c_sub); + } + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_DUPAPPR.pgc b/app/src/vl/svc/VL_DUPAPPR.pgc index 0744aae..e161b4f 100644 --- a/app/src/vl/svc/VL_DUPAPPR.pgc +++ b/app/src/vl/svc/VL_DUPAPPR.pgc @@ -138,6 +138,37 @@ void VL_DUPAPPR(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_DUPAPPR", 0L); + if (v_flag == 0) { + userlog("VL_DUPAPPR: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + userlog("VL_DUPAPPR: 승인 요약 대조 연계 -> AUTH_SUMMARY pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("AUTH_SUMMARY", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_DUPAPPR: tpcall(AUTH_SUMMARY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9075); Bchg(b, T_MSG, 0, "승인 요약 대조 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_DUPAPPR: AUTH_SUMMARY 이상 회신 rc=%ld", c_sub); + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_DUPAUTH.pgc b/app/src/vl/svc/VL_DUPAUTH.pgc index 9f62fee..c74c430 100644 --- a/app/src/vl/svc/VL_DUPAUTH.pgc +++ b/app/src/vl/svc/VL_DUPAUTH.pgc @@ -138,6 +138,41 @@ void VL_DUPAUTH(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_DUPAUTH", 0L); + if (v_flag == 0) { + userlog("VL_DUPAUTH: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + if (c_pid <= 0 || strlen(c_date) < 8) { + userlog("VL_DUPAUTH: 매입키 미지정 — 대사 연계 생략 pid=%ld", c_pid); + } else { + userlog("VL_DUPAUTH: 중복승인 미매칭 대사 연계 -> RC_UNMATCH pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("RC_UNMATCH", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_DUPAUTH: tpcall(RC_UNMATCH) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9072); Bchg(b, T_MSG, 0, "중복승인 미매칭 대사 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_DUPAUTH: RC_UNMATCH 이상 회신 rc=%ld", c_sub); + } + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_DUPLEDGR.pgc b/app/src/vl/svc/VL_DUPLEDGR.pgc index f2f0599..215bec9 100644 --- a/app/src/vl/svc/VL_DUPLEDGR.pgc +++ b/app/src/vl/svc/VL_DUPLEDGR.pgc @@ -137,6 +137,37 @@ void VL_DUPLEDGR(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_DUPLEDGR", 0L); + if (v_flag == 0) { + userlog("VL_DUPLEDGR: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + userlog("VL_DUPLEDGR: 원장 중복 스캔 연계 -> LG_DUPSCAN pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("LG_DUPSCAN", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_DUPLEDGR: tpcall(LG_DUPSCAN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9076); Bchg(b, T_MSG, 0, "원장 중복 스캔 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_DUPLEDGR: LG_DUPSCAN 이상 회신 rc=%ld", c_sub); + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_DUPPAY.pgc b/app/src/vl/svc/VL_DUPPAY.pgc index ec2ebe2..229fc59 100644 --- a/app/src/vl/svc/VL_DUPPAY.pgc +++ b/app/src/vl/svc/VL_DUPPAY.pgc @@ -138,6 +138,41 @@ void VL_DUPPAY(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_DUPPAY", 0L); + if (v_flag == 0) { + userlog("VL_DUPPAY: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + if (c_pid <= 0 || strlen(c_date) < 8) { + userlog("VL_DUPPAY: 매입키 미지정 — 대사 연계 생략 pid=%ld", c_pid); + } else { + userlog("VL_DUPPAY: 중복지급 대사 확인 연계 -> RC_DUPCHK pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("RC_DUPCHK", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_DUPPAY: tpcall(RC_DUPCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9074); Bchg(b, T_MSG, 0, "중복지급 대사 확인 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_DUPPAY: RC_DUPCHK 이상 회신 rc=%ld", c_sub); + } + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_DUPPURCH.pgc b/app/src/vl/svc/VL_DUPPURCH.pgc index ef47a70..f20c388 100644 --- a/app/src/vl/svc/VL_DUPPURCH.pgc +++ b/app/src/vl/svc/VL_DUPPURCH.pgc @@ -137,6 +137,33 @@ void VL_DUPPURCH(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_DUPPURCH", 0L); + userlog("VL_DUPPURCH: 중복매입 검증 감사적재 연계 -> CM_LOG pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_DUPPURCH: tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9028); Bchg(b, T_MSG, 0, "중복매입 검증 감사적재 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_DUPPURCH: CM_LOG 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_DUPSETTLE.pgc b/app/src/vl/svc/VL_DUPSETTLE.pgc index 40fec6f..90f07f2 100644 --- a/app/src/vl/svc/VL_DUPSETTLE.pgc +++ b/app/src/vl/svc/VL_DUPSETTLE.pgc @@ -142,6 +142,41 @@ void VL_DUPSETTLE(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_DUPSETTLE", 0L); + if (v_flag == 0) { + userlog("VL_DUPSETTLE: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + if (c_pid <= 0 || strlen(c_date) < 8) { + userlog("VL_DUPSETTLE: 매입키 미지정 — 대사 연계 생략 pid=%ld", c_pid); + } else { + userlog("VL_DUPSETTLE: 중복정산 미매칭 대사 연계 -> RC_UNMATCH pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("RC_UNMATCH", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_DUPSETTLE: tpcall(RC_UNMATCH) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9073); Bchg(b, T_MSG, 0, "중복정산 미매칭 대사 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_DUPSETTLE: RC_UNMATCH 이상 회신 rc=%ld", c_sub); + } + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_EXPIRY.pgc b/app/src/vl/svc/VL_EXPIRY.pgc index 48162af..7d9a425 100644 --- a/app/src/vl/svc/VL_EXPIRY.pgc +++ b/app/src/vl/svc/VL_EXPIRY.pgc @@ -113,6 +113,41 @@ void VL_EXPIRY(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_EXPIRY", 0L); + userlog("VL_EXPIRY: 카드번호 유효성 선검증 연계 -> CM_LUHN pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LUHN", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_EXPIRY: tpcall(CM_LUHN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9064); Bchg(b, T_MSG, 0, "카드번호 유효성 선검증 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_EXPIRY: CM_LUHN 이상 회신 rc=%ld", c_sub); + userlog("VL_EXPIRY: 카드 유효기간 확인 연계 -> CARD_EXPIRE_CHK pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CARD_EXPIRE_CHK", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_EXPIRY: tpcall(CARD_EXPIRE_CHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9065); Bchg(b, T_MSG, 0, "카드 유효기간 확인 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_EXPIRY: CARD_EXPIRE_CHK 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_FEE.pgc b/app/src/vl/svc/VL_FEE.pgc index 338af39..9a87c39 100644 --- a/app/src/vl/svc/VL_FEE.pgc +++ b/app/src/vl/svc/VL_FEE.pgc @@ -138,6 +138,33 @@ void VL_FEE(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_FEE", 0L); + userlog("VL_FEE: 수수료 검증결과 감사적재 연계 -> CM_LOG pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_FEE: tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9021); Bchg(b, T_MSG, 0, "수수료 검증결과 감사적재 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_FEE: CM_LOG 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_FEERECALC.pgc b/app/src/vl/svc/VL_FEERECALC.pgc index 3735ca0..eec7045 100644 --- a/app/src/vl/svc/VL_FEERECALC.pgc +++ b/app/src/vl/svc/VL_FEERECALC.pgc @@ -138,6 +138,33 @@ void VL_FEERECALC(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_FEERECALC", 0L); + userlog("VL_FEERECALC: 수수료 재계산 라운딩 대조 연계 -> CM_AMT_ROUND pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_AMT_ROUND", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_FEERECALC: tpcall(CM_AMT_ROUND) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9095); Bchg(b, T_MSG, 0, "수수료 재계산 라운딩 대조 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_FEERECALC: CM_AMT_ROUND 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); v_step = 8; diff --git a/app/src/vl/svc/VL_FORMAT.pgc b/app/src/vl/svc/VL_FORMAT.pgc index 6c3912b..748ce89 100644 --- a/app/src/vl/svc/VL_FORMAT.pgc +++ b/app/src/vl/svc/VL_FORMAT.pgc @@ -136,6 +136,33 @@ void VL_FORMAT(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_FORMAT", 0L); + userlog("VL_FORMAT: 번호형식 체크디지트 검증 연계 -> CM_LUHN pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LUHN", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_FORMAT: tpcall(CM_LUHN) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9066); Bchg(b, T_MSG, 0, "번호형식 체크디지트 검증 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_FORMAT: CM_LUHN 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_FXCHK.pgc b/app/src/vl/svc/VL_FXCHK.pgc index 429af95..f0cefa1 100644 --- a/app/src/vl/svc/VL_FXCHK.pgc +++ b/app/src/vl/svc/VL_FXCHK.pgc @@ -137,6 +137,33 @@ void VL_FXCHK(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_FXCHK", 0L); + userlog("VL_FXCHK: 적용환율 유효성 확인 연계 -> CM_FX_VALID pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_FX_VALID", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_FXCHK: tpcall(CM_FX_VALID) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9023); Bchg(b, T_MSG, 0, "적용환율 유효성 확인 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_FXCHK: CM_FX_VALID 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); v_step = 8; diff --git a/app/src/vl/svc/VL_LEDGBAL.pgc b/app/src/vl/svc/VL_LEDGBAL.pgc index 303e28a..aa5bac7 100644 --- a/app/src/vl/svc/VL_LEDGBAL.pgc +++ b/app/src/vl/svc/VL_LEDGBAL.pgc @@ -113,6 +113,37 @@ void VL_LEDGBAL(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_LEDGBAL", 0L); + if (v_flag == 0) { + userlog("VL_LEDGBAL: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + userlog("VL_LEDGBAL: 원장 잔액 대조 연계 -> LG_BALCHK pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("LG_BALCHK", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_LEDGBAL: tpcall(LG_BALCHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9043); Bchg(b, T_MSG, 0, "원장 잔액 대조 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_LEDGBAL: LG_BALCHK 이상 회신 rc=%ld", c_sub); + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_LEDGENTRY.pgc b/app/src/vl/svc/VL_LEDGENTRY.pgc index 32bdb02..6ea4ca3 100644 --- a/app/src/vl/svc/VL_LEDGENTRY.pgc +++ b/app/src/vl/svc/VL_LEDGENTRY.pgc @@ -143,6 +143,33 @@ void VL_LEDGENTRY(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_LEDGENTRY", 0L); + userlog("VL_LEDGENTRY: 원장 전표 조회 연계 -> LG_INQUIRY pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("LG_INQUIRY", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_LEDGENTRY: tpcall(LG_INQUIRY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9096); Bchg(b, T_MSG, 0, "원장 전표 조회 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_LEDGENTRY: LG_INQUIRY 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_LEDGER.pgc b/app/src/vl/svc/VL_LEDGER.pgc index d60c77e..5e1bf4d 100644 --- a/app/src/vl/svc/VL_LEDGER.pgc +++ b/app/src/vl/svc/VL_LEDGER.pgc @@ -139,6 +139,33 @@ void VL_LEDGER(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_LEDGER", 0L); + userlog("VL_LEDGER: 원장 검증결과 감사적재 연계 -> CM_LOG pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_LEDGER: tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9017); Bchg(b, T_MSG, 0, "원장 검증결과 감사적재 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_LEDGER: CM_LOG 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_LIMIT.pgc b/app/src/vl/svc/VL_LIMIT.pgc index d6751f6..6fb904a 100644 --- a/app/src/vl/svc/VL_LIMIT.pgc +++ b/app/src/vl/svc/VL_LIMIT.pgc @@ -142,6 +142,37 @@ void VL_LIMIT(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_LIMIT", 0L); + if (v_metric < 3) { + userlog("VL_LIMIT: 임계 미달 — 후속 연계 생략 base=%ld thr=%ld", v_base, v_thr); + } else { + userlog("VL_LIMIT: 한도 확인 연계 -> LIMIT_CHK pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("LIMIT_CHK", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_LIMIT: tpcall(LIMIT_CHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9091); Bchg(b, T_MSG, 0, "한도 확인 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_LIMIT: LIMIT_CHK 이상 회신 rc=%ld", c_sub); + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_MDRRATE.pgc b/app/src/vl/svc/VL_MDRRATE.pgc index 0011f6d..767d776 100644 --- a/app/src/vl/svc/VL_MDRRATE.pgc +++ b/app/src/vl/svc/VL_MDRRATE.pgc @@ -112,6 +112,33 @@ void VL_MDRRATE(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_MDRRATE", 0L); + userlog("VL_MDRRATE: 가맹점 요율표 조회 연계 -> ST_RATECARD pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("ST_RATECARD", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_MDRRATE: tpcall(ST_RATECARD) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9094); Bchg(b, T_MSG, 0, "가맹점 요율표 조회 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_MDRRATE: ST_RATECARD 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_NEGBAL.pgc b/app/src/vl/svc/VL_NEGBAL.pgc index 8b8c993..6db76a8 100644 --- a/app/src/vl/svc/VL_NEGBAL.pgc +++ b/app/src/vl/svc/VL_NEGBAL.pgc @@ -112,6 +112,41 @@ void VL_NEGBAL(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_NEGBAL", 0L); + if (v_flag == 0) { + userlog("VL_NEGBAL: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + if (c_pid <= 0 || strlen(c_date) < 8) { + userlog("VL_NEGBAL: 매입키 미지정 — 대사 연계 생략 pid=%ld", c_pid); + } else { + userlog("VL_NEGBAL: 음수잔액 대사예외 등록 연계 -> RC_EXCEPTION pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("RC_EXCEPTION", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_NEGBAL: tpcall(RC_EXCEPTION) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9045); Bchg(b, T_MSG, 0, "음수잔액 대사예외 등록 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_NEGBAL: RC_EXCEPTION 이상 회신 rc=%ld", c_sub); + } + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_NEGFEE.pgc b/app/src/vl/svc/VL_NEGFEE.pgc index d56e0e4..7f6e608 100644 --- a/app/src/vl/svc/VL_NEGFEE.pgc +++ b/app/src/vl/svc/VL_NEGFEE.pgc @@ -117,6 +117,41 @@ void VL_NEGFEE(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_NEGFEE", 0L); + if (v_flag == 0) { + userlog("VL_NEGFEE: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + if (c_pid <= 0 || strlen(c_date) < 8) { + userlog("VL_NEGFEE: 매입키 미지정 — 대사 연계 생략 pid=%ld", c_pid); + } else { + userlog("VL_NEGFEE: 음수수수료 대사예외 등록 연계 -> RC_EXCEPTION pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("RC_EXCEPTION", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_NEGFEE: tpcall(RC_EXCEPTION) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9047); Bchg(b, T_MSG, 0, "음수수수료 대사예외 등록 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_NEGFEE: RC_EXCEPTION 이상 회신 rc=%ld", c_sub); + } + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_NEGNET.pgc b/app/src/vl/svc/VL_NEGNET.pgc index 2fed81e..64c75ba 100644 --- a/app/src/vl/svc/VL_NEGNET.pgc +++ b/app/src/vl/svc/VL_NEGNET.pgc @@ -112,6 +112,41 @@ void VL_NEGNET(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_NEGNET", 0L); + if (v_flag == 0) { + userlog("VL_NEGNET: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + if (c_pid <= 0 || strlen(c_date) < 8) { + userlog("VL_NEGNET: 매입키 미지정 — 대사 연계 생략 pid=%ld", c_pid); + } else { + userlog("VL_NEGNET: 음수정산액 대사예외 등록 연계 -> RC_EXCEPTION pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("RC_EXCEPTION", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_NEGNET: tpcall(RC_EXCEPTION) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9046); Bchg(b, T_MSG, 0, "음수정산액 대사예외 등록 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_NEGNET: RC_EXCEPTION 이상 회신 rc=%ld", c_sub); + } + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_NIGHTTXN.pgc b/app/src/vl/svc/VL_NIGHTTXN.pgc index 434379c..3aec455 100644 --- a/app/src/vl/svc/VL_NIGHTTXN.pgc +++ b/app/src/vl/svc/VL_NIGHTTXN.pgc @@ -112,6 +112,37 @@ void VL_NIGHTTXN(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_NIGHTTXN", 0L); + if (v_metric < 3) { + userlog("VL_NIGHTTXN: 임계 미달 — 후속 연계 생략 base=%ld thr=%ld", v_base, v_thr); + } else { + userlog("VL_NIGHTTXN: 심야거래 룰 평가 연계 -> FRAUD_RULE_NIGHT pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("FRAUD_RULE_NIGHT", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_NIGHTTXN: tpcall(FRAUD_RULE_NIGHT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9055); Bchg(b, T_MSG, 0, "심야거래 룰 평가 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_NIGHTTXN: FRAUD_RULE_NIGHT 이상 회신 rc=%ld", c_sub); + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); v_step = 8; diff --git a/app/src/vl/svc/VL_OUTLIER.pgc b/app/src/vl/svc/VL_OUTLIER.pgc index 81e8ecb..6f03321 100644 --- a/app/src/vl/svc/VL_OUTLIER.pgc +++ b/app/src/vl/svc/VL_OUTLIER.pgc @@ -112,6 +112,37 @@ void VL_OUTLIER(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_OUTLIER", 0L); + if (v_metric < 3) { + userlog("VL_OUTLIER: 임계 미달 — 후속 연계 생략 base=%ld thr=%ld", v_base, v_thr); + } else { + userlog("VL_OUTLIER: 이상치 부정탐지 연계 연계 -> FRAUD_DETECT pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("FRAUD_DETECT", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_OUTLIER: tpcall(FRAUD_DETECT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9053); Bchg(b, T_MSG, 0, "이상치 부정탐지 연계 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_OUTLIER: FRAUD_DETECT 이상 회신 rc=%ld", c_sub); + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); v_step = 8; diff --git a/app/src/vl/svc/VL_OVERLIMIT.pgc b/app/src/vl/svc/VL_OVERLIMIT.pgc index 40b6b84..a81dba4 100644 --- a/app/src/vl/svc/VL_OVERLIMIT.pgc +++ b/app/src/vl/svc/VL_OVERLIMIT.pgc @@ -112,6 +112,37 @@ void VL_OVERLIMIT(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_OVERLIMIT", 0L); + if (v_metric < 3) { + userlog("VL_OVERLIMIT: 임계 미달 — 후속 연계 생략 base=%ld thr=%ld", v_base, v_thr); + } else { + userlog("VL_OVERLIMIT: 한도 초과 확인 연계 -> LIMIT_CHK pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("LIMIT_CHK", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_OVERLIMIT: tpcall(LIMIT_CHK) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9092); Bchg(b, T_MSG, 0, "한도 초과 확인 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_OVERLIMIT: LIMIT_CHK 이상 회신 rc=%ld", c_sub); + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_PURNOAPPR.pgc b/app/src/vl/svc/VL_PURNOAPPR.pgc index 3f17492..71f4649 100644 --- a/app/src/vl/svc/VL_PURNOAPPR.pgc +++ b/app/src/vl/svc/VL_PURNOAPPR.pgc @@ -117,6 +117,37 @@ void VL_PURNOAPPR(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_PURNOAPPR", 0L); + if (v_flag == 0) { + userlog("VL_PURNOAPPR: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + userlog("VL_PURNOAPPR: 무승인 매입 승인이력 대조 연계 -> AUTH_HISTORY pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("AUTH_HISTORY", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_PURNOAPPR: tpcall(AUTH_HISTORY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9014); Bchg(b, T_MSG, 0, "무승인 매입 승인이력 대조 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_PURNOAPPR: AUTH_HISTORY 이상 회신 rc=%ld", c_sub); + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_REFINTEG.pgc b/app/src/vl/svc/VL_REFINTEG.pgc index 7b4eb78..88b0301 100644 --- a/app/src/vl/svc/VL_REFINTEG.pgc +++ b/app/src/vl/svc/VL_REFINTEG.pgc @@ -138,6 +138,33 @@ void VL_REFINTEG(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_REFINTEG", 0L); + userlog("VL_REFINTEG: 원장 참조 조회 연계 -> LG_INQUIRY pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("LG_INQUIRY", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_REFINTEG: tpcall(LG_INQUIRY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9081); Bchg(b, T_MSG, 0, "원장 참조 조회 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_REFINTEG: LG_INQUIRY 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_RIAPPR.pgc b/app/src/vl/svc/VL_RIAPPR.pgc index 68a75f6..2452907 100644 --- a/app/src/vl/svc/VL_RIAPPR.pgc +++ b/app/src/vl/svc/VL_RIAPPR.pgc @@ -111,6 +111,33 @@ void VL_RIAPPR(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_RIAPPR", 0L); + userlog("VL_RIAPPR: 승인 상태 조회 연계 -> AUTH_STATUS pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("AUTH_STATUS", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_RIAPPR: tpcall(AUTH_STATUS) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9015); Bchg(b, T_MSG, 0, "승인 상태 조회 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_RIAPPR: AUTH_STATUS 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_RICANCEL.pgc b/app/src/vl/svc/VL_RICANCEL.pgc index b23e204..cda36cd 100644 --- a/app/src/vl/svc/VL_RICANCEL.pgc +++ b/app/src/vl/svc/VL_RICANCEL.pgc @@ -112,6 +112,33 @@ void VL_RICANCEL(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_RICANCEL", 0L); + userlog("VL_RICANCEL: 취소 상태 조회 연계 -> CANCEL_STATUS pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CANCEL_STATUS", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_RICANCEL: tpcall(CANCEL_STATUS) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9086); Bchg(b, T_MSG, 0, "취소 상태 조회 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_RICANCEL: CANCEL_STATUS 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_RIFX.pgc b/app/src/vl/svc/VL_RIFX.pgc index e3965b9..2d23d38 100644 --- a/app/src/vl/svc/VL_RIFX.pgc +++ b/app/src/vl/svc/VL_RIFX.pgc @@ -111,6 +111,33 @@ void VL_RIFX(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_RIFX", 0L); + userlog("VL_RIFX: 환율 참조 조회 연계 -> CM_FX_CONV pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_FX_CONV", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_RIFX: tpcall(CM_FX_CONV) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9087); Bchg(b, T_MSG, 0, "환율 참조 조회 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_RIFX: CM_FX_CONV 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_RIINSTALL.pgc b/app/src/vl/svc/VL_RIINSTALL.pgc index 0381627..bf80b26 100644 --- a/app/src/vl/svc/VL_RIINSTALL.pgc +++ b/app/src/vl/svc/VL_RIINSTALL.pgc @@ -111,6 +111,33 @@ void VL_RIINSTALL(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_RIINSTALL", 0L); + userlog("VL_RIINSTALL: 할부 원승인 조회 연계 -> PREAUTH_INQ pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("PREAUTH_INQ", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_RIINSTALL: tpcall(PREAUTH_INQ) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9088); Bchg(b, T_MSG, 0, "할부 원승인 조회 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_RIINSTALL: PREAUTH_INQ 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_RILEDGER.pgc b/app/src/vl/svc/VL_RILEDGER.pgc index 834a5e5..963e5fc 100644 --- a/app/src/vl/svc/VL_RILEDGER.pgc +++ b/app/src/vl/svc/VL_RILEDGER.pgc @@ -112,6 +112,33 @@ void VL_RILEDGER(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_RILEDGER", 0L); + userlog("VL_RILEDGER: 원장 상태 조회 연계 -> LG_STATUS pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("LG_STATUS", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_RILEDGER: tpcall(LG_STATUS) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9085); Bchg(b, T_MSG, 0, "원장 상태 조회 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_RILEDGER: LG_STATUS 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_RIMERCH.pgc b/app/src/vl/svc/VL_RIMERCH.pgc index ba1de49..1d24dc4 100644 --- a/app/src/vl/svc/VL_RIMERCH.pgc +++ b/app/src/vl/svc/VL_RIMERCH.pgc @@ -117,6 +117,33 @@ void VL_RIMERCH(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_RIMERCH", 0L); + userlog("VL_RIMERCH: 가맹점 코드 조회 연계 -> CM_CODE pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_CODE", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_RIMERCH: tpcall(CM_CODE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9082); Bchg(b, T_MSG, 0, "가맹점 코드 조회 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_RIMERCH: CM_CODE 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_RIPAY.pgc b/app/src/vl/svc/VL_RIPAY.pgc index 2cef9ab..e9cd1b6 100644 --- a/app/src/vl/svc/VL_RIPAY.pgc +++ b/app/src/vl/svc/VL_RIPAY.pgc @@ -116,6 +116,33 @@ void VL_RIPAY(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_RIPAY", 0L); + userlog("VL_RIPAY: 지급 원장 조회 대조 연계 -> LG_INQUIRY pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("LG_INQUIRY", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_RIPAY: tpcall(LG_INQUIRY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9025); Bchg(b, T_MSG, 0, "지급 원장 조회 대조 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_RIPAY: LG_INQUIRY 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_RIPURCH.pgc b/app/src/vl/svc/VL_RIPURCH.pgc index cf3505e..b82c829 100644 --- a/app/src/vl/svc/VL_RIPURCH.pgc +++ b/app/src/vl/svc/VL_RIPURCH.pgc @@ -117,6 +117,33 @@ void VL_RIPURCH(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_RIPURCH", 0L); + userlog("VL_RIPURCH: 매입 원승인 조회 연계 -> AUTH_HISTORY pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("AUTH_HISTORY", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_RIPURCH: tpcall(AUTH_HISTORY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9083); Bchg(b, T_MSG, 0, "매입 원승인 조회 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_RIPURCH: AUTH_HISTORY 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_RISETTLE.pgc b/app/src/vl/svc/VL_RISETTLE.pgc index 90ef071..b65b83b 100644 --- a/app/src/vl/svc/VL_RISETTLE.pgc +++ b/app/src/vl/svc/VL_RISETTLE.pgc @@ -138,6 +138,33 @@ void VL_RISETTLE(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_RISETTLE", 0L); + userlog("VL_RISETTLE: 정산 상태 조회 연계 -> ST_STATUS pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("ST_STATUS", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_RISETTLE: tpcall(ST_STATUS) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9084); Bchg(b, T_MSG, 0, "정산 상태 조회 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_RISETTLE: ST_STATUS 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_RITAXINV.pgc b/app/src/vl/svc/VL_RITAXINV.pgc index fb08039..8bea07c 100644 --- a/app/src/vl/svc/VL_RITAXINV.pgc +++ b/app/src/vl/svc/VL_RITAXINV.pgc @@ -111,6 +111,33 @@ void VL_RITAXINV(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_RITAXINV", 0L); + userlog("VL_RITAXINV: 세금계산서 부가세 명세 대조 연계 -> ST_VATDETAIL pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("ST_VATDETAIL", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_RITAXINV: tpcall(ST_VATDETAIL) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9089); Bchg(b, T_MSG, 0, "세금계산서 부가세 명세 대조 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_RITAXINV: ST_VATDETAIL 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_SALES.pgc b/app/src/vl/svc/VL_SALES.pgc index aeae455..3c0cd64 100644 --- a/app/src/vl/svc/VL_SALES.pgc +++ b/app/src/vl/svc/VL_SALES.pgc @@ -139,6 +139,41 @@ void VL_SALES(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_SALES", 0L); + if (v_flag == 0) { + userlog("VL_SALES: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + if (c_pid <= 0 || strlen(c_date) < 8) { + userlog("VL_SALES: 매입키 미지정 — 대사 연계 생략 pid=%ld", c_pid); + } else { + userlog("VL_SALES: 매출 검증위반 대사예외 등록 연계 -> RC_EXCEPTION pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("RC_EXCEPTION", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_SALES: tpcall(RC_EXCEPTION) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9041); Bchg(b, T_MSG, 0, "매출 검증위반 대사예외 등록 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_SALES: RC_EXCEPTION 이상 회신 rc=%ld", c_sub); + } + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_SETTLE.pgc b/app/src/vl/svc/VL_SETTLE.pgc index ecb6d84..e220efa 100644 --- a/app/src/vl/svc/VL_SETTLE.pgc +++ b/app/src/vl/svc/VL_SETTLE.pgc @@ -138,6 +138,41 @@ void VL_SETTLE(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_SETTLE", 0L); + if (v_flag == 0) { + userlog("VL_SETTLE: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + if (c_pid <= 0 || strlen(c_date) < 8) { + userlog("VL_SETTLE: 매입키 미지정 — 대사 연계 생략 pid=%ld", c_pid); + } else { + userlog("VL_SETTLE: 정산 검증위반 대사예외 등록 연계 -> RC_EXCEPTION pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("RC_EXCEPTION", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_SETTLE: tpcall(RC_EXCEPTION) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9042); Bchg(b, T_MSG, 0, "정산 검증위반 대사예외 등록 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_SETTLE: RC_EXCEPTION 이상 회신 rc=%ld", c_sub); + } + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_SPIKEAMT.pgc b/app/src/vl/svc/VL_SPIKEAMT.pgc index f35072c..aba224c 100644 --- a/app/src/vl/svc/VL_SPIKEAMT.pgc +++ b/app/src/vl/svc/VL_SPIKEAMT.pgc @@ -112,6 +112,37 @@ void VL_SPIKEAMT(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_SPIKEAMT", 0L); + if (v_metric < 3) { + userlog("VL_SPIKEAMT: 임계 미달 — 후속 연계 생략 base=%ld thr=%ld", v_base, v_thr); + } else { + userlog("VL_SPIKEAMT: 금액 급증 룰 평가 연계 -> FRAUD_RULE_AMT pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("FRAUD_RULE_AMT", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_SPIKEAMT: tpcall(FRAUD_RULE_AMT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9054); Bchg(b, T_MSG, 0, "금액 급증 룰 평가 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_SPIKEAMT: FRAUD_RULE_AMT 이상 회신 rc=%ld", c_sub); + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); v_step = 8; diff --git a/app/src/vl/svc/VL_STATUS_CHK.pgc b/app/src/vl/svc/VL_STATUS_CHK.pgc index be59aba..2cc79fa 100644 --- a/app/src/vl/svc/VL_STATUS_CHK.pgc +++ b/app/src/vl/svc/VL_STATUS_CHK.pgc @@ -138,6 +138,33 @@ void VL_STATUS_CHK(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_STATUS_CHK", 0L); + userlog("VL_STATUS_CHK: 공통 상태코드 대조 연계 -> CM_STATUS pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_STATUS", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_STATUS_CHK: tpcall(CM_STATUS) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9018); Bchg(b, T_MSG, 0, "공통 상태코드 대조 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_STATUS_CHK: CM_STATUS 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_SUMFEECHK.pgc b/app/src/vl/svc/VL_SUMFEECHK.pgc index 68a3d82..2fa63f7 100644 --- a/app/src/vl/svc/VL_SUMFEECHK.pgc +++ b/app/src/vl/svc/VL_SUMFEECHK.pgc @@ -112,6 +112,33 @@ void VL_SUMFEECHK(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_SUMFEECHK", 0L); + userlog("VL_SUMFEECHK: 수수료합계 검증 감사적재 연계 -> CM_LOG pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_SUMFEECHK: tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9022); Bchg(b, T_MSG, 0, "수수료합계 검증 감사적재 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_SUMFEECHK: CM_LOG 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_SUMGROSS.pgc b/app/src/vl/svc/VL_SUMGROSS.pgc index af7afbe..f5207a5 100644 --- a/app/src/vl/svc/VL_SUMGROSS.pgc +++ b/app/src/vl/svc/VL_SUMGROSS.pgc @@ -136,6 +136,33 @@ void VL_SUMGROSS(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_SUMGROSS", 0L); + userlog("VL_SUMGROSS: 총액합계 검증 감사적재 연계 -> CM_LOG pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_SUMGROSS: tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9026); Bchg(b, T_MSG, 0, "총액합계 검증 감사적재 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_SUMGROSS: CM_LOG 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_SUMRECON.pgc b/app/src/vl/svc/VL_SUMRECON.pgc index 5199fd5..5640181 100644 --- a/app/src/vl/svc/VL_SUMRECON.pgc +++ b/app/src/vl/svc/VL_SUMRECON.pgc @@ -136,6 +136,33 @@ void VL_SUMRECON(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_SUMRECON", 0L); + userlog("VL_SUMRECON: 합계대사 검증 감사적재 연계 -> CM_LOG pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_SUMRECON: tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9029); Bchg(b, T_MSG, 0, "합계대사 검증 감사적재 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_SUMRECON: CM_LOG 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_SUMTXNCNT.pgc b/app/src/vl/svc/VL_SUMTXNCNT.pgc index 6c46638..0f338e0 100644 --- a/app/src/vl/svc/VL_SUMTXNCNT.pgc +++ b/app/src/vl/svc/VL_SUMTXNCNT.pgc @@ -136,6 +136,33 @@ void VL_SUMTXNCNT(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_SUMTXNCNT", 0L); + userlog("VL_SUMTXNCNT: 건수합계 검증 감사적재 연계 -> CM_LOG pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("CM_LOG", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_SUMTXNCNT: tpcall(CM_LOG) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9027); Bchg(b, T_MSG, 0, "건수합계 검증 감사적재 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_SUMTXNCNT: CM_LOG 이상 회신 rc=%ld", c_sub); + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_SUSPACT.pgc b/app/src/vl/svc/VL_SUSPACT.pgc index c897917..540a7c5 100644 --- a/app/src/vl/svc/VL_SUSPACT.pgc +++ b/app/src/vl/svc/VL_SUSPACT.pgc @@ -143,6 +143,37 @@ void VL_SUSPACT(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_SUSPACT", 0L); + if (v_flag == 0) { + userlog("VL_SUSPACT: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + userlog("VL_SUSPACT: 위험도 조회 연계 -> RISK_SCORE_INQ pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("RISK_SCORE_INQ", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_SUSPACT: tpcall(RISK_SCORE_INQ) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9057); Bchg(b, T_MSG, 0, "위험도 조회 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_SUSPACT: RISK_SCORE_INQ 이상 회신 rc=%ld", c_sub); + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_SUSPESCAL.pgc b/app/src/vl/svc/VL_SUSPESCAL.pgc index b3f1984..5aea017 100644 --- a/app/src/vl/svc/VL_SUSPESCAL.pgc +++ b/app/src/vl/svc/VL_SUSPESCAL.pgc @@ -116,6 +116,41 @@ void VL_SUSPESCAL(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_SUSPESCAL", 0L); + if (v_flag == 0) { + userlog("VL_SUSPESCAL: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + if (c_pid <= 0 || strlen(c_date) < 8) { + userlog("VL_SUSPESCAL: 매입키 미지정 — 대사 연계 생략 pid=%ld", c_pid); + } else { + userlog("VL_SUSPESCAL: 의심거래 대사 상향 연계 -> RC_ESCALATE pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("RC_ESCALATE", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_SUSPESCAL: tpcall(RC_ESCALATE) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9058); Bchg(b, T_MSG, 0, "의심거래 대사 상향 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_SUSPESCAL: RC_ESCALATE 이상 회신 rc=%ld", c_sub); + } + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_THRESHOLD.pgc b/app/src/vl/svc/VL_THRESHOLD.pgc index af9fb2e..549ddf7 100644 --- a/app/src/vl/svc/VL_THRESHOLD.pgc +++ b/app/src/vl/svc/VL_THRESHOLD.pgc @@ -120,6 +120,37 @@ void VL_THRESHOLD(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_THRESHOLD", 0L); + if (v_metric < 3) { + userlog("VL_THRESHOLD: 임계 미달 — 후속 연계 생략 base=%ld thr=%ld", v_base, v_thr); + } else { + userlog("VL_THRESHOLD: 임계 초과 부정탐지 연계 연계 -> FRAUD_DETECT pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("FRAUD_DETECT", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_THRESHOLD: tpcall(FRAUD_DETECT) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9052); Bchg(b, T_MSG, 0, "임계 초과 부정탐지 연계 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_THRESHOLD: FRAUD_DETECT 이상 회신 rc=%ld", c_sub); + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/src/vl/svc/VL_VELOCITY.pgc b/app/src/vl/svc/VL_VELOCITY.pgc index ea4d1d3..c624f38 100644 --- a/app/src/vl/svc/VL_VELOCITY.pgc +++ b/app/src/vl/svc/VL_VELOCITY.pgc @@ -112,6 +112,37 @@ void VL_VELOCITY(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_VELOCITY", 0L); + if (v_metric < 3) { + userlog("VL_VELOCITY: 임계 미달 — 후속 연계 생략 base=%ld thr=%ld", v_base, v_thr); + } else { + userlog("VL_VELOCITY: 일별 속도(빈도) 대조 연계 -> VELOCITY_DAY pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("VELOCITY_DAY", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_VELOCITY: tpcall(VELOCITY_DAY) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9056); Bchg(b, T_MSG, 0, "일별 속도(빈도) 대조 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_VELOCITY: VELOCITY_DAY 이상 회신 rc=%ld", c_sub); + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); v_step = 8; diff --git a/app/src/vl/svc/VL_ZERONET.pgc b/app/src/vl/svc/VL_ZERONET.pgc index 0556f60..978a102 100644 --- a/app/src/vl/svc/VL_ZERONET.pgc +++ b/app/src/vl/svc/VL_ZERONET.pgc @@ -112,6 +112,41 @@ void VL_ZERONET(TPSVCINFO *p) } v_step = 7; + /* --- 7-1) 후속 업무 체인(tpcall) — CHAIN-BEGIN --------------------- + * 검증 결과를 후속 업무 서비스로 연계한다. 하위는 다른 XA 브랜치라 + * 이 브랜치의 미커밋 행이 보이지 않으므로 판단값은 전문(T_*)으로 넘기고, + * 최종 응답(T_RC/1차 산출)은 아래 응답부·원 처리부가 재확정한다. --- */ + { + long c_rlen = 0, c_sub = 0, c_keep = getl(b, T_RC); + long c_pid = getl(b, T_PURCHASE_ID); + char c_date[16]; + gets_(b, T_BIZDATE, c_date, sizeof(c_date)); + if (c_date[0] == 0 && v_bizdate[0]) { + strncpy(c_date, v_bizdate, sizeof(c_date) - 1); + c_date[sizeof(c_date) - 1] = 0; + Bchg(b, T_BIZDATE, 0, c_date, 0L); + } + setl(b, T_ARG2, v_flag); setl(b, T_AMT1, v_base); setl(b, T_AMT3, v_thr); + Bchg(b, T_SVCNAME, 0, "VL_ZERONET", 0L); + if (v_flag == 0) { + userlog("VL_ZERONET: 위반 없음 — 후속 연계 생략 metric=%ld", v_metric); + } else { + if (c_pid <= 0 || strlen(c_date) < 8) { + userlog("VL_ZERONET: 매입키 미지정 — 대사 연계 생략 pid=%ld", c_pid); + } else { + userlog("VL_ZERONET: 정산액 영(0) 대사예외 등록 연계 -> RC_EXCEPTION pid=%ld date=[%s]", c_pid, c_date); + if (tpcall("RC_EXCEPTION", (char *)b, 0L, (char **)&b, &c_rlen, 0L) < 0) { + userlog("VL_ZERONET: tpcall(RC_EXCEPTION) 실패: %s", tpstrerror(tperrno)); + setl(b, T_RC, 9048); Bchg(b, T_MSG, 0, "정산액 영(0) 대사예외 등록 연계 실패", 0L); + FAIL(b); + } + c_sub = getl(b, T_RC); + if (c_sub != 0) userlog("VL_ZERONET: RC_EXCEPTION 이상 회신 rc=%ld", c_sub); + } + } + setl(b, T_RC, c_keep); /* 기존 계약 복원 — 응답부/원 처리부가 최종 확정 */ + } + /* --- 8) 응답부(보조): 진단 필드 세팅. 최종 T_RC/1차 산출은 원 처리부 확정 --- */ setl(b, T_ARG2, v_flag); setl(b, T_ARG1, v_metric); diff --git a/app/ui/index.html b/app/ui/index.html index a40028d..7a7f740 100644 --- a/app/ui/index.html +++ b/app/ui/index.html @@ -199,11 +199,16 @@ const SVC_SCREENS = [ "desc": "매입 중복 알림: 가맹점의 영업일 매입 중 동일 금액이 2건 이상 반복된", "in": [ "T_MERCHANT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_COUNT", "T_ARG1", "T_ARG2", @@ -268,12 +273,16 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_AMOUNT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", "T_DELTA", "T_FEE", "T_NET", @@ -309,11 +318,16 @@ const SVC_SCREENS = [ "desc": "승인 연계: 매입 건에 승인 원장 행을 연결한다. 이미 승인이 있으면 추가", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_ARG3", "T_COUNT", "T_ID1", "T_ARG1", @@ -327,15 +341,19 @@ const SVC_SCREENS = [ "desc": "승인 매핑 조회: 한 매입에 연결된 승인 원장의 총 건수와 승인/거절 분포를", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_ARG3", "T_COUNT", "T_ARG1", "T_ARG2", - "T_ARG3", "T_ID1", "T_ARG7", "T_ARG8", @@ -495,12 +513,19 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_AMOUNT", "T_BIZDATE", - "T_REASON" + "T_REASON", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", - "T_CANCEL_ID", + "T_PURCHASE_ID", "T_AMOUNT", + "T_CANCEL_ID", + "T_ARG3", + "T_ARG4", + "T_ARG5", + "T_ARG6", "T_FEE", "T_ARG1", "T_COUNT", @@ -574,13 +599,17 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_AMOUNT", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_CANCEL_ID", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", + "T_CANCEL_ID", "T_GROSS", "T_ARG1" ] @@ -616,14 +645,19 @@ const SVC_SCREENS = [ "desc": "지불거절 역전: 방어 승소로 CB 를 무효화한다. 최근 CB/CB2 행 사유를", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", + "T_ARG3", "T_COUNT", "T_ARG1", - "T_AMOUNT", "T_ARG2", "T_ID1" ] @@ -865,14 +899,18 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_ID1", - "T_ARG1", - "T_AMOUNT" + "T_ARG1" ] }, { @@ -902,16 +940,20 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_AMOUNT", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ADJ", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", + "T_DELTA", + "T_ADJ", "T_FEE", "T_NET", - "T_DELTA", "T_ARG1" ] }, @@ -1108,13 +1150,17 @@ const SVC_SCREENS = [ "T_CCY", "T_FX_AMT", "T_ARG1", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ID1", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", + "T_ID1", "T_FX_AMT", "T_ARG2", "T_ARG3", @@ -1156,11 +1202,16 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_AMOUNT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_COUNT", "T_ARG1", "T_ARG2", @@ -1201,12 +1252,16 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_AMOUNT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", "T_PURCHASE_ID", + "T_AMOUNT", + "T_COUNT", "T_FEE", "T_NET", "T_ARG1", @@ -1222,12 +1277,16 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_DOCNO", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_ID1", "T_FEE", "T_NET", @@ -1266,13 +1325,17 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_DOCNO", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ID1", + "T_PURCHASE_ID", "T_AMOUNT", + "T_ARG3", + "T_ID1", "T_ARG1" ] }, @@ -1417,14 +1480,17 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_AMOUNT", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ID1", + "T_PURCHASE_ID", "T_AMOUNT", "T_AMT1", + "T_ID1", "T_ARG1", "T_GROSS" ] @@ -1437,14 +1503,17 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ID1", + "T_PURCHASE_ID", "T_AMOUNT", "T_AMT1", + "T_ID1", "T_AMT2", "T_ARG1", "T_ARG2" @@ -1481,14 +1550,18 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_REASON", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_FX_AMT", "T_CANCEL_ID", "T_DELTA", - "T_AMOUNT", "T_ARG1", "T_ID1" ] @@ -1502,13 +1575,18 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_REASON", "T_BIZDATE", - "T_DELTA" + "T_DELTA", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ADJ", + "T_PURCHASE_ID", + "T_AMOUNT", "T_DELTA", + "T_AMT1", + "T_ADJ", "T_FEE", "T_NET", "T_ARG1" @@ -1546,11 +1624,17 @@ const SVC_SCREENS = [ "desc": "수수료 재산정: 가맹점의 현행 MDR 로 수수료를 다시 계산해 기존 수수료와", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", + "T_ARG3", "T_ADJ", "T_FEE", "T_NET", @@ -1590,7 +1674,9 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_CCY", "T_FX_AMT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", @@ -1598,6 +1684,7 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_AMOUNT", "T_FX_AMT", + "T_AMT1", "T_ARG2", "T_FEE", "T_NET", @@ -1615,14 +1702,17 @@ const SVC_SCREENS = [ "T_CCY", "T_FX_AMT", "T_BIZDATE", - "T_ARG1" + "T_ARG1", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ID1", + "T_PURCHASE_ID", "T_AMOUNT", "T_FX_AMT", + "T_ID1", "T_ARG2", "T_ARG1" ] @@ -1634,15 +1724,19 @@ const SVC_SCREENS = [ "desc": "통화 적용환율 조회: 해외매입 원장에서 특정 통화의 최근 영업일 평균/최저/", "in": [ "T_CCY", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_ARG3", "T_COUNT", "T_ARG1", "T_ARG2", - "T_ARG3", "T_ARG4", "T_ARG5", "T_GROSS", @@ -1685,13 +1779,18 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_ARG1", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ID1", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", + "T_AMT2", + "T_ID1", "T_ARG2", "T_GROSS", "T_ARG1" @@ -1754,16 +1853,19 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", + "T_PURCHASE_ID", "T_AMOUNT", + "T_ARG3", "T_COUNT", "T_GROSS", "T_ARG1", "T_ARG2", - "T_ARG3", "T_ARG4", "T_ID1" ] @@ -1824,14 +1926,18 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_INSTALL_N", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_COUNT", + "T_PURCHASE_ID", + "T_AMOUNT", "T_INSTALL_N", "T_AMT1", + "T_COUNT", "T_ARG1", "T_ARG2", "T_GROSS" @@ -1845,13 +1951,18 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_COUNT", + "T_PURCHASE_ID", + "T_AMOUNT", "T_INSTALL_N", + "T_AMT1", + "T_COUNT", "T_GROSS", "T_ARG1", "T_ID1" @@ -1980,17 +2091,22 @@ const SVC_SCREENS = [ "desc": "매입 한도 점검: 가맹점 일한도와 당일 누적 매입을 비교해 초과 여부를", "in": [ "T_MERCHANT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", + "T_AMT2", "T_GROSS", "T_ARG1", "T_ARG2", "T_ARG3", "T_COUNT", - "T_AMT1", "T_ARG4", "T_ARG7", "T_ARG8", @@ -2004,11 +2120,17 @@ const SVC_SCREENS = [ "desc": "매입 한도 예외처리: 가맹점 일한도와 당일 누적 매입을 비교해 한도 초과 시", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", + "T_AMT2", "T_GROSS", "T_ARG1", "T_ARG2", @@ -2069,11 +2191,14 @@ const SVC_SCREENS = [ "desc": "가맹점 일별 집계: 영업일 매입을 재집계해 merchant_summary 에 upsert 하고", "in": [ "T_MERCHANT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_COUNT", + "T_AMT1", "T_GROSS", "T_FEE", "T_NET", @@ -2117,16 +2242,21 @@ const SVC_SCREENS = [ "desc": "정산금 재계산: 매입금액에서 수수료와 원천세 누계를 차감한 실정산금을", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", + "T_AMT2", "T_NET", "T_DELTA", "T_TAX", "T_FEE", - "T_AMOUNT", "T_ARG1" ] }, @@ -2159,13 +2289,20 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_AMOUNT", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_CANCEL_ID", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", + "T_ARG3", + "T_AMT2", + "T_AMT3", + "T_CANCEL_ID", "T_FEE", "T_ARG1", "T_ARG2" @@ -2200,14 +2337,18 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_AMOUNT", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_CANCEL_ID", + "T_PURCHASE_ID", "T_AMOUNT", "T_AMT1", + "T_AMT2", + "T_CANCEL_ID", "T_ARG1", "T_ARG2", "T_ID1" @@ -2221,12 +2362,16 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_AMOUNT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_FEE", "T_NET", "T_DELTA", @@ -2413,13 +2558,19 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_AMOUNT", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_CANCEL_ID", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", + "T_AMT2", + "T_ARG5", + "T_CANCEL_ID", "T_ARG1", "T_ARG2" ] @@ -2432,14 +2583,18 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_ARG1", - "T_ID1", - "T_AMOUNT" + "T_ID1" ] }, { @@ -2449,11 +2604,16 @@ const SVC_SCREENS = [ "desc": "승인미매칭 재처리: 미매입 원장에 남은 건에 유효 승인이 도착했는지 다시", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_COUNT", "T_ARG1", "T_ARG2", @@ -2468,11 +2628,16 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_COUNT", "T_ARG1" ] @@ -2485,12 +2650,17 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_AMOUNT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", + "T_ARG3", "T_FEE", "T_NET", "T_COUNT", @@ -2505,12 +2675,17 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", + "T_ARG3", "T_ARG1", "T_COUNT", "T_GROSS", @@ -2549,13 +2724,17 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_CANCEL_ID", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", + "T_CANCEL_ID", "T_ARG1" ] }, @@ -2666,11 +2845,28 @@ const SVC_SCREENS = [ "desc": "정산 연계: 대사완료 매입에 대해 settlement 링크 행(status='LINKED')을", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC", + "T_ARG1", + "T_AMT2", + "T_AMT3", + "T_ARG7", + "T_ARG8", + "T_ARG5", + "T_ARG6" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", + "T_ARG3", + "T_AMT2", + "T_AMT3", + "T_ID1", + "T_DELTA", "T_SETTLE_ID", "T_NET", "T_ARG1" @@ -2709,16 +2905,20 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_ARG1", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_COUNT", + "T_PURCHASE_ID", + "T_AMOUNT", "T_AMT1", + "T_ARG3", + "T_COUNT", "T_GROSS", - "T_ARG2", - "T_ARG3" + "T_ARG2" ] }, { @@ -2777,14 +2977,18 @@ const SVC_SCREENS = [ "desc": "세금계산서 취소: 원본 계산서를 상쇄하는 음수(공급가/부가세 부호 반전)", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_TAX", "T_ID1", "T_GROSS", - "T_TAX", "T_COUNT", "T_ARG1" ] @@ -2797,13 +3001,18 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ID1", + "T_PURCHASE_ID", + "T_AMOUNT", "T_TAX", + "T_AMT1", + "T_ID1", "T_GROSS", "T_ARG1" ] @@ -2879,15 +3088,19 @@ const SVC_SCREENS = [ "desc": "세금계산서 역발행: 매출 취소분에 대한 (-)공급가 계산서를 새로 발행한다.", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_TAX", "T_ID1", "T_ID2", "T_GROSS", - "T_TAX", "T_ARG1" ] }, @@ -2923,15 +3136,19 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ID1", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_COUNT", - "T_ARG1", - "T_AMOUNT" + "T_ID1", + "T_ARG1" ] }, { @@ -2942,16 +3159,20 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_ARG1", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", "T_COUNT", + "T_AMT1", "T_ARG2", "T_ARG3", "T_ARG4", - "T_AMT1", "T_AMT2", "T_GROSS", "T_ARG7", @@ -2967,12 +3188,16 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", "T_DELTA", "T_ARG1", "T_ID1" @@ -3010,11 +3235,20 @@ const SVC_SCREENS = [ "desc": "원천징수: 가맹점 수수료에 대한 원천세를 운영 파라미터(WHT_BPS) 기준으로", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC", + "T_TAX" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", + "T_ARG3", + "T_AMT2", + "T_AMT3", "T_TAX", "T_ID1", "T_ARG2", @@ -3030,14 +3264,18 @@ const SVC_SCREENS = [ "desc": "이체 연계: 정산 완료 매입의 지급 이체를 원장에 XFER 분개로 연결한다.", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_ID1", "T_NET", - "T_AMOUNT", "T_ARG1" ] }, @@ -3069,11 +3307,14 @@ const SVC_SCREENS = [ "T_KEY1", "T_MERCHANT", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_RC", + "T_ARG1" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_ID1" ] }, @@ -3089,7 +3330,8 @@ const SVC_SCREENS = [ "T_AMOUNT", "T_ID1", "T_DELTA", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", @@ -3108,11 +3350,13 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ID1", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -3127,11 +3371,13 @@ const SVC_SCREENS = [ "T_REASON", "T_ID1", "T_AMOUNT", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_CANCEL_ID" ] }, @@ -3146,11 +3392,15 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ID1", - "T_ID2" + "T_ID2", + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_PURCHASE_ID", + "T_AMOUNT" ] }, { @@ -3165,11 +3415,14 @@ const SVC_SCREENS = [ "T_AMOUNT", "T_REASON", "T_ID1", - "T_ID2" + "T_ID2", + "T_STR1", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -3201,13 +3454,16 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_KEY1", "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_RC", + "T_ARG1" ], "out": [ "T_RC", "T_FEE", - "T_ARG1", - "T_ID1" + "T_ID1", + "T_AMOUNT", + "T_ARG1" ] }, { @@ -3220,11 +3476,13 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_COUNT", "T_GROSS", "T_ID1" @@ -3258,11 +3516,13 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ID1", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -3274,11 +3534,13 @@ const SVC_SCREENS = [ "T_KEY1", "T_MERCHANT", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_AMT1", "T_ID2" ] @@ -3294,13 +3556,14 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_ID1", "T_AMOUNT", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", "T_FEE", - "T_CANCEL_ID", - "T_AMOUNT" + "T_AMOUNT", + "T_CANCEL_ID" ] }, { @@ -3332,11 +3595,13 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ID1", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -3385,7 +3650,10 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ID1", - "T_ID2" + "T_ID2", + "T_STR1", + "T_CHANNEL", + "T_RC" ], "out": [ "T_RC", @@ -3404,11 +3672,15 @@ const SVC_SCREENS = [ "T_KEY1", "T_ID1", "T_AMOUNT", - "T_ID2" + "T_ID2", + "T_STR1", + "T_CHANNEL", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -3422,11 +3694,13 @@ const SVC_SCREENS = [ "T_KEY1", "T_ID1", "T_AMOUNT", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -3498,11 +3772,13 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_ID1", "T_AMOUNT", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_CANCEL_ID" ] }, @@ -3550,11 +3826,15 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_KEY1" + "T_KEY1", + "T_RC", + "T_ARG1" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_ID1", + "T_AMOUNT" ] }, { @@ -3850,11 +4130,15 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_KEY1", - "T_REASON" + "T_REASON", + "T_STR1", + "T_CHANNEL", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -3955,11 +4239,15 @@ const SVC_SCREENS = [ "T_AMOUNT", "T_KEY1", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STR1", + "T_CHANNEL", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_ID1" ] }, @@ -3990,11 +4278,14 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_KEY1" + "T_KEY1", + "T_STR5", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -4136,11 +4427,16 @@ const SVC_SCREENS = [ "T_KEY1", "T_BIZDATE", "T_ID1", - "T_AMOUNT" + "T_AMOUNT", + "T_STR8", + "T_STR1", + "T_CHANNEL", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_ARG1", "T_ID2" ] @@ -4285,11 +4581,13 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_INSTALL_N" + "T_INSTALL_N", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_COUNT" ] }, @@ -4339,11 +4637,18 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_KEY1", - "T_AMOUNT" + "T_AMOUNT", + "T_AMT1", + "T_AMT2", + "T_STR8", + "T_STR1", + "T_RC", + "T_ID1" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_AMT1", "T_AMT2" ] @@ -4396,11 +4701,16 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_KEY1", - "T_AMOUNT" + "T_AMOUNT", + "T_STR8", + "T_STR1", + "T_CHANNEL", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -4413,12 +4723,16 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_STR1", + "T_RC", + "T_ID1" ], "out": [ "T_RC", "T_COUNT", "T_FEE", + "T_AMOUNT", "T_ARG1" ] }, @@ -4431,11 +4745,15 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_KEY1" + "T_KEY1", + "T_STR1", + "T_RC", + "T_ID1" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -4528,11 +4846,15 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_KEY1" + "T_KEY1", + "T_STR1", + "T_RC", + "T_ID1" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_ARG1", "T_AMT1" ] @@ -4617,11 +4939,16 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_KEY1" + "T_KEY1", + "T_STR8", + "T_STR1", + "T_CHANNEL", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -4793,11 +5120,15 @@ const SVC_SCREENS = [ "T_KEY1", "T_AMOUNT", "T_MERCHANT", - "T_BIZDATE" + "T_BIZDATE", + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_PURCHASE_ID", + "T_AMOUNT", "T_COUNT", "T_GROSS" ] @@ -4829,11 +5160,13 @@ const SVC_SCREENS = [ "T_KEY1", "T_MERCHANT", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_ID2" ] }, @@ -4847,11 +5180,13 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_AMT1" ] }, @@ -4865,11 +5200,13 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_BIZDATE", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_ID1" ] }, @@ -4884,11 +5221,13 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ID2", - "T_ARG1" + "T_ARG1", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -4922,11 +5261,13 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_ID2", - "T_AMOUNT" + "T_AMOUNT", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_AMT1" ] }, @@ -4958,11 +5299,15 @@ const SVC_SCREENS = [ "T_KEY1", "T_MERCHANT", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_RC", + "T_STR1", + "T_CHANNEL" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_ID1" ] }, @@ -5033,11 +5378,13 @@ const SVC_SCREENS = [ "T_KEY1", "T_MERCHANT", "T_AMOUNT", - "T_BIZDATE" + "T_BIZDATE", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_COUNT", "T_GROSS" ] @@ -5254,11 +5601,14 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_KEY1" + "T_KEY1", + "T_STR5", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -5305,11 +5655,15 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_KEY1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ARG1" ], "out": [ "T_RC", "T_FEE", + "T_ID1", + "T_AMOUNT", "T_COUNT", "T_GROSS" ] @@ -5515,7 +5869,20 @@ const SVC_SCREENS = [ "svc": "CL_AMTXCHECK", "desc": "마감 금액 크로스체크: 마감이력 total_amount vs 매입 amount 합계 vs 스냅샷", "in": [ - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5527,7 +5894,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5" ] }, { @@ -5537,7 +5908,20 @@ const SVC_SCREENS = [ "desc": "마감 승인 위임: 위임 대상자(T_STR1)를 memo(APPR:DELEG:..)에 기록하고 상태 유지.", "in": [ "T_ID1", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5545,7 +5929,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5555,7 +5945,9 @@ const SVC_SCREENS = [ "desc": "최종 마감 승인: 2차 승인(APPR:L2) 마감을 최종 승인(status=A)으로 확정.", "in": [ "T_ID1", - "T_STR1" + "T_STR1", + "T_STR8", + "T_STATUS" ], "out": [ "T_RC", @@ -5592,7 +5984,22 @@ const SVC_SCREENS = [ "desc": "1차 마감 승인: 개시(O)/완료(C) 마감을 1차 승인(memo=APPR:L1) 단계로 전이.", "in": [ "T_ID1", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT", + "T_STR7", + "T_STR6" ], "out": [ "T_RC", @@ -5600,7 +6007,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5610,7 +6023,23 @@ const SVC_SCREENS = [ "desc": "2차 마감 승인: 1차 승인(APPR:L1) 마감을 2차 승인(APPR:L2)으로 전이.", "in": [ "T_ID1", - "T_STR1" + "T_STR1", + "T_STR8", + "T_STATUS", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT", + "T_STR7", + "T_STR6" ], "out": [ "T_RC", @@ -5618,7 +6047,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5628,7 +6063,22 @@ const SVC_SCREENS = [ "desc": "마감 승인: 상태 A.", "in": [ "T_ID1", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT", + "T_STR7", + "T_STR6" ], "out": [ "T_RC", @@ -5636,7 +6086,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5646,7 +6102,20 @@ const SVC_SCREENS = [ "desc": "마감 승인 반려: 승인(A) 상태 마감을 완료(C)로 되돌리며 반려 사유를 기록.", "in": [ "T_ID1", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5654,7 +6123,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5664,7 +6139,22 @@ const SVC_SCREENS = [ "desc": "마감 승인 요청: C 상태이며 집계건수>0 인 마감에 승인요청(APPR_REQ) 표시를", "in": [ "T_ID1", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT", + "T_STR7", + "T_STR6" ], "out": [ "T_RC", @@ -5672,7 +6162,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5760,7 +6256,19 @@ const SVC_SCREENS = [ "desc": "잔액 검증: 스냅샷 net 합 vs close_log total 비교.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5773,7 +6281,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -5805,7 +6318,19 @@ const SVC_SCREENS = [ "in": [ "T_ID1", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5813,7 +6338,13 @@ const SVC_SCREENS = [ "T_ARG6", "T_ARG7", "T_ARG8", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5822,7 +6353,20 @@ const SVC_SCREENS = [ "svc": "CL_CHKALL", "desc": "마감 전 통합 체크: 미마감(M)/미매칭/보류(H)/void(V) 합산 점수 산출.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5830,7 +6374,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5856,7 +6406,20 @@ const SVC_SCREENS = [ "svc": "CL_CHKPENDING", "desc": "마감 전 보류 체크: 당일 보류(H) 매입 존재 여부 판정.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5864,7 +6427,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5873,7 +6442,20 @@ const SVC_SCREENS = [ "svc": "CL_CHKUNMATCH", "desc": "마감 전 미매칭 체크: 당일 미매칭(ac_unmatch) 존재 여부 판정.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5881,7 +6463,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5890,7 +6478,20 @@ const SVC_SCREENS = [ "svc": "CL_CHKVOID", "desc": "마감 전 void 체크: 당일 void(V) 매입 잔존 여부 판정.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5898,7 +6499,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5930,7 +6537,19 @@ const SVC_SCREENS = [ "desc": "채널별 마감 검증: 영업일+채널의 매입건수와 해당 매입에 연결된 ledger", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5943,7 +6562,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -5974,7 +6598,19 @@ const SVC_SCREENS = [ "desc": "건수 정합검증: 마감이력 txn_count 와 해당 영업일 매입 실건수를 대사한다.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5987,7 +6623,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -5996,7 +6637,20 @@ const SVC_SCREENS = [ "svc": "CL_CNTXCHECK", "desc": "마감 건수 크로스체크: 마감이력 txn_count vs 실매입 count vs 스냅샷", "in": [ - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6008,7 +6662,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5" ] }, { @@ -6037,7 +6695,20 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_STR1", - "T_ISSUER" + "T_ISSUER", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6048,7 +6719,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6058,7 +6734,19 @@ const SVC_SCREENS = [ "desc": "법인별 마감 검증: 마감이력 헤더 건수/금액과 스냅샷 집계 정합 점검.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6071,7 +6759,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -6188,14 +6881,32 @@ const SVC_SCREENS = [ "svc": "CL_DAILY", "desc": "일 마감: 당일 매입 집계 후 마감이력(DAILY) 생성.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", "T_ID1", "T_ARG6", "T_ARG7", - "T_ARG8" + "T_ARG8", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6205,7 +6916,19 @@ const SVC_SCREENS = [ "desc": "일 마감 검증: 당일 마감이력 집계와 매입 실집계 대사.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6218,7 +6941,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -6271,7 +6999,19 @@ const SVC_SCREENS = [ "desc": "차액 점검: close_log total vs 스냅샷 gross 합.", "in": [ "T_BIZDATE", - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6279,7 +7019,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6290,7 +7036,20 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_STR1", - "T_CATEGORY" + "T_CATEGORY", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6301,7 +7060,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6331,7 +7095,20 @@ const SVC_SCREENS = [ "svc": "CL_DUPCHK", "desc": "중복 마감 탐지: 취소(X) 제외 동일 (close_type, period_key) 에 마감이 2건", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6339,7 +7116,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6364,7 +7147,20 @@ const SVC_SCREENS = [ "svc": "CL_FEECROSS", "desc": "수수료 크로스검증: 마감 스냅샷 fee 합계와 해당 영업일 매입 fee 합계를 대사한다.", "in": [ - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6376,7 +7172,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5" ] }, { @@ -6386,7 +7186,19 @@ const SVC_SCREENS = [ "desc": "수수료 검증: 마감 스냅샷의 fee 합계와 해당 영업일 매입 fee 합계에", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6399,7 +7211,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -6430,7 +7247,20 @@ const SVC_SCREENS = [ "desc": "강제 마감: 체크리스트를 우회해 해당 영업일의 미확정 개시(O) 마감을 제거한", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6441,7 +7271,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6493,7 +7328,20 @@ const SVC_SCREENS = [ "desc": "반기 결산 마감: 연도(T_STR1=YYYY)와 반기(T_ARG1=1|2)를 받아 상/하반기", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6504,7 +7352,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6574,7 +7427,19 @@ const SVC_SCREENS = [ "desc": "반기 마감 검증: 반기 마감이력과 반기 매입 실집계 대사.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6587,7 +7452,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -6689,7 +7559,20 @@ const SVC_SCREENS = [ "desc": "본마감: 가마감(O) 이력을 당일 전체 매입으로 재집계해 확정(C)으로 승격.", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6700,7 +7583,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6732,6 +7620,95 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_STR1", + "T_MERCHANT", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" + ], + "out": [ + "T_RC", + "T_ID1", + "T_FEE", + "T_NET", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" + ] + }, + { + "mod": "cl", + "modnm": "마감", + "svc": "CL_MERXCHECK", + "desc": "가맹점별 크로스검증: 마감 스냅샷 gross 와 매입 amount 를 가맹점 단위로 대사해", + "in": [ + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" + ], + "out": [ + "T_RC", + "T_AMT1", + "T_AMT2", + "T_AMT3", + "T_DELTA", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5" + ] + }, + { + "mod": "cl", + "modnm": "마감", + "svc": "CL_MIDCLOSE", + "desc": "중간 마감: 당일 중간 스냅 마감이력(MID) 생성.", + "in": [ + "T_BIZDATE", + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", "T_MERCHANT" ], "out": [ @@ -6743,49 +7720,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" - ] - }, - { - "mod": "cl", - "modnm": "마감", - "svc": "CL_MERXCHECK", - "desc": "가맹점별 크로스검증: 마감 스냅샷 gross 와 매입 amount 를 가맹점 단위로 대사해", - "in": [ - "T_ID1" - ], - "out": [ - "T_RC", - "T_AMT1", + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", "T_AMT2", - "T_AMT3", - "T_DELTA", - "T_ARG6", - "T_ARG7", - "T_ARG8", - "T_COUNT", - "T_GROSS" - ] - }, - { - "mod": "cl", - "modnm": "마감", - "svc": "CL_MIDCLOSE", - "desc": "중간 마감: 당일 중간 스냅 마감이력(MID) 생성.", - "in": [ - "T_BIZDATE", - "T_STR1" - ], - "out": [ - "T_RC", - "T_ID1", - "T_FEE", - "T_NET", - "T_ARG6", - "T_ARG7", - "T_ARG8", - "T_COUNT", - "T_GROSS" + "T_AMT3" ] }, { @@ -6795,7 +7735,20 @@ const SVC_SCREENS = [ "desc": "월 마감: 해당 월(YYYY-MM) 매입 집계 후 마감이력(MONTHLY).", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6806,7 +7759,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6816,7 +7774,19 @@ const SVC_SCREENS = [ "desc": "월 마감 검증: 월 마감이력과 월 매입 실집계 대사.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6829,7 +7799,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -6838,7 +7813,20 @@ const SVC_SCREENS = [ "svc": "CL_NETCROSS", "desc": "정산액 크로스검증: 마감 스냅샷 net 합계와 해당 영업일 매입 net 합계를 대사한다.", "in": [ - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6850,7 +7838,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5" ] }, { @@ -6860,7 +7852,19 @@ const SVC_SCREENS = [ "desc": "정산액 검증: 마감 스냅샷에서 gross - fee <> net 인 내부 모순 행을 찾아", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6873,7 +7877,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -6964,7 +7973,19 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_STR1", "T_KEY1", - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6974,7 +7995,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -6983,7 +8009,20 @@ const SVC_SCREENS = [ "svc": "CL_PRECHECK", "desc": "마감 전 체크리스트 검증: (1)미마감 M 매입 (2)미매칭 ac_unmatch (3)기간 기잠금", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6991,7 +8030,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -7061,7 +8106,19 @@ const SVC_SCREENS = [ "desc": "분기 마감 검증: 분기 마감이력과 분기 매입 실집계 대사.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7074,7 +8131,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -7084,7 +8146,20 @@ const SVC_SCREENS = [ "desc": "분기 마감: 분기 프리픽스(YYYY-MM LIKE)로 집계.", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7095,7 +8170,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -7105,7 +8185,19 @@ const SVC_SCREENS = [ "desc": "재마감: 상태 R 로 표시하고 총계 재집계.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7114,7 +8206,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -7162,7 +8259,19 @@ const SVC_SCREENS = [ "desc": "마감 대사: 실제 매입건수 vs close_log txn_count 대사.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7175,7 +8284,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -7242,7 +8356,19 @@ const SVC_SCREENS = [ "in": [ "T_ID1", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7250,7 +8376,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -7500,7 +8632,19 @@ const SVC_SCREENS = [ "desc": "부문별 마감 검증: 부문 마감이력 총액과 해당 부문 매입 집계 대사.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7513,7 +8657,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -7523,7 +8672,20 @@ const SVC_SCREENS = [ "desc": "반월 마감: 전반(1~15)/후반(16~말) 구간 집계 후 SEMIMON 마감.", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7534,7 +8696,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -7693,7 +8860,19 @@ const SVC_SCREENS = [ "in": [ "T_ID1", "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7701,7 +8880,13 @@ const SVC_SCREENS = [ "T_ARG6", "T_ARG7", "T_ARG8", - "T_COUNT" + "T_COUNT", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -7710,7 +8895,20 @@ const SVC_SCREENS = [ "svc": "CL_SNAPXCHECK", "desc": "스냅샷-원장 크로스체크: 마감 스냅샷 net 합계 vs 같은 영업일 ledger SETTLE", "in": [ - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7722,7 +8920,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5" ] }, { @@ -7791,7 +8993,20 @@ const SVC_SCREENS = [ "svc": "CL_STCROSS", "desc": "상태 크로스검증: 당일 매입 상태 분포(A/M/S/C)를 집계해 미마감(A+M) 잔량으로", "in": [ - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7803,7 +9018,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5" ] }, { @@ -7832,7 +9051,20 @@ const SVC_SCREENS = [ "desc": "순(10일) 마감: 상/중/하순 구간 매입 집계 후 TENDAY 마감이력 생성.", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7843,7 +9075,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -7918,7 +9155,19 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_STR1", "T_KEY1", - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7928,7 +9177,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -8000,7 +9254,19 @@ const SVC_SCREENS = [ "desc": "마감 검증: close_log 총건수 vs 실제 매입건수 비교.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -8013,7 +9279,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -8023,7 +9294,20 @@ const SVC_SCREENS = [ "desc": "주 마감: 주간(월~일) 매입을 집계해 WEEKLY 마감이력 생성.", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -8034,7 +9318,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -8044,7 +9333,19 @@ const SVC_SCREENS = [ "desc": "주 마감 검증: 주간 마감이력과 주간 매입 실집계 대사.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -8057,7 +9358,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -8067,7 +9373,20 @@ const SVC_SCREENS = [ "desc": "연말 마감: 연도(YYYY) 프리픽스로 집계.", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -8078,7 +9397,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -8109,7 +9433,19 @@ const SVC_SCREENS = [ "desc": "연 마감 검증: 연간 마감이력과 연간 매입 실집계 대사.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -8122,7 +9458,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -8134,14 +9475,21 @@ const SVC_SCREENS = [ "T_STR1", "T_ARG1", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR3" ], "out": [ "T_STR3", "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8363,7 +9711,14 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR4" ], "out": [ "T_STR4", @@ -8371,7 +9726,8 @@ const SVC_SCREENS = [ "T_COUNT", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8384,13 +9740,20 @@ const SVC_SCREENS = [ "T_STR1", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR4" ], "out": [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8403,7 +9766,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG2", + "T_ARG3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_ID1", + "T_MSG", + "T_RC", + "T_STR4" ], "out": [ "T_COUNT", @@ -8414,7 +9787,8 @@ const SVC_SCREENS = [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8450,7 +9824,15 @@ const SVC_SCREENS = [ "T_REASON", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_ID1", + "T_MSG", + "T_RC", + "T_STR4" ], "out": [ "T_RC", @@ -8458,7 +9840,8 @@ const SVC_SCREENS = [ "T_COUNT", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8471,14 +9854,23 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", "T_COUNT", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8535,13 +9927,21 @@ const SVC_SCREENS = [ "T_STR1", "T_ARG1", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8572,7 +9972,14 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_ARG1", "T_AMOUNT", - "T_STR1" + "T_STR1", + "T_ARG2", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR4" ], "out": [ "T_RC", @@ -8580,7 +9987,8 @@ const SVC_SCREENS = [ "T_ARG2", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8593,7 +10001,14 @@ const SVC_SCREENS = [ "T_STR2", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG2", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC" ], "out": [ "T_RC", @@ -8602,7 +10017,8 @@ const SVC_SCREENS = [ "T_ARG2", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8614,14 +10030,21 @@ const SVC_SCREENS = [ "T_STR1", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR3" ], "out": [ "T_RC", "T_MSG", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8633,14 +10056,22 @@ const SVC_SCREENS = [ "T_STR1", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR3" ], "out": [ "T_COUNT", "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8675,13 +10106,20 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STATUS" + "T_STATUS", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR3" ], "out": [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8788,13 +10226,20 @@ const SVC_SCREENS = [ "T_ARG1", "T_BIZDATE", "T_AMOUNT", - "T_STATUS" + "T_STATUS", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR3" ], "out": [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -9087,14 +10532,22 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STATUS" + "T_STATUS", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_MSG", "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -9210,7 +10663,12 @@ const SVC_SCREENS = [ "T_FX_AMT", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC" ], "out": [ "T_AMOUNT", @@ -9231,7 +10689,14 @@ const SVC_SCREENS = [ "T_STR1", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_AMT1", + "T_AMT2", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC" ], "out": [ "T_ARG1", @@ -9240,7 +10705,8 @@ const SVC_SCREENS = [ "T_AMT2", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -9277,7 +10743,13 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG2", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC" ], "out": [ "T_RC", @@ -9285,7 +10757,8 @@ const SVC_SCREENS = [ "T_ARG2", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -9299,7 +10772,15 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_STR1", - "T_CCY" + "T_CCY", + "T_ARG3", + "T_ARG4", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_DELTA", + "T_MSG", + "T_RC" ], "out": [ "T_RC", @@ -9308,7 +10789,8 @@ const SVC_SCREENS = [ "T_DELTA", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -9343,13 +10825,21 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_ARG1", "T_AMOUNT", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -9409,7 +10899,14 @@ const SVC_SCREENS = [ "T_STR1", "T_ARG1", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_ARG2", + "T_ARG3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC" ], "out": [ "T_RC", @@ -9417,7 +10914,8 @@ const SVC_SCREENS = [ "T_ARG3", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10008,7 +11506,13 @@ const SVC_SCREENS = [ "T_STR1", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR3" ], "out": [ "T_STR3", @@ -10016,7 +11520,8 @@ const SVC_SCREENS = [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10143,14 +11648,22 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STATUS" + "T_STATUS", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", "T_MSG", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10204,14 +11717,21 @@ const SVC_SCREENS = [ "T_STR1", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR3" ], "out": [ "T_STR3", "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10246,7 +11766,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_ARG1", "T_AMOUNT", - "T_STR1" + "T_STR1", + "T_ARG2", + "T_ARG3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_ARG2", @@ -10255,7 +11785,8 @@ const SVC_SCREENS = [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10268,7 +11799,14 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID2", + "T_MSG", + "T_RC", + "T_SVCNAME" ], "out": [ "T_RC", @@ -10276,7 +11814,8 @@ const SVC_SCREENS = [ "T_MSG", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10290,14 +11829,21 @@ const SVC_SCREENS = [ "T_MSG", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID1", + "T_RC", + "T_SVCNAME" ], "out": [ "T_RC", "T_ID1", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10335,7 +11881,14 @@ const SVC_SCREENS = [ "T_STR1", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID1", + "T_MSG", + "T_RC", + "T_SVCNAME" ], "out": [ "T_RC", @@ -10343,7 +11896,8 @@ const SVC_SCREENS = [ "T_MSG", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10620,7 +12174,13 @@ const SVC_SCREENS = [ "T_STR1", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR3" ], "out": [ "T_STR3", @@ -10628,7 +12188,8 @@ const SVC_SCREENS = [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10681,14 +12242,22 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_ARG1", "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10701,7 +12270,16 @@ const SVC_SCREENS = [ "T_ARG1", "T_BIZDATE", "T_AMOUNT", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_ID1", + "T_ID2", + "T_MSG", + "T_RC", + "T_SVCNAME" ], "out": [ "T_RC", @@ -10710,7 +12288,8 @@ const SVC_SCREENS = [ "T_COUNT", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10723,7 +12302,15 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR4", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_ARG1", @@ -10731,7 +12318,8 @@ const SVC_SCREENS = [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10744,7 +12332,16 @@ const SVC_SCREENS = [ "T_ARG1", "T_BIZDATE", "T_AMOUNT", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_ID1", + "T_ID2", + "T_MSG", + "T_RC", + "T_SVCNAME" ], "out": [ "T_RC", @@ -10753,7 +12350,8 @@ const SVC_SCREENS = [ "T_COUNT", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10787,14 +12385,23 @@ const SVC_SCREENS = [ "T_ARG1", "T_BIZDATE", "T_AMOUNT", - "T_STR1" + "T_STR1", + "T_ARG2", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", "T_ARG2", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10807,7 +12414,15 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR4", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", @@ -10815,7 +12430,8 @@ const SVC_SCREENS = [ "T_STR4", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10828,7 +12444,15 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR4", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", @@ -10836,7 +12460,8 @@ const SVC_SCREENS = [ "T_STR4", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10999,7 +12624,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11008,7 +12643,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_AMT2", + "T_AMT3" ] }, { @@ -11150,7 +12789,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11158,7 +12807,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -11197,7 +12851,17 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_FEE", "T_NET", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11205,7 +12869,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -11220,7 +12888,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_MERCHANT", "T_KEY1", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11228,7 +12906,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -11242,7 +12924,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_COUNT" + "T_COUNT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11252,7 +12944,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT3" ] }, { @@ -11266,7 +12961,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_COUNT" + "T_COUNT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11276,7 +12981,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT3" ] }, { @@ -11424,7 +13132,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_REASON" + "T_REASON", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11432,7 +13150,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -11445,7 +13167,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11454,7 +13186,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT3" ] }, { @@ -11468,7 +13203,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11478,7 +13223,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -11514,7 +13262,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11524,7 +13282,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -11607,7 +13368,17 @@ const SVC_SCREENS = [ "T_AMOUNT", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11616,7 +13387,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_AMT2", + "T_AMT3" ] }, { @@ -11629,7 +13404,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11639,7 +13424,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -11720,7 +13508,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11728,7 +13526,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -11784,7 +13587,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11793,7 +13606,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -11806,14 +13624,29 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12008,7 +13841,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12017,7 +13860,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -12056,7 +13902,17 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_KEY1", "T_KEY2", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12064,7 +13920,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12146,7 +14006,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12155,7 +14025,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12170,7 +14044,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_MERCHANT", "T_FEE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12178,7 +14062,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12240,7 +14128,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12249,7 +14147,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12418,14 +14320,29 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12461,7 +14378,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12472,7 +14399,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -12509,7 +14439,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12518,7 +14458,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT3" ] }, { @@ -12532,7 +14475,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12541,7 +14494,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12578,7 +14536,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12587,7 +14555,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_AMT2", + "T_AMT3" ] }, { @@ -12807,7 +14779,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12816,7 +14798,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12851,7 +14838,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12861,7 +14858,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -12877,7 +14877,17 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_KEY1", "T_KEY2", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12885,7 +14895,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12899,7 +14913,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_COUNT" + "T_COUNT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12908,7 +14932,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12921,7 +14949,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12929,7 +14967,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12944,7 +14986,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12953,7 +15005,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT3" ] }, { @@ -12990,7 +15045,8 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_STR8" ], "out": [ "T_RC", @@ -13055,7 +15111,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13064,7 +15130,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_AMT2", + "T_AMT3" ] }, { @@ -13077,7 +15147,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13087,7 +15167,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -13100,7 +15183,17 @@ const SVC_SCREENS = [ "T_AMOUNT", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13109,7 +15202,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_AMT2", + "T_AMT3" ] }, { @@ -13164,7 +15261,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13173,7 +15280,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_AMT2", + "T_AMT3" ] }, { @@ -13228,7 +15339,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13237,7 +15358,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_AMT2", + "T_AMT3" ] }, { @@ -13292,7 +15417,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13301,7 +15436,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13362,7 +15502,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_MERCHANT", "T_NET", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13370,7 +15520,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13409,7 +15563,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_MERCHANT", "T_KEY1", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13419,7 +15583,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -13571,7 +15738,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13581,7 +15758,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT3" ] }, { @@ -13644,7 +15824,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_MERCHANT", "T_KEY1", - "T_KEY2" + "T_KEY2", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13652,7 +15842,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13666,7 +15860,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13676,7 +15880,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -13710,7 +15917,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13718,7 +15935,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13732,7 +15953,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_COUNT" + "T_COUNT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13741,7 +15972,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13799,7 +16034,16 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_MERCHANT", "T_STR2", - "T_MSG" + "T_MSG", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS" ], "out": [ "T_RC", @@ -13807,7 +16051,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13845,7 +16093,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13853,7 +16111,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13866,7 +16129,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13874,7 +16147,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13889,7 +16166,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_MERCHANT", "T_KEY1", - "T_KEY2" + "T_KEY2", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13897,7 +16184,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13932,7 +16223,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13941,7 +16242,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13977,7 +16283,16 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_ID1" + "T_ID1", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STATUS", + "T_STR8" ], "out": [ "T_RC", @@ -13988,7 +16303,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_STATUS" + "T_STATUS", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14193,7 +16511,16 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_ARG1", - "T_ID1" + "T_ID1", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR6", + "T_STR8" ], "out": [ "T_RC", @@ -14204,7 +16531,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_STR6" + "T_STR6", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14245,7 +16575,18 @@ const SVC_SCREENS = [ "T_STR3", "T_STR5", "T_AMOUNT", - "T_STR6" + "T_STR6", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_BIZDATE", + "T_CHANNEL", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -14257,7 +16598,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_STR3", - "T_COUNT" + "T_COUNT", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14402,7 +16746,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_STR1", "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STATUS", + "T_STR5", + "T_STR8" ], "out": [ "T_RC", @@ -14414,7 +16768,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_STATUS", - "T_STR5" + "T_STR5", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14427,7 +16784,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_STR1", "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_AMT2", + "T_AMT3", + "T_ARG3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STATUS", + "T_STR8" ], "out": [ "T_RC", @@ -14439,7 +16806,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_STATUS", - "T_ARG3" + "T_ARG3", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14503,7 +16873,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_STR1", "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STATUS", + "T_STR5", + "T_STR8" ], "out": [ "T_RC", @@ -14515,7 +16895,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_STATUS", - "T_STR5" + "T_STR5", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14539,7 +16922,9 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_STATUS" + "T_STATUS", + "T_ARG2", + "T_ARG3" ] }, { @@ -14602,7 +16987,17 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR2" + "T_STR2", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR5", + "T_STR8" ], "out": [ "T_RC", @@ -14615,7 +17010,10 @@ const SVC_SCREENS = [ "T_STR8", "T_STR5", "T_STR2", - "T_COUNT" + "T_COUNT", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14679,7 +17077,18 @@ const SVC_SCREENS = [ "T_STR4", "T_STR3", "T_STR5", - "T_AMOUNT" + "T_AMOUNT", + "T_AMT2", + "T_AMT3", + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_BIZDATE", + "T_CHANNEL", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -14842,7 +17251,17 @@ const SVC_SCREENS = [ "T_STR5", "T_AMOUNT", "T_CHANNEL", - "T_ARG1" + "T_ARG1", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_BIZDATE", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -14854,7 +17273,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_STR3", - "T_COUNT" + "T_COUNT", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14998,7 +17420,17 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_ID1" + "T_ID1", + "T_AMT2", + "T_AMT3", + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID2", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -15010,7 +17442,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_ID2", - "T_ARG1" + "T_ARG1", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -15024,7 +17459,16 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_ID1" + "T_ID1", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID2", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -15035,7 +17479,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_ID2" + "T_ID2", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -15244,7 +17691,17 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR4", + "T_STR8" ], "out": [ "T_RC", @@ -15259,7 +17716,8 @@ const SVC_SCREENS = [ "T_STR1", "T_STR4", "T_AMOUNT", - "T_COUNT" + "T_COUNT", + "T_CHANNEL" ] }, { @@ -15405,7 +17863,17 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID1", + "T_MSG", + "T_RC", + "T_STR4", + "T_STR8" ], "out": [ "T_RC", @@ -15419,7 +17887,8 @@ const SVC_SCREENS = [ "T_STR1", "T_STR4", "T_AMOUNT", - "T_ID1" + "T_ID1", + "T_CHANNEL" ] }, { @@ -15459,7 +17928,19 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_KEY2" + "T_KEY2", + "T_AMT2", + "T_AMT3", + "T_ARG3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_KEY1", + "T_MSG", + "T_RC", + "T_STR8", + "T_STR2", + "T_ARG1" ], "out": [ "T_RC", @@ -15471,7 +17952,8 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_KEY1", - "T_ARG3" + "T_ARG3", + "T_AMOUNT" ] }, { @@ -15535,7 +18017,19 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_STR1", "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_AMT2", + "T_AMT3", + "T_ARG3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_KEY1", + "T_MSG", + "T_RC", + "T_STR8", + "T_STR2", + "T_ARG1" ], "out": [ "T_RC", @@ -15547,7 +18041,8 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_KEY1", - "T_ARG3" + "T_ARG3", + "T_AMOUNT" ] }, { @@ -15612,7 +18107,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_STR1", "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_AMT2", + "T_AMT3", + "T_ARG3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -15625,7 +18130,9 @@ const SVC_SCREENS = [ "T_STR8", "T_CHANNEL", "T_COUNT", - "T_ARG3" + "T_ARG3", + "T_STR1", + "T_AMOUNT" ] }, { @@ -15664,7 +18171,18 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_STR3", - "T_ID1" + "T_ID1", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_KEY1", + "T_MSG", + "T_RC", + "T_STR8", + "T_STR2", + "T_ARG1" ], "out": [ "T_RC", @@ -15675,7 +18193,8 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_KEY1" + "T_KEY1", + "T_AMOUNT" ] }, { @@ -15689,7 +18208,19 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_KEY1", + "T_MSG", + "T_RC", + "T_STR8", + "T_STR2", + "T_ARG1" ], "out": [ "T_RC", @@ -15701,7 +18232,8 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_KEY1", - "T_ARG3" + "T_ARG3", + "T_AMOUNT" ] }, { @@ -15715,7 +18247,18 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_KEY1", + "T_MSG", + "T_RC", + "T_STR8", + "T_STR2", + "T_ARG1" ], "out": [ "T_RC", @@ -15726,7 +18269,8 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_KEY1" + "T_KEY1", + "T_AMOUNT" ] }, { @@ -15740,7 +18284,18 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_ID1" + "T_ID1", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_KEY2", + "T_MSG", + "T_RC", + "T_STR8", + "T_STR2", + "T_ARG1" ], "out": [ "T_RC", @@ -15751,7 +18306,8 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_KEY2" + "T_KEY2", + "T_AMOUNT" ] }, { @@ -15766,7 +18322,15 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_ID1", - "T_RC" + "T_RC", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_STATUS", + "T_STR8" ], "out": [ "T_RC", @@ -15777,7 +18341,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_STATUS" + "T_STATUS", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -15874,7 +18441,17 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR4" + "T_STR4", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR3", + "T_STR8" ], "out": [ "T_RC", @@ -15886,7 +18463,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_STR3", - "T_COUNT" + "T_COUNT", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -15926,7 +18506,19 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_KEY1", + "T_MSG", + "T_RC", + "T_STR4", + "T_STR8", + "T_STATUS" ], "out": [ "T_RC", @@ -15939,7 +18531,10 @@ const SVC_SCREENS = [ "T_STR8", "T_STR1", "T_STR4", - "T_COUNT" + "T_COUNT", + "T_KEY1", + "T_MERCHANT", + "T_AMOUNT" ] }, { @@ -16115,7 +18710,18 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_AMT2", + "T_AMT3", + "T_ARG2", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR3", + "T_STR8" ], "out": [ "T_RC", @@ -16128,7 +18734,10 @@ const SVC_SCREENS = [ "T_STR8", "T_STR3", "T_COUNT", - "T_ARG2" + "T_ARG2", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -16143,7 +18752,17 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_STR3", - "T_STR5" + "T_STR5", + "T_AMT2", + "T_AMT3", + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID1", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -16155,7 +18774,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_ARG1", - "T_ID1" + "T_ID1", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -16197,7 +18819,16 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_ARG1", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID2", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -16208,7 +18839,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_ID2" + "T_ID2", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -16223,7 +18857,16 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_ID2", - "T_ARG4" + "T_ARG4", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -16234,7 +18877,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_COUNT" + "T_COUNT", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -16285,6 +18931,7 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", + "T_ARG4", "T_ID1", "T_ARG1" ] @@ -16381,7 +19028,16 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_STR1", "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR3", + "T_STR8" ], "out": [ "T_RC", @@ -16392,7 +19048,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_STR3" + "T_STR3", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -16610,7 +19269,17 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID1", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -16622,7 +19291,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_ARG1", - "T_ID1" + "T_ID1", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -16661,7 +19333,16 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -16672,7 +19353,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_COUNT" + "T_COUNT", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -16686,7 +19370,16 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_AMT2", + "T_AMT3", + "T_ARG2", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -16697,7 +19390,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_ARG2" + "T_ARG2", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -17281,7 +19977,16 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR6", + "T_STR8" ], "out": [ "T_RC", @@ -17295,7 +20000,8 @@ const SVC_SCREENS = [ "T_STR3", "T_STR6", "T_STR1", - "T_AMOUNT" + "T_AMOUNT", + "T_CHANNEL" ] }, { @@ -17334,7 +20040,16 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR4", + "T_STR8" ], "out": [ "T_RC", @@ -17347,7 +20062,8 @@ const SVC_SCREENS = [ "T_STR8", "T_STR1", "T_STR4", - "T_AMOUNT" + "T_AMOUNT", + "T_CHANNEL" ] }, { @@ -17494,10 +20210,16 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_STR1", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_RC", + "T_STR5", + "T_STR3" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -17507,10 +20229,17 @@ const SVC_SCREENS = [ "desc": "기능: 정산계좌 검증 실행 (형식 검사 + ACCT_VRF 검증 이력 적재).", "in": [ "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_RC", + "T_STR1", + "T_STR5", + "T_STR3" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -17592,7 +20321,8 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_ARG1", - "T_KEY1" + "T_KEY1", + "T_RC" ], "out": [ "T_RC" @@ -17665,10 +20395,15 @@ const SVC_SCREENS = [ "T_STR1", "T_STR2", "T_STR3", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_RC", + "T_ARG1" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -17850,9 +20585,13 @@ const SVC_SCREENS = [ "T_KEY1", "T_ISSUER", "T_STR5", - "T_CCY" + "T_CCY", + "T_MERCHANT", + "T_RC" ], - "out": [] + "out": [ + "T_RC" + ] }, { "mod": "mm", @@ -17862,11 +20601,17 @@ const SVC_SCREENS = [ "in": [ "T_STR2", "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_COUNT", + "T_RC", + "T_ARG1" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_AMOUNT" ] }, { @@ -18021,12 +20766,17 @@ const SVC_SCREENS = [ "desc": "기능: 한도 마스터 정합성 점검 (활성 가맹점 한도 누락 + 한도 체계 역전 검출).", "in": [ "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_ARG1", + "T_COUNT", + "T_RC" ], "out": [ "T_COUNT", "T_ARG1", - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -18147,9 +20897,14 @@ const SVC_SCREENS = [ "in": [ "T_STR1", "T_KEY1", - "T_STR2" + "T_STR2", + "T_MERCHANT", + "T_STR3", + "T_RC" ], - "out": [] + "out": [ + "T_RC" + ] }, { "mod": "mm", @@ -18170,10 +20925,15 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_ARG1", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_RC", + "T_STR1" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -18242,10 +21002,15 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_ARG1", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_RC", + "T_STR1" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -18269,10 +21034,16 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_ARG1", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_RC", + "T_STR1", + "T_STR2" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -18325,9 +21096,15 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_STR4", "T_ARG1", - "T_KEY1" + "T_KEY1", + "T_BIZDATE", + "T_FEE", + "T_PURCHASE_ID" ], - "out": [] + "out": [ + "T_FEE", + "T_RC" + ] }, { "mod": "mm", @@ -18367,7 +21144,9 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_STR2", "T_REASON", - "T_KEY1" + "T_KEY1", + "T_RC", + "T_STR1" ], "out": [ "T_RC" @@ -18456,9 +21235,13 @@ const SVC_SCREENS = [ "T_STR1", "T_STR2", "T_KEY1", - "T_CCY" + "T_CCY", + "T_MERCHANT", + "T_RC" ], - "out": [] + "out": [ + "T_RC" + ] }, { "mod": "mm", @@ -18485,9 +21268,14 @@ const SVC_SCREENS = [ "T_AMT1", "T_AMT2", "T_AMT3", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_RC" ], - "out": [] + "out": [ + "T_AMOUNT", + "T_RC" + ] }, { "mod": "mm", @@ -18560,9 +21348,14 @@ const SVC_SCREENS = [ "T_STR1", "T_ARG1", "T_CATEGORY", - "T_KEY1" + "T_KEY1", + "T_MERCHANT", + "T_STR3", + "T_RC" ], - "out": [] + "out": [ + "T_RC" + ] }, { "mod": "mm", @@ -18606,7 +21399,10 @@ const SVC_SCREENS = [ "T_CATEGORY", "T_STR1", "T_ARG1", - "T_KEY1" + "T_KEY1", + "T_MERCHANT", + "T_RC", + "T_STR3" ], "out": [ "T_RC" @@ -18647,11 +21443,20 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_REASON", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR1", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_AMOUNT" ] }, { @@ -18673,11 +21478,20 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_REASON", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_GROSS", + "T_MSG", + "T_RC", + "T_STR1", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", - "T_GROSS" + "T_GROSS", + "T_AMOUNT" ] }, { @@ -18688,9 +21502,12 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_STR2", - "T_KEY1" + "T_KEY1", + "T_RC" ], - "out": [] + "out": [ + "T_RC" + ] }, { "mod": "mm", @@ -18711,11 +21528,20 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_REASON", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR1", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_AMOUNT" ] }, { @@ -18728,9 +21554,13 @@ const SVC_SCREENS = [ "T_STR1", "T_STR2", "T_STR3", - "T_KEY1" + "T_KEY1", + "T_STATUS", + "T_RC" ], - "out": [] + "out": [ + "T_RC" + ] }, { "mod": "mm", @@ -18739,11 +21569,20 @@ const SVC_SCREENS = [ "desc": "기능: 가맹점 영업 재개 (HOLD -> ACTIVE, 정지 단말 재가동).", "in": [ "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR1", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_AMOUNT" ] }, { @@ -18754,9 +21593,12 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_STATUS", - "T_KEY1" + "T_KEY1", + "T_RC" ], - "out": [] + "out": [ + "T_RC" + ] }, { "mod": "mm", @@ -18781,9 +21623,12 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_STR1", "T_STR3", - "T_KEY1" + "T_KEY1", + "T_RC" ], - "out": [] + "out": [ + "T_RC" + ] }, { "mod": "mm", @@ -18863,11 +21708,18 @@ const SVC_SCREENS = [ "desc": "기능: 수수료율 변경 승인 (대기 요청을 실제 요율 마스터에 반영, RATE_APV 이력).", "in": [ "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_AMT1", + "T_BIZDATE", + "T_FEE", + "T_RC", + "T_STR2", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_AMT1" + "T_AMT1", + "T_FEE" ] }, { @@ -18938,11 +21790,20 @@ const SVC_SCREENS = [ "T_STR2", "T_REASON", "T_ARG1", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_AMT1", + "T_BIZDATE", + "T_MSG", + "T_RC", + "T_STR1", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", - "T_AMT1" + "T_AMT1", + "T_AMOUNT" ] }, { @@ -19075,11 +21936,20 @@ const SVC_SCREENS = [ "desc": "기능: 가맹점 리스크 점수 산정 (MCC 위험도*20 + 저등급 가산 + 비활성 상태 가산).", "in": [ "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_ARG1", + "T_BIZDATE", + "T_MSG", + "T_RC", + "T_STR1", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", - "T_ARG1" + "T_ARG1", + "T_AMOUNT" ] }, { @@ -19090,7 +21960,8 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_ARG1", - "T_KEY1" + "T_KEY1", + "T_RC" ], "out": [ "T_RC" @@ -19131,9 +22002,16 @@ const SVC_SCREENS = [ "T_STR5", "T_MERCHANT", "T_STR6", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_STR1", + "T_ARG1" ], - "out": [] + "out": [ + "T_AMOUNT", + "T_RC" + ] }, { "mod": "mm", @@ -19205,10 +22083,16 @@ const SVC_SCREENS = [ "T_STR5", "T_MERCHANT", "T_STR6", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_RC", + "T_STR1", + "T_ARG1" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -19337,10 +22221,18 @@ const SVC_SCREENS = [ "desc": "기능: 가맹점 마스터 정합성 검사 (존재+수수료율 존재).", "in": [ "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_MSG", + "T_RC", + "T_STR1", + "T_SVCNAME", + "T_ID1" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -19362,11 +22254,28 @@ const SVC_SCREENS = [ "svc": "PAY_ACCTCHK", "desc": "지급계좌 유효성 점검: dbio 로 계좌 상태/잔액을 읽어 ACTIVE 여부를 회신.", "in": [ - "T_KEY1" + "T_KEY1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS" ], "out": [ "T_RC", - "T_AMT1" + "T_AMT1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -19416,11 +22325,28 @@ const SVC_SCREENS = [ "desc": "지급계좌 검증: 계좌의 상태/예금주/잔액을 조회하고, 요청에 예금주가 주어지면", "in": [ "T_KEY1", - "T_STR1" + "T_STR1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS" ], "out": [ "T_RC", - "T_AMT1" + "T_AMT1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -19432,11 +22358,28 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_DELTA", "T_ID1", - "T_REASON" + "T_REASON", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS" ], "out": [ "T_RC", - "T_ADJ" + "T_ADJ", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -19510,13 +22453,34 @@ const SVC_SCREENS = [ "desc": "소액 일괄 승인: 당일 요청(R)건 중 net 이 승인한도 이하인 건을 한 번의", "in": [ "T_AMT1", - "T_BIZDATE" + "T_BIZDATE", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_DELTA", + "T_STR7", + "T_ID2" ], "out": [ "T_RC", "T_COUNT", "T_AMT1", - "T_ARG1" + "T_ARG1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_ARG7", + "T_ARG8", + "T_DELTA", + "T_GROSS" ] }, { @@ -19565,11 +22529,33 @@ const SVC_SCREENS = [ "svc": "PAY_APPROVE", "desc": "지급 승인: 금액을 먼저 조회한 뒤 요청(R) 상태만 승인(A)으로 전이하고 금액을", "in": [ - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_DELTA", + "T_STR7", + "T_ID2" ], "out": [ "T_RC", - "T_AMOUNT" + "T_AMOUNT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_ARG7", + "T_ARG8", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -19606,13 +22592,28 @@ const SVC_SCREENS = [ "desc": "은행별 지급파일 생성: 지정 은행코드의 승인(A) 지급건만 py_account 조인으로", "in": [ "T_BIZDATE", - "T_KEY1" + "T_KEY1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_CHANNEL" ], "out": [ "T_RC", "T_ID2", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -19621,14 +22622,31 @@ const SVC_SCREENS = [ "svc": "PAY_BANKVERIFY", "desc": "지급파일 검증: 파일 헤더(record_count/total_amount)와 실제 편성 지급건의", "in": [ - "T_ID2" + "T_ID2", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_KEY1" ], "out": [ "T_RC", "T_COUNT", "T_AMT1", "T_AMT2", - "T_DELTA" + "T_DELTA", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS" ] }, { @@ -19657,11 +22675,28 @@ const SVC_SCREENS = [ "T_AMOUNT", "T_BIZDATE", "T_ID1", - "T_REASON" + "T_REASON", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_DELTA" ], "out": [ "T_RC", - "T_ADJ" + "T_ADJ", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_DELTA" ] }, { @@ -19703,12 +22738,27 @@ const SVC_SCREENS = [ "desc": "지급 되물림: 분쟁 등으로 지급완료(P) 건을 되물릴 때, 원건은 보존한 채", "in": [ "T_BIZDATE", - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS" ], "out": [ "T_RC", "T_ID2", - "T_NET" + "T_NET", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_COUNT", + "T_GROSS" ] }, { @@ -19717,11 +22767,26 @@ const SVC_SCREENS = [ "svc": "PAY_CLOSE", "desc": "일마감: 당일 지급완료(P)건을 마감(X)으로 일괄 전환하고 전환 건수를 회신.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS" ] }, { @@ -19744,13 +22809,27 @@ const SVC_SCREENS = [ "desc": "지급 합산: 같은 계좌의 당일 요청(R) 건들을 하나로 합산 지급한다. 합계", "in": [ "T_BIZDATE", - "T_KEY1" + "T_KEY1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS" ], "out": [ "T_RC", "T_ID2", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -19759,10 +22838,27 @@ const SVC_SCREENS = [ "svc": "PAY_CONFIRM", "desc": "지급 확정(confirm): 지급 파일 상태를 확정(C)으로 전이하고 확정 시각 기록.", "in": [ - "T_ID2" + "T_ID2", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -20036,13 +23132,31 @@ const SVC_SCREENS = [ "svc": "PAY_FILEGEN", "desc": "지급 파일 헤더 생성: 당일 승인(A) 지급건 집계 -> py_file.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_STR8", + "T_ARG7", + "T_ARG8", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_KEY1" ], "out": [ "T_RC", "T_ID2", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -20051,12 +23165,28 @@ const SVC_SCREENS = [ "svc": "PAY_FILEREBUILD", "desc": "지급파일 재생성: 아직 미확정(G)인 파일 헤더를 실제 편성 상세 기준으로", "in": [ - "T_ID2" + "T_ID2", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_KEY1" ], "out": [ "T_RC", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -20124,10 +23254,29 @@ const SVC_SCREENS = [ "svc": "PAY_HOLD", "desc": "지급 보류: 이미 지급완료(P)/마감(X)된 건은 보류 불가 - dbio 로 현재 상태를", "in": [ - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_DELTA" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -20371,13 +23520,27 @@ const SVC_SCREENS = [ "desc": "지급 합산: 가맹점 당일 요청(R) STD 건이 2건 이상이면 전부 취소(C) 표시 후", "in": [ "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_STATUS", + "T_KEY1" ], "out": [ "T_RC", "T_ID2", "T_COUNT", - "T_NET" + "T_NET", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_GROSS" ] }, { @@ -20387,11 +23550,26 @@ const SVC_SCREENS = [ "desc": "상계(net-off): 지급건의 net 을 조회해 차감액을 반영하고 갱신.", "in": [ "T_AMOUNT", - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS" ], "out": [ "T_RC", - "T_NET" + "T_NET", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_COUNT", + "T_GROSS" ] }, { @@ -20567,11 +23745,29 @@ const SVC_SCREENS = [ "desc": "과지급 환수: 지급완료(P) 건에서 요청 환수액(T_AMOUNT, net 한도)만큼을", "in": [ "T_AMOUNT", - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_DELTA" ], "out": [ "T_RC", - "T_AMT1" + "T_AMT1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_DELTA" ] }, { @@ -20595,11 +23791,27 @@ const SVC_SCREENS = [ "desc": "지급 환입: 지급완료(P) 건을 역분개(V)하며 지급계좌에 net 을 복원하고", "in": [ "T_ID1", - "T_REASON" + "T_REASON", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS" ], "out": [ "T_RC", - "T_NET" + "T_NET", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_COUNT", + "T_GROSS" ] }, { @@ -20621,10 +23833,29 @@ const SVC_SCREENS = [ "svc": "PAY_RELEASE", "desc": "보류 해제: 직전 상태를 조회하여 보류(H)가 아니면 무효 처리, 보류면 dbio 로", "in": [ - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_DELTA" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -20635,10 +23866,27 @@ const SVC_SCREENS = [ "in": [ "T_ID1", "T_KEY1", - "T_NET" + "T_NET", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_CHANNEL" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -20676,10 +23924,29 @@ const SVC_SCREENS = [ "svc": "PAY_REPROC", "desc": "재처리: 직전 상태를 조회한 뒤 실패/보류/취소(J,H,C) -> 요청(R) 전이, 이전 상태 회신.", "in": [ - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_DELTA" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -20688,11 +23955,27 @@ const SVC_SCREENS = [ "svc": "PAY_REQUEUE", "desc": "실패 일괄 재처리 적재: 당일 반려(J) 건 중 재시도 여력(retry_count<3)이", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_CHANNEL" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS" ] }, { @@ -20701,10 +23984,27 @@ const SVC_SCREENS = [ "svc": "PAY_RESULT", "desc": "지급 결과 반영: 편성/요청(F,R) 상태만 지급완료(P)로 전이, 반영 건수를 T_RC 로.", "in": [ - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -20728,10 +24028,28 @@ const SVC_SCREENS = [ "desc": "예약 변경: 아직 실행되지 않은 예약(S) 의 실행일(run_date)을 새 일자로", "in": [ "T_BIZDATE", - "T_ID2" + "T_ID2", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_ARG1" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_ARG1", + "T_COUNT", + "T_GROSS" ] }, { @@ -20740,10 +24058,29 @@ const SVC_SCREENS = [ "svc": "PAY_RETRY", "desc": "실패 지급 재시도: 실패/보류(J,H) 건만 요청(R)으로 되돌리고 retry_count 증가.", "in": [ - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_DELTA" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -20752,11 +24089,29 @@ const SVC_SCREENS = [ "svc": "PAY_RETRYONE", "desc": "단건 재시도: 반려(J) 지급건 하나를 요청(R)으로 되돌리며 retry_count 를", "in": [ - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_DELTA" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_GROSS" ] }, { @@ -20767,10 +24122,28 @@ const SVC_SCREENS = [ "in": [ "T_AMOUNT", "T_ID1", - "T_KEY1" + "T_KEY1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_DELTA" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_DELTA" ] }, { @@ -20780,11 +24153,28 @@ const SVC_SCREENS = [ "desc": "미지급 일괄 이월: 지정 기준일 이전의 미지급(R) 건 전부를 차기 영업일", "in": [ "T_BIZDATE", - "T_KEY2" + "T_KEY2", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_ARG1" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_ARG1", + "T_GROSS" ] }, { @@ -20807,11 +24197,29 @@ const SVC_SCREENS = [ "desc": "지급 예약 등록: 지정 실행일로 py_schedule 예약(S) 레코드를 생성.", "in": [ "T_BIZDATE", - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_ARG1" ], "out": [ "T_RC", - "T_ID2" + "T_ID2", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_ARG1", + "T_COUNT", + "T_GROSS" ] }, { @@ -20892,11 +24300,23 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_COUNT", "T_KEY1", - "T_MERCHANT" + "T_MERCHANT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS" ] }, { @@ -20907,12 +24327,26 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_COUNT", - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_KEY1" ], "out": [ "T_RC", "T_COUNT", - "T_AMOUNT" + "T_AMOUNT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_GROSS" ] }, { @@ -20922,14 +24356,32 @@ const SVC_SCREENS = [ "desc": "비율 분할: 요청(R) 건을 bps 비율로 두 건의 SPLIT 지급건으로 쪼개고", "in": [ "T_ARG1", - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_KEY1" ], "out": [ "T_RC", "T_ID2", "T_AMT1", "T_AMT2", - "T_ARG2" + "T_ARG2", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -21112,13 +24564,25 @@ const SVC_SCREENS = [ "T_AMOUNT", "T_BIZDATE", "T_KEY1", - "T_MERCHANT" + "T_MERCHANT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ID1", "T_FEE", - "T_NET" + "T_NET", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_COUNT", + "T_GROSS" ] }, { @@ -21144,10 +24608,27 @@ const SVC_SCREENS = [ "desc": "지급 무효(단건): 아직 지급 전인 요청/승인(R/A) 건만 무효 취소(C)로 전이하고", "in": [ "T_ID1", - "T_REASON" + "T_REASON", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -21201,10 +24682,26 @@ const SVC_SCREENS = [ "in": [ "T_AMOUNT", "T_BIZDATE", - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_CHANNEL" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -21272,10 +24769,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_NET" + "T_NET", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21286,10 +24792,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_NET" + "T_NET", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ID1" ] }, @@ -21299,10 +24814,20 @@ const SVC_SCREENS = [ "svc": "RC_ACQMATCH", "desc": "업무: 매입-입금 축 대사: 당일 매입 순액 합계와 원장 RECON 입금 합계를 비교해 차액을 산출.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", "T_ARG2", "T_DELTA" @@ -21316,11 +24841,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_NET" + "T_NET", + "T_RC" ], "out": [ "T_RC", - "T_GROSS" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21348,10 +24881,23 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_PURCHASE_ID", "T_MSG", - "T_STR1" + "T_STR1", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_MERCHANT", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ID1" ] }, @@ -21363,10 +24909,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_NET" + "T_NET", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_DELTA" ] }, @@ -21376,11 +24931,20 @@ const SVC_SCREENS = [ "svc": "RC_APPRGAP", "desc": "업무: 승인 누락 감지: 당일 매입 중 승인 원장이 없는 건을 예외로 등록하고 누락 건수를 반환.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21389,13 +24953,22 @@ const SVC_SCREENS = [ "svc": "RC_APPRMATCH", "desc": "업무: 승인-매입 축 대사: 당일 매입 중 승인건과 매칭된 건수와 승인 누락 건수를 분리 집계.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", - "T_ARG2", - "T_COUNT" + "T_ARG2" ] }, { @@ -21406,10 +24979,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_NET" + "T_NET", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ID1" ] }, @@ -21463,10 +25045,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_AMOUNT" + "T_AMOUNT", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21709,14 +25300,22 @@ const SVC_SCREENS = [ "svc": "RC_CLOSEDAY", "desc": "업무: 일마감 확정 (예외/보류 잔량 시 거부).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_ARG1", - "T_ARG2", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", "T_COUNT", - "T_GROSS" + "T_ARG3", + "T_AMT2", + "T_ARG4", + "T_ARG1", + "T_ARG2" ] }, { @@ -21725,11 +25324,20 @@ const SVC_SCREENS = [ "svc": "RC_CNTDIFF", "desc": "업무: 건수 차이 대사: 매입 건수 vs 대사 로그 건수.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21738,10 +25346,19 @@ const SVC_SCREENS = [ "svc": "RC_CONFIRM", "desc": "업무: 대사 확정 (MATCHED -> CONFIRMED).", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21765,11 +25382,20 @@ const SVC_SCREENS = [ "svc": "RC_DEPGAP", "desc": "업무: 입금 누락 감지: 매입은 있으나 RECON 원장이 없는 미입금 건수를 집계.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21779,12 +25405,20 @@ const SVC_SCREENS = [ "desc": "업무: 입금(정산) 대사.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", - "T_AMT1", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", "T_AMT2", + "T_ARG4", + "T_AMT1", "T_ID1" ] }, @@ -21867,11 +25501,20 @@ const SVC_SCREENS = [ "svc": "RC_DUPCHK", "desc": "업무: 중복 대사 매입 검출 + WARN 경보.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21911,11 +25554,20 @@ const SVC_SCREENS = [ "svc": "RC_ESCALATE", "desc": "업무: 미해결 예외 경보 WARN -> CRIT 일괄 승격.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21926,10 +25578,23 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_REASON" + "T_REASON", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_MERCHANT", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ID1" ] }, @@ -21939,11 +25604,20 @@ const SVC_SCREENS = [ "svc": "RC_EXCNOTIFY", "desc": "업무: 대사 예외 알림: 당일 미해결 예외 건수를 집계해 임계 초과 시 rc_alert 경보를 발생.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21967,11 +25641,20 @@ const SVC_SCREENS = [ "svc": "RC_FEEDIFF", "desc": "업무: 당일 수수료 불일치 건수/차액 합계.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_DELTA" ] }, @@ -21982,12 +25665,20 @@ const SVC_SCREENS = [ "desc": "업무: MDR 기준 수수료 대사.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", - "T_DELTA", + "T_AMOUNT", "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", + "T_DELTA", "T_ID1" ] }, @@ -22011,13 +25702,21 @@ const SVC_SCREENS = [ "desc": "업무: 수수료 자동보정: 매입 수수료가 MDR 이론치와 다르면 차이를 조정 델타로 반환.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", - "T_DELTA", - "T_FEE" + "T_DELTA" ] }, { @@ -22027,10 +25726,19 @@ const SVC_SCREENS = [ "desc": "업무: 외화 자동보정: ac_fx 의 원화환산액과 원통화*환율 이론치의 차이를 산출.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", "T_ARG2", "T_DELTA" @@ -22042,11 +25750,20 @@ const SVC_SCREENS = [ "svc": "RC_FIXROUND", "desc": "업무: 반올림 자동보정: 절대차 1 이하 단수 차이를 수수료조정(ac_fee_adj)으로 상계 기록.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22068,10 +25785,20 @@ const SVC_SCREENS = [ "svc": "RC_FXDIFF", "desc": "업무: 외화 환산 차이: 당일 ac_fx 원화환산 합계와 원통화*환율 이론합계의 차이를 집계.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", "T_ARG2", "T_DELTA" @@ -22099,12 +25826,20 @@ const SVC_SCREENS = [ "desc": "업무: 외화 원화환산 대사.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", - "T_AMT1", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", "T_AMT2", + "T_ARG4", + "T_AMT1", "T_ID1" ] }, @@ -22156,11 +25891,19 @@ const SVC_SCREENS = [ "desc": "업무: 대사 보류 해제: 보류(H) 매입을 접수(A)로 되돌리고 관련 예외를 해결 처리.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22201,10 +25944,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_REASON" + "T_REASON", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ID1" ] }, @@ -22278,13 +26030,22 @@ const SVC_SCREENS = [ "svc": "RC_LEDGERBAL", "desc": "업무: 원장 축 잔액 대사: 당일 RECON/SETTLE/XFER 기표 합계의 순잔액이 0 인지 확인.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", "T_ARG2", - "T_ARG3", "T_DELTA" ] }, @@ -22296,10 +26057,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_NET" + "T_NET", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22309,12 +26079,21 @@ const SVC_SCREENS = [ "desc": "업무: 가맹점 일한도 초과 검증.", "in": [ "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_AMT1", - "T_AMT2" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", + "T_AMT1" ] }, { @@ -22442,10 +26221,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_NET" + "T_NET", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ID1" ] }, @@ -22483,13 +26271,22 @@ const SVC_SCREENS = [ "svc": "RC_NOTIFY", "desc": "업무: 대사 결과 요약 통보 (경보 발송).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", - "T_ARG2", - "T_GROSS" + "T_ARG2" ] }, { @@ -22498,11 +26295,20 @@ const SVC_SCREENS = [ "svc": "RC_ORPHAN", "desc": "업무: 승인 없는 고아 매입 적재.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22511,11 +26317,20 @@ const SVC_SCREENS = [ "svc": "RC_OVERAMT", "desc": "업무: 과다 차이 분석: 당일 rc_diff 중 실제가 기대를 초과(diff_amt<0)한 과다 건수/합계.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_DELTA" ] }, @@ -22582,13 +26397,22 @@ const SVC_SCREENS = [ "svc": "RC_PAYLEDGER", "desc": "업무: 지급-원장 축 대사: 정산 순액과 원장 SETTLE 기표 합계가 일치하는지 검증하고 차액 반환.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", - "T_DELTA", - "T_GROSS" + "T_DELTA" ] }, { @@ -22598,10 +26422,19 @@ const SVC_SCREENS = [ "desc": "업무: 지급(원장) 대사 + 차이 적재.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_DELTA", "T_ID1" ] @@ -22625,10 +26458,20 @@ const SVC_SCREENS = [ "svc": "RC_PROGRESS", "desc": "업무: 진행률(%) = MATCHED / 전체매입 * 100.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22733,11 +26576,19 @@ const SVC_SCREENS = [ "desc": "업무: 정정후 재대사: 수수료조정이 반영된 매입을 대상으로 순액 재검증 후 로그를 남긴다.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", - "T_NET" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22747,10 +26598,19 @@ const SVC_SCREENS = [ "desc": "업무: 차이발생 재대사: 지정 매입의 기대 순액과 SETTLE 실적 차이를 재산출해 rc_diff 갱신.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_DELTA" ] }, @@ -22760,12 +26620,21 @@ const SVC_SCREENS = [ "svc": "RC_REFULL", "desc": "업무: 전체 재대사: 당일 전체 매입 대비 대사완료(M/S) 비율을 재계산해 진척률로 반환.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_ARG1", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", + "T_ARG1" ] }, { @@ -22801,10 +26670,19 @@ const SVC_SCREENS = [ "svc": "RC_RELEASE", "desc": "업무: 대사 보류 해제 (HOLD -> RELEASED).", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22815,10 +26693,22 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_NET" + "T_NET", + "T_AMOUNT", + "T_FEE", + "T_MERCHANT", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22840,10 +26730,24 @@ const SVC_SCREENS = [ "svc": "RC_REPROC", "desc": "업무: 재처리: EXCEPTION 대사 로그를 MATCHED 로 되돌림.", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_MERCHANT", + "T_BIZDATE", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22853,11 +26757,20 @@ const SVC_SCREENS = [ "desc": "업무: 임계초과 건 재대사 등록 (커서 순회).", "in": [ "T_BIZDATE", - "T_AMT1" + "T_AMT1", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22909,11 +26822,20 @@ const SVC_SCREENS = [ "svc": "RC_ROUNDDIFF", "desc": "업무: 반올림 차이 분석: 절대차가 1 이하인 단수 차이 건을 반올림 오차로 분류해 집계.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22935,14 +26857,22 @@ const SVC_SCREENS = [ "svc": "RC_SNAPSHOT", "desc": "업무: 현재 시점 대사 현황 스냅샷 upsert.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_ARG1", - "T_ARG2", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", "T_COUNT", - "T_GROSS" + "T_ARG3", + "T_AMT2", + "T_ARG4", + "T_ARG1", + "T_ARG2" ] }, { @@ -22964,10 +26894,19 @@ const SVC_SCREENS = [ "svc": "RC_STATUS", "desc": "업무: 최근 대사 상태 조회.", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22976,10 +26915,20 @@ const SVC_SCREENS = [ "svc": "RC_SUMCHK", "desc": "업무: 요약 대 실측 정합성 검증.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", "T_ARG2" ] @@ -23049,10 +26998,19 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_PURCHASE_ID", "T_DELTA", - "T_ARG1" + "T_ARG1", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -23091,11 +27049,20 @@ const SVC_SCREENS = [ "svc": "RC_UNDERAMT", "desc": "업무: 과소 차이 분석: 당일 rc_diff 중 실제가 기대에 미달(diff_amt>0)한 과소 건수/합계.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_DELTA" ] }, @@ -23105,11 +27072,20 @@ const SVC_SCREENS = [ "svc": "RC_UNMATCH", "desc": "업무: 미대사 건수 조회. (KEEP)", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -23181,10 +27157,25 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_NET", "T_MERCHANT", - "T_BIZDATE" + "T_BIZDATE", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_COUNT", + "T_GROSS", + "T_STATUS", + "T_DELTA" ], "out": [ - "T_SETTLE_ID" + "T_SETTLE_ID", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_RC", + "T_COUNT", + "T_GROSS" ] }, { @@ -23236,7 +27227,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -23245,7 +27239,14 @@ const SVC_SCREENS = [ "T_DELTA", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -23265,7 +27266,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -23274,7 +27278,14 @@ const SVC_SCREENS = [ "T_DELTA", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -23354,14 +27365,25 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ARG6", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -23381,14 +27403,24 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ARG6", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT" ] }, { @@ -23560,14 +27592,24 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ARG6", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -23616,7 +27658,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -23628,7 +27673,11 @@ const SVC_SCREENS = [ "T_GROSS", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_NET" ] }, { @@ -23732,7 +27781,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -23740,7 +27792,13 @@ const SVC_SCREENS = [ "T_ID1", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT" ] }, { @@ -23821,14 +27879,25 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ARG6", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -23877,7 +27946,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -23885,7 +27957,14 @@ const SVC_SCREENS = [ "T_NET", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -24101,7 +28180,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -24110,7 +28192,12 @@ const SVC_SCREENS = [ "T_GROSS", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -24275,7 +28362,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -24284,7 +28374,13 @@ const SVC_SCREENS = [ "T_NET", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_COUNT", + "T_GROSS" ] }, { @@ -24749,7 +28845,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -24757,7 +28856,13 @@ const SVC_SCREENS = [ "T_ID1", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT" ] }, { @@ -24777,14 +28882,23 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ARG6", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT" ] }, { @@ -24831,7 +28945,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -24839,7 +28956,14 @@ const SVC_SCREENS = [ "T_ID1", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT" ] }, { @@ -24891,7 +29015,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -24900,7 +29027,12 @@ const SVC_SCREENS = [ "T_GROSS", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -24949,7 +29081,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -24960,7 +29095,12 @@ const SVC_SCREENS = [ "T_GROSS", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -25027,9 +29167,25 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_FEE", - "T_BIZDATE" + "T_BIZDATE", + "T_SETTLE_ID", + "T_AMOUNT", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS" ], - "out": [] + "out": [ + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_RC", + "T_COUNT", + "T_GROSS" + ] }, { "mod": "st", @@ -25223,7 +29379,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -25232,7 +29391,12 @@ const SVC_SCREENS = [ "T_GROSS", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -25252,7 +29416,11 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS", + "T_ARG1" ], "out": [ "T_RC", @@ -25260,7 +29428,14 @@ const SVC_SCREENS = [ "T_ID1", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_ARG1", + "T_COUNT" ] }, { @@ -25280,7 +29455,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -25289,7 +29467,14 @@ const SVC_SCREENS = [ "T_DELTA", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -25393,7 +29578,11 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS", + "T_ARG1" ], "out": [ "T_RC", @@ -25401,7 +29590,14 @@ const SVC_SCREENS = [ "T_ID1", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_ARG1", + "T_COUNT" ] }, { @@ -25507,14 +29703,24 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ARG6", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -25592,7 +29798,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -25601,7 +29810,13 @@ const SVC_SCREENS = [ "T_ID1", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_NET", + "T_DELTA", + "T_COUNT" ] }, { @@ -25804,7 +30019,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -25812,7 +30030,14 @@ const SVC_SCREENS = [ "T_NET", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -25950,7 +30175,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -25959,7 +30187,14 @@ const SVC_SCREENS = [ "T_DELTA", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -26037,14 +30272,23 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ARG6", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT" ] }, { @@ -26151,7 +30395,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -26162,7 +30409,13 @@ const SVC_SCREENS = [ "T_GROSS", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA" ] }, { @@ -26445,7 +30698,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -26456,7 +30712,12 @@ const SVC_SCREENS = [ "T_GROSS", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -26714,7 +30975,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -26724,7 +30988,13 @@ const SVC_SCREENS = [ "T_FEE", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_NET", + "T_DELTA", + "T_COUNT" ] }, { @@ -26744,7 +31014,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -26754,7 +31027,12 @@ const SVC_SCREENS = [ "T_FEE", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_NET", + "T_COUNT" ] }, { @@ -26836,14 +31114,24 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ARG6", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -26892,7 +31180,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -26902,7 +31193,13 @@ const SVC_SCREENS = [ "T_FEE", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_NET", + "T_DELTA", + "T_COUNT" ] }, { @@ -27011,7 +31308,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -27020,7 +31320,12 @@ const SVC_SCREENS = [ "T_GROSS", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -27066,7 +31371,10 @@ const SVC_SCREENS = [ "svc": "VL_AMOUNT", "desc": "기능: 금액 유효성(0 daily_limit → RC 1, 3=가맹점 없음).", "in": [ "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -27574,8 +31929,8 @@ const SVC_SCREENS = [ "T_AMT3", "T_ARG6", "T_ARG2", - "T_ARG1", "T_AMT1", + "T_ARG1", "T_GROSS", "T_DELTA" ] @@ -27588,7 +31943,9 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -27598,6 +31955,7 @@ const SVC_SCREENS = [ "T_AMT3", "T_ARG6", "T_ARG2", + "T_AMT1", "T_ARG1", "T_COUNT" ] @@ -27609,7 +31967,8 @@ const SVC_SCREENS = [ "desc": "기능: 중복 승인 검출 건별 (동일 매입 승인가결 2건 이상, RC 1=중복; 검증로그 기록).", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", @@ -27618,6 +31977,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -27628,7 +31989,9 @@ const SVC_SCREENS = [ "svc": "VL_DUPAUTH", "desc": "기능: 중복 승인 검증 (approval 2건 이상 → RC 1).", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -27637,6 +32000,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -27647,7 +32012,9 @@ const SVC_SCREENS = [ "svc": "VL_DUPLEDGR", "desc": "기능: 중복 원장 엔트리 검출 (동일 매입+엔트리유형 최대 그룹 건수>1, RC 1=중복).", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -27656,6 +32023,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -27667,7 +32036,8 @@ const SVC_SCREENS = [ "desc": "기능: 건별 중복지급 검출 (ledger XFER 엔트리 2건 이상 → RC 1, 검증로그 기록).", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", @@ -27676,6 +32046,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_GROSS" @@ -27705,7 +32077,9 @@ const SVC_SCREENS = [ "svc": "VL_DUPPURCH", "desc": "기능: 중복 매입 검출 건별 (동일 가맹점+금액+영업일의 타 매입 존재, RC 1=중복).", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -27714,6 +32088,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -27725,7 +32101,9 @@ const SVC_SCREENS = [ "desc": "기능: 건별 중복 정산 검출 (동일 매입에 정산 2건 이상 → RC 1, 최초/최종 정산 ID 반환).", "in": [ "T_PURCHASE_ID", - "T_ID1" + "T_ID1", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -27734,6 +32112,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_NET", @@ -27769,6 +32149,8 @@ const SVC_SCREENS = [ "desc": "기능: 카드 유효기간(YYYYMM) vs 영업일 검증 (RC 1=만료).", "in": [ "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID", "T_STR2" ], "out": [ @@ -27777,6 +32159,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1" ] }, @@ -27786,7 +32170,9 @@ const SVC_SCREENS = [ "svc": "VL_FEE", "desc": "기능: 수수료 재계산 정합 검증 (저장 fee vs MDR 재계산, RC 1=불일치).", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -27795,6 +32181,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_FEE", "T_DELTA" @@ -27847,6 +32235,8 @@ const SVC_SCREENS = [ "desc": "기능: 수수료 재계산 검증 (가맹점 요율 mdr_bps로 기대수수료 재산출, |fee-기대|>허용오차 → RC 1, 3=매입/가맹점 없음).", "in": [ "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE", "T_ARG1" ], "out": [ @@ -27856,8 +32246,9 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", - "T_FEE", "T_AMT1", + "T_AMT3", + "T_FEE", "T_DELTA" ] }, @@ -27867,7 +32258,10 @@ const SVC_SCREENS = [ "svc": "VL_FORMAT", "desc": "기능: 가맹점ID 형식(길이 4~16) 검증 (RC 1=형식 위반).", "in": [ - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" ], "out": [ "T_RC", @@ -27877,6 +32271,7 @@ const SVC_SCREENS = [ "T_AMT3", "T_ARG6", "T_ARG2", + "T_AMT1", "T_ARG1", "T_COUNT" ] @@ -27888,6 +32283,8 @@ const SVC_SCREENS = [ "desc": "기능: 해외 매입 환산 정합 검증 (krw vs fx*rate_bps/10000, 오차>T_ARG1 → RC 1, 2=해외 내역 없음).", "in": [ "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE", "T_ARG1" ], "out": [ @@ -27897,8 +32294,9 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", - "T_FX_AMT", "T_AMT1", + "T_AMT3", + "T_FX_AMT", "T_DELTA" ] }, @@ -27948,7 +32346,9 @@ const SVC_SCREENS = [ "svc": "VL_LEDGBAL", "desc": "기능: 일자별 원장 대차 정합 검증 (차변 RECON 합 vs 대변 SETTLE+XFER 합, RC 1=대차 불일치).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -27956,8 +32356,9 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", - "T_ARG1", "T_AMT1", + "T_AMT3", + "T_ARG1", "T_AMT2", "T_COUNT", "T_DELTA" @@ -27991,7 +32392,9 @@ const SVC_SCREENS = [ "desc": "기능: 건별 원장 대사 엔트리 검증 (purchase.amount vs ledger RECON 합, RC 1=금액불일치 2=원장없음 3=매입없음", "in": [ "T_PURCHASE_ID", - "T_AMOUNT" + "T_AMOUNT", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -28000,9 +32403,10 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_AMOUNT", - "T_AMT1", "T_COUNT" ] }, @@ -28013,7 +32417,8 @@ const SVC_SCREENS = [ "desc": "기능: 원장 합계 정합 검증 (sum(ledger) vs purchase.net, RC 1=불일치).", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", @@ -28023,6 +32428,8 @@ const SVC_SCREENS = [ "T_ARG6", "T_ID2", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_GROSS" ] @@ -28034,7 +32441,10 @@ const SVC_SCREENS = [ "desc": "기능: 매입금액 vs 가맹점 일한도 검증 (RC 1=초과).", "in": [ "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" ], "out": [ "T_RC", @@ -28044,6 +32454,7 @@ const SVC_SCREENS = [ "T_AMT3", "T_ARG6", "T_ARG2", + "T_AMT1", "T_ARG1" ] }, @@ -28114,13 +32525,19 @@ const SVC_SCREENS = [ "modnm": "정합성검증", "svc": "VL_MDRRATE", "desc": "기능: 가맹점 요율 위반 검출 (mdr_bps<0 또는 규칙 MDR_MAX 초과, RC 1=위반 존재).", - "in": [], + "in": [ + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" + ], "out": [ "T_RC", "T_ARG8", "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -28150,7 +32567,9 @@ const SVC_SCREENS = [ "svc": "VL_NEGBAL", "desc": "기능: 마이너스 잔액 가맹점 검출 (merchant_summary.net_amount<0, RC 1=존재; 최악치 반환).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28158,9 +32577,10 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", - "T_COUNT", - "T_AMT1" + "T_COUNT" ] }, { @@ -28170,7 +32590,9 @@ const SVC_SCREENS = [ "desc": "기능: 음수 수수료 매입 검출 (일자별 fee<0 매입 수, RC 1=존재; 최소 매입ID 반환).", "in": [ "T_BIZDATE", - "T_ID1" + "T_ID1", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28178,6 +32600,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_ID1" @@ -28189,7 +32613,9 @@ const SVC_SCREENS = [ "svc": "VL_NEGNET", "desc": "기능: 일자별 음수 순액/역전 수수료 매입 검출 (net<0, fee<0, fee>amount, RC 1=존재).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28197,6 +32623,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -28208,6 +32636,8 @@ const SVC_SCREENS = [ "desc": "기능: 심야 거래 패턴 탐지 (0-6시 거래 비중>=T_ARG1% 기본20, RC 1=편중).", "in": [ "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID", "T_ARG1" ], "out": [ @@ -28216,6 +32646,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_COUNT", "T_ARG3" ] @@ -28227,6 +32659,8 @@ const SVC_SCREENS = [ "desc": "기능: 이상치 매입 탐지 (금액>당일 평균*배수 T_ARG1 기본4 건수, RC 1=존재).", "in": [ "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID", "T_ARG1" ], "out": [ @@ -28235,6 +32669,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_COUNT" ] }, @@ -28244,7 +32680,9 @@ const SVC_SCREENS = [ "svc": "VL_OVERLIMIT", "desc": "기능: 가맹점 한도위반 검출 (일 매입합>일한도 가맹점 수, RC 1=존재).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28252,6 +32690,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -28263,7 +32703,9 @@ const SVC_SCREENS = [ "desc": "기능: 무승인 매입 검출 (일자별 승인 전무 매입 수, 취소분 제외, RC 1=존재).", "in": [ "T_BIZDATE", - "T_ID1" + "T_ID1", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28271,6 +32713,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_ID1" @@ -28301,7 +32745,9 @@ const SVC_SCREENS = [ "svc": "VL_REFINTEG", "desc": "기능: 참조무결성(purchase.merchant_id ∈ merchant) 검증.", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -28310,6 +32756,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1" ] }, @@ -28357,13 +32805,19 @@ const SVC_SCREENS = [ "modnm": "정합성검증", "svc": "VL_RIAPPR", "desc": "기능: 참조무결성 승인 (취소/무효 매입에 승인가결 존재 건수, RC 1=위반).", - "in": [], + "in": [ + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" + ], "out": [ "T_RC", "T_ARG8", "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -28374,7 +32828,9 @@ const SVC_SCREENS = [ "svc": "VL_RICANCEL", "desc": "기능: 참조무결성 취소 (일자별 매입 원거래 없는 취소 수, RC 1=위반; 최소 취소ID 반환).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28382,6 +32838,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_CANCEL_ID" @@ -28392,16 +32850,21 @@ const SVC_SCREENS = [ "modnm": "정합성검증", "svc": "VL_RIFX", "desc": "기능: 참조무결성 해외 (매입 원거래 없는 해외 내역 수+환산합, RC 1=위반).", - "in": [], + "in": [ + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" + ], "out": [ "T_RC", "T_ARG8", "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", - "T_COUNT", - "T_AMT1" + "T_COUNT" ] }, { @@ -28409,13 +32872,19 @@ const SVC_SCREENS = [ "modnm": "정합성검증", "svc": "VL_RIINSTALL", "desc": "기능: 참조무결성 할부 (매입 원거래 없는 할부 내역 수, NOT IN, RC 1=위반).", - "in": [], + "in": [ + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" + ], "out": [ "T_RC", "T_ARG8", "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -28426,7 +32895,9 @@ const SVC_SCREENS = [ "svc": "VL_RILEDGER", "desc": "기능: 참조무결성 세분 검증 - 원장→매입 고아 엔트리 (RC 비트합 1=RECON 2=SETTLE 4=XFER 고아).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28434,6 +32905,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_ARG3", "T_COUNT" @@ -28446,7 +32919,9 @@ const SVC_SCREENS = [ "desc": "기능: 참조무결성 세분 검증 - 매입→가맹점 (일자별 고아 매입 수, RC 1=고아 존재).", "in": [ "T_BIZDATE", - "T_ID1" + "T_ID1", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28454,6 +32929,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_ID1" @@ -28465,7 +32942,10 @@ const SVC_SCREENS = [ "svc": "VL_RIPAY", "desc": "기능: 참조무결성 지급 (지급 XFER 원장의 매입 원거래 부재 건수, RC 1=위반).", "in": [ - "T_ID1" + "T_ID1", + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" ], "out": [ "T_RC", @@ -28473,6 +32953,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_ID1" @@ -28485,7 +32967,9 @@ const SVC_SCREENS = [ "desc": "기능: 참조무결성 세분 검증 - 정산→매입 (일자별 고아 정산 수/금액, RC 1=고아 존재).", "in": [ "T_BIZDATE", - "T_ID1" + "T_ID1", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28493,6 +32977,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_ID1", @@ -28506,7 +32992,8 @@ const SVC_SCREENS = [ "desc": "기능: 참조무결성 세분 검증 - 정산 가맹점 불일치 (settlement.merchant_id <> purchase.merchant_id, RC", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", @@ -28515,6 +33002,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_PURCHASE_ID" @@ -28525,13 +33014,19 @@ const SVC_SCREENS = [ "modnm": "정합성검증", "svc": "VL_RITAXINV", "desc": "기능: 참조무결성 세금계산서 (매입 원거래 없는 세금계산서 수, LEFT JOIN, RC 1=위반).", - "in": [], + "in": [ + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" + ], "out": [ "T_RC", "T_ARG8", "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -28781,7 +33276,8 @@ const SVC_SCREENS = [ "desc": "기능: 매입 원거래 존재 검증 (RC 1=미존재).", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", @@ -28790,6 +33286,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1" ] }, @@ -28799,7 +33297,9 @@ const SVC_SCREENS = [ "svc": "VL_SETTLE", "desc": "기능: 정산금액 정합 검증 (settlement.net vs purchase.net, RC 1=불일치).", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -28808,6 +33308,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_NET" ] @@ -28838,6 +33340,8 @@ const SVC_SCREENS = [ "desc": "기능: 금액 급증 탐지 (당일 최대 매입>평균*배수 T_ARG1 기본5, RC 1=급증).", "in": [ "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID", "T_ARG1" ], "out": [ @@ -28847,6 +33351,7 @@ const SVC_SCREENS = [ "T_ARG6", "T_ARG2", "T_AMT1", + "T_AMT3", "T_AMT2", "T_COUNT" ] @@ -28892,7 +33397,9 @@ const SVC_SCREENS = [ "svc": "VL_STATUS_CHK", "desc": "기능: 매입 상태 유효값 검증 (허용집합 밖 → RC 1).", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -28901,6 +33408,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1" ] }, @@ -28935,7 +33444,9 @@ const SVC_SCREENS = [ "svc": "VL_SUMFEECHK", "desc": "기능: 통계-원천 수수료 대사 (일자별 가맹점 수수료 집계 vs 원천 합 불일치 수, RC 1=존재).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28943,6 +33454,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -28954,7 +33467,9 @@ const SVC_SCREENS = [ "desc": "기능: 통계-원천 총액 대사 (merchant_summary 총액 vs 원천 매입금액 합, RC 1=불일치 8=통계없음).", "in": [ "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28964,9 +33479,9 @@ const SVC_SCREENS = [ "T_AMT3", "T_ARG6", "T_ARG2", + "T_AMT1", "T_ARG1", "T_GROSS", - "T_AMT1", "T_DELTA" ] }, @@ -29017,7 +33532,9 @@ const SVC_SCREENS = [ "desc": "기능: 통계-원천 대사 검증 (merchant_summary 건수/총액 vs purchase 재집계, RC 비트합 1=건수 2=총액, 8=통계 ", "in": [ "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -29027,10 +33544,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_ARG6", "T_ARG2", + "T_AMT1", "T_ARG1", "T_COUNT", - "T_GROSS", - "T_AMT1" + "T_GROSS" ] }, { @@ -29040,7 +33557,9 @@ const SVC_SCREENS = [ "desc": "기능: 통계-원천 건수 대사 (merchant_summary 건수 vs 원천 매입 건수, RC 1=불일치 8=통계없음).", "in": [ "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -29050,6 +33569,7 @@ const SVC_SCREENS = [ "T_AMT3", "T_ARG6", "T_ARG2", + "T_AMT1", "T_ARG1", "T_COUNT", "T_DELTA" @@ -29082,6 +33602,7 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_PURCHASE_ID", "T_ID1", + "T_RC", "T_REASON" ], "out": [ @@ -29091,6 +33612,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_PURCHASE_ID" ] @@ -29154,7 +33677,10 @@ const SVC_SCREENS = [ "svc": "VL_SUSPESCAL", "desc": "기능: 의심거래 상향 (WARN→ERROR→CRIT 단계 승격, RC 1=상향불가 3=미존재).", "in": [ - "T_ID1" + "T_ID1", + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" ], "out": [ "T_RC", @@ -29162,6 +33688,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1" ] }, @@ -29333,7 +33861,10 @@ const SVC_SCREENS = [ "desc": "기능: 규칙 임계치 검사 (dbio get_rule; amount>threshold → RC 1).", "in": [ "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" ], "out": [ "T_RC", @@ -29341,6 +33872,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1" ] }, @@ -29540,6 +34073,8 @@ const SVC_SCREENS = [ "desc": "기능: 거래 속도 이상 탐지 (당일 매입 건수>T_ARG1 기본100 가맹점 수, RC 1=존재).", "in": [ "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID", "T_ARG1" ], "out": [ @@ -29548,6 +34083,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_COUNT" ] }, @@ -29557,7 +34094,9 @@ const SVC_SCREENS = [ "svc": "VL_ZERONET", "desc": "기능: 정산순액 소실 검출 (금액>0인데 순액=0 매입 수, RC 1=존재).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -29565,6 +34104,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -29982,8 +34523,30 @@ document.getElementById('q').addEventListener('input', e => { it.style.display = (!q || it.dataset.k.includes(q)) ? (q ? 'block' : '') : 'none'); }); +/* 화면 기본값을 실제 운영 데이터로 교정. + * DEF 의 초기값은 서비스 시그니처에서 자동 생성된 플레이스홀더라 실존 행이 아니다. + * (예: 카드 4111111111111111 은 card_limit 에 없어 AUTH 가 "한도원장 조회 실패" 로 거절, + * 영업일도 20260721 형식이라 10자리 'YYYY-MM-DD' 를 요구하는 서비스가 전부 거절한다.) + * 실제 시드 키를 한 번 읽어 덮어써야 처리성 화면이 그대로 실행된다. */ +async function seedRealDefaults(){ + const one = async (q) => { const r = await runQuery(q); return (r.ok && r.rows.length) ? r.rows[0] : null; }; + try { + /* 게이트웨이(acq_httpgw)는 단일 스레드 직렬 accept 루프다. + * 동시 요청은 큐에 쌓여 앞선 요청이 끝날 때까지 응답이 안 온다. 반드시 순차로. */ + const card = await one("select card_no from card_limit where status='ACTIVE' order by card_no limit 1"); + const mer = await one("select merchant_id from merchant where status='ACTIVE' order by merchant_id limit 1"); + const pur = await one("select purchase_id::text, biz_date::text from purchase where status='S' order by purchase_id desc limit 1"); + const set = await one("select settlement_id::text from settlement order by settlement_id desc limit 1"); + if (card) { DEF.T_KEY1 = card[0]; DEF.T_STR5 = card[0]; } + if (mer) DEF.T_MERCHANT = mer[0]; + if (pur) { DEF.T_PURCHASE_ID = pur[0]; DEF.T_BIZDATE = pur[1]; } + if (set) DEF.T_SETTLE_ID = set[0]; + } catch (e) { /* 게이트웨이 미기동 시엔 플레이스홀더 그대로 사용 */ } +} + /* 시작: 대시보드 (+ 해시로 특정 화면: #q=QR0101 / #s=ACQUIRE / #m=1 가맹점관리) */ -setTimeout(() => { +setTimeout(async () => { + await seedRealDefaults(); /* 첫 화면이 그려지기 전에 기본값을 확정한다 */ openQueryTab(QSCREENS[0]); const h = location.hash; if (h.startsWith('#q=')) { const q = QSCREENS.find(x=>x.cd===h.slice(3)); if (q) openQueryTab(q); } diff --git a/app/ui/screens.js b/app/ui/screens.js index 3d081da..68fc217 100644 --- a/app/ui/screens.js +++ b/app/ui/screens.js @@ -73,11 +73,16 @@ const SVC_SCREENS = [ "desc": "매입 중복 알림: 가맹점의 영업일 매입 중 동일 금액이 2건 이상 반복된", "in": [ "T_MERCHANT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_COUNT", "T_ARG1", "T_ARG2", @@ -142,12 +147,16 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_AMOUNT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", "T_DELTA", "T_FEE", "T_NET", @@ -183,11 +192,16 @@ const SVC_SCREENS = [ "desc": "승인 연계: 매입 건에 승인 원장 행을 연결한다. 이미 승인이 있으면 추가", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_ARG3", "T_COUNT", "T_ID1", "T_ARG1", @@ -201,15 +215,19 @@ const SVC_SCREENS = [ "desc": "승인 매핑 조회: 한 매입에 연결된 승인 원장의 총 건수와 승인/거절 분포를", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_ARG3", "T_COUNT", "T_ARG1", "T_ARG2", - "T_ARG3", "T_ID1", "T_ARG7", "T_ARG8", @@ -369,12 +387,19 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_AMOUNT", "T_BIZDATE", - "T_REASON" + "T_REASON", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", - "T_CANCEL_ID", + "T_PURCHASE_ID", "T_AMOUNT", + "T_CANCEL_ID", + "T_ARG3", + "T_ARG4", + "T_ARG5", + "T_ARG6", "T_FEE", "T_ARG1", "T_COUNT", @@ -448,13 +473,17 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_AMOUNT", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_CANCEL_ID", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", + "T_CANCEL_ID", "T_GROSS", "T_ARG1" ] @@ -490,14 +519,19 @@ const SVC_SCREENS = [ "desc": "지불거절 역전: 방어 승소로 CB 를 무효화한다. 최근 CB/CB2 행 사유를", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", + "T_ARG3", "T_COUNT", "T_ARG1", - "T_AMOUNT", "T_ARG2", "T_ID1" ] @@ -739,14 +773,18 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_ID1", - "T_ARG1", - "T_AMOUNT" + "T_ARG1" ] }, { @@ -776,16 +814,20 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_AMOUNT", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ADJ", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", + "T_DELTA", + "T_ADJ", "T_FEE", "T_NET", - "T_DELTA", "T_ARG1" ] }, @@ -982,13 +1024,17 @@ const SVC_SCREENS = [ "T_CCY", "T_FX_AMT", "T_ARG1", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ID1", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", + "T_ID1", "T_FX_AMT", "T_ARG2", "T_ARG3", @@ -1030,11 +1076,16 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_AMOUNT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_COUNT", "T_ARG1", "T_ARG2", @@ -1075,12 +1126,16 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_AMOUNT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", "T_PURCHASE_ID", + "T_AMOUNT", + "T_COUNT", "T_FEE", "T_NET", "T_ARG1", @@ -1096,12 +1151,16 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_DOCNO", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_ID1", "T_FEE", "T_NET", @@ -1140,13 +1199,17 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_DOCNO", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ID1", + "T_PURCHASE_ID", "T_AMOUNT", + "T_ARG3", + "T_ID1", "T_ARG1" ] }, @@ -1291,14 +1354,17 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_AMOUNT", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ID1", + "T_PURCHASE_ID", "T_AMOUNT", "T_AMT1", + "T_ID1", "T_ARG1", "T_GROSS" ] @@ -1311,14 +1377,17 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ID1", + "T_PURCHASE_ID", "T_AMOUNT", "T_AMT1", + "T_ID1", "T_AMT2", "T_ARG1", "T_ARG2" @@ -1355,14 +1424,18 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_REASON", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_FX_AMT", "T_CANCEL_ID", "T_DELTA", - "T_AMOUNT", "T_ARG1", "T_ID1" ] @@ -1376,13 +1449,18 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_REASON", "T_BIZDATE", - "T_DELTA" + "T_DELTA", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ADJ", + "T_PURCHASE_ID", + "T_AMOUNT", "T_DELTA", + "T_AMT1", + "T_ADJ", "T_FEE", "T_NET", "T_ARG1" @@ -1420,11 +1498,17 @@ const SVC_SCREENS = [ "desc": "수수료 재산정: 가맹점의 현행 MDR 로 수수료를 다시 계산해 기존 수수료와", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", + "T_ARG3", "T_ADJ", "T_FEE", "T_NET", @@ -1464,7 +1548,9 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_CCY", "T_FX_AMT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", @@ -1472,6 +1558,7 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_AMOUNT", "T_FX_AMT", + "T_AMT1", "T_ARG2", "T_FEE", "T_NET", @@ -1489,14 +1576,17 @@ const SVC_SCREENS = [ "T_CCY", "T_FX_AMT", "T_BIZDATE", - "T_ARG1" + "T_ARG1", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ID1", + "T_PURCHASE_ID", "T_AMOUNT", "T_FX_AMT", + "T_ID1", "T_ARG2", "T_ARG1" ] @@ -1508,15 +1598,19 @@ const SVC_SCREENS = [ "desc": "통화 적용환율 조회: 해외매입 원장에서 특정 통화의 최근 영업일 평균/최저/", "in": [ "T_CCY", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_ARG3", "T_COUNT", "T_ARG1", "T_ARG2", - "T_ARG3", "T_ARG4", "T_ARG5", "T_GROSS", @@ -1559,13 +1653,18 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_ARG1", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ID1", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", + "T_AMT2", + "T_ID1", "T_ARG2", "T_GROSS", "T_ARG1" @@ -1628,16 +1727,19 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", + "T_PURCHASE_ID", "T_AMOUNT", + "T_ARG3", "T_COUNT", "T_GROSS", "T_ARG1", "T_ARG2", - "T_ARG3", "T_ARG4", "T_ID1" ] @@ -1698,14 +1800,18 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_INSTALL_N", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_COUNT", + "T_PURCHASE_ID", + "T_AMOUNT", "T_INSTALL_N", "T_AMT1", + "T_COUNT", "T_ARG1", "T_ARG2", "T_GROSS" @@ -1719,13 +1825,18 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_COUNT", + "T_PURCHASE_ID", + "T_AMOUNT", "T_INSTALL_N", + "T_AMT1", + "T_COUNT", "T_GROSS", "T_ARG1", "T_ID1" @@ -1854,17 +1965,22 @@ const SVC_SCREENS = [ "desc": "매입 한도 점검: 가맹점 일한도와 당일 누적 매입을 비교해 초과 여부를", "in": [ "T_MERCHANT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", + "T_AMT2", "T_GROSS", "T_ARG1", "T_ARG2", "T_ARG3", "T_COUNT", - "T_AMT1", "T_ARG4", "T_ARG7", "T_ARG8", @@ -1878,11 +1994,17 @@ const SVC_SCREENS = [ "desc": "매입 한도 예외처리: 가맹점 일한도와 당일 누적 매입을 비교해 한도 초과 시", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", + "T_AMT2", "T_GROSS", "T_ARG1", "T_ARG2", @@ -1943,11 +2065,14 @@ const SVC_SCREENS = [ "desc": "가맹점 일별 집계: 영업일 매입을 재집계해 merchant_summary 에 upsert 하고", "in": [ "T_MERCHANT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_COUNT", + "T_AMT1", "T_GROSS", "T_FEE", "T_NET", @@ -1991,16 +2116,21 @@ const SVC_SCREENS = [ "desc": "정산금 재계산: 매입금액에서 수수료와 원천세 누계를 차감한 실정산금을", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", + "T_AMT2", "T_NET", "T_DELTA", "T_TAX", "T_FEE", - "T_AMOUNT", "T_ARG1" ] }, @@ -2033,13 +2163,20 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_AMOUNT", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_CANCEL_ID", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", + "T_ARG3", + "T_AMT2", + "T_AMT3", + "T_CANCEL_ID", "T_FEE", "T_ARG1", "T_ARG2" @@ -2074,14 +2211,18 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_AMOUNT", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_CANCEL_ID", + "T_PURCHASE_ID", "T_AMOUNT", "T_AMT1", + "T_AMT2", + "T_CANCEL_ID", "T_ARG1", "T_ARG2", "T_ID1" @@ -2095,12 +2236,16 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_AMOUNT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_FEE", "T_NET", "T_DELTA", @@ -2287,13 +2432,19 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_AMOUNT", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_CANCEL_ID", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", + "T_AMT2", + "T_ARG5", + "T_CANCEL_ID", "T_ARG1", "T_ARG2" ] @@ -2306,14 +2457,18 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_ARG1", - "T_ID1", - "T_AMOUNT" + "T_ID1" ] }, { @@ -2323,11 +2478,16 @@ const SVC_SCREENS = [ "desc": "승인미매칭 재처리: 미매입 원장에 남은 건에 유효 승인이 도착했는지 다시", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_COUNT", "T_ARG1", "T_ARG2", @@ -2342,11 +2502,16 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_COUNT", "T_ARG1" ] @@ -2359,12 +2524,17 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_AMOUNT", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", + "T_ARG3", "T_FEE", "T_NET", "T_COUNT", @@ -2379,12 +2549,17 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", + "T_ARG3", "T_ARG1", "T_COUNT", "T_GROSS", @@ -2423,13 +2598,17 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_CANCEL_ID", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", + "T_CANCEL_ID", "T_ARG1" ] }, @@ -2540,11 +2719,28 @@ const SVC_SCREENS = [ "desc": "정산 연계: 대사완료 매입에 대해 settlement 링크 행(status='LINKED')을", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC", + "T_ARG1", + "T_AMT2", + "T_AMT3", + "T_ARG7", + "T_ARG8", + "T_ARG5", + "T_ARG6" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", + "T_ARG3", + "T_AMT2", + "T_AMT3", + "T_ID1", + "T_DELTA", "T_SETTLE_ID", "T_NET", "T_ARG1" @@ -2583,16 +2779,20 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_ARG1", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_COUNT", + "T_PURCHASE_ID", + "T_AMOUNT", "T_AMT1", + "T_ARG3", + "T_COUNT", "T_GROSS", - "T_ARG2", - "T_ARG3" + "T_ARG2" ] }, { @@ -2651,14 +2851,18 @@ const SVC_SCREENS = [ "desc": "세금계산서 취소: 원본 계산서를 상쇄하는 음수(공급가/부가세 부호 반전)", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_TAX", "T_ID1", "T_GROSS", - "T_TAX", "T_COUNT", "T_ARG1" ] @@ -2671,13 +2875,18 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ID1", + "T_PURCHASE_ID", + "T_AMOUNT", "T_TAX", + "T_AMT1", + "T_ID1", "T_GROSS", "T_ARG1" ] @@ -2753,15 +2962,19 @@ const SVC_SCREENS = [ "desc": "세금계산서 역발행: 매출 취소분에 대한 (-)공급가 계산서를 새로 발행한다.", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_TAX", "T_ID1", "T_ID2", "T_GROSS", - "T_TAX", "T_ARG1" ] }, @@ -2797,15 +3010,19 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", - "T_ID1", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_COUNT", - "T_ARG1", - "T_AMOUNT" + "T_ID1", + "T_ARG1" ] }, { @@ -2816,16 +3033,20 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_ARG1", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", "T_COUNT", + "T_AMT1", "T_ARG2", "T_ARG3", "T_ARG4", - "T_AMT1", "T_AMT2", "T_GROSS", "T_ARG7", @@ -2841,12 +3062,16 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", "T_AMOUNT", + "T_AMT1", "T_DELTA", "T_ARG1", "T_ID1" @@ -2884,11 +3109,20 @@ const SVC_SCREENS = [ "desc": "원천징수: 가맹점 수수료에 대한 원천세를 운영 파라미터(WHT_BPS) 기준으로", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC", + "T_TAX" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", + "T_ARG3", + "T_AMT2", + "T_AMT3", "T_TAX", "T_ID1", "T_ARG2", @@ -2904,14 +3138,18 @@ const SVC_SCREENS = [ "desc": "이체 연계: 정산 완료 매입의 지급 이체를 원장에 XFER 분개로 연결한다.", "in": [ "T_PURCHASE_ID", - "T_BIZDATE" + "T_BIZDATE", + "T_STATUS", + "T_RC" ], "out": [ "T_RC", "T_ARG6", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_AMT1", "T_ID1", "T_NET", - "T_AMOUNT", "T_ARG1" ] }, @@ -2943,11 +3181,14 @@ const SVC_SCREENS = [ "T_KEY1", "T_MERCHANT", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_RC", + "T_ARG1" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_ID1" ] }, @@ -2963,7 +3204,8 @@ const SVC_SCREENS = [ "T_AMOUNT", "T_ID1", "T_DELTA", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", @@ -2982,11 +3224,13 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ID1", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -3001,11 +3245,13 @@ const SVC_SCREENS = [ "T_REASON", "T_ID1", "T_AMOUNT", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_CANCEL_ID" ] }, @@ -3020,11 +3266,15 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ID1", - "T_ID2" + "T_ID2", + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_PURCHASE_ID", + "T_AMOUNT" ] }, { @@ -3039,11 +3289,14 @@ const SVC_SCREENS = [ "T_AMOUNT", "T_REASON", "T_ID1", - "T_ID2" + "T_ID2", + "T_STR1", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -3075,13 +3328,16 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_KEY1", "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_RC", + "T_ARG1" ], "out": [ "T_RC", "T_FEE", - "T_ARG1", - "T_ID1" + "T_ID1", + "T_AMOUNT", + "T_ARG1" ] }, { @@ -3094,11 +3350,13 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_COUNT", "T_GROSS", "T_ID1" @@ -3132,11 +3390,13 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ID1", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -3148,11 +3408,13 @@ const SVC_SCREENS = [ "T_KEY1", "T_MERCHANT", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_AMT1", "T_ID2" ] @@ -3168,13 +3430,14 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_ID1", "T_AMOUNT", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", "T_FEE", - "T_CANCEL_ID", - "T_AMOUNT" + "T_AMOUNT", + "T_CANCEL_ID" ] }, { @@ -3206,11 +3469,13 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ID1", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -3259,7 +3524,10 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ID1", - "T_ID2" + "T_ID2", + "T_STR1", + "T_CHANNEL", + "T_RC" ], "out": [ "T_RC", @@ -3278,11 +3546,15 @@ const SVC_SCREENS = [ "T_KEY1", "T_ID1", "T_AMOUNT", - "T_ID2" + "T_ID2", + "T_STR1", + "T_CHANNEL", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -3296,11 +3568,13 @@ const SVC_SCREENS = [ "T_KEY1", "T_ID1", "T_AMOUNT", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -3372,11 +3646,13 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_ID1", "T_AMOUNT", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_CANCEL_ID" ] }, @@ -3424,11 +3700,15 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_KEY1" + "T_KEY1", + "T_RC", + "T_ARG1" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_ID1", + "T_AMOUNT" ] }, { @@ -3724,11 +4004,15 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_KEY1", - "T_REASON" + "T_REASON", + "T_STR1", + "T_CHANNEL", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -3829,11 +4113,15 @@ const SVC_SCREENS = [ "T_AMOUNT", "T_KEY1", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_STR1", + "T_CHANNEL", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_ID1" ] }, @@ -3864,11 +4152,14 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_KEY1" + "T_KEY1", + "T_STR5", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -4010,11 +4301,16 @@ const SVC_SCREENS = [ "T_KEY1", "T_BIZDATE", "T_ID1", - "T_AMOUNT" + "T_AMOUNT", + "T_STR8", + "T_STR1", + "T_CHANNEL", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_ARG1", "T_ID2" ] @@ -4159,11 +4455,13 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_INSTALL_N" + "T_INSTALL_N", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_COUNT" ] }, @@ -4213,11 +4511,18 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_KEY1", - "T_AMOUNT" + "T_AMOUNT", + "T_AMT1", + "T_AMT2", + "T_STR8", + "T_STR1", + "T_RC", + "T_ID1" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_AMT1", "T_AMT2" ] @@ -4270,11 +4575,16 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_KEY1", - "T_AMOUNT" + "T_AMOUNT", + "T_STR8", + "T_STR1", + "T_CHANNEL", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -4287,12 +4597,16 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_STR1", + "T_RC", + "T_ID1" ], "out": [ "T_RC", "T_COUNT", "T_FEE", + "T_AMOUNT", "T_ARG1" ] }, @@ -4305,11 +4619,15 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_KEY1" + "T_KEY1", + "T_STR1", + "T_RC", + "T_ID1" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -4402,11 +4720,15 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_KEY1" + "T_KEY1", + "T_STR1", + "T_RC", + "T_ID1" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_ARG1", "T_AMT1" ] @@ -4491,11 +4813,16 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_KEY1" + "T_KEY1", + "T_STR8", + "T_STR1", + "T_CHANNEL", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -4667,11 +4994,15 @@ const SVC_SCREENS = [ "T_KEY1", "T_AMOUNT", "T_MERCHANT", - "T_BIZDATE" + "T_BIZDATE", + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_PURCHASE_ID", + "T_AMOUNT", "T_COUNT", "T_GROSS" ] @@ -4703,11 +5034,13 @@ const SVC_SCREENS = [ "T_KEY1", "T_MERCHANT", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_ID2" ] }, @@ -4721,11 +5054,13 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_AMT1" ] }, @@ -4739,11 +5074,13 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_BIZDATE", - "T_ID2" + "T_ID2", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_ID1" ] }, @@ -4758,11 +5095,13 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ID2", - "T_ARG1" + "T_ARG1", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -4796,11 +5135,13 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_ID2", - "T_AMOUNT" + "T_AMOUNT", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_AMT1" ] }, @@ -4832,11 +5173,15 @@ const SVC_SCREENS = [ "T_KEY1", "T_MERCHANT", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_RC", + "T_STR1", + "T_CHANNEL" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_ID1" ] }, @@ -4907,11 +5252,13 @@ const SVC_SCREENS = [ "T_KEY1", "T_MERCHANT", "T_AMOUNT", - "T_BIZDATE" + "T_BIZDATE", + "T_RC" ], "out": [ "T_RC", "T_FEE", + "T_AMOUNT", "T_COUNT", "T_GROSS" ] @@ -5128,11 +5475,14 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_BIZDATE", "T_AMOUNT", - "T_KEY1" + "T_KEY1", + "T_STR5", + "T_RC" ], "out": [ "T_RC", - "T_FEE" + "T_FEE", + "T_AMOUNT" ] }, { @@ -5179,11 +5529,15 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_KEY1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ARG1" ], "out": [ "T_RC", "T_FEE", + "T_ID1", + "T_AMOUNT", "T_COUNT", "T_GROSS" ] @@ -5389,7 +5743,20 @@ const SVC_SCREENS = [ "svc": "CL_AMTXCHECK", "desc": "마감 금액 크로스체크: 마감이력 total_amount vs 매입 amount 합계 vs 스냅샷", "in": [ - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5401,7 +5768,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5" ] }, { @@ -5411,7 +5782,20 @@ const SVC_SCREENS = [ "desc": "마감 승인 위임: 위임 대상자(T_STR1)를 memo(APPR:DELEG:..)에 기록하고 상태 유지.", "in": [ "T_ID1", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5419,7 +5803,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5429,7 +5819,9 @@ const SVC_SCREENS = [ "desc": "최종 마감 승인: 2차 승인(APPR:L2) 마감을 최종 승인(status=A)으로 확정.", "in": [ "T_ID1", - "T_STR1" + "T_STR1", + "T_STR8", + "T_STATUS" ], "out": [ "T_RC", @@ -5466,7 +5858,22 @@ const SVC_SCREENS = [ "desc": "1차 마감 승인: 개시(O)/완료(C) 마감을 1차 승인(memo=APPR:L1) 단계로 전이.", "in": [ "T_ID1", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT", + "T_STR7", + "T_STR6" ], "out": [ "T_RC", @@ -5474,7 +5881,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5484,7 +5897,23 @@ const SVC_SCREENS = [ "desc": "2차 마감 승인: 1차 승인(APPR:L1) 마감을 2차 승인(APPR:L2)으로 전이.", "in": [ "T_ID1", - "T_STR1" + "T_STR1", + "T_STR8", + "T_STATUS", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT", + "T_STR7", + "T_STR6" ], "out": [ "T_RC", @@ -5492,7 +5921,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5502,7 +5937,22 @@ const SVC_SCREENS = [ "desc": "마감 승인: 상태 A.", "in": [ "T_ID1", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT", + "T_STR7", + "T_STR6" ], "out": [ "T_RC", @@ -5510,7 +5960,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5520,7 +5976,20 @@ const SVC_SCREENS = [ "desc": "마감 승인 반려: 승인(A) 상태 마감을 완료(C)로 되돌리며 반려 사유를 기록.", "in": [ "T_ID1", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5528,7 +5997,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5538,7 +6013,22 @@ const SVC_SCREENS = [ "desc": "마감 승인 요청: C 상태이며 집계건수>0 인 마감에 승인요청(APPR_REQ) 표시를", "in": [ "T_ID1", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT", + "T_STR7", + "T_STR6" ], "out": [ "T_RC", @@ -5546,7 +6036,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5634,7 +6130,19 @@ const SVC_SCREENS = [ "desc": "잔액 검증: 스냅샷 net 합 vs close_log total 비교.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5647,7 +6155,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -5679,7 +6192,19 @@ const SVC_SCREENS = [ "in": [ "T_ID1", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5687,7 +6212,13 @@ const SVC_SCREENS = [ "T_ARG6", "T_ARG7", "T_ARG8", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5696,7 +6227,20 @@ const SVC_SCREENS = [ "svc": "CL_CHKALL", "desc": "마감 전 통합 체크: 미마감(M)/미매칭/보류(H)/void(V) 합산 점수 산출.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5704,7 +6248,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5730,7 +6280,20 @@ const SVC_SCREENS = [ "svc": "CL_CHKPENDING", "desc": "마감 전 보류 체크: 당일 보류(H) 매입 존재 여부 판정.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5738,7 +6301,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5747,7 +6316,20 @@ const SVC_SCREENS = [ "svc": "CL_CHKUNMATCH", "desc": "마감 전 미매칭 체크: 당일 미매칭(ac_unmatch) 존재 여부 판정.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5755,7 +6337,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5764,7 +6352,20 @@ const SVC_SCREENS = [ "svc": "CL_CHKVOID", "desc": "마감 전 void 체크: 당일 void(V) 매입 잔존 여부 판정.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5772,7 +6373,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5804,7 +6411,19 @@ const SVC_SCREENS = [ "desc": "채널별 마감 검증: 영업일+채널의 매입건수와 해당 매입에 연결된 ledger", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5817,7 +6436,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -5848,7 +6472,19 @@ const SVC_SCREENS = [ "desc": "건수 정합검증: 마감이력 txn_count 와 해당 영업일 매입 실건수를 대사한다.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5861,7 +6497,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -5870,7 +6511,20 @@ const SVC_SCREENS = [ "svc": "CL_CNTXCHECK", "desc": "마감 건수 크로스체크: 마감이력 txn_count vs 실매입 count vs 스냅샷", "in": [ - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5882,7 +6536,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5" ] }, { @@ -5911,7 +6569,20 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_STR1", - "T_ISSUER" + "T_ISSUER", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5922,7 +6593,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -5932,7 +6608,19 @@ const SVC_SCREENS = [ "desc": "법인별 마감 검증: 마감이력 헤더 건수/금액과 스냅샷 집계 정합 점검.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -5945,7 +6633,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -6062,14 +6755,32 @@ const SVC_SCREENS = [ "svc": "CL_DAILY", "desc": "일 마감: 당일 매입 집계 후 마감이력(DAILY) 생성.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", "T_ID1", "T_ARG6", "T_ARG7", - "T_ARG8" + "T_ARG8", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6079,7 +6790,19 @@ const SVC_SCREENS = [ "desc": "일 마감 검증: 당일 마감이력 집계와 매입 실집계 대사.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6092,7 +6815,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -6145,7 +6873,19 @@ const SVC_SCREENS = [ "desc": "차액 점검: close_log total vs 스냅샷 gross 합.", "in": [ "T_BIZDATE", - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6153,7 +6893,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6164,7 +6910,20 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_STR1", - "T_CATEGORY" + "T_CATEGORY", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6175,7 +6934,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6205,7 +6969,20 @@ const SVC_SCREENS = [ "svc": "CL_DUPCHK", "desc": "중복 마감 탐지: 취소(X) 제외 동일 (close_type, period_key) 에 마감이 2건", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6213,7 +6990,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6238,7 +7021,20 @@ const SVC_SCREENS = [ "svc": "CL_FEECROSS", "desc": "수수료 크로스검증: 마감 스냅샷 fee 합계와 해당 영업일 매입 fee 합계를 대사한다.", "in": [ - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6250,7 +7046,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5" ] }, { @@ -6260,7 +7060,19 @@ const SVC_SCREENS = [ "desc": "수수료 검증: 마감 스냅샷의 fee 합계와 해당 영업일 매입 fee 합계에", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6273,7 +7085,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -6304,7 +7121,20 @@ const SVC_SCREENS = [ "desc": "강제 마감: 체크리스트를 우회해 해당 영업일의 미확정 개시(O) 마감을 제거한", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6315,7 +7145,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6367,7 +7202,20 @@ const SVC_SCREENS = [ "desc": "반기 결산 마감: 연도(T_STR1=YYYY)와 반기(T_ARG1=1|2)를 받아 상/하반기", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6378,7 +7226,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6448,7 +7301,19 @@ const SVC_SCREENS = [ "desc": "반기 마감 검증: 반기 마감이력과 반기 매입 실집계 대사.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6461,7 +7326,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -6563,7 +7433,20 @@ const SVC_SCREENS = [ "desc": "본마감: 가마감(O) 이력을 당일 전체 매입으로 재집계해 확정(C)으로 승격.", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6574,7 +7457,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6606,6 +7494,95 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_STR1", + "T_MERCHANT", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" + ], + "out": [ + "T_RC", + "T_ID1", + "T_FEE", + "T_NET", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" + ] + }, + { + "mod": "cl", + "modnm": "마감", + "svc": "CL_MERXCHECK", + "desc": "가맹점별 크로스검증: 마감 스냅샷 gross 와 매입 amount 를 가맹점 단위로 대사해", + "in": [ + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" + ], + "out": [ + "T_RC", + "T_AMT1", + "T_AMT2", + "T_AMT3", + "T_DELTA", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5" + ] + }, + { + "mod": "cl", + "modnm": "마감", + "svc": "CL_MIDCLOSE", + "desc": "중간 마감: 당일 중간 스냅 마감이력(MID) 생성.", + "in": [ + "T_BIZDATE", + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", "T_MERCHANT" ], "out": [ @@ -6617,49 +7594,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" - ] - }, - { - "mod": "cl", - "modnm": "마감", - "svc": "CL_MERXCHECK", - "desc": "가맹점별 크로스검증: 마감 스냅샷 gross 와 매입 amount 를 가맹점 단위로 대사해", - "in": [ - "T_ID1" - ], - "out": [ - "T_RC", - "T_AMT1", + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", "T_AMT2", - "T_AMT3", - "T_DELTA", - "T_ARG6", - "T_ARG7", - "T_ARG8", - "T_COUNT", - "T_GROSS" - ] - }, - { - "mod": "cl", - "modnm": "마감", - "svc": "CL_MIDCLOSE", - "desc": "중간 마감: 당일 중간 스냅 마감이력(MID) 생성.", - "in": [ - "T_BIZDATE", - "T_STR1" - ], - "out": [ - "T_RC", - "T_ID1", - "T_FEE", - "T_NET", - "T_ARG6", - "T_ARG7", - "T_ARG8", - "T_COUNT", - "T_GROSS" + "T_AMT3" ] }, { @@ -6669,7 +7609,20 @@ const SVC_SCREENS = [ "desc": "월 마감: 해당 월(YYYY-MM) 매입 집계 후 마감이력(MONTHLY).", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6680,7 +7633,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6690,7 +7648,19 @@ const SVC_SCREENS = [ "desc": "월 마감 검증: 월 마감이력과 월 매입 실집계 대사.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6703,7 +7673,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -6712,7 +7687,20 @@ const SVC_SCREENS = [ "svc": "CL_NETCROSS", "desc": "정산액 크로스검증: 마감 스냅샷 net 합계와 해당 영업일 매입 net 합계를 대사한다.", "in": [ - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6724,7 +7712,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5" ] }, { @@ -6734,7 +7726,19 @@ const SVC_SCREENS = [ "desc": "정산액 검증: 마감 스냅샷에서 gross - fee <> net 인 내부 모순 행을 찾아", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6747,7 +7751,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -6838,7 +7847,19 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_STR1", "T_KEY1", - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6848,7 +7869,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -6857,7 +7883,20 @@ const SVC_SCREENS = [ "svc": "CL_PRECHECK", "desc": "마감 전 체크리스트 검증: (1)미마감 M 매입 (2)미매칭 ac_unmatch (3)기간 기잠금", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6865,7 +7904,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6935,7 +7980,19 @@ const SVC_SCREENS = [ "desc": "분기 마감 검증: 분기 마감이력과 분기 매입 실집계 대사.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6948,7 +8005,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -6958,7 +8020,20 @@ const SVC_SCREENS = [ "desc": "분기 마감: 분기 프리픽스(YYYY-MM LIKE)로 집계.", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6969,7 +8044,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -6979,7 +8059,19 @@ const SVC_SCREENS = [ "desc": "재마감: 상태 R 로 표시하고 총계 재집계.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -6988,7 +8080,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -7036,7 +8133,19 @@ const SVC_SCREENS = [ "desc": "마감 대사: 실제 매입건수 vs close_log txn_count 대사.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7049,7 +8158,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -7116,7 +8230,19 @@ const SVC_SCREENS = [ "in": [ "T_ID1", "T_REASON", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7124,7 +8250,13 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -7374,7 +8506,19 @@ const SVC_SCREENS = [ "desc": "부문별 마감 검증: 부문 마감이력 총액과 해당 부문 매입 집계 대사.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7387,7 +8531,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -7397,7 +8546,20 @@ const SVC_SCREENS = [ "desc": "반월 마감: 전반(1~15)/후반(16~말) 구간 집계 후 SEMIMON 마감.", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7408,7 +8570,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -7567,7 +8734,19 @@ const SVC_SCREENS = [ "in": [ "T_ID1", "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7575,7 +8754,13 @@ const SVC_SCREENS = [ "T_ARG6", "T_ARG7", "T_ARG8", - "T_COUNT" + "T_COUNT", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -7584,7 +8769,20 @@ const SVC_SCREENS = [ "svc": "CL_SNAPXCHECK", "desc": "스냅샷-원장 크로스체크: 마감 스냅샷 net 합계 vs 같은 영업일 ledger SETTLE", "in": [ - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7596,7 +8794,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5" ] }, { @@ -7665,7 +8867,20 @@ const SVC_SCREENS = [ "svc": "CL_STCROSS", "desc": "상태 크로스검증: 당일 매입 상태 분포(A/M/S/C)를 집계해 미마감(A+M) 잔량으로", "in": [ - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_BIZDATE", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7677,7 +8892,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5" ] }, { @@ -7706,7 +8925,20 @@ const SVC_SCREENS = [ "desc": "순(10일) 마감: 상/중/하순 구간 매입 집계 후 TENDAY 마감이력 생성.", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7717,7 +8949,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -7792,7 +9029,19 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_STR1", "T_KEY1", - "T_ID1" + "T_ID1", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7802,7 +9051,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -7874,7 +9128,19 @@ const SVC_SCREENS = [ "desc": "마감 검증: close_log 총건수 vs 실제 매입건수 비교.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7887,7 +9153,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -7897,7 +9168,20 @@ const SVC_SCREENS = [ "desc": "주 마감: 주간(월~일) 매입을 집계해 WEEKLY 마감이력 생성.", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7908,7 +9192,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -7918,7 +9207,19 @@ const SVC_SCREENS = [ "desc": "주 마감 검증: 주간 마감이력과 주간 매입 실집계 대사.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7931,7 +9232,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -7941,7 +9247,20 @@ const SVC_SCREENS = [ "desc": "연말 마감: 연도(YYYY) 프리픽스로 집계.", "in": [ "T_BIZDATE", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID1", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7952,7 +9271,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT2", + "T_AMT3" ] }, { @@ -7983,7 +9307,19 @@ const SVC_SCREENS = [ "desc": "연 마감 검증: 연간 마감이력과 연간 매입 실집계 대사.", "in": [ "T_ID1", - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_ID2", + "T_AMOUNT", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG", + "T_MERCHANT" ], "out": [ "T_RC", @@ -7996,7 +9332,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_ARG5", + "T_AMT3" ] }, { @@ -8008,14 +9349,21 @@ const SVC_SCREENS = [ "T_STR1", "T_ARG1", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR3" ], "out": [ "T_STR3", "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8237,7 +9585,14 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR4" ], "out": [ "T_STR4", @@ -8245,7 +9600,8 @@ const SVC_SCREENS = [ "T_COUNT", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8258,13 +9614,20 @@ const SVC_SCREENS = [ "T_STR1", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR4" ], "out": [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8277,7 +9640,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG2", + "T_ARG3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_ID1", + "T_MSG", + "T_RC", + "T_STR4" ], "out": [ "T_COUNT", @@ -8288,7 +9661,8 @@ const SVC_SCREENS = [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8324,7 +9698,15 @@ const SVC_SCREENS = [ "T_REASON", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_ID1", + "T_MSG", + "T_RC", + "T_STR4" ], "out": [ "T_RC", @@ -8332,7 +9714,8 @@ const SVC_SCREENS = [ "T_COUNT", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8345,14 +9728,23 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", "T_COUNT", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8409,13 +9801,21 @@ const SVC_SCREENS = [ "T_STR1", "T_ARG1", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8446,7 +9846,14 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_ARG1", "T_AMOUNT", - "T_STR1" + "T_STR1", + "T_ARG2", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR4" ], "out": [ "T_RC", @@ -8454,7 +9861,8 @@ const SVC_SCREENS = [ "T_ARG2", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8467,7 +9875,14 @@ const SVC_SCREENS = [ "T_STR2", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG2", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC" ], "out": [ "T_RC", @@ -8476,7 +9891,8 @@ const SVC_SCREENS = [ "T_ARG2", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8488,14 +9904,21 @@ const SVC_SCREENS = [ "T_STR1", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR3" ], "out": [ "T_RC", "T_MSG", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8507,14 +9930,22 @@ const SVC_SCREENS = [ "T_STR1", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR3" ], "out": [ "T_COUNT", "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8549,13 +9980,20 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STATUS" + "T_STATUS", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR3" ], "out": [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8662,13 +10100,20 @@ const SVC_SCREENS = [ "T_ARG1", "T_BIZDATE", "T_AMOUNT", - "T_STATUS" + "T_STATUS", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR3" ], "out": [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -8961,14 +10406,22 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STATUS" + "T_STATUS", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_MSG", "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -9084,7 +10537,12 @@ const SVC_SCREENS = [ "T_FX_AMT", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC" ], "out": [ "T_AMOUNT", @@ -9105,7 +10563,14 @@ const SVC_SCREENS = [ "T_STR1", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_AMT1", + "T_AMT2", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC" ], "out": [ "T_ARG1", @@ -9114,7 +10579,8 @@ const SVC_SCREENS = [ "T_AMT2", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -9151,7 +10617,13 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG2", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC" ], "out": [ "T_RC", @@ -9159,7 +10631,8 @@ const SVC_SCREENS = [ "T_ARG2", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -9173,7 +10646,15 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_STR1", - "T_CCY" + "T_CCY", + "T_ARG3", + "T_ARG4", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_DELTA", + "T_MSG", + "T_RC" ], "out": [ "T_RC", @@ -9182,7 +10663,8 @@ const SVC_SCREENS = [ "T_DELTA", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -9217,13 +10699,21 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_ARG1", "T_AMOUNT", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -9283,7 +10773,14 @@ const SVC_SCREENS = [ "T_STR1", "T_ARG1", "T_BIZDATE", - "T_AMOUNT" + "T_AMOUNT", + "T_ARG2", + "T_ARG3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC" ], "out": [ "T_RC", @@ -9291,7 +10788,8 @@ const SVC_SCREENS = [ "T_ARG3", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -9882,7 +11380,13 @@ const SVC_SCREENS = [ "T_STR1", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR3" ], "out": [ "T_STR3", @@ -9890,7 +11394,8 @@ const SVC_SCREENS = [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10017,14 +11522,22 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STATUS" + "T_STATUS", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", "T_MSG", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10078,14 +11591,21 @@ const SVC_SCREENS = [ "T_STR1", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR3" ], "out": [ "T_STR3", "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10120,7 +11640,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_ARG1", "T_AMOUNT", - "T_STR1" + "T_STR1", + "T_ARG2", + "T_ARG3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_ARG2", @@ -10129,7 +11659,8 @@ const SVC_SCREENS = [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10142,7 +11673,14 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID2", + "T_MSG", + "T_RC", + "T_SVCNAME" ], "out": [ "T_RC", @@ -10150,7 +11688,8 @@ const SVC_SCREENS = [ "T_MSG", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10164,14 +11703,21 @@ const SVC_SCREENS = [ "T_MSG", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID1", + "T_RC", + "T_SVCNAME" ], "out": [ "T_RC", "T_ID1", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10209,7 +11755,14 @@ const SVC_SCREENS = [ "T_STR1", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID1", + "T_MSG", + "T_RC", + "T_SVCNAME" ], "out": [ "T_RC", @@ -10217,7 +11770,8 @@ const SVC_SCREENS = [ "T_MSG", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10494,7 +12048,13 @@ const SVC_SCREENS = [ "T_STR1", "T_BIZDATE", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR3" ], "out": [ "T_STR3", @@ -10502,7 +12062,8 @@ const SVC_SCREENS = [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10555,14 +12116,22 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_ARG1", "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10575,7 +12144,16 @@ const SVC_SCREENS = [ "T_ARG1", "T_BIZDATE", "T_AMOUNT", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_ID1", + "T_ID2", + "T_MSG", + "T_RC", + "T_SVCNAME" ], "out": [ "T_RC", @@ -10584,7 +12162,8 @@ const SVC_SCREENS = [ "T_COUNT", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10597,7 +12176,15 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR4", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_ARG1", @@ -10605,7 +12192,8 @@ const SVC_SCREENS = [ "T_RC", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10618,7 +12206,16 @@ const SVC_SCREENS = [ "T_ARG1", "T_BIZDATE", "T_AMOUNT", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_ID1", + "T_ID2", + "T_MSG", + "T_RC", + "T_SVCNAME" ], "out": [ "T_RC", @@ -10627,7 +12224,8 @@ const SVC_SCREENS = [ "T_COUNT", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10661,14 +12259,23 @@ const SVC_SCREENS = [ "T_ARG1", "T_BIZDATE", "T_AMOUNT", - "T_STR1" + "T_STR1", + "T_ARG2", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", "T_ARG2", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10681,7 +12288,15 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR4", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", @@ -10689,7 +12304,8 @@ const SVC_SCREENS = [ "T_STR4", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10702,7 +12318,15 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_AMOUNT", "T_ARG1", - "T_STR1" + "T_STR1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR4", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", @@ -10710,7 +12334,8 @@ const SVC_SCREENS = [ "T_STR4", "T_ARG8", "T_ARG7", - "T_ARG6" + "T_ARG6", + "T_AMOUNT" ] }, { @@ -10873,7 +12498,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -10882,7 +12517,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_AMT2", + "T_AMT3" ] }, { @@ -11024,7 +12663,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11032,7 +12681,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -11071,7 +12725,17 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_FEE", "T_NET", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11079,7 +12743,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -11094,7 +12762,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_MERCHANT", "T_KEY1", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11102,7 +12780,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -11116,7 +12798,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_COUNT" + "T_COUNT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11126,7 +12818,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT3" ] }, { @@ -11140,7 +12835,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_COUNT" + "T_COUNT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11150,7 +12855,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT3" ] }, { @@ -11298,7 +13006,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_REASON" + "T_REASON", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11306,7 +13024,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -11319,7 +13041,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11328,7 +13060,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT3" ] }, { @@ -11342,7 +13077,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11352,7 +13097,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -11388,7 +13136,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11398,7 +13156,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -11481,7 +13242,17 @@ const SVC_SCREENS = [ "T_AMOUNT", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11490,7 +13261,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_AMT2", + "T_AMT3" ] }, { @@ -11503,7 +13278,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11513,7 +13298,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -11594,7 +13382,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11602,7 +13400,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -11658,7 +13461,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11667,7 +13480,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -11680,14 +13498,29 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -11882,7 +13715,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11891,7 +13734,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -11930,7 +13776,17 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_KEY1", "T_KEY2", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -11938,7 +13794,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12020,7 +13880,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12029,7 +13899,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12044,7 +13918,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_MERCHANT", "T_FEE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12052,7 +13936,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12114,7 +14002,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12123,7 +14021,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12292,14 +14194,29 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12335,7 +14252,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12346,7 +14273,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -12383,7 +14313,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12392,7 +14332,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT3" ] }, { @@ -12406,7 +14349,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12415,7 +14368,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12452,7 +14410,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12461,7 +14429,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_AMT2", + "T_AMT3" ] }, { @@ -12681,7 +14653,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12690,7 +14672,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12725,7 +14712,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12735,7 +14732,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -12751,7 +14751,17 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_KEY1", "T_KEY2", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12759,7 +14769,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12773,7 +14787,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_COUNT" + "T_COUNT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12782,7 +14806,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12795,7 +14823,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12803,7 +14841,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -12818,7 +14860,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12827,7 +14879,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT3" ] }, { @@ -12864,7 +14919,8 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_STR8" ], "out": [ "T_RC", @@ -12929,7 +14985,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12938,7 +15004,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_AMT2", + "T_AMT3" ] }, { @@ -12951,7 +15021,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12961,7 +15041,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -12974,7 +15057,17 @@ const SVC_SCREENS = [ "T_AMOUNT", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -12983,7 +15076,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_AMT2", + "T_AMT3" ] }, { @@ -13038,7 +15135,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13047,7 +15154,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_AMT2", + "T_AMT3" ] }, { @@ -13102,7 +15213,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13111,7 +15232,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_AMT2", + "T_AMT3" ] }, { @@ -13166,7 +15291,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13175,7 +15310,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13236,7 +15376,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_MERCHANT", "T_NET", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13244,7 +15394,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13283,7 +15437,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_MERCHANT", "T_KEY1", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13293,7 +15457,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -13445,7 +15612,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13455,7 +15632,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT3" ] }, { @@ -13518,7 +15698,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_MERCHANT", "T_KEY1", - "T_KEY2" + "T_KEY2", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13526,7 +15716,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13540,7 +15734,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13550,7 +15754,10 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2" ] }, { @@ -13584,7 +15791,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13592,7 +15809,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13606,7 +15827,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_COUNT" + "T_COUNT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13615,7 +15846,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13673,7 +15908,16 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_MERCHANT", "T_STR2", - "T_MSG" + "T_MSG", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS" ], "out": [ "T_RC", @@ -13681,7 +15925,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13719,7 +15967,17 @@ const SVC_SCREENS = [ "T_DELTA", "T_BIZDATE", "T_MERCHANT", - "T_STR1" + "T_STR1", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13727,7 +15985,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13740,7 +16003,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13748,7 +16021,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13763,7 +16040,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_MERCHANT", "T_KEY1", - "T_KEY2" + "T_KEY2", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13771,7 +16058,11 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13806,7 +16097,17 @@ const SVC_SCREENS = [ "T_ID1", "T_DELTA", "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_ID2", + "T_ARG5", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_AMT2", + "T_AMT3", + "T_STATUS", + "T_MSG" ], "out": [ "T_RC", @@ -13815,7 +16116,12 @@ const SVC_SCREENS = [ "T_ARG7", "T_ARG8", "T_ARG5", - "T_ARG6" + "T_ARG6", + "T_ID1", + "T_AMOUNT", + "T_ID2", + "T_AMT2", + "T_AMT3" ] }, { @@ -13851,7 +16157,16 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_ID1" + "T_ID1", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STATUS", + "T_STR8" ], "out": [ "T_RC", @@ -13862,7 +16177,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_STATUS" + "T_STATUS", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14067,7 +16385,16 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_ARG1", - "T_ID1" + "T_ID1", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR6", + "T_STR8" ], "out": [ "T_RC", @@ -14078,7 +16405,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_STR6" + "T_STR6", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14119,7 +16449,18 @@ const SVC_SCREENS = [ "T_STR3", "T_STR5", "T_AMOUNT", - "T_STR6" + "T_STR6", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_BIZDATE", + "T_CHANNEL", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -14131,7 +16472,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_STR3", - "T_COUNT" + "T_COUNT", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14276,7 +16620,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_STR1", "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STATUS", + "T_STR5", + "T_STR8" ], "out": [ "T_RC", @@ -14288,7 +16642,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_STATUS", - "T_STR5" + "T_STR5", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14301,7 +16658,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_STR1", "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_AMT2", + "T_AMT3", + "T_ARG3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STATUS", + "T_STR8" ], "out": [ "T_RC", @@ -14313,7 +16680,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_STATUS", - "T_ARG3" + "T_ARG3", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14377,7 +16747,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_STR1", "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STATUS", + "T_STR5", + "T_STR8" ], "out": [ "T_RC", @@ -14389,7 +16769,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_STATUS", - "T_STR5" + "T_STR5", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14413,7 +16796,9 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_STATUS" + "T_STATUS", + "T_ARG2", + "T_ARG3" ] }, { @@ -14476,7 +16861,17 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR2" + "T_STR2", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR5", + "T_STR8" ], "out": [ "T_RC", @@ -14489,7 +16884,10 @@ const SVC_SCREENS = [ "T_STR8", "T_STR5", "T_STR2", - "T_COUNT" + "T_COUNT", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14553,7 +16951,18 @@ const SVC_SCREENS = [ "T_STR4", "T_STR3", "T_STR5", - "T_AMOUNT" + "T_AMOUNT", + "T_AMT2", + "T_AMT3", + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_BIZDATE", + "T_CHANNEL", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -14716,7 +17125,17 @@ const SVC_SCREENS = [ "T_STR5", "T_AMOUNT", "T_CHANNEL", - "T_ARG1" + "T_ARG1", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_BIZDATE", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -14728,7 +17147,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_STR3", - "T_COUNT" + "T_COUNT", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14872,7 +17294,17 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_ID1" + "T_ID1", + "T_AMT2", + "T_AMT3", + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID2", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -14884,7 +17316,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_ID2", - "T_ARG1" + "T_ARG1", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -14898,7 +17333,16 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_ID1" + "T_ID1", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID2", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -14909,7 +17353,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_ID2" + "T_ID2", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -15118,7 +17565,17 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR4", + "T_STR8" ], "out": [ "T_RC", @@ -15133,7 +17590,8 @@ const SVC_SCREENS = [ "T_STR1", "T_STR4", "T_AMOUNT", - "T_COUNT" + "T_COUNT", + "T_CHANNEL" ] }, { @@ -15279,7 +17737,17 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID1", + "T_MSG", + "T_RC", + "T_STR4", + "T_STR8" ], "out": [ "T_RC", @@ -15293,7 +17761,8 @@ const SVC_SCREENS = [ "T_STR1", "T_STR4", "T_AMOUNT", - "T_ID1" + "T_ID1", + "T_CHANNEL" ] }, { @@ -15333,7 +17802,19 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_KEY2" + "T_KEY2", + "T_AMT2", + "T_AMT3", + "T_ARG3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_KEY1", + "T_MSG", + "T_RC", + "T_STR8", + "T_STR2", + "T_ARG1" ], "out": [ "T_RC", @@ -15345,7 +17826,8 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_KEY1", - "T_ARG3" + "T_ARG3", + "T_AMOUNT" ] }, { @@ -15409,7 +17891,19 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_STR1", "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_AMT2", + "T_AMT3", + "T_ARG3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_KEY1", + "T_MSG", + "T_RC", + "T_STR8", + "T_STR2", + "T_ARG1" ], "out": [ "T_RC", @@ -15421,7 +17915,8 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_KEY1", - "T_ARG3" + "T_ARG3", + "T_AMOUNT" ] }, { @@ -15486,7 +17981,17 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_STR1", "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_AMT2", + "T_AMT3", + "T_ARG3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -15499,7 +18004,9 @@ const SVC_SCREENS = [ "T_STR8", "T_CHANNEL", "T_COUNT", - "T_ARG3" + "T_ARG3", + "T_STR1", + "T_AMOUNT" ] }, { @@ -15538,7 +18045,18 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_STR3", - "T_ID1" + "T_ID1", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_KEY1", + "T_MSG", + "T_RC", + "T_STR8", + "T_STR2", + "T_ARG1" ], "out": [ "T_RC", @@ -15549,7 +18067,8 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_KEY1" + "T_KEY1", + "T_AMOUNT" ] }, { @@ -15563,7 +18082,19 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_KEY1", + "T_MSG", + "T_RC", + "T_STR8", + "T_STR2", + "T_ARG1" ], "out": [ "T_RC", @@ -15575,7 +18106,8 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_KEY1", - "T_ARG3" + "T_ARG3", + "T_AMOUNT" ] }, { @@ -15589,7 +18121,18 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_KEY1", + "T_MSG", + "T_RC", + "T_STR8", + "T_STR2", + "T_ARG1" ], "out": [ "T_RC", @@ -15600,7 +18143,8 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_KEY1" + "T_KEY1", + "T_AMOUNT" ] }, { @@ -15614,7 +18158,18 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_ID1" + "T_ID1", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_KEY2", + "T_MSG", + "T_RC", + "T_STR8", + "T_STR2", + "T_ARG1" ], "out": [ "T_RC", @@ -15625,7 +18180,8 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_KEY2" + "T_KEY2", + "T_AMOUNT" ] }, { @@ -15640,7 +18196,15 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_ID1", - "T_RC" + "T_RC", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_STATUS", + "T_STR8" ], "out": [ "T_RC", @@ -15651,7 +18215,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_STATUS" + "T_STATUS", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -15748,7 +18315,17 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR4" + "T_STR4", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR3", + "T_STR8" ], "out": [ "T_RC", @@ -15760,7 +18337,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_STR3", - "T_COUNT" + "T_COUNT", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -15800,7 +18380,19 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_KEY1", + "T_MSG", + "T_RC", + "T_STR4", + "T_STR8", + "T_STATUS" ], "out": [ "T_RC", @@ -15813,7 +18405,10 @@ const SVC_SCREENS = [ "T_STR8", "T_STR1", "T_STR4", - "T_COUNT" + "T_COUNT", + "T_KEY1", + "T_MERCHANT", + "T_AMOUNT" ] }, { @@ -15989,7 +18584,18 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_AMT2", + "T_AMT3", + "T_ARG2", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR3", + "T_STR8" ], "out": [ "T_RC", @@ -16002,7 +18608,10 @@ const SVC_SCREENS = [ "T_STR8", "T_STR3", "T_COUNT", - "T_ARG2" + "T_ARG2", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -16017,7 +18626,17 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_STR3", - "T_STR5" + "T_STR5", + "T_AMT2", + "T_AMT3", + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID1", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -16029,7 +18648,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_ARG1", - "T_ID1" + "T_ID1", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -16071,7 +18693,16 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_ARG1", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID2", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -16082,7 +18713,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_ID2" + "T_ID2", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -16097,7 +18731,16 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_AMOUNT", "T_ID2", - "T_ARG4" + "T_ARG4", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -16108,7 +18751,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_COUNT" + "T_COUNT", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -16159,6 +18805,7 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", + "T_ARG4", "T_ID1", "T_ARG1" ] @@ -16255,7 +18902,16 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_STR1", "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR3", + "T_STR8" ], "out": [ "T_RC", @@ -16266,7 +18922,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_STR3" + "T_STR3", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -16484,7 +19143,17 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG1", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_ID1", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -16496,7 +19165,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_STR8", "T_ARG1", - "T_ID1" + "T_ID1", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -16535,7 +19207,16 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -16546,7 +19227,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_COUNT" + "T_COUNT", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -16560,7 +19244,16 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_ARG1" + "T_ARG1", + "T_AMT2", + "T_AMT3", + "T_ARG2", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR8" ], "out": [ "T_RC", @@ -16571,7 +19264,10 @@ const SVC_SCREENS = [ "T_AMT2", "T_AMT3", "T_STR8", - "T_ARG2" + "T_ARG2", + "T_CHANNEL", + "T_STR1", + "T_AMOUNT" ] }, { @@ -17155,7 +19851,16 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR6", + "T_STR8" ], "out": [ "T_RC", @@ -17169,7 +19874,8 @@ const SVC_SCREENS = [ "T_STR3", "T_STR6", "T_STR1", - "T_AMOUNT" + "T_AMOUNT", + "T_CHANNEL" ] }, { @@ -17208,7 +19914,16 @@ const SVC_SCREENS = [ "T_STR1", "T_MERCHANT", "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_AMT2", + "T_AMT3", + "T_ARG6", + "T_ARG7", + "T_ARG8", + "T_MSG", + "T_RC", + "T_STR4", + "T_STR8" ], "out": [ "T_RC", @@ -17221,7 +19936,8 @@ const SVC_SCREENS = [ "T_STR8", "T_STR1", "T_STR4", - "T_AMOUNT" + "T_AMOUNT", + "T_CHANNEL" ] }, { @@ -17368,10 +20084,16 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_STR1", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_RC", + "T_STR5", + "T_STR3" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -17381,10 +20103,17 @@ const SVC_SCREENS = [ "desc": "기능: 정산계좌 검증 실행 (형식 검사 + ACCT_VRF 검증 이력 적재).", "in": [ "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_RC", + "T_STR1", + "T_STR5", + "T_STR3" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -17466,7 +20195,8 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_ARG1", - "T_KEY1" + "T_KEY1", + "T_RC" ], "out": [ "T_RC" @@ -17539,10 +20269,15 @@ const SVC_SCREENS = [ "T_STR1", "T_STR2", "T_STR3", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_RC", + "T_ARG1" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -17724,9 +20459,13 @@ const SVC_SCREENS = [ "T_KEY1", "T_ISSUER", "T_STR5", - "T_CCY" + "T_CCY", + "T_MERCHANT", + "T_RC" ], - "out": [] + "out": [ + "T_RC" + ] }, { "mod": "mm", @@ -17736,11 +20475,17 @@ const SVC_SCREENS = [ "in": [ "T_STR2", "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_COUNT", + "T_RC", + "T_ARG1" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_AMOUNT" ] }, { @@ -17895,12 +20640,17 @@ const SVC_SCREENS = [ "desc": "기능: 한도 마스터 정합성 점검 (활성 가맹점 한도 누락 + 한도 체계 역전 검출).", "in": [ "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_ARG1", + "T_COUNT", + "T_RC" ], "out": [ "T_COUNT", "T_ARG1", - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -18021,9 +20771,14 @@ const SVC_SCREENS = [ "in": [ "T_STR1", "T_KEY1", - "T_STR2" + "T_STR2", + "T_MERCHANT", + "T_STR3", + "T_RC" ], - "out": [] + "out": [ + "T_RC" + ] }, { "mod": "mm", @@ -18044,10 +20799,15 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_ARG1", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_RC", + "T_STR1" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -18116,10 +20876,15 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_ARG1", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_RC", + "T_STR1" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -18143,10 +20908,16 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_ARG1", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_RC", + "T_STR1", + "T_STR2" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -18199,9 +20970,15 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_STR4", "T_ARG1", - "T_KEY1" + "T_KEY1", + "T_BIZDATE", + "T_FEE", + "T_PURCHASE_ID" ], - "out": [] + "out": [ + "T_FEE", + "T_RC" + ] }, { "mod": "mm", @@ -18241,7 +21018,9 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_STR2", "T_REASON", - "T_KEY1" + "T_KEY1", + "T_RC", + "T_STR1" ], "out": [ "T_RC" @@ -18330,9 +21109,13 @@ const SVC_SCREENS = [ "T_STR1", "T_STR2", "T_KEY1", - "T_CCY" + "T_CCY", + "T_MERCHANT", + "T_RC" ], - "out": [] + "out": [ + "T_RC" + ] }, { "mod": "mm", @@ -18359,9 +21142,14 @@ const SVC_SCREENS = [ "T_AMT1", "T_AMT2", "T_AMT3", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_RC" ], - "out": [] + "out": [ + "T_AMOUNT", + "T_RC" + ] }, { "mod": "mm", @@ -18434,9 +21222,14 @@ const SVC_SCREENS = [ "T_STR1", "T_ARG1", "T_CATEGORY", - "T_KEY1" + "T_KEY1", + "T_MERCHANT", + "T_STR3", + "T_RC" ], - "out": [] + "out": [ + "T_RC" + ] }, { "mod": "mm", @@ -18480,7 +21273,10 @@ const SVC_SCREENS = [ "T_CATEGORY", "T_STR1", "T_ARG1", - "T_KEY1" + "T_KEY1", + "T_MERCHANT", + "T_RC", + "T_STR3" ], "out": [ "T_RC" @@ -18521,11 +21317,20 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_REASON", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR1", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_AMOUNT" ] }, { @@ -18547,11 +21352,20 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_REASON", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_GROSS", + "T_MSG", + "T_RC", + "T_STR1", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", - "T_GROSS" + "T_GROSS", + "T_AMOUNT" ] }, { @@ -18562,9 +21376,12 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_STR2", - "T_KEY1" + "T_KEY1", + "T_RC" ], - "out": [] + "out": [ + "T_RC" + ] }, { "mod": "mm", @@ -18585,11 +21402,20 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_REASON", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR1", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_AMOUNT" ] }, { @@ -18602,9 +21428,13 @@ const SVC_SCREENS = [ "T_STR1", "T_STR2", "T_STR3", - "T_KEY1" + "T_KEY1", + "T_STATUS", + "T_RC" ], - "out": [] + "out": [ + "T_RC" + ] }, { "mod": "mm", @@ -18613,11 +21443,20 @@ const SVC_SCREENS = [ "desc": "기능: 가맹점 영업 재개 (HOLD -> ACTIVE, 정지 단말 재가동).", "in": [ "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_COUNT", + "T_MSG", + "T_RC", + "T_STR1", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_AMOUNT" ] }, { @@ -18628,9 +21467,12 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_STATUS", - "T_KEY1" + "T_KEY1", + "T_RC" ], - "out": [] + "out": [ + "T_RC" + ] }, { "mod": "mm", @@ -18655,9 +21497,12 @@ const SVC_SCREENS = [ "T_MERCHANT", "T_STR1", "T_STR3", - "T_KEY1" + "T_KEY1", + "T_RC" ], - "out": [] + "out": [ + "T_RC" + ] }, { "mod": "mm", @@ -18737,11 +21582,18 @@ const SVC_SCREENS = [ "desc": "기능: 수수료율 변경 승인 (대기 요청을 실제 요율 마스터에 반영, RATE_APV 이력).", "in": [ "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_AMT1", + "T_BIZDATE", + "T_FEE", + "T_RC", + "T_STR2", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_AMT1" + "T_AMT1", + "T_FEE" ] }, { @@ -18812,11 +21664,20 @@ const SVC_SCREENS = [ "T_STR2", "T_REASON", "T_ARG1", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_AMT1", + "T_BIZDATE", + "T_MSG", + "T_RC", + "T_STR1", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", - "T_AMT1" + "T_AMT1", + "T_AMOUNT" ] }, { @@ -18949,11 +21810,20 @@ const SVC_SCREENS = [ "desc": "기능: 가맹점 리스크 점수 산정 (MCC 위험도*20 + 저등급 가산 + 비활성 상태 가산).", "in": [ "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_ARG1", + "T_BIZDATE", + "T_MSG", + "T_RC", + "T_STR1", + "T_SVCNAME", + "T_ID1" ], "out": [ "T_RC", - "T_ARG1" + "T_ARG1", + "T_AMOUNT" ] }, { @@ -18964,7 +21834,8 @@ const SVC_SCREENS = [ "in": [ "T_MERCHANT", "T_ARG1", - "T_KEY1" + "T_KEY1", + "T_RC" ], "out": [ "T_RC" @@ -19005,9 +21876,16 @@ const SVC_SCREENS = [ "T_STR5", "T_MERCHANT", "T_STR6", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_STR1", + "T_ARG1" ], - "out": [] + "out": [ + "T_AMOUNT", + "T_RC" + ] }, { "mod": "mm", @@ -19079,10 +21957,16 @@ const SVC_SCREENS = [ "T_STR5", "T_MERCHANT", "T_STR6", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_RC", + "T_STR1", + "T_ARG1" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -19211,10 +22095,18 @@ const SVC_SCREENS = [ "desc": "기능: 가맹점 마스터 정합성 검사 (존재+수수료율 존재).", "in": [ "T_MERCHANT", - "T_KEY1" + "T_KEY1", + "T_AMOUNT", + "T_BIZDATE", + "T_MSG", + "T_RC", + "T_STR1", + "T_SVCNAME", + "T_ID1" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT" ] }, { @@ -19236,11 +22128,28 @@ const SVC_SCREENS = [ "svc": "PAY_ACCTCHK", "desc": "지급계좌 유효성 점검: dbio 로 계좌 상태/잔액을 읽어 ACTIVE 여부를 회신.", "in": [ - "T_KEY1" + "T_KEY1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS" ], "out": [ "T_RC", - "T_AMT1" + "T_AMT1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -19290,11 +22199,28 @@ const SVC_SCREENS = [ "desc": "지급계좌 검증: 계좌의 상태/예금주/잔액을 조회하고, 요청에 예금주가 주어지면", "in": [ "T_KEY1", - "T_STR1" + "T_STR1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS" ], "out": [ "T_RC", - "T_AMT1" + "T_AMT1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -19306,11 +22232,28 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_DELTA", "T_ID1", - "T_REASON" + "T_REASON", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS" ], "out": [ "T_RC", - "T_ADJ" + "T_ADJ", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -19384,13 +22327,34 @@ const SVC_SCREENS = [ "desc": "소액 일괄 승인: 당일 요청(R)건 중 net 이 승인한도 이하인 건을 한 번의", "in": [ "T_AMT1", - "T_BIZDATE" + "T_BIZDATE", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_DELTA", + "T_STR7", + "T_ID2" ], "out": [ "T_RC", "T_COUNT", "T_AMT1", - "T_ARG1" + "T_ARG1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_ARG7", + "T_ARG8", + "T_DELTA", + "T_GROSS" ] }, { @@ -19439,11 +22403,33 @@ const SVC_SCREENS = [ "svc": "PAY_APPROVE", "desc": "지급 승인: 금액을 먼저 조회한 뒤 요청(R) 상태만 승인(A)으로 전이하고 금액을", "in": [ - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_DELTA", + "T_STR7", + "T_ID2" ], "out": [ "T_RC", - "T_AMOUNT" + "T_AMOUNT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_ARG7", + "T_ARG8", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -19480,13 +22466,28 @@ const SVC_SCREENS = [ "desc": "은행별 지급파일 생성: 지정 은행코드의 승인(A) 지급건만 py_account 조인으로", "in": [ "T_BIZDATE", - "T_KEY1" + "T_KEY1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_CHANNEL" ], "out": [ "T_RC", "T_ID2", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -19495,14 +22496,31 @@ const SVC_SCREENS = [ "svc": "PAY_BANKVERIFY", "desc": "지급파일 검증: 파일 헤더(record_count/total_amount)와 실제 편성 지급건의", "in": [ - "T_ID2" + "T_ID2", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_KEY1" ], "out": [ "T_RC", "T_COUNT", "T_AMT1", "T_AMT2", - "T_DELTA" + "T_DELTA", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS" ] }, { @@ -19531,11 +22549,28 @@ const SVC_SCREENS = [ "T_AMOUNT", "T_BIZDATE", "T_ID1", - "T_REASON" + "T_REASON", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_DELTA" ], "out": [ "T_RC", - "T_ADJ" + "T_ADJ", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_DELTA" ] }, { @@ -19577,12 +22612,27 @@ const SVC_SCREENS = [ "desc": "지급 되물림: 분쟁 등으로 지급완료(P) 건을 되물릴 때, 원건은 보존한 채", "in": [ "T_BIZDATE", - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS" ], "out": [ "T_RC", "T_ID2", - "T_NET" + "T_NET", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_COUNT", + "T_GROSS" ] }, { @@ -19591,11 +22641,26 @@ const SVC_SCREENS = [ "svc": "PAY_CLOSE", "desc": "일마감: 당일 지급완료(P)건을 마감(X)으로 일괄 전환하고 전환 건수를 회신.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS" ] }, { @@ -19618,13 +22683,27 @@ const SVC_SCREENS = [ "desc": "지급 합산: 같은 계좌의 당일 요청(R) 건들을 하나로 합산 지급한다. 합계", "in": [ "T_BIZDATE", - "T_KEY1" + "T_KEY1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS" ], "out": [ "T_RC", "T_ID2", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -19633,10 +22712,27 @@ const SVC_SCREENS = [ "svc": "PAY_CONFIRM", "desc": "지급 확정(confirm): 지급 파일 상태를 확정(C)으로 전이하고 확정 시각 기록.", "in": [ - "T_ID2" + "T_ID2", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -19910,13 +23006,31 @@ const SVC_SCREENS = [ "svc": "PAY_FILEGEN", "desc": "지급 파일 헤더 생성: 당일 승인(A) 지급건 집계 -> py_file.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_STR8", + "T_ARG7", + "T_ARG8", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_KEY1" ], "out": [ "T_RC", "T_ID2", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -19925,12 +23039,28 @@ const SVC_SCREENS = [ "svc": "PAY_FILEREBUILD", "desc": "지급파일 재생성: 아직 미확정(G)인 파일 헤더를 실제 편성 상세 기준으로", "in": [ - "T_ID2" + "T_ID2", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_KEY1" ], "out": [ "T_RC", "T_COUNT", - "T_GROSS" + "T_GROSS", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -19998,10 +23128,29 @@ const SVC_SCREENS = [ "svc": "PAY_HOLD", "desc": "지급 보류: 이미 지급완료(P)/마감(X)된 건은 보류 불가 - dbio 로 현재 상태를", "in": [ - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_DELTA" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -20245,13 +23394,27 @@ const SVC_SCREENS = [ "desc": "지급 합산: 가맹점 당일 요청(R) STD 건이 2건 이상이면 전부 취소(C) 표시 후", "in": [ "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_STATUS", + "T_KEY1" ], "out": [ "T_RC", "T_ID2", "T_COUNT", - "T_NET" + "T_NET", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_GROSS" ] }, { @@ -20261,11 +23424,26 @@ const SVC_SCREENS = [ "desc": "상계(net-off): 지급건의 net 을 조회해 차감액을 반영하고 갱신.", "in": [ "T_AMOUNT", - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS" ], "out": [ "T_RC", - "T_NET" + "T_NET", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_COUNT", + "T_GROSS" ] }, { @@ -20441,11 +23619,29 @@ const SVC_SCREENS = [ "desc": "과지급 환수: 지급완료(P) 건에서 요청 환수액(T_AMOUNT, net 한도)만큼을", "in": [ "T_AMOUNT", - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_DELTA" ], "out": [ "T_RC", - "T_AMT1" + "T_AMT1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_DELTA" ] }, { @@ -20469,11 +23665,27 @@ const SVC_SCREENS = [ "desc": "지급 환입: 지급완료(P) 건을 역분개(V)하며 지급계좌에 net 을 복원하고", "in": [ "T_ID1", - "T_REASON" + "T_REASON", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS" ], "out": [ "T_RC", - "T_NET" + "T_NET", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_COUNT", + "T_GROSS" ] }, { @@ -20495,10 +23707,29 @@ const SVC_SCREENS = [ "svc": "PAY_RELEASE", "desc": "보류 해제: 직전 상태를 조회하여 보류(H)가 아니면 무효 처리, 보류면 dbio 로", "in": [ - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_DELTA" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -20509,10 +23740,27 @@ const SVC_SCREENS = [ "in": [ "T_ID1", "T_KEY1", - "T_NET" + "T_NET", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_CHANNEL" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -20550,10 +23798,29 @@ const SVC_SCREENS = [ "svc": "PAY_REPROC", "desc": "재처리: 직전 상태를 조회한 뒤 실패/보류/취소(J,H,C) -> 요청(R) 전이, 이전 상태 회신.", "in": [ - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_DELTA" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -20562,11 +23829,27 @@ const SVC_SCREENS = [ "svc": "PAY_REQUEUE", "desc": "실패 일괄 재처리 적재: 당일 반려(J) 건 중 재시도 여력(retry_count<3)이", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_CHANNEL" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS" ] }, { @@ -20575,10 +23858,27 @@ const SVC_SCREENS = [ "svc": "PAY_RESULT", "desc": "지급 결과 반영: 편성/요청(F,R) 상태만 지급완료(P)로 전이, 반영 건수를 T_RC 로.", "in": [ - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -20602,10 +23902,28 @@ const SVC_SCREENS = [ "desc": "예약 변경: 아직 실행되지 않은 예약(S) 의 실행일(run_date)을 새 일자로", "in": [ "T_BIZDATE", - "T_ID2" + "T_ID2", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_ARG1" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_ARG1", + "T_COUNT", + "T_GROSS" ] }, { @@ -20614,10 +23932,29 @@ const SVC_SCREENS = [ "svc": "PAY_RETRY", "desc": "실패 지급 재시도: 실패/보류(J,H) 건만 요청(R)으로 되돌리고 retry_count 증가.", "in": [ - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_DELTA" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -20626,11 +23963,29 @@ const SVC_SCREENS = [ "svc": "PAY_RETRYONE", "desc": "단건 재시도: 반려(J) 지급건 하나를 요청(R)으로 되돌리며 retry_count 를", "in": [ - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_DELTA" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_GROSS" ] }, { @@ -20641,10 +23996,28 @@ const SVC_SCREENS = [ "in": [ "T_AMOUNT", "T_ID1", - "T_KEY1" + "T_KEY1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_DELTA" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_DELTA" ] }, { @@ -20654,11 +24027,28 @@ const SVC_SCREENS = [ "desc": "미지급 일괄 이월: 지정 기준일 이전의 미지급(R) 건 전부를 차기 영업일", "in": [ "T_BIZDATE", - "T_KEY2" + "T_KEY2", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_ARG1" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_ARG1", + "T_GROSS" ] }, { @@ -20681,11 +24071,29 @@ const SVC_SCREENS = [ "desc": "지급 예약 등록: 지정 실행일로 py_schedule 예약(S) 레코드를 생성.", "in": [ "T_BIZDATE", - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_ARG1" ], "out": [ "T_RC", - "T_ID2" + "T_ID2", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_ARG1", + "T_COUNT", + "T_GROSS" ] }, { @@ -20766,11 +24174,23 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_COUNT", "T_KEY1", - "T_MERCHANT" + "T_MERCHANT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", - "T_COUNT" + "T_COUNT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS" ] }, { @@ -20781,12 +24201,26 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_COUNT", - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_KEY1" ], "out": [ "T_RC", "T_COUNT", - "T_AMOUNT" + "T_AMOUNT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_GROSS" ] }, { @@ -20796,14 +24230,32 @@ const SVC_SCREENS = [ "desc": "비율 분할: 요청(R) 건을 bps 비율로 두 건의 SPLIT 지급건으로 쪼개고", "in": [ "T_ARG1", - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS", + "T_KEY1" ], "out": [ "T_RC", "T_ID2", "T_AMT1", "T_AMT2", - "T_ARG2" + "T_ARG2", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -20986,13 +24438,25 @@ const SVC_SCREENS = [ "T_AMOUNT", "T_BIZDATE", "T_KEY1", - "T_MERCHANT" + "T_MERCHANT", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ID1", "T_FEE", - "T_NET" + "T_NET", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_COUNT", + "T_GROSS" ] }, { @@ -21018,10 +24482,27 @@ const SVC_SCREENS = [ "desc": "지급 무효(단건): 아직 지급 전인 요청/승인(R/A) 건만 무효 취소(C)로 전이하고", "in": [ "T_ID1", - "T_REASON" + "T_REASON", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_BIZDATE", + "T_MERCHANT", + "T_STATUS" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -21075,10 +24556,26 @@ const SVC_SCREENS = [ "in": [ "T_AMOUNT", "T_BIZDATE", - "T_ID1" + "T_ID1", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS", + "T_CHANNEL" ], "out": [ - "T_RC" + "T_RC", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -21146,10 +24643,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_NET" + "T_NET", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21160,10 +24666,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_NET" + "T_NET", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ID1" ] }, @@ -21173,10 +24688,20 @@ const SVC_SCREENS = [ "svc": "RC_ACQMATCH", "desc": "업무: 매입-입금 축 대사: 당일 매입 순액 합계와 원장 RECON 입금 합계를 비교해 차액을 산출.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", "T_ARG2", "T_DELTA" @@ -21190,11 +24715,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_NET" + "T_NET", + "T_RC" ], "out": [ "T_RC", - "T_GROSS" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21222,10 +24755,23 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_PURCHASE_ID", "T_MSG", - "T_STR1" + "T_STR1", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_MERCHANT", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ID1" ] }, @@ -21237,10 +24783,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_NET" + "T_NET", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_DELTA" ] }, @@ -21250,11 +24805,20 @@ const SVC_SCREENS = [ "svc": "RC_APPRGAP", "desc": "업무: 승인 누락 감지: 당일 매입 중 승인 원장이 없는 건을 예외로 등록하고 누락 건수를 반환.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21263,13 +24827,22 @@ const SVC_SCREENS = [ "svc": "RC_APPRMATCH", "desc": "업무: 승인-매입 축 대사: 당일 매입 중 승인건과 매칭된 건수와 승인 누락 건수를 분리 집계.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", - "T_ARG2", - "T_COUNT" + "T_ARG2" ] }, { @@ -21280,10 +24853,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_NET" + "T_NET", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ID1" ] }, @@ -21337,10 +24919,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_AMOUNT" + "T_AMOUNT", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21583,14 +25174,22 @@ const SVC_SCREENS = [ "svc": "RC_CLOSEDAY", "desc": "업무: 일마감 확정 (예외/보류 잔량 시 거부).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_ARG1", - "T_ARG2", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", "T_COUNT", - "T_GROSS" + "T_ARG3", + "T_AMT2", + "T_ARG4", + "T_ARG1", + "T_ARG2" ] }, { @@ -21599,11 +25198,20 @@ const SVC_SCREENS = [ "svc": "RC_CNTDIFF", "desc": "업무: 건수 차이 대사: 매입 건수 vs 대사 로그 건수.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21612,10 +25220,19 @@ const SVC_SCREENS = [ "svc": "RC_CONFIRM", "desc": "업무: 대사 확정 (MATCHED -> CONFIRMED).", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21639,11 +25256,20 @@ const SVC_SCREENS = [ "svc": "RC_DEPGAP", "desc": "업무: 입금 누락 감지: 매입은 있으나 RECON 원장이 없는 미입금 건수를 집계.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21653,12 +25279,20 @@ const SVC_SCREENS = [ "desc": "업무: 입금(정산) 대사.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", - "T_AMT1", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", "T_AMT2", + "T_ARG4", + "T_AMT1", "T_ID1" ] }, @@ -21741,11 +25375,20 @@ const SVC_SCREENS = [ "svc": "RC_DUPCHK", "desc": "업무: 중복 대사 매입 검출 + WARN 경보.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21785,11 +25428,20 @@ const SVC_SCREENS = [ "svc": "RC_ESCALATE", "desc": "업무: 미해결 예외 경보 WARN -> CRIT 일괄 승격.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21800,10 +25452,23 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_REASON" + "T_REASON", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_MERCHANT", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ID1" ] }, @@ -21813,11 +25478,20 @@ const SVC_SCREENS = [ "svc": "RC_EXCNOTIFY", "desc": "업무: 대사 예외 알림: 당일 미해결 예외 건수를 집계해 임계 초과 시 rc_alert 경보를 발생.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21841,11 +25515,20 @@ const SVC_SCREENS = [ "svc": "RC_FEEDIFF", "desc": "업무: 당일 수수료 불일치 건수/차액 합계.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_DELTA" ] }, @@ -21856,12 +25539,20 @@ const SVC_SCREENS = [ "desc": "업무: MDR 기준 수수료 대사.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", - "T_DELTA", + "T_AMOUNT", "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", + "T_DELTA", "T_ID1" ] }, @@ -21885,13 +25576,21 @@ const SVC_SCREENS = [ "desc": "업무: 수수료 자동보정: 매입 수수료가 MDR 이론치와 다르면 차이를 조정 델타로 반환.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", - "T_DELTA", - "T_FEE" + "T_DELTA" ] }, { @@ -21901,10 +25600,19 @@ const SVC_SCREENS = [ "desc": "업무: 외화 자동보정: ac_fx 의 원화환산액과 원통화*환율 이론치의 차이를 산출.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", "T_ARG2", "T_DELTA" @@ -21916,11 +25624,20 @@ const SVC_SCREENS = [ "svc": "RC_FIXROUND", "desc": "업무: 반올림 자동보정: 절대차 1 이하 단수 차이를 수수료조정(ac_fee_adj)으로 상계 기록.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -21942,10 +25659,20 @@ const SVC_SCREENS = [ "svc": "RC_FXDIFF", "desc": "업무: 외화 환산 차이: 당일 ac_fx 원화환산 합계와 원통화*환율 이론합계의 차이를 집계.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", "T_ARG2", "T_DELTA" @@ -21973,12 +25700,20 @@ const SVC_SCREENS = [ "desc": "업무: 외화 원화환산 대사.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", - "T_AMT1", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", "T_AMT2", + "T_ARG4", + "T_AMT1", "T_ID1" ] }, @@ -22030,11 +25765,19 @@ const SVC_SCREENS = [ "desc": "업무: 대사 보류 해제: 보류(H) 매입을 접수(A)로 되돌리고 관련 예외를 해결 처리.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22075,10 +25818,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_REASON" + "T_REASON", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ID1" ] }, @@ -22152,13 +25904,22 @@ const SVC_SCREENS = [ "svc": "RC_LEDGERBAL", "desc": "업무: 원장 축 잔액 대사: 당일 RECON/SETTLE/XFER 기표 합계의 순잔액이 0 인지 확인.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", "T_ARG2", - "T_ARG3", "T_DELTA" ] }, @@ -22170,10 +25931,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_NET" + "T_NET", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22183,12 +25953,21 @@ const SVC_SCREENS = [ "desc": "업무: 가맹점 일한도 초과 검증.", "in": [ "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_AMT1", - "T_AMT2" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", + "T_AMT1" ] }, { @@ -22316,10 +26095,19 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_NET" + "T_NET", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ID1" ] }, @@ -22357,13 +26145,22 @@ const SVC_SCREENS = [ "svc": "RC_NOTIFY", "desc": "업무: 대사 결과 요약 통보 (경보 발송).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", - "T_ARG2", - "T_GROSS" + "T_ARG2" ] }, { @@ -22372,11 +26169,20 @@ const SVC_SCREENS = [ "svc": "RC_ORPHAN", "desc": "업무: 승인 없는 고아 매입 적재.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22385,11 +26191,20 @@ const SVC_SCREENS = [ "svc": "RC_OVERAMT", "desc": "업무: 과다 차이 분석: 당일 rc_diff 중 실제가 기대를 초과(diff_amt<0)한 과다 건수/합계.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_DELTA" ] }, @@ -22456,13 +26271,22 @@ const SVC_SCREENS = [ "svc": "RC_PAYLEDGER", "desc": "업무: 지급-원장 축 대사: 정산 순액과 원장 SETTLE 기표 합계가 일치하는지 검증하고 차액 반환.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", - "T_DELTA", - "T_GROSS" + "T_DELTA" ] }, { @@ -22472,10 +26296,19 @@ const SVC_SCREENS = [ "desc": "업무: 지급(원장) 대사 + 차이 적재.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_DELTA", "T_ID1" ] @@ -22499,10 +26332,20 @@ const SVC_SCREENS = [ "svc": "RC_PROGRESS", "desc": "업무: 진행률(%) = MATCHED / 전체매입 * 100.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22607,11 +26450,19 @@ const SVC_SCREENS = [ "desc": "업무: 정정후 재대사: 수수료조정이 반영된 매입을 대상으로 순액 재검증 후 로그를 남긴다.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", - "T_NET" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22621,10 +26472,19 @@ const SVC_SCREENS = [ "desc": "업무: 차이발생 재대사: 지정 매입의 기대 순액과 SETTLE 실적 차이를 재산출해 rc_diff 갱신.", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_DELTA" ] }, @@ -22634,12 +26494,21 @@ const SVC_SCREENS = [ "svc": "RC_REFULL", "desc": "업무: 전체 재대사: 당일 전체 매입 대비 대사완료(M/S) 비율을 재계산해 진척률로 반환.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_ARG1", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", + "T_ARG1" ] }, { @@ -22675,10 +26544,19 @@ const SVC_SCREENS = [ "svc": "RC_RELEASE", "desc": "업무: 대사 보류 해제 (HOLD -> RELEASED).", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22689,10 +26567,22 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_PURCHASE_ID", - "T_NET" + "T_NET", + "T_AMOUNT", + "T_FEE", + "T_MERCHANT", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22714,10 +26604,24 @@ const SVC_SCREENS = [ "svc": "RC_REPROC", "desc": "업무: 재처리: EXCEPTION 대사 로그를 MATCHED 로 되돌림.", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_MERCHANT", + "T_BIZDATE", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22727,11 +26631,20 @@ const SVC_SCREENS = [ "desc": "업무: 임계초과 건 재대사 등록 (커서 순회).", "in": [ "T_BIZDATE", - "T_AMT1" + "T_AMT1", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22783,11 +26696,20 @@ const SVC_SCREENS = [ "svc": "RC_ROUNDDIFF", "desc": "업무: 반올림 차이 분석: 절대차가 1 이하인 단수 차이 건을 반올림 오차로 분류해 집계.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22809,14 +26731,22 @@ const SVC_SCREENS = [ "svc": "RC_SNAPSHOT", "desc": "업무: 현재 시점 대사 현황 스냅샷 upsert.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_ARG1", - "T_ARG2", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", "T_COUNT", - "T_GROSS" + "T_ARG3", + "T_AMT2", + "T_ARG4", + "T_ARG1", + "T_ARG2" ] }, { @@ -22838,10 +26768,19 @@ const SVC_SCREENS = [ "svc": "RC_STATUS", "desc": "업무: 최근 대사 상태 조회.", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22850,10 +26789,20 @@ const SVC_SCREENS = [ "svc": "RC_SUMCHK", "desc": "업무: 요약 대 실측 정합성 검증.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_ARG1", "T_ARG2" ] @@ -22923,10 +26872,19 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_PURCHASE_ID", "T_DELTA", - "T_ARG1" + "T_ARG1", + "T_RC" ], "out": [ - "T_RC" + "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -22965,11 +26923,20 @@ const SVC_SCREENS = [ "svc": "RC_UNDERAMT", "desc": "업무: 과소 차이 분석: 당일 rc_diff 중 실제가 기대에 미달(diff_amt>0)한 과소 건수/합계.", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4", "T_DELTA" ] }, @@ -22979,11 +26946,20 @@ const SVC_SCREENS = [ "svc": "RC_UNMATCH", "desc": "업무: 미대사 건수 조회. (KEEP)", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", - "T_COUNT" + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_GROSS", + "T_COUNT", + "T_ARG3", + "T_AMT2", + "T_ARG4" ] }, { @@ -23055,10 +27031,25 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_NET", "T_MERCHANT", - "T_BIZDATE" + "T_BIZDATE", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_COUNT", + "T_GROSS", + "T_STATUS", + "T_DELTA" ], "out": [ - "T_SETTLE_ID" + "T_SETTLE_ID", + "T_PURCHASE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_RC", + "T_COUNT", + "T_GROSS" ] }, { @@ -23110,7 +27101,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -23119,7 +27113,14 @@ const SVC_SCREENS = [ "T_DELTA", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -23139,7 +27140,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -23148,7 +27152,14 @@ const SVC_SCREENS = [ "T_DELTA", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -23228,14 +27239,25 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ARG6", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -23255,14 +27277,24 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ARG6", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT" ] }, { @@ -23434,14 +27466,24 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ARG6", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -23490,7 +27532,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -23502,7 +27547,11 @@ const SVC_SCREENS = [ "T_GROSS", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_NET" ] }, { @@ -23606,7 +27655,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -23614,7 +27666,13 @@ const SVC_SCREENS = [ "T_ID1", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT" ] }, { @@ -23695,14 +27753,25 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ARG6", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -23751,7 +27820,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -23759,7 +27831,14 @@ const SVC_SCREENS = [ "T_NET", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -23975,7 +28054,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -23984,7 +28066,12 @@ const SVC_SCREENS = [ "T_GROSS", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -24149,7 +28236,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -24158,7 +28248,13 @@ const SVC_SCREENS = [ "T_NET", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_COUNT", + "T_GROSS" ] }, { @@ -24623,7 +28719,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -24631,7 +28730,13 @@ const SVC_SCREENS = [ "T_ID1", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT" ] }, { @@ -24651,14 +28756,23 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ARG6", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT" ] }, { @@ -24705,7 +28819,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -24713,7 +28830,14 @@ const SVC_SCREENS = [ "T_ID1", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA", + "T_COUNT" ] }, { @@ -24765,7 +28889,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -24774,7 +28901,12 @@ const SVC_SCREENS = [ "T_GROSS", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -24823,7 +28955,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -24834,7 +28969,12 @@ const SVC_SCREENS = [ "T_GROSS", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -24901,9 +29041,25 @@ const SVC_SCREENS = [ "in": [ "T_PURCHASE_ID", "T_FEE", - "T_BIZDATE" + "T_BIZDATE", + "T_SETTLE_ID", + "T_AMOUNT", + "T_NET", + "T_COUNT", + "T_GROSS", + "T_MERCHANT", + "T_STATUS" ], - "out": [] + "out": [ + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_RC", + "T_COUNT", + "T_GROSS" + ] }, { "mod": "st", @@ -25097,7 +29253,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -25106,7 +29265,12 @@ const SVC_SCREENS = [ "T_GROSS", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -25126,7 +29290,11 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS", + "T_ARG1" ], "out": [ "T_RC", @@ -25134,7 +29302,14 @@ const SVC_SCREENS = [ "T_ID1", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_ARG1", + "T_COUNT" ] }, { @@ -25154,7 +29329,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -25163,7 +29341,14 @@ const SVC_SCREENS = [ "T_DELTA", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -25267,7 +29452,11 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS", + "T_ARG1" ], "out": [ "T_RC", @@ -25275,7 +29464,14 @@ const SVC_SCREENS = [ "T_ID1", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_ARG1", + "T_COUNT" ] }, { @@ -25381,14 +29577,24 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ARG6", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -25466,7 +29672,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -25475,7 +29684,13 @@ const SVC_SCREENS = [ "T_ID1", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_NET", + "T_DELTA", + "T_COUNT" ] }, { @@ -25678,7 +29893,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -25686,7 +29904,14 @@ const SVC_SCREENS = [ "T_NET", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_DELTA", + "T_COUNT", + "T_GROSS" ] }, { @@ -25824,7 +30049,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -25833,7 +30061,14 @@ const SVC_SCREENS = [ "T_DELTA", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -25911,14 +30146,23 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ARG6", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT" ] }, { @@ -26025,7 +30269,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -26036,7 +30283,13 @@ const SVC_SCREENS = [ "T_GROSS", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_DELTA" ] }, { @@ -26319,7 +30572,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -26330,7 +30586,12 @@ const SVC_SCREENS = [ "T_GROSS", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -26588,7 +30849,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -26598,7 +30862,13 @@ const SVC_SCREENS = [ "T_FEE", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_NET", + "T_DELTA", + "T_COUNT" ] }, { @@ -26618,7 +30888,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -26628,7 +30901,12 @@ const SVC_SCREENS = [ "T_FEE", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_NET", + "T_COUNT" ] }, { @@ -26710,14 +30988,24 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", "T_ARG6", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET", + "T_COUNT", + "T_GROSS" ] }, { @@ -26766,7 +31054,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -26776,7 +31067,13 @@ const SVC_SCREENS = [ "T_FEE", "T_GROSS", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_NET", + "T_DELTA", + "T_COUNT" ] }, { @@ -26885,7 +31182,10 @@ const SVC_SCREENS = [ "T_PURCHASE_ID", "T_SETTLE_ID", "T_ARG2", - "T_CHANNEL" + "T_CHANNEL", + "T_COUNT", + "T_GROSS", + "T_STATUS" ], "out": [ "T_RC", @@ -26894,7 +31194,12 @@ const SVC_SCREENS = [ "T_GROSS", "T_ARG3", "T_ARG5", - "T_ARG4" + "T_ARG4", + "T_PURCHASE_ID", + "T_SETTLE_ID", + "T_AMOUNT", + "T_FEE", + "T_NET" ] }, { @@ -26940,7 +31245,10 @@ const SVC_SCREENS = [ "svc": "VL_AMOUNT", "desc": "기능: 금액 유효성(0 daily_limit → RC 1, 3=가맹점 없음).", "in": [ "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -27448,8 +31803,8 @@ const SVC_SCREENS = [ "T_AMT3", "T_ARG6", "T_ARG2", - "T_ARG1", "T_AMT1", + "T_ARG1", "T_GROSS", "T_DELTA" ] @@ -27462,7 +31817,9 @@ const SVC_SCREENS = [ "in": [ "T_BIZDATE", "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -27472,6 +31829,7 @@ const SVC_SCREENS = [ "T_AMT3", "T_ARG6", "T_ARG2", + "T_AMT1", "T_ARG1", "T_COUNT" ] @@ -27483,7 +31841,8 @@ const SVC_SCREENS = [ "desc": "기능: 중복 승인 검출 건별 (동일 매입 승인가결 2건 이상, RC 1=중복; 검증로그 기록).", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", @@ -27492,6 +31851,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -27502,7 +31863,9 @@ const SVC_SCREENS = [ "svc": "VL_DUPAUTH", "desc": "기능: 중복 승인 검증 (approval 2건 이상 → RC 1).", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -27511,6 +31874,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -27521,7 +31886,9 @@ const SVC_SCREENS = [ "svc": "VL_DUPLEDGR", "desc": "기능: 중복 원장 엔트리 검출 (동일 매입+엔트리유형 최대 그룹 건수>1, RC 1=중복).", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -27530,6 +31897,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -27541,7 +31910,8 @@ const SVC_SCREENS = [ "desc": "기능: 건별 중복지급 검출 (ledger XFER 엔트리 2건 이상 → RC 1, 검증로그 기록).", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", @@ -27550,6 +31920,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_GROSS" @@ -27579,7 +31951,9 @@ const SVC_SCREENS = [ "svc": "VL_DUPPURCH", "desc": "기능: 중복 매입 검출 건별 (동일 가맹점+금액+영업일의 타 매입 존재, RC 1=중복).", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -27588,6 +31962,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -27599,7 +31975,9 @@ const SVC_SCREENS = [ "desc": "기능: 건별 중복 정산 검출 (동일 매입에 정산 2건 이상 → RC 1, 최초/최종 정산 ID 반환).", "in": [ "T_PURCHASE_ID", - "T_ID1" + "T_ID1", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -27608,6 +31986,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_NET", @@ -27643,6 +32023,8 @@ const SVC_SCREENS = [ "desc": "기능: 카드 유효기간(YYYYMM) vs 영업일 검증 (RC 1=만료).", "in": [ "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID", "T_STR2" ], "out": [ @@ -27651,6 +32033,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1" ] }, @@ -27660,7 +32044,9 @@ const SVC_SCREENS = [ "svc": "VL_FEE", "desc": "기능: 수수료 재계산 정합 검증 (저장 fee vs MDR 재계산, RC 1=불일치).", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -27669,6 +32055,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_FEE", "T_DELTA" @@ -27721,6 +32109,8 @@ const SVC_SCREENS = [ "desc": "기능: 수수료 재계산 검증 (가맹점 요율 mdr_bps로 기대수수료 재산출, |fee-기대|>허용오차 → RC 1, 3=매입/가맹점 없음).", "in": [ "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE", "T_ARG1" ], "out": [ @@ -27730,8 +32120,9 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", - "T_FEE", "T_AMT1", + "T_AMT3", + "T_FEE", "T_DELTA" ] }, @@ -27741,7 +32132,10 @@ const SVC_SCREENS = [ "svc": "VL_FORMAT", "desc": "기능: 가맹점ID 형식(길이 4~16) 검증 (RC 1=형식 위반).", "in": [ - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" ], "out": [ "T_RC", @@ -27751,6 +32145,7 @@ const SVC_SCREENS = [ "T_AMT3", "T_ARG6", "T_ARG2", + "T_AMT1", "T_ARG1", "T_COUNT" ] @@ -27762,6 +32157,8 @@ const SVC_SCREENS = [ "desc": "기능: 해외 매입 환산 정합 검증 (krw vs fx*rate_bps/10000, 오차>T_ARG1 → RC 1, 2=해외 내역 없음).", "in": [ "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE", "T_ARG1" ], "out": [ @@ -27771,8 +32168,9 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", - "T_FX_AMT", "T_AMT1", + "T_AMT3", + "T_FX_AMT", "T_DELTA" ] }, @@ -27822,7 +32220,9 @@ const SVC_SCREENS = [ "svc": "VL_LEDGBAL", "desc": "기능: 일자별 원장 대차 정합 검증 (차변 RECON 합 vs 대변 SETTLE+XFER 합, RC 1=대차 불일치).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -27830,8 +32230,9 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", - "T_ARG1", "T_AMT1", + "T_AMT3", + "T_ARG1", "T_AMT2", "T_COUNT", "T_DELTA" @@ -27865,7 +32266,9 @@ const SVC_SCREENS = [ "desc": "기능: 건별 원장 대사 엔트리 검증 (purchase.amount vs ledger RECON 합, RC 1=금액불일치 2=원장없음 3=매입없음", "in": [ "T_PURCHASE_ID", - "T_AMOUNT" + "T_AMOUNT", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -27874,9 +32277,10 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_AMOUNT", - "T_AMT1", "T_COUNT" ] }, @@ -27887,7 +32291,8 @@ const SVC_SCREENS = [ "desc": "기능: 원장 합계 정합 검증 (sum(ledger) vs purchase.net, RC 1=불일치).", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", @@ -27897,6 +32302,8 @@ const SVC_SCREENS = [ "T_ARG6", "T_ID2", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_GROSS" ] @@ -27908,7 +32315,10 @@ const SVC_SCREENS = [ "desc": "기능: 매입금액 vs 가맹점 일한도 검증 (RC 1=초과).", "in": [ "T_MERCHANT", - "T_AMOUNT" + "T_AMOUNT", + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" ], "out": [ "T_RC", @@ -27918,6 +32328,7 @@ const SVC_SCREENS = [ "T_AMT3", "T_ARG6", "T_ARG2", + "T_AMT1", "T_ARG1" ] }, @@ -27988,13 +32399,19 @@ const SVC_SCREENS = [ "modnm": "정합성검증", "svc": "VL_MDRRATE", "desc": "기능: 가맹점 요율 위반 검출 (mdr_bps<0 또는 규칙 MDR_MAX 초과, RC 1=위반 존재).", - "in": [], + "in": [ + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" + ], "out": [ "T_RC", "T_ARG8", "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -28024,7 +32441,9 @@ const SVC_SCREENS = [ "svc": "VL_NEGBAL", "desc": "기능: 마이너스 잔액 가맹점 검출 (merchant_summary.net_amount<0, RC 1=존재; 최악치 반환).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28032,9 +32451,10 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", - "T_COUNT", - "T_AMT1" + "T_COUNT" ] }, { @@ -28044,7 +32464,9 @@ const SVC_SCREENS = [ "desc": "기능: 음수 수수료 매입 검출 (일자별 fee<0 매입 수, RC 1=존재; 최소 매입ID 반환).", "in": [ "T_BIZDATE", - "T_ID1" + "T_ID1", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28052,6 +32474,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_ID1" @@ -28063,7 +32487,9 @@ const SVC_SCREENS = [ "svc": "VL_NEGNET", "desc": "기능: 일자별 음수 순액/역전 수수료 매입 검출 (net<0, fee<0, fee>amount, RC 1=존재).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28071,6 +32497,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -28082,6 +32510,8 @@ const SVC_SCREENS = [ "desc": "기능: 심야 거래 패턴 탐지 (0-6시 거래 비중>=T_ARG1% 기본20, RC 1=편중).", "in": [ "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID", "T_ARG1" ], "out": [ @@ -28090,6 +32520,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_COUNT", "T_ARG3" ] @@ -28101,6 +32533,8 @@ const SVC_SCREENS = [ "desc": "기능: 이상치 매입 탐지 (금액>당일 평균*배수 T_ARG1 기본4 건수, RC 1=존재).", "in": [ "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID", "T_ARG1" ], "out": [ @@ -28109,6 +32543,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_COUNT" ] }, @@ -28118,7 +32554,9 @@ const SVC_SCREENS = [ "svc": "VL_OVERLIMIT", "desc": "기능: 가맹점 한도위반 검출 (일 매입합>일한도 가맹점 수, RC 1=존재).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28126,6 +32564,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -28137,7 +32577,9 @@ const SVC_SCREENS = [ "desc": "기능: 무승인 매입 검출 (일자별 승인 전무 매입 수, 취소분 제외, RC 1=존재).", "in": [ "T_BIZDATE", - "T_ID1" + "T_ID1", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28145,6 +32587,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_ID1" @@ -28175,7 +32619,9 @@ const SVC_SCREENS = [ "svc": "VL_REFINTEG", "desc": "기능: 참조무결성(purchase.merchant_id ∈ merchant) 검증.", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -28184,6 +32630,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1" ] }, @@ -28231,13 +32679,19 @@ const SVC_SCREENS = [ "modnm": "정합성검증", "svc": "VL_RIAPPR", "desc": "기능: 참조무결성 승인 (취소/무효 매입에 승인가결 존재 건수, RC 1=위반).", - "in": [], + "in": [ + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" + ], "out": [ "T_RC", "T_ARG8", "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -28248,7 +32702,9 @@ const SVC_SCREENS = [ "svc": "VL_RICANCEL", "desc": "기능: 참조무결성 취소 (일자별 매입 원거래 없는 취소 수, RC 1=위반; 최소 취소ID 반환).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28256,6 +32712,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_CANCEL_ID" @@ -28266,16 +32724,21 @@ const SVC_SCREENS = [ "modnm": "정합성검증", "svc": "VL_RIFX", "desc": "기능: 참조무결성 해외 (매입 원거래 없는 해외 내역 수+환산합, RC 1=위반).", - "in": [], + "in": [ + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" + ], "out": [ "T_RC", "T_ARG8", "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", - "T_COUNT", - "T_AMT1" + "T_COUNT" ] }, { @@ -28283,13 +32746,19 @@ const SVC_SCREENS = [ "modnm": "정합성검증", "svc": "VL_RIINSTALL", "desc": "기능: 참조무결성 할부 (매입 원거래 없는 할부 내역 수, NOT IN, RC 1=위반).", - "in": [], + "in": [ + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" + ], "out": [ "T_RC", "T_ARG8", "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -28300,7 +32769,9 @@ const SVC_SCREENS = [ "svc": "VL_RILEDGER", "desc": "기능: 참조무결성 세분 검증 - 원장→매입 고아 엔트리 (RC 비트합 1=RECON 2=SETTLE 4=XFER 고아).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28308,6 +32779,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_ARG3", "T_COUNT" @@ -28320,7 +32793,9 @@ const SVC_SCREENS = [ "desc": "기능: 참조무결성 세분 검증 - 매입→가맹점 (일자별 고아 매입 수, RC 1=고아 존재).", "in": [ "T_BIZDATE", - "T_ID1" + "T_ID1", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28328,6 +32803,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_ID1" @@ -28339,7 +32816,10 @@ const SVC_SCREENS = [ "svc": "VL_RIPAY", "desc": "기능: 참조무결성 지급 (지급 XFER 원장의 매입 원거래 부재 건수, RC 1=위반).", "in": [ - "T_ID1" + "T_ID1", + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" ], "out": [ "T_RC", @@ -28347,6 +32827,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_ID1" @@ -28359,7 +32841,9 @@ const SVC_SCREENS = [ "desc": "기능: 참조무결성 세분 검증 - 정산→매입 (일자별 고아 정산 수/금액, RC 1=고아 존재).", "in": [ "T_BIZDATE", - "T_ID1" + "T_ID1", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28367,6 +32851,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_ID1", @@ -28380,7 +32866,8 @@ const SVC_SCREENS = [ "desc": "기능: 참조무결성 세분 검증 - 정산 가맹점 불일치 (settlement.merchant_id <> purchase.merchant_id, RC", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", @@ -28389,6 +32876,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT", "T_PURCHASE_ID" @@ -28399,13 +32888,19 @@ const SVC_SCREENS = [ "modnm": "정합성검증", "svc": "VL_RITAXINV", "desc": "기능: 참조무결성 세금계산서 (매입 원거래 없는 세금계산서 수, LEFT JOIN, RC 1=위반).", - "in": [], + "in": [ + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" + ], "out": [ "T_RC", "T_ARG8", "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -28655,7 +33150,8 @@ const SVC_SCREENS = [ "desc": "기능: 매입 원거래 존재 검증 (RC 1=미존재).", "in": [ "T_BIZDATE", - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC" ], "out": [ "T_RC", @@ -28664,6 +33160,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1" ] }, @@ -28673,7 +33171,9 @@ const SVC_SCREENS = [ "svc": "VL_SETTLE", "desc": "기능: 정산금액 정합 검증 (settlement.net vs purchase.net, RC 1=불일치).", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -28682,6 +33182,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_NET" ] @@ -28712,6 +33214,8 @@ const SVC_SCREENS = [ "desc": "기능: 금액 급증 탐지 (당일 최대 매입>평균*배수 T_ARG1 기본5, RC 1=급증).", "in": [ "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID", "T_ARG1" ], "out": [ @@ -28721,6 +33225,7 @@ const SVC_SCREENS = [ "T_ARG6", "T_ARG2", "T_AMT1", + "T_AMT3", "T_AMT2", "T_COUNT" ] @@ -28766,7 +33271,9 @@ const SVC_SCREENS = [ "svc": "VL_STATUS_CHK", "desc": "기능: 매입 상태 유효값 검증 (허용집합 밖 → RC 1).", "in": [ - "T_PURCHASE_ID" + "T_PURCHASE_ID", + "T_RC", + "T_BIZDATE" ], "out": [ "T_RC", @@ -28775,6 +33282,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1" ] }, @@ -28809,7 +33318,9 @@ const SVC_SCREENS = [ "svc": "VL_SUMFEECHK", "desc": "기능: 통계-원천 수수료 대사 (일자별 가맹점 수수료 집계 vs 원천 합 불일치 수, RC 1=존재).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28817,6 +33328,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ] @@ -28828,7 +33341,9 @@ const SVC_SCREENS = [ "desc": "기능: 통계-원천 총액 대사 (merchant_summary 총액 vs 원천 매입금액 합, RC 1=불일치 8=통계없음).", "in": [ "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28838,9 +33353,9 @@ const SVC_SCREENS = [ "T_AMT3", "T_ARG6", "T_ARG2", + "T_AMT1", "T_ARG1", "T_GROSS", - "T_AMT1", "T_DELTA" ] }, @@ -28891,7 +33406,9 @@ const SVC_SCREENS = [ "desc": "기능: 통계-원천 대사 검증 (merchant_summary 건수/총액 vs purchase 재집계, RC 비트합 1=건수 2=총액, 8=통계 ", "in": [ "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28901,10 +33418,10 @@ const SVC_SCREENS = [ "T_AMT3", "T_ARG6", "T_ARG2", + "T_AMT1", "T_ARG1", "T_COUNT", - "T_GROSS", - "T_AMT1" + "T_GROSS" ] }, { @@ -28914,7 +33431,9 @@ const SVC_SCREENS = [ "desc": "기능: 통계-원천 건수 대사 (merchant_summary 건수 vs 원천 매입 건수, RC 1=불일치 8=통계없음).", "in": [ "T_BIZDATE", - "T_MERCHANT" + "T_MERCHANT", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -28924,6 +33443,7 @@ const SVC_SCREENS = [ "T_AMT3", "T_ARG6", "T_ARG2", + "T_AMT1", "T_ARG1", "T_COUNT", "T_DELTA" @@ -28956,6 +33476,7 @@ const SVC_SCREENS = [ "T_BIZDATE", "T_PURCHASE_ID", "T_ID1", + "T_RC", "T_REASON" ], "out": [ @@ -28965,6 +33486,8 @@ const SVC_SCREENS = [ "T_ARG4", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_PURCHASE_ID" ] @@ -29028,7 +33551,10 @@ const SVC_SCREENS = [ "svc": "VL_SUSPESCAL", "desc": "기능: 의심거래 상향 (WARN→ERROR→CRIT 단계 승격, RC 1=상향불가 3=미존재).", "in": [ - "T_ID1" + "T_ID1", + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" ], "out": [ "T_RC", @@ -29036,6 +33562,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1" ] }, @@ -29207,7 +33735,10 @@ const SVC_SCREENS = [ "desc": "기능: 규칙 임계치 검사 (dbio get_rule; amount>threshold → RC 1).", "in": [ "T_AMOUNT", - "T_STR3" + "T_STR3", + "T_RC", + "T_PURCHASE_ID", + "T_BIZDATE" ], "out": [ "T_RC", @@ -29215,6 +33746,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1" ] }, @@ -29414,6 +33947,8 @@ const SVC_SCREENS = [ "desc": "기능: 거래 속도 이상 탐지 (당일 매입 건수>T_ARG1 기본100 가맹점 수, RC 1=존재).", "in": [ "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID", "T_ARG1" ], "out": [ @@ -29422,6 +33957,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_COUNT" ] }, @@ -29431,7 +33968,9 @@ const SVC_SCREENS = [ "svc": "VL_ZERONET", "desc": "기능: 정산순액 소실 검출 (금액>0인데 순액=0 매입 수, RC 1=존재).", "in": [ - "T_BIZDATE" + "T_BIZDATE", + "T_RC", + "T_PURCHASE_ID" ], "out": [ "T_RC", @@ -29439,6 +33978,8 @@ const SVC_SCREENS = [ "T_ARG5", "T_ARG6", "T_ARG2", + "T_AMT1", + "T_AMT3", "T_ARG1", "T_COUNT" ]