/*==========================================================================*/
/*  PAY_FILEGEN.pc  -  지급파일 생성 배치 (As-Is 원본, Oracle Pro*C)          */
/*--------------------------------------------------------------------------*/
/*  대상 : BC 매입시스템 / 지급(펌뱅킹) 파일 생성 배치 PAYFGEN                 */
/*  DBMS : Oracle 19c   전처리 : Pro*C/C++ (proc)                            */
/*  실행 : payfgen <YYYYMMDD>   (인자 생략시 SYSDATE)                         */
/*  기능 : 당일 승인(A) 지급건을 커서로 스윕하여 py_file 헤더 채번 +          */
/*         평문 지급레코드를 UTL_FILE 로 디스크 파일에 기록(펌뱅킹 규격).      */
/*  ※ 이 파일은 **As-Is 역사 원본**이다. 현행 오픈스택 이식본은               */
/*     app/src/py/svc/PAY_FILEGEN.pgc (ECPG/PostgreSQL, Tuxedo 서비스화;      */
/*     디스크 I/O 는 별도 xfer 로 분리됨). 컴파일 대상 아님(빌드 제외).        */
/*--------------------------------------------------------------------------*/
/*  변경이력                                                                  */
/*   2000.07.03  KIM K.H   최초작성 (전은행 공통 지급파일 EBCDIC->ASCII)       */
/*   2006.12.20  PARK J.S  정책 파라미터(cm_param) 기반 최대건수 분할          */
/*   2013.04.09  LEE S.W   UTL_FILE 로 헤더/명세/트레일러 3레코드 규격화        */
/*   2019.09.01  CHOI H.W  Oracle 11g -> 19c, CHAR->VARCHAR2 정비             */
/*==========================================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

EXEC SQL INCLUDE sqlca;
EXEC SQL INCLUDE oraca;
EXEC ORACLE OPTION (ORACA=YES);

EXEC SQL BEGIN DECLARE SECTION;
    VARCHAR   h_user[32];
    VARCHAR   h_pass[32];
    VARCHAR   h_dbstr[32];
    VARCHAR   h_bizdate[9];       /* YYYYMMDD */
    VARCHAR   h_fname[64];
    VARCHAR   h_dir[32];
    VARCHAR   h_bankcd[4];
    VARCHAR   h_acctno[20];
    VARCHAR   h_merch[16];
    VARCHAR   h_line[256];
    VARCHAR   h_pval[16];
    long      h_fileid;
    long      h_payid;
    long      h_amount;
    long      h_fee;
    long      h_net;
    long      h_reccnt;
    long      h_totamt;
    long      h_thr;
    long      h_seq;
EXEC SQL END DECLARE SECTION;

/* 당일 승인(A) 지급 대상 커서 — 계좌 마스터 외부조인으로 은행/계좌 획득 */
EXEC SQL DECLARE cur_pay CURSOR FOR
    SELECT p.payout_id,
           p.merchant_id,
           NVL(a.bank_code, '000'),
           NVL(a.account_no, 'X'),
           NVL(p.amount, 0),
           NVL(p.fee,    0),
           NVL(p.net,    0)
      FROM py_payout p, py_account a
     WHERE a.merchant_id (+) = p.merchant_id
       AND p.biz_date         = TO_DATE(:h_bizdate,'YYYYMMDD')
       AND p.status           = 'A'
     ORDER BY p.merchant_id, p.payout_id;

static void sql_error(const char *stage);

