Oracle存储过程--案例

限额控制

CREATE OR REPLACE PACKAGE BODY NP_PCKG_MERCHANT_LIMIT
AS
  PROCEDURE CHECK_LIMIT (
      in_iplCode         IN   VARCHAR2,       --行业编号
      in_iplState        IN   VARCHAR2,       --卡类型
      in_posNo           IN   VARCHAR2,      --商户号
      in_tranAmt         IN   VARCHAR2,      --交易金额
      out_retcode        OUT  VARCHAR2      --返回码
  )
  IS
      v_date             VARCHAR2(8);      --系统日期
      --v_merchantType     VARCHAR2(30);    --行业类型
      v_debitSingleMax   NUMBER(18,2);    --借记卡单笔限额
      v_debitDayMax      NUMBER(18,2);    --借记卡日累计限额
      v_debitMonthMax    NUMBER(18,2);    --借记卡月累计限额
      v_debitYearMax     NUMBER(18,2);    --借记卡年累计限额
      v_debitDaySum      NUMBER(18,2);   --借记卡日累计限额当日发生额
      v_debitMonthSum    NUMBER(18,2);   --借记卡月累计限额当月发生额
      v_debitYearSum     NUMBER(18,2);   --借记卡年累计限额当年发生额
      v_debitLastDate    NUMBER(18,2);   --借记卡限额上次交易日
      v_creditSingleMax  NUMBER(18,2);   --贷记卡单笔限额
      v_creditDayMax     NUMBER(18,2);   --贷记卡日累计限额
      v_creditMonthMax   NUMBER(18,2);   --贷记卡月累计限额
      v_creditYearMax    NUMBER(18,2);   --贷记卡年累计限额
      v_creditDaySum     NUMBER(18,2);   --贷记卡日累计限额当日发生额
      v_creditMonthSum   NUMBER(18,2);   --贷记卡月累计限额当月发生额
      v_creditYearSum    NUMBER(18,2);   --贷记卡年累计限额当年发生额
      v_creditLastDate   NUMBER(18,2);   --贷记卡限额上次交易日
      --v_stt              VARCHAR2(1);      --账户状态
  BEGIN
    out_retcode := '0';


        --取当前日期
        v_date := to_char(SYSDATE, 'yyyymmdd');
        ----------------------------------------------------------------
        -- 判断商户收单限额(设置的客商户日累计限额)
        ----------------------------------------------------------------
        --取收单限额 也要区分借记卡 和 贷记卡

          IF in_iplState = 1 THEN --是借记卡
            BEGIN
              SELECT
                  IPL_DEBIT_SINGLE,IPL_DEBIT_DAYMAX,IPL_DEBIT_MONTHMAX,IPL_DEBIT_YEARMAX
              INTO
                  v_debitSingleMax,v_debitDayMax,v_debitMonthMax,v_debitYearMax
              FROM
                  IM_PAY_LIMIT
              WHERE
                  IPL_CODE = in_iplCode AND --此处需要一个参数,行业的code
                  IPL_STATE in('00','01') ;  --先判断限额状态 00标示  如果是借记卡和贷记卡都可以用,或者借记卡和贷记卡只有一个能用,或者都不能用

              EXCEPTION
                  WHEN NO_DATA_FOUND THEN
                      NULL;
              dbms_output.put_line(v_debitSingleMax);
             END;
           ELSIF in_iplState = 2 THEN --是贷记卡
             BEGIN
                  SELECT
                        IPL_CREDIT_SINGLE,IPL_CREDIT_DAYMAX,IPL_CREDIT_MONTHMAX,IPL_CREDIT_YEARMAX
                    INTO
                        v_creditSingleMax,v_creditDayMax,v_creditMonthMax,v_creditYearMax
                    FROM
                        IM_PAY_LIMIT
                    WHERE
                        IPL_CODE = in_iplCode AND --此处需要一个参数,行业的code
                        IPL_STATE in('00','10');  --先判断限额状态 00标示  如果是借记卡和贷记卡都可以用,或者借记卡和贷记卡只有一个能用,或者都不能用

                    EXCEPTION
                        WHEN NO_DATA_FOUND THEN
                            NULL;
              END;
           END IF;


        --取商户年月日累计限额 ---
       BEGIN
            SELECT
                IMD_DEBIT_DAYAMT,
                IMD_DEBIT_MONTHAMT,
                IMD_DEBIT_YEARAMT,
                IMD_DEBIT_TRANSDAY,
                IMD_CREDIT_DAYAMT,
                IMD_CREDIT_MONTHAMT,
                IMD_CREDIT_YEARAMT,
                IMD_CREDIT_TRANSDAY
            INTO
                v_debitDaySum,
                v_debitMonthSum,
                v_debitYearSum,
                v_debitLastDate,
                v_creditDaySum,
                v_creditMonthSum,
                v_creditYearSum,
                v_creditLastDate
            FROM
                IM_MERCHANT_DAYSUM
            WHERE
                IMD_POSNO = in_posNo;

            EXCEPTION
                WHEN NO_DATA_FOUND THEN
                    INSERT INTO IM_MERCHANT_DAYSUM (IMD_POSNO,IMD_DEBIT_DAYAMT,IMD_DEBIT_MONTHAMT,IMD_DEBIT_YEARAMT,IMD_CREDIT_DAYAMT,IMD_CREDIT_MONTHAMT,IMD_CREDIT_YEARAMT,IMD_DEBIT_TRANSDAY,IMD_CREDIT_TRANSDAY) VALUES (in_posNo,'0.00','0.00','0.00','0.00','0.00','0.00',v_date,v_date);
        END;
     
     
         --判断是商户借记卡 =1    还是贷记卡 =2  START
        IF in_iplState = 1 THEN
          --如果是借记卡,则判断借记卡的单笔,日累计,月累计,年累计限额  v_debitSingleMax
           IF TO_NUMBER(in_tranAmt) > v_debitSingleMax THEN
              out_retcode := 'NPML1001';                    --错误码NPML1001:超过借记卡单笔限额
              --ROLLBACK;
              RETURN;
           END IF;
           -- 判断借记卡日累计交易限额否需要清零 ,如果是昨天的交易,今天需要清零 开始
              IF v_date <> v_debitLastDate THEN --here
                  v_debitDaySum := 0;
              END IF;
           -- 判断借记卡日累计交易限额否需要清零 ,如果是昨天的交易,今天需要清零 结束
           IF v_debitDaySum + TO_NUMBER(in_tranAmt) > v_debitDayMax THEN --借记卡日累计限额
              out_retcode := 'NPML1002';                    --错误码NPML1002:超过借记卡日累计限额
              --ROLLBACK;
              RETURN;
           END IF;
           --判断借记卡月累计交易限额是否需要清零,如果是上个月的交易,则临时置空 开始
              IF substr(v_date,1,6) <> substr(v_debitLastDate,1,6) THEN
                 v_debitMonthSum := 0;
              END IF;
           --判断借记卡月累计交易限额是否需要清零,如果是上个月的交易,则临时置空 结束
           IF v_debitMonthSum + TO_NUMBER(in_tranAmt) > v_debitMonthMax THEN --借记卡月累计限额
              out_retcode := 'NPML1003';                    --错误码NPML1003:超过借记卡月累计限额
              --ROLLBACK;
              RETURN;
           END IF;
           --判断借记卡年累计交易限额是否需要清零,如果是去年的交易,则临时置空 开始
              IF substr(v_date,1,4) <> substr(v_debitLastDate,1,4) THEN
                 v_debitYearSum := 0;
              END IF;
           --判断借记卡年累计交易限额是否需要清零,如果是去年的交易,则临时置空 结束
           IF v_debitYearSum + TO_NUMBER(in_tranAmt) > v_debitYearMax THEN --借记卡年累计限额
              out_retcode := 'NPML1004';                    --错误码NPML1004:超过借记卡年累计限额
              --ROLLBACK;
              RETURN;
           END IF;
        ELSIF in_iplState = 2 THEN
          --如果是贷记卡
          IF TO_NUMBER(in_tranAmt) > v_creditSingleMax THEN
              out_retcode := 'NPML1005';                    --错误码NPML1005:超过贷记卡单笔限额
              --ROLLBACK;
              RETURN;
           END IF;
              -- 判断贷记卡日累计交易限额是否需要清零 开始
              IF v_date <> v_creditLastDate THEN --here
                  v_creditDaySum := 0;
              END IF;
              -- 判断贷记卡日累计交易限额是否需要清零 结束
           IF v_creditDaySum + TO_NUMBER(in_tranAmt) > v_creditDayMax THEN --贷记卡日累计限额
              out_retcode := 'NPML1006';                    --错误码NPML1006:超过贷记卡日累计限额
              --ROLLBACK;
              RETURN;
           END IF;
           --判断贷记卡月累计交易限额是否需要清零,如果是上个月的交易,则临时置空 开始
              IF substr(v_date,1,6) <> substr(v_creditLastDate,1,6) THEN
                 v_creditMonthSum := 0;
              END IF;
           --判断贷记卡月累计交易限额是否需要清零,如果是上个月的交易,则临时置空 结束
           IF v_creditMonthSum + TO_NUMBER(in_tranAmt) > v_creditMonthMax THEN --贷记卡月累计限额
              out_retcode := 'NPML1007';                    --错误码NPML1007:超过贷记卡月累计限额
              --ROLLBACK;
              RETURN;
           END IF;
           --判断贷记卡年累计交易限额是否需要清零,如果是去年的交易,则临时置空 开始
              IF substr(v_date,1,4) <> substr(v_creditLastDate,1,4) THEN
                 v_creditYearSum := 0;
              END IF;
           --判断贷记卡年累计交易限额是否需要清零,如果是去年的交易,则临时置空 结束
           IF v_creditYearSum + TO_NUMBER(in_tranAmt) > v_creditYearMax THEN --贷记卡月累计限额
              out_retcode := 'NPML1008';                    --错误码NPML1008:超过贷记卡年累计限额
              --ROLLBACK;
              RETURN;
           END IF;
        END IF;
        --判断是商户借记卡 =1    还是贷记卡 =2  END


        COMMIT;
    END;


    PROCEDURE UPDATE_LIMIT (
        in_posNo               IN    VARCHAR2,            --商户号
        in_iplState            IN    VARCHAR2,            --卡类型
        in_tranAmt             IN    VARCHAR2,            --交易金额
        out_retcode            OUT   VARCHAR2            --返回码
    )
    IS
    v_date             VARCHAR2(8);      --系统日期
    v_debitDaySum      NUMBER(18,2);   --借记卡日累计限额当日发生额
    v_debitMonthSum    NUMBER(18,2);   --借记卡月累计限额当月发生额
    v_debitYearSum     NUMBER(18,2);   --借记卡年累计限额当年发生额
    v_debitLastDate    NUMBER(18,2);   --借记卡限额上次交易日

    v_creditDaySum     NUMBER(18,2);   --贷记卡日累计限额当日发生额
    v_creditMonthSum   NUMBER(18,2);   --贷记卡月累计限额当月发生额
    v_creditYearSum    NUMBER(18,2);   --贷记卡年累计限额当年发生额
    v_creditLastDate   NUMBER(18,2);   --贷记卡限额上次交易日

    BEGIN
        out_retcode := '0';

        --取当前日期
        v_date := to_char(SYSDATE, 'yyyymmdd');

        --取客户日累计限额
    BEGIN
            SELECT
                IMD_DEBIT_DAYAMT,
                IMD_DEBIT_MONTHAMT,
                IMD_DEBIT_YEARAMT,
                IMD_CREDIT_DAYAMT,
                IMD_CREDIT_MONTHAMT,
                IMD_CREDIT_YEARAMT
            INTO
                v_debitDaySum,
                v_debitMonthSum,
                v_debitYearSum,
                v_creditDaySum,
                v_creditMonthSum,
                v_creditYearSum
            FROM
                IM_MERCHANT_DAYSUM
            WHERE
                 IMD_POSNO = in_posNo
            FOR UPDATE;

            EXCEPTION
                WHEN NO_DATA_FOUND THEN
                    NULL;
        END;
        --判断借记卡日累计交易限额否需要清零
        IF v_date <> v_debitLastDate THEN
             v_debitDaySum := 0;
        END IF;
         -- 判断贷记卡日累计交易限额是否需要清零
        IF v_date <> v_creditLastDate THEN --here
            v_creditDaySum := 0;
        END IF;
        --判断借记卡月累计交易限额否需要清零
        IF substr(v_date,1,6) <> substr(v_debitLastDate,1,6) THEN
            v_debitMonthSum := 0;
        END IF;
        --判断贷记卡月累计交易限额否需要清零
        IF substr(v_date,1,6) <> substr(v_creditLastDate,1,6) THEN
            v_creditMonthSum := 0;
        END IF;
        --判断借记卡年累计交易限额否需要清零
        IF substr(v_date,1,4) <> substr(v_debitLastDate,1,4) THEN
            v_debitYearSum := 0;
        END IF;
        --判断贷记卡年累计交易限额否需要清零
        IF substr(v_date,1,4) <> substr(v_creditLastDate,1,4) THEN
            v_creditYearSum := 0;
        END IF;
        --更新商户收单限额累计表    需要区分借记卡和贷记卡
        IF in_iplState = 1 THEN --借记卡
          UPDATE IM_MERCHANT_DAYSUM --更新借记卡收单累计限额
          SET
               IMD_DEBIT_DAYAMT = v_debitDaySum + TO_NUMBER(in_tranAmt),
               IMD_DEBIT_MONTHAMT = v_debitMonthSum + TO_NUMBER(in_tranAmt),
               IMD_DEBIT_YEARAMT = v_debitYearSum + TO_NUMBER(in_tranAmt),
               IMD_DEBIT_TRANSDAY = v_date
          WHERE
              IMD_POSNO = in_posNo;

          COMMIT;
      ELSIF in_iplState = 2 THEN --贷记卡
        UPDATE IM_MERCHANT_DAYSUM --更新贷记卡收单累计限额
          SET
               IMD_CREDIT_DAYAMT = v_creditDaySum + TO_NUMBER(in_tranAmt),
               IMD_CREDIT_MONTHAMT = v_creditMonthSum + TO_NUMBER(in_tranAmt),
               IMD_CREDIT_YEARAMT = v_creditYearSum + TO_NUMBER(in_tranAmt),
               IMD_CREDIT_TRANSDAY = v_date
          WHERE
              IMD_POSNO = in_posNo;

          COMMIT;
      END IF;
    END;


    PROCEDURE ROLL_LIMIT (
    in_posNo        IN  VARCHAR2,     --商户号
    in_iplState           IN VARCHAR2,        --卡类型
    in_orderNo        IN  VARCHAR2,     --交易流水号
    out_retcode       OUT VARCHAR2      --存储过程返回码
  )
  IS
    v_amt     VARCHAR2(20);
    v_transDate VARCHAR2(8);
    v_nowDate   VARCHAR2(8);
  BEGIN
    out_retcode:='0';
    v_nowDate:=to_char(SYSDATE, 'yyyymmdd');

    --取客户日累计限额
    BEGIN
            SELECT
                substr(NPF_TRAN_TIME,1,8),
                NPF_ORDER_AMT
            INTO
                v_transDate,
                v_amt
            FROM
                NP_PAY_FLOW
            WHERE
                NPF_FLOWNO = in_orderNo
            FOR UPDATE;

            EXCEPTION
                WHEN NO_DATA_FOUND THEN
                    NULL;
        END;

        IF v_transDate ='' THEN

      out_retCode:='0';
      return;
    END IF;

    --IF v_transDate<> v_nowDate then--如果不是今天的指令,不处理当日的限额
    --  out_retCode:='0';
    --  return;
    --END IF;
        --查找到该订单,并且回滚的是今天的订单
        --如果是借记卡交易
        --
        IF in_iplState = 1 then --回滚借记卡
          IF v_transDate = v_nowDate then--如果交易日期小于今天当天日期,则判断是否为本月的交易,    回滚当月和当年的
            UPDATE IM_MERCHANT_DAYSUM--更新当天、本月、本年的累计额度
            SET
              IMD_DEBIT_DAYAMT = IMD_DEBIT_DAYAMT - v_amt,--更新当日的限额
              IMD_DEBIT_MONTHAMT = IMD_DEBIT_MONTHAMT - v_amt,--更新本月的限额
              IMD_DEBIT_YEARAMT = IMD_DEBIT_YEARAMT - v_amt--更新本年的限额
            WHERE
              IMD_POSNO = in_posNo;--商户号
          COMMIT;
          ELSIF v_transDate < v_nowDate then --如果交易时间不是今天,则判断是否为本月的交易
            IF substr(v_transDate,1,6) = substr(v_nowDate,1,6) THEN--不是当天的交易,则判断是否为本月的交易START
              UPDATE IM_MERCHANT_DAYSUM--更新本月、本年的交易
              SET
                IMD_DEBIT_MONTHAMT = IMD_DEBIT_MONTHAMT - v_amt,--更新本月的限额
                IMD_DEBIT_YEARAMT = IMD_DEBIT_YEARAMT - v_amt --更新本年的限额
              WHERE
                IMD_POSNO = in_posNo;--商户号
            COMMIT;
          ELSIF substr(v_transDate,1,6) < substr(v_nowDate,1,6) THEN--不是当天的交易,也不是本月的交易,则判断是否为本年的交易
            IF substr(v_transDate,1,4) = substr(v_nowDate,1,4) THEN--不是当天的交易,也不是本月的交易,是本年的交易
              UPDATE IM_MERCHANT_DAYSUM--更新本年的交易
                SET
                  IMD_DEBIT_YEARAMT = IMD_DEBIT_YEARAMT - v_amt--更新本年的限额
                WHERE
                  IMD_POSNO = in_posNo;--商户号
              COMMIT;
            END IF;
            END IF;--不是当天的交易,则判断是否为本月的交易END
          END IF;--回滚借记卡结束
      ELSIF in_iplState = 2 then  --回滚贷记卡
        IF v_transDate = v_nowDate then--如果交易日期小于今天当天日期,则判断是否为本月的交易,    回滚当月和当年的
            UPDATE IM_MERCHANT_DAYSUM--更新当天、本月、本年的累计额度
            SET
              IMD_CREDIT_DAYAMT = IMD_CREDIT_DAYAMT - v_amt,--更新当日的限额
              IMD_CREDIT_MONTHAMT = IMD_CREDIT_DAYAMT - v_amt,--更新本月的限额
              IMD_CREDIT_YEARAMT = IMD_CREDIT_YEARAMT - v_amt--更新本年的限额
            WHERE
              IMD_POSNO = in_posNo;--商户号
          COMMIT;
          ELSIF v_transDate < v_nowDate then --如果交易时间不是今天,则判断是否为本月的交易
            IF substr(v_transDate,1,6) = substr(v_nowDate,1,6) THEN--不是当天的交易,则判断是否为本月的交易START
              UPDATE IM_MERCHANT_DAYSUM--更新本月、本年的交易
              SET
                IMD_CREDIT_MONTHAMT = IMD_CREDIT_MONTHAMT - v_amt,--更新本月的限额
                IMD_CREDIT_YEARAMT = IMD_CREDIT_YEARAMT - v_amt--更新本年的限额
              WHERE
                IMD_POSNO = in_posNo;--商户号
            COMMIT;
          ELSIF substr(v_transDate,1,6) < substr(v_nowDate,1,6) THEN--不是当天的交易,也不是本月的交易,则判断是否为本年的交易
            IF substr(v_transDate,1,4) = substr(v_nowDate,1,4) THEN--不是当天的交易,也不是本月的交易,是本年的交易
              UPDATE IM_MERCHANT_DAYSUM--更新本年的交易
                SET
                  IMD_CREDIT_YEARAMT = IMD_CREDIT_YEARAMT - v_amt --更新本年的限额
                WHERE
                  IMD_POSNO = in_posNo;--商户号
              COMMIT;
            END IF;
            END IF;--不是当天的交易,则判断是否为本月的交易END
          END IF;--回滚借记卡结束
      END IF;--回滚借记卡、贷记卡结束
        --
  END;

END NP_PCKG_MERCHANT_LIMIT;

 表结构:

 

posted @ 2017-11-10 17:40  kangjie  阅读(3274)  评论(1编辑  收藏  举报