/* @tier hard @module rc @transform reconciliation-batch */ /* * rc_bt_0006.pgc - 건수 불일치 검출 배치 (RC_BT_0006) * * 지정 영업일의 상태별 건수를 집계하여 대사 정합성을 점검하는 * 읽기전용(리포트 전용) 배치이다. 커서/갱신을 사용하지 않고 표준 * DBIO API rc_rec_count() 만으로 상태별 건수를 조회한다. * 업무규칙: 접수('R') 잔량이 남아 있으면 아직 대사가 완료되지 않은 * 것으로 보아 '미처리' 로 판정한다. * * 실행: rc_bt_0006 [db@host] */ #include #include #include #include "txcore.h" #include "txcore_dbio.h" #include "acq_util.h" #include "rc_core.h" EXEC SQL INCLUDE sqlca; static int run_rc_bt_0006(const char *biz_date) { EXEC SQL BEGIN DECLARE SECTION; char h_bd[9]; long h_db_total; long h_db_unmatch; long h_db_sum; EXEC SQL END DECLARE SECTION; long cntR, cntM, cntU, cntS; long total, processed; long proc_rate, settle_rate, fail_rate; int mismatch; strncpy(h_bd, biz_date, sizeof(h_bd) - 1); h_bd[sizeof(h_bd) - 1] = '\0'; /* 상태별 건수 조회 (읽기전용) */ cntR = rc_rec_count(biz_date, RC_ST_RECV); cntM = rc_rec_count(biz_date, RC_ST_DONE); cntU = rc_rec_count(biz_date, RC_ST_FAIL); cntS = rc_rec_count(biz_date, RC_ST_SETTLED); if (cntR < 0) { tx_log(TX_LOG_ERROR, "[rc_bt_0006] 접수(R) 건수 조회 실패 date=%s", biz_date); return TX_EDB; } if (cntM < 0) { tx_log(TX_LOG_ERROR, "[rc_bt_0006] 매입확정(M) 건수 조회 실패 date=%s", biz_date); return TX_EDB; } if (cntU < 0) { tx_log(TX_LOG_ERROR, "[rc_bt_0006] 불일치(U) 건수 조회 실패 date=%s", biz_date); return TX_EDB; } if (cntS < 0) { tx_log(TX_LOG_ERROR, "[rc_bt_0006] 정산(S) 건수 조회 실패 date=%s", biz_date); return TX_EDB; } total = cntR + cntM + cntU + cntS; processed = cntM + cntU + cntS; mismatch = (cntR > 0) ? 1 : 0; /* 처리율/정산율/불일치율 (백분율, 정수 반올림) */ if (total > 0) { proc_rate = (processed * 100) / total; settle_rate = (cntS * 100) / total; fail_rate = (cntU * 100) / total; } else { proc_rate = settle_rate = fail_rate = 0; } tx_log(TX_LOG_INFO, "[rc_bt_0006] 요약 date=%s 합계=%ld 처리=%ld 미처리여부=%d", biz_date, total, processed, mismatch); printf("======= 건수 불일치 검출 배치 [rc_bt_0006] =======\n"); printf(" 영업일 : %s\n", biz_date); printf(" ----------------------------------------\n"); printf(" 접수(R) : %ld\n", cntR); printf(" 매입확정(M) : %ld\n", cntM); printf(" 불일치(U) : %ld\n", cntU); printf(" 정산(S) : %ld\n", cntS); printf(" ----------------------------------------\n"); printf(" 합계 : %ld\n", total); printf(" 처리 완료 : %ld\n", processed); printf(" 처리율(%%) : %ld\n", proc_rate); printf(" 정산율(%%) : %ld\n", settle_rate); printf(" 불일치율(%%) : %ld\n", fail_rate); printf(" 미처리 여부 : %s\n", mismatch ? "미처리(접수 잔량)" : "완료"); printf("===============================================\n"); /* 원장에서 직접 총건수/불일치건수/총금액을 임베디드 SQL 로 교차집계 */ h_db_total = 0; h_db_unmatch = 0; h_db_sum = 0; EXEC SQL SELECT COUNT(*), COALESCE(SUM(amount), 0) INTO :h_db_total, :h_db_sum FROM rc_ledger WHERE biz_date = :h_bd; if (sqlca.sqlcode != TX_SQL_OK && sqlca.sqlcode != TX_SQL_NOTFOUND) { TX_DBIO_LOG_ERR("SELECT rc_ledger dbtotal (rc_bt_0006)"); return TX_EDB; } EXEC SQL SELECT COUNT(*) INTO :h_db_unmatch FROM rc_ledger WHERE biz_date = :h_bd AND status = 'U'; if (sqlca.sqlcode != TX_SQL_OK && sqlca.sqlcode != TX_SQL_NOTFOUND) { TX_DBIO_LOG_ERR("SELECT rc_ledger unmatch (rc_bt_0006)"); return TX_EDB; } printf("------- 원장 직접 교차집계 (rc_bt_0006) -------\n"); printf(" DB 총건수 : %ld\n", h_db_total); printf(" DB 불일치건수 : %ld\n", h_db_unmatch); printf(" DB 총금액 : %ld\n", h_db_sum); if (h_db_total != total) tx_log(TX_LOG_WARN, "[rc_bt_0006] 집계 교차검증 상이 count=%ld db=%ld", total, h_db_total); printf("===============================================\n"); return TX_OK; } int main(int argc, char **argv) { const char *biz_date; const char *target; int rc; tx_set_loglevel(TX_LOG_INFO); if (argc < 2) { fprintf(stderr, "사용법: %s [db@host]\n", argv[0]); return 2; } biz_date = argv[1]; target = (argc >= 3) ? argv[2] : NULL; if (!date_is_valid(biz_date)) { fprintf(stderr, "오류: 유효하지 않은 영업일 '%s'\n", biz_date); return 2; } tx_log(TX_LOG_INFO, "[rc_bt_0006] 배치 시작 date=%s", biz_date); rc = rc_dbio_connect(target); if (rc != TX_OK) { tx_log(TX_LOG_ERROR, "[rc_bt_0006] DB 접속 실패 rc=%d", rc); return 1; } rc = run_rc_bt_0006(biz_date); rc_dbio_disconnect(); tx_log(TX_LOG_INFO, "[rc_bt_0006] 배치 종료 rc=%d(%s)", rc, tx_strerror(rc)); return (rc == TX_OK) ? 0 : 1; }