int main(int argc, char **argv)
{
    int done = 0;

    strcpy((char *)h_user.arr,  "pybatch");  h_user.len  = strlen((char *)h_user.arr);
    strcpy((char *)h_pass.arr,  "pybatch");  h_pass.len  = strlen((char *)h_pass.arr);
    strcpy((char *)h_dbstr.arr, "ACQPRD");   h_dbstr.len = strlen((char *)h_dbstr.arr);

    EXEC SQL WHENEVER SQLERROR GOTO connect_err;
    EXEC SQL CONNECT :h_user IDENTIFIED BY :h_pass USING :h_dbstr;
    EXEC SQL WHENEVER SQLERROR GOTO sqlfail;

    /* ---- 1) 영업일 결정 -------------------------------------------- */
    if (argc >= 2) {
        strncpy((char *)h_bizdate.arr, argv[1], 8);
        h_bizdate.arr[8] = '\0';
        h_bizdate.len = strlen((char *)h_bizdate.arr);
    } else {
        EXEC SQL SELECT TO_CHAR(SYSDATE,'YYYYMMDD') INTO :h_bizdate FROM DUAL;
    }
    printf("[PAY_FILEGEN] 지급파일 생성 개시 bizdate=%.8s\n", h_bizdate.arr);

    /* ---- 2) 편성 대상 사전집계 (건수/총액) ------------------------- */
    EXEC SQL
        SELECT COUNT(*), NVL(SUM(net), 0)
          INTO :h_reccnt, :h_totamt
          FROM py_payout
         WHERE biz_date = TO_DATE(:h_bizdate,'YYYYMMDD')
           AND status   = 'A';
    if (h_reccnt == 0) {
        printf("[PAY_FILEGEN] 편성 대상 승인건 없음 - 파일생성 생략\n");
        EXEC SQL ROLLBACK WORK RELEASE;
        return 0;
    }
    if (h_totamt <= 0) {
        fprintf(stderr, "[PAY_FILEGEN] 편성 총액 비정상 amt=%ld\n", h_totamt);
        EXEC SQL ROLLBACK WORK RELEASE;
        return 4;
    }

    /* ---- 3) 정책 파라미터 조회 (최대 레코드수) — NVL 널가드 --------- */
    EXEC SQL
        SELECT NVL(MAX(param_val), '100000')
          INTO :h_pval
          FROM cm_param
         WHERE param_key = 'pay_filegen_max_rec';
    h_thr = atol((char *)h_pval.arr);
    if (h_thr <= 0) h_thr = 100000;
    if (h_reccnt > h_thr) {
        fprintf(stderr, "[PAY_FILEGEN] 최대 레코드수 초과 %ld > %ld - 분할 필요\n",
                h_reccnt, h_thr);
        EXEC SQL ROLLBACK WORK RELEASE;
        return 5;
    }

    /* ---- 4) 파일 채번 및 헤더행 적재 (시퀀스 .NEXTVAL) ------------- */
    EXEC SQL SELECT py_file_seq.NEXTVAL INTO :h_fileid FROM DUAL;
    sprintf((char *)h_fname.arr, "PAYOUT_%.8s_%ld.dat",
            h_bizdate.arr, h_fileid);
    h_fname.len = strlen((char *)h_fname.arr);
    strcpy((char *)h_dir.arr, "PAYOUT_OUT");   /* DIRECTORY 객체명 */
    h_dir.len = strlen((char *)h_dir.arr);

    EXEC SQL
        INSERT INTO py_file
               (file_id, biz_date, file_name, record_count, total_amount, status, created_at)
        VALUES (:h_fileid, TO_DATE(:h_bizdate,'YYYYMMDD'), :h_fname,
                :h_reccnt, :h_totamt, 'G', SYSDATE);

    /* UTL_FILE 로 파일 오픈 후 헤더레코드('H') 기록 (PL/SQL 익명블록) */
    EXEC SQL EXECUTE
        BEGIN
            pkg_payfile.open_file(:h_dir, :h_fname);
            pkg_payfile.put_header(:h_bizdate, :h_reccnt, :h_totamt);
        END;
    END-EXEC;

    /* ---- 5) 본처리: 지급건 커서 루프 + 명세레코드('D') 기록 -------- */
    h_seq = 0;
    EXEC SQL OPEN cur_pay;
    for (;;) {
        EXEC SQL WHENEVER NOTFOUND DO done = 1;
        EXEC SQL FETCH cur_pay
                  INTO :h_payid, :h_merch, :h_bankcd, :h_acctno,
                       :h_amount, :h_fee, :h_net;
        if (done) break;

        h_seq += 1;

        /* 무계좌(외부조인 미스) 건은 파일에서 제외하고 보류 전이 */
        if (strncmp((char *)h_bankcd.arr, "000", 3) == 0) {
            printf("[PAY_FILEGEN] 계좌미등록 payout=%ld merch=%.*s - 보류전이\n",
                   h_payid, h_merch.len, h_merch.arr);
            EXEC SQL
                UPDATE py_payout
                   SET status = 'H', updated_at = SYSDATE
                 WHERE payout_id = :h_payid;
            h_seq -= 1;
            continue;
        }

        /* 펌뱅킹 명세레코드 조립 (고정폭: 구분1 은행3 계좌20 금액13) */
        sprintf((char *)h_line.arr, "D%3.3s%-20.20s%013ld",
                h_bankcd.arr, h_acctno.arr, h_net);
        h_line.len = strlen((char *)h_line.arr);

        EXEC SQL EXECUTE
            BEGIN
                pkg_payfile.put_line(:h_line);
            END;
        END-EXEC;

        /* 지급건을 이 파일로 편성 ('A'->'F') */
        EXEC SQL
            UPDATE py_payout
               SET file_id    = :h_fileid,
                   status     = DECODE(status, 'A', 'F', status),
                   updated_at = SYSDATE
             WHERE payout_id  = :h_payid;

        if (h_seq % 1000 == 0) {
            printf("[PAY_FILEGEN] 진행 %ld건 편성 - 중간커밋\n", h_seq);
            EXEC SQL COMMIT WORK;
        }
    }
    EXEC SQL CLOSE cur_pay;

    /* ---- 6) 트레일러('T') 기록 및 파일 클로즈 --------------------- */
    EXEC SQL EXECUTE
        BEGIN
            pkg_payfile.put_trailer(:h_seq, :h_totamt);
            pkg_payfile.close_file;
        END;
    END-EXEC;

    /* ---- 7) 파일헤더 확정 (실제 기록건수 반영, 'G'->'C') ----------- */
    EXEC SQL
        UPDATE py_file
           SET record_count = :h_seq,
               status       = 'C',
               closed_at    = SYSDATE
         WHERE file_id      = :h_fileid;

    EXEC SQL
        INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date)
        VALUES (cm_log_seq.NEXTVAL, 'PAY_FILEGEN', 'I',
                'PAY_FILEGEN file='||:h_fileid||' name='||:h_fname
                    ||' rec='||:h_seq||' amt='||:h_totamt,
                TO_DATE(:h_bizdate,'YYYYMMDD'));

    /* ---- 8) 최종 커밋 --------------------------------------------- */
    EXEC SQL COMMIT WORK;

    printf("[PAY_FILEGEN] 완료 file=%ld name=%.*s rec=%ld amt=%ld\n",
           h_fileid, h_fname.len, h_fname.arr, h_seq, h_totamt);
    EXEC SQL COMMIT WORK RELEASE;
    return 0;

connect_err:
    fprintf(stderr, "[PAY_FILEGEN] DB 접속 실패: %.70s\n", sqlca.sqlerrm.sqlerrmc);
    return 8;

sqlfail:
    sql_error("지급파일 생성");
    /* UTL_FILE 핸들 정리 (best-effort) */
    EXEC SQL WHENEVER SQLERROR CONTINUE;
    EXEC SQL EXECUTE BEGIN pkg_payfile.close_file; END; END-EXEC;
    EXEC SQL ROLLBACK WORK RELEASE;
    return 12;
}

/*--------------------------------------------------------------------------*/
/*  sql_error  -  오류 로깅 (sqlca/oraca)                                     */
/*--------------------------------------------------------------------------*/
static void sql_error(const char *stage)
{
    fprintf(stderr, "[PAY_FILEGEN] SQL 오류 (%s): %.70s\n",
            stage, sqlca.sqlerrm.sqlerrmc);
    fprintf(stderr, "              sqlcode=%ld rows=%ld\n",
            sqlca.sqlcode, sqlca.sqlerrd[2]);
}
