/*
 * ST_VATADJUST.pgc - st (정산/수수료) 모듈 서비스 ST_VATADJUST (one service = one file).
 * 공급가액 조정 재부가세 기록. (심화판).
 * 심화 온라인 프로그램: 입력검증 -> 마스터/정책 조회 -> 업무규칙 분기 -> 본처리 ->
 * 이력적재 -> 집계 재계산 -> 예외보상 -> 응답 -> 로깅. 호출자의 XA 브랜치에서 수행하며
 * EXEC SQL CONNECT 는 두지 않는다. 진입 서명/서비스명/입출력 계약은 불변.
 */
#include "ST_VATADJUST.h"

/* ST_VATADJUST - 공급가액 조정 재부가세 기록. (심화판). (심화판) */
void ST_VATADJUST(TPSVCINFO *p)
{
    UBFH *b = (UBFH *)p->data;
    /* ---- 지역 스크래치 (DECLARE SECTION 밖에서 초기화) ---- */
    char merch[64], bizdate[16], paydate[16], reason[128], ftype[16];
    char msgbuf[200], ym[16], chan[16];
    long amount, net0, fee0, delta0, tmp;
    int  vstep = 0;

    EXEC SQL BEGIN DECLARE SECTION;
    long h_pid, h_sid, h_amount, h_fee, h_net, h_bps, h_mdr, h_limit;
    long h_cnt, h_sum, h_gmax, h_gmin, h_avg, h_rows, h_id, h_prior;
    long h_delta, h_gross, h_feesum, h_netsum, h_tax, h_days, h_base, h_supply, h_n;
    char h_merch[64], h_bizdate[16], h_paydate[16], h_status[16], h_ftype[16];
    char h_reason[128], h_msg[200], h_svc[24], h_mstatus[16], h_ym[16], h_like[24];
    EXEC SQL END DECLARE SECTION;

    strcpy(h_svc, "ST_VATADJUST");
    h_fee = 0; h_delta = 0; h_id = 0; h_cnt = 0; h_netsum = 0; h_base = 0;
    h_days = 0; h_supply = 0; h_tax = 0; h_gross = 0; h_prior = 0; h_n = 0;
    h_amount = 0; h_net = 0; h_sum = 0; h_gmax = 0; h_gmin = 0; h_avg = 0; h_rows = 0;
    h_feesum = 0;

    /* ===== 1) 입력 검증부 ===== */
    gets_(b, T_MERCHANT, merch, sizeof(merch));
    gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
    gets_(b, T_REASON, reason, sizeof(reason));
    gets_(b, T_STR1, ftype, sizeof(ftype));
    amount = getl(b, T_AMOUNT); net0 = getl(b, T_NET); fee0 = getl(b, T_FEE);
    delta0 = getl(b, T_DELTA); h_pid = getl(b, T_PURCHASE_ID); h_sid = getl(b, T_SETTLE_ID);
    if (bizdate[0] == 0) strcpy(bizdate, "2026-07-20");
    if (ftype[0] == 0)  strcpy(ftype, "VAT");
    if (reason[0] == 0) strcpy(reason, "ST_VATADJUST");
    userlog("[정산심화] 공급가액 조정 재부가세 기록. (심화판) 진입 pid=%ld merch=%s biz=%s", h_pid, merch, bizdate);
    if (amount < 0) { setl(b, T_RC, 11); Bchg(b, T_MSG, 0, "매입 금액은 음수가 될 수 없습니다", 0L); FAIL(b); }
    if (fee0 < 0)   { setl(b, T_RC, 12); Bchg(b, T_MSG, 0, "수수료 입력값이 음수입니다", 0L); FAIL(b); }
    if (strlen(bizdate) < 8) { setl(b, T_RC, 13); Bchg(b, T_MSG, 0, "영업일 형식 오류(YYYY-MM-DD)", 0L); FAIL(b); }
    if (net0 < 0 && fee0 == 0) { setl(b, T_RC, 16); Bchg(b, T_MSG, 0, "정산 금액(net) 음수 입력 불가", 0L); FAIL(b); }
    if (h_sid < 0) { setl(b, T_RC, 17); Bchg(b, T_MSG, 0, "정산 ID(settlement_id) 음수 오류", 0L); FAIL(b); }
    if (delta0 > 100000000 || delta0 < -100000000) { setl(b, T_RC, 18); Bchg(b, T_MSG, 0, "조정 금액 허용범위(±1억) 초과", 0L); FAIL(b); }
    if (merch[0] == 0) { setl(b, T_RC, 14); Bchg(b, T_MSG, 0, "가맹점 ID는 필수입니다", 0L); FAIL(b); }
    if (h_pid <= 0) { setl(b, T_RC, 15); Bchg(b, T_MSG, 0, "매입 ID(purchase_id) 누락", 0L); FAIL(b); }
    strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
    strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
    strncpy(h_ftype, ftype, sizeof(h_ftype)-1); h_ftype[sizeof(h_ftype)-1] = 0;
    strncpy(h_reason, reason, sizeof(h_reason)-1); h_reason[sizeof(h_reason)-1] = 0;
    vstep = 1;

    /* ===== 2) 마스터/정책/상태 조회부 ===== */
    h_mdr = 25; h_limit = 0; strcpy(h_mstatus, "ACTIVE");
    if (merch[0] != 0) {
        EXEC SQL SELECT mdr_bps, daily_limit, status
            INTO :h_mdr, :h_limit, :h_mstatus FROM merchant WHERE merchant_id = :h_merch;
        if (sqlca.sqlcode == 100) { setl(b, T_RC, 21); Bchg(b, T_MSG, 0, "미등록 가맹점입니다", 0L); FAIL(b); }
        if (sqlca.sqlcode < 0)   { setl(b, T_RC, 22); Bchg(b, T_MSG, 0, "가맹점 마스터 조회 오류", 0L); FAIL(b); }
        if (strcmp(h_mstatus, "ACTIVE") != 0) { setl(b, T_RC, 23); Bchg(b, T_MSG, 0, "비활성 가맹점은 정산 불가", 0L); FAIL(b); }
    }
    h_bps = getl(b, T_ARG2); if (h_bps <= 0) h_bps = h_mdr;   /* 계약 요율 우선, 없으면 가맹점 MDR */
    if (h_pid > 0) {
        EXEC SQL SELECT status, coalesce(net,0) INTO :h_status, :h_net
            FROM settlement WHERE purchase_id = :h_pid ORDER BY settlement_id DESC LIMIT 1;
        if (sqlca.sqlcode < 0) { setl(b, T_RC, 24); Bchg(b, T_MSG, 0, "정산 원장 상태 조회 오류", 0L); FAIL(b); }
        if (sqlca.sqlcode == 100) { strcpy(h_status, "NONE"); h_net = 0; }
    } else { strcpy(h_status, "NONE"); }
    vstep = 2;

    /* ===== 2b) 한도/직전 지급잔량 조회부 ===== */
    h_sum = 0; h_avg = 0; h_n = 0; h_gross = 0;
    if (merch[0] != 0) {
        EXEC SQL SELECT coalesce(sum(amount),0) INTO :h_sum FROM purchase
            WHERE merchant_id = :h_merch AND biz_date = :h_bizdate;
        if (sqlca.sqlcode < 0) { setl(b, T_RC, 26); Bchg(b, T_MSG, 0, "당일 매입 누계 조회 오류", 0L); FAIL(b); }
        h_avg = h_limit - h_sum;   /* 일 한도 잔여 */
        if (h_limit > 0 && h_sum > h_limit)
            userlog("[정산심화] 공급가액 조정 재부가세 기록. (심화판) 일 한도 초과 감지 sum=%ld limit=%ld", h_sum, h_limit);
    }
    EXEC SQL SELECT count(*), coalesce(sum(net_amount),0) INTO :h_n, :h_gross
        FROM st_payment WHERE merchant_id = :h_merch AND status = 'SCHEDULED';
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 27); Bchg(b, T_MSG, 0, "예정 지급 잔량 조회 오류", 0L); FAIL(b); }
    setl(b, T_ARG6, h_avg);
    vstep = 3;

    /* ===== 3) 업무규칙 분기부 ===== */
    if (amount >= 10000000) { h_prior = 3; userlog("[정산심화] %s 대액 구간(>=1천만) 처리", "공급가액 조정 재부가세 기록. (심화판)"); }
    else if (amount >= 1000000) { h_prior = 2; userlog("[정산심화] %s 중액 구간 처리", "공급가액 조정 재부가세 기록. (심화판)"); }
    else { h_prior = 1; userlog("[정산심화] %s 소액 구간 처리", "공급가액 조정 재부가세 기록. (심화판)"); }
    gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "POS");
    if (strcmp(chan, "FOREIGN") == 0) { h_prior += 10; userlog("[정산심화] %s 해외 채널 가산 분기", "공급가액 조정 재부가세 기록. (심화판)"); }
    else if (strcmp(chan, "EDI") == 0) { h_prior += 5; userlog("[정산심화] %s EDI 채널 분기", "공급가액 조정 재부가세 기록. (심화판)"); }
    else { userlog("[정산심화] %s 국내 채널 표준 분기", "공급가액 조정 재부가세 기록. (심화판)"); }
    if (h_mdr >= 30) userlog("[정산심화] 공급가액 조정 재부가세 기록. (심화판) 고율 등급 가맹점(bps=%ld)", h_mdr);
    else if (h_mdr <= 20) userlog("[정산심화] 공급가액 조정 재부가세 기록. (심화판) 우대 등급 가맹점(bps=%ld)", h_mdr);
    if (h_bps < 0) h_bps = 0;
    if (h_bps > 1000) { setl(b, T_RC, 33); Bchg(b, T_MSG, 0, "요율(bps) 상한 초과", 0L); FAIL(b); }
    vstep = 3;

    /* ===== 4) 본처리부 ===== */
    h_base = fee0>0?fee0:amount; h_fee = acq_vat(h_base);
    if (h_fee < 0) h_fee = 0;
    userlog("[정산심화] 공급가액 조정 재부가세 기록. (심화판): 부가세 10% 산출 fee=%ld bps=%ld", h_fee, h_bps);
    h_id = stdb_insert_fee_dtl(h_sid, h_pid, merch, "VAT", h_fee, bizdate);
    if (h_id < 0) { setl(b, T_RC, 41); Bchg(b, T_MSG, 0, "정산 상세(st_settle_dtl) 기록 실패", 0L); FAIL(b); }
    setl(b, T_TAX, h_fee); setl(b, T_ID1, h_id); setl(b, T_FEE, h_fee);
    vstep = 4;

    /* ===== 5) 이력/감사 적재부 (cm_log) ===== */
    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 (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;

    /* ===== 6) 집계/요약 갱신부 ===== */
    EXEC SQL SELECT count(*), coalesce(sum(p.amount),0), coalesce(sum(p.fee),0), coalesce(sum(s.net),0)
        INTO :h_cnt, :h_gross, :h_feesum, :h_netsum
        FROM settlement s JOIN purchase p ON p.purchase_id = s.purchase_id
        WHERE s.merchant_id = :h_merch AND s.biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 61); Bchg(b, T_MSG, 0, "가맹점 집계 재계산 오류", 0L); FAIL(b); }
    if (stdb_upsert_merch_settle(merch, bizdate, h_gross, h_feesum, h_netsum, h_cnt) < 0)
        { setl(b, T_RC, 64); Bchg(b, T_MSG, 0, "가맹점 정산집계 upsert 실패", 0L); FAIL(b); }
    setl(b, T_GROSS, h_gross);
    vstep = 6;

    /* ===== 7) 예외/보상 검증부 ===== */
    EXEC SQL SELECT count(*) INTO :h_rows FROM cm_log
        WHERE svc_name = :h_svc AND biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0) { setl(b, T_RC, 71); Bchg(b, T_MSG, 0, "감사 로그 검증 조회 오류", 0L); FAIL(b); }
    if (h_rows <= 0) { setl(b, T_RC, 72); Bchg(b, T_MSG, 0, "감사 로그 미적재(보상 롤백)", 0L); FAIL(b); }
    setl(b, T_ARG5, h_rows);
    userlog("[정산심화] 공급가액 조정 재부가세 기록. (심화판) 보상검증 통과 logrows=%ld step=%d", h_rows, vstep);
    vstep = 7;

    /* ===== 8) 응답부 ===== */
    if (Bpres(b, T_RC, 0) == 0) setl(b, T_RC, 0);
    Bchg(b, T_SVCNAME, 0, "ST_VATADJUST", 0L);
    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);
}

/* vim: set ts=4 sw=4 et smartindent: */
