본문 바로가기
  • 노란색 세상은 어디에 있을까?
  • 봄이 오면 여기에 있겠지.
  • 잠시나마 유유자적 하겠네.
오라클/패키지(시스템공통)

[ 데이터검증 ] sys_valid_api 패키지를 생성합니다.

by 태백성 2024. 4. 4.
create or replace package bsys.sys_valid_api
is
    -- 고정변수 선언
    c_package_name                     constant varchar2(0200) default 'sys_valid_api';

    -- 프로시저 및 펑션
    procedure date_range_p
        (pi_start_date                 in     date                   -- 시작일자
        ,pi_end_date                   in     date                   -- 종료일자
        ,po_result_cd                  in out number                 -- 결과코드(0: 정상, -1: 오류)
        ,po_result_descr               in out varchar2               -- 결과내용
        );

    procedure date_range_p
        (pi_estab_date                 in     date                   -- 설립일자
        ,pi_start_date                 in     date                   -- 시작일자
        ,po_result_cd                  in out number                 -- 결과코드(0: 정상, -1: 오류)
        ,po_result_descr               in out varchar2               -- 결과내용
        );
        
    procedure char_valid_p
        (pi_valid_name                 in     varchar2               -- 검증한글명
        ,pi_valid_value                in     varchar2               -- 검증값
        ,pi_min_size                   in     varchar2               -- 최소자릿수
        ,pi_inclue_eng_yn              in     varchar2 default 'Y'   -- 영문포함
        ,pi_inclue_num_yn              in     varchar2 default 'Y'   -- 숫자포함
        ,pi_inclue_spc_yn              in     varchar2 default 'Y'   -- 특수문자포함
        ,pi_inclue_kor_yn              in     varchar2 default 'N'   -- 한글포함
        ,po_result_cd                  in out number                 -- 결과코드(0: 정상, -1: 오류)
        ,po_result_descr               in out varchar2               -- 결과내용
        );

    function per_ssn_f
        (pi_per_ssn                    in     varchar2               -- 주민번호
        ) return boolean;

    function corp_num_f
        (pi_corp_num                   in     varchar2               -- 사업자번호
        ) return boolean;

    function biz_num_f
        (pi_biz_num                    in     varchar2               -- 사업자번호
        ) return boolean;
        
    function upd_lang_value
        (pi_sys_lang_cd                in     varchar2               -- 시스템언어코드
        ,pi_lang_cd                    in     varchar2               -- 언어코드
        ,pi_value                      in     varchar2               -- 항목의값
        ) return varchar2;

    function mask_f
        (pi_mask_type                  in     varchar2               -- 마스크유형
        ,pi_text_value                 in     varchar2               -- 값
        ) return varchar2;

end sys_valid_api;

 

create or replace package body bsys.sys_valid_api
    /* ********************************************************************************************
       * 업 무  단 위 : 응용프로그램
       * 패   키   지 : bsys.sys_valid_api
       * 사 용  목 적 : 주요 데이터 검증 패키지
       * 생 성  일 자 : 2024-02-01
       * 생   성   자 : Admin 
       --------------------------------------------------------------------------------------------
       * 수정일자       수정자      수정내역
       --------------------------------------------------------------------------------------------
       * 2024-02-01     Admin       최초 작성
    ******************************************************************************************** */
 is
    /* ********************************************************************************************
       * 사 용  목 적 : 날짜 검증
       * 생 성  일 자 : 2023-11-30
       * 생   성   자 : Admin 
    ******************************************************************************************** */
    procedure date_range_p
        (pi_start_date                 in     date                   -- 시작일자
        ,pi_end_date                   in     date                   -- 종료일자
        ,po_result_cd                  in out number                 -- 결과코드(0: 정상, -1: 오류)
        ,po_result_descr               in out varchar2               -- 결과내용
        )
    is
        l_start_date                   date        default null;
        l_end_date                     date        default null;
        l_user_exception               exception;
    begin
        -- 기본값 할당
        po_result_cd    := 0;
        po_result_descr := '';

        -- 자료검증
        begin
            -- 시작일자 및 종료일자 검증
            l_start_date := trunc(pi_start_date);
            l_end_date   := trunc(pi_end_date);

            --
            if l_start_date is not null and l_end_date is not null then
                if l_start_date > l_end_date then
                    po_result_descr := '종료일자는 시작일자보다 크거나 같아야 합니다.';
                    raise l_user_exception;
                end if;

            elsif l_start_date is null then
                po_result_descr := '시작일자는 필수 항목입니다.';
                raise l_user_exception;

            end if;

        exception
            when l_user_exception then
                po_result_cd    := -1;
                dbms_output.put_line('po_result_descr => ' || po_result_descr);
            when others then
                po_result_cd    := -1;
                po_result_descr := sqlerrm;
                dbms_output.put_line('po_result_descr => ' || po_result_descr);
        end;
    end date_range_p;    
    
    /* ********************************************************************************************
       * 사 용  목 적 : 날짜 검증
       * 생 성  일 자 : 2023-11-30
       * 생   성   자 : Admin 
    ******************************************************************************************** */
    procedure date_range_p
        (pi_estab_date                 in     date                   -- 설립일자
        ,pi_start_date                 in     date                   -- 시작일자
        ,po_result_cd                  in out number                 -- 결과코드(0: 정상, -1: 오류)
        ,po_result_descr               in out varchar2               -- 결과내용
        )
    is
        l_estab_date                   date        default null;
        l_start_date                   date        default null;        
        l_user_exception               exception;
    begin
        -- 기본값 할당
        po_result_cd    := 0;
        po_result_descr := '';

        -- 자료검증
        begin
            -- 설립일자 및 시작일자 검증
            l_estab_date := trunc(pi_estab_date);
            l_start_date := trunc(pi_start_date);

            --
            if l_estab_date is not null and l_start_date is not null then
                if l_estab_date > l_start_date then
                    po_result_descr := '시작일자는 설립일자보다 크거나 같아야 합니다.';
                    raise l_user_exception;
                end if;

            elsif l_estab_date is null then
                po_result_descr := '설립일자는 필수 항목입니다.';
                raise l_user_exception;

            end if;

        exception
            when l_user_exception then
                po_result_cd    := -1;
                dbms_output.put_line('po_result_descr => ' || po_result_descr);
            when others then
                po_result_cd    := -1;
                po_result_descr := sqlerrm;
                dbms_output.put_line('po_result_descr => ' || po_result_descr);
        end;
    end date_range_p;

    /* ********************************************************************************************
       * 사 용  목 적 : 자료 검증
       * 생 성  일 자 : 2023-11-30
       * 생   성   자 : Admin 
    ******************************************************************************************** */
    procedure char_valid_p
        (pi_valid_name                 in     varchar2               -- 검증한글명
        ,pi_valid_value                in     varchar2               -- 검증값
        ,pi_min_size                   in     varchar2               -- 최소자릿수
        ,pi_inclue_eng_yn              in     varchar2 default 'Y'   -- 영문포함
        ,pi_inclue_num_yn              in     varchar2 default 'Y'   -- 숫자포함
        ,pi_inclue_spc_yn              in     varchar2 default 'Y'   -- 특수문자포함
        ,pi_inclue_kor_yn              in     varchar2 default 'N'   -- 한글포함
        ,po_result_cd                  in out number                 -- 결과코드(0: 정상, -1: 오류)
        ,po_result_descr               in out varchar2               -- 결과내용
        )
    is
        l_one_chr                      varchar2(3) default null;
        l_one_asc                      number      default null;
        l_point                        number      default 1;
        l_eng_cnt                      number      default 0;
        l_num_cnt                      number      default 0;
        l_spc_cnt                      number      default 0;
        l_oth_cnt                      number      default 0;
        l_valid_len                    number      default 0;
        l_user_exception               exception;
    begin
        -- 기본값 할당
        po_result_cd    := 0;
        po_result_descr := '';

        -- 자료검증
        begin
            l_valid_len := nvl(length(pi_valid_value), 0);
            if pi_valid_name = '비밀번호' then
                if l_valid_len = 0 or l_valid_len < pi_min_size then
                    po_result_descr := pi_valid_name || '는 최소 ' || pi_min_size || '자리 이상 입력합니다.';
                    raise l_user_exception;
                end if;

            elsif pi_valid_name = '주민번호' then
                if l_valid_len = 0 or l_valid_len != pi_min_size then
                    po_result_descr := pi_valid_name || '는 ' || pi_min_size || '자리를 반드시 입력합니다.';
                    raise l_user_exception;
                end if;

            end if;

            -- 숫자 및 특수문자 포함 검증
            loop
                l_one_chr := substr(pi_valid_value, l_point, 1);
                l_one_asc := ascii(l_one_chr);

                -- 영문 글자수(a...z, a...z)
                if l_one_asc between 65 and 90 or l_one_asc between 97 and 122     then l_eng_cnt := 1;

                -- 숫자 글자수(0...9)
                elsif l_one_asc between 48 and 57                                  then l_num_cnt := 1;

                -- 특수문자 글자수(!.../, :...@, [...', {...~
                elsif l_one_asc between 33 and 47 or l_one_asc between 58  and 64
                   or l_one_asc between 91 and 96 or l_one_asc between 123 and 125 then l_spc_cnt := 1;

                -- 그외 문자(한글 등)
                else                                                                    l_oth_cnt := 1;
                end if;

                -- 루프 종료
                if l_point = length(pi_valid_value) then
                    exit;
                else
                    l_point := l_point +1;
                end if;
            end loop;

            -- 영문, 숫자, 특수문자 및 한글 포함 검증
            if pi_inclue_eng_yn = 'Y' and l_eng_cnt = 0 then
                po_result_descr := '1자 이상의 영문이 포함되어야 합니다.';
                raise l_user_exception;

            elsif pi_inclue_eng_yn = 'N' and l_eng_cnt = 1 then
                po_result_descr := '영문자가 포함되어 처리 불가합니다.';
                raise l_user_exception;

            elsif pi_inclue_num_yn = 'Y' and l_num_cnt = 0 then
                po_result_descr := '1자 이상의 숫자가 포함되어야 합니다.';
                raise l_user_exception;

            elsif pi_inclue_num_yn = 'N' and l_num_cnt = 1 then
                po_result_descr := '숫자가 포함되어 처리 불가합니다.';
                raise l_user_exception;

            elsif pi_inclue_spc_yn = 'Y' and l_spc_cnt = 0 then
                po_result_descr := '1자 이상의 특수문자가 포함되어야 합니다.';
                raise l_user_exception;

            elsif pi_inclue_spc_yn = 'N' and l_spc_cnt = 1 then
                po_result_descr := '특수문자가 포함되어 처리 불가합니다.';
                raise l_user_exception;

            elsif pi_inclue_kor_yn = 'Y' and l_oth_cnt = 0 then
                po_result_descr := '1자 이상의 한글이 포함되어야 합니다.';
                raise l_user_exception;

            elsif pi_inclue_kor_yn = 'N' and l_oth_cnt = 1 then
                po_result_descr := '한글이 포함되어 처리 불가합니다.';
                raise l_user_exception;

            end if;

        exception
            when l_user_exception then
                po_result_cd    := -1;
                dbms_output.put_line('po_result_descr => ' || po_result_descr);

            when others then
                po_result_cd    := -1;
                po_result_descr := sqlerrm;
                dbms_output.put_line('po_result_descr => ' || po_result_descr);
        end;
    end char_valid_p;

    /* ********************************************************************************************
       * 사 용  목 적 : 주민번호 유효성 검증
       * 생 성  일 자 : 2024-02-01
       * 생   성   자 : Admin 

       --------------------------------------------------------------------------------------------
       주민번호 검사 공식
       --------------------------------------------------------------------------------------------
       600101 - 1000001
       234567   892345
       --------------------------------------------------------------------------------------------
       1. 주민번호 한자리를 차례로 234567892345로 곱한후 모두 합산 (마지막13번쨰 자리는 제외)
          합 = 6*2+0*3...+0*5
       2. 합산한 값을 11로 나눈후 나머지를 -11로 뺌
          수 = 11-합%11;
       3. 2번결과를 10으로 나누어서 나머지가 주민번호 마지막 13번째 자리와 숫자가 동일하면 올바른 주민번호
          수 = 수%10 의 결과가 주민번호 끝자리 수와 맞으면 Ok
    ******************************************************************************************** */
    function per_ssn_f
        (pi_per_ssn                    in     varchar2               -- 주민번호
        ) return boolean
    is
        l_per_ssn                      varchar2(30) default null;
        l_sum                          number       default 0;
    begin
        -- 데이터 검증
        if pi_per_ssn is null then
           return null;
        end if;

        -- 숫자만 추출
        select regexp_replace(regexp_replace(trim(lower(pi_per_ssn)), '[^a-z,A-Z,0-9]', ''), '[[:space:]]{1,}', ' ')
          into l_per_ssn
          from dual;
          
        -- 예외처리(테스트를 위하여 한시적으로 사용)
        if l_per_ssn like '111%' then
            return true;
        end if;

        -- 주민번호 합산
        for i in 1..12 loop
            if i < 9 then
                 l_sum := l_sum + to_number(substr(l_per_ssn, i, 1)) * (i + 1);
            else l_sum := l_sum + to_number(substr(l_per_ssn, i, 1)) * (i - 7);
            end if;

        end loop;

        -- 합산 값 11로 나누고 나머지를 - 11
        if mod(11 - mod(l_sum, 11), 10) = to_number(substr(l_per_ssn, 13, 1)) then
             return true;
        else return false;
        end if;
    end per_ssn_f;

    /* ********************************************************************************************
       * 사 용  목 적 : 법인번호 유효성 검증
       * 생 성  일 자 : 2024-02-01
       * 생   성   자 : Admin 

       --------------------------------------------------------------------------------------------
       법인번호 검사 공식
       --------------------------------------------------------------------------------------------
       1. 등기관서별 분류번호, 법인종류별 분류번호 및 일련번호를 차례로 연결한 12자리의 숫자를 만든다.
       (예시)
       1 1 0 1 1 1 - 0 0 6 2 4 3
       ----- --- -----------
       | | |
       +--------+---------+------------------ 등기관서별 분류번호
       | |
       +---------+------------------ 법인종류별 분류번호
       |
       +------------------ 일련번호

       2. 각 숫자에 차례로 1과 2를 곱한 값을 모두 더하여 합을 구한다.
       (예시)
       1 1 0 1 1 1 - 0 0 6 2 4 3
       ×1 2 1 2 1 2 - 1 2 1 2 1 2
       ----------------------------
       1 2 0 2 1 2 0 0 6 4 4 6
       1 + 2 + 2 + 1 + 2 + 6 + 4 + 4 + 6= 28

       3. 합을 10으로 나누어 몫과 나머지를 구한다.
       (예시) 28 ÷ 10 = 2 나머지 8

       4. 10에서 나머지를 뺀 값을 오류검색번호로 한다.
       다만 10에서 나머지를 뺀 값이 10인 때에는 0을 오류검색번호로 한다.
       (예시) 10 - 8 = 2 ------ 오류검색번호
    ******************************************************************************************** */
    function corp_num_f
        (pi_corp_num                   in     varchar2               -- 법인번호
        ) return boolean
    is
        l_corp_num                     varchar2(30) default null;
        l_return_value                 varchar2(1)  default 'Y';
    begin
        -- 데이터 검증
        if pi_corp_num is null or length(l_corp_num) != 13 then
            return null;
        end if;

        -- 숫자만 추출
        select regexp_replace(regexp_replace(trim(lower(pi_corp_num)), '[^a-z,A-Z,0-9]', ''), '[[:space:]]{1,}', ' ')
          into l_corp_num
          from dual;
          
        -- 예외처리(테스트를 위하여 한시적으로 사용)
        if l_corp_num like '111%' then
            return true;
        end if;

        -- 법인번호 검증
        begin
        select decode(g7, 10 - mod(g1 + g2 + g3 + g4 + g5 + g6 + g11 + g12 + g13 + g14 + g15 + g16,10), 'Y', 'N')
          into l_return_value
          from  (
                 select substr(l_corp_num, 1, 1)  * 1 as g1
                       ,substr(l_corp_num, 2, 1)  * 2 as g2
                       ,substr(l_corp_num, 3, 1)  * 1 as g3
                       ,substr(l_corp_num, 4, 1)  * 2 as g4
                       ,substr(l_corp_num, 5, 1)  * 1 as g5
                       ,substr(l_corp_num, 6, 1)  * 2 as g6
                       ,substr(l_corp_num, 7, 1)  * 1 as g11
                       ,substr(l_corp_num, 8, 1)  * 2 as g12
                       ,substr(l_corp_num, 9, 1)  * 1 as g13
                       ,substr(l_corp_num, 10, 1) * 2 as g14
                       ,substr(l_corp_num, 11, 1) * 1 as g15
                       ,substr(l_corp_num, 12, 1) * 2 as g16
                       ,substr(l_corp_num, 13, 1) * 1 as g7
                   from dual
                );
        exception
            when others then
                l_return_value := 'N';
        end;

        -- 리턴
        if l_return_value = 'Y' then
            return true;
        else
            return false;
        end if;
    end corp_num_f;

    /* ********************************************************************************************
       * 사 용  목 적 : 사업자번호 유효성 검증
       * 생 성  일 자 : 2024-02-01
       * 생   성   자 : Admin 

       --------------------------------------------------------------------------------------------
       사업자번호 검사 공식
       --------------------------------------------------------------------------------------------
       1. 청·서코드(3자리)
       순수한 신규개업자(폐업 후 재개업이 아닌 자)에게만 사업자등록번호 최초 부여관서의 청·서코드를
       부여하며 관서간 세적이전, 관할구역 변경의 경우에는 청·서코드 변경을 하지 아니함


       2. 개인·법인 구분코드(2자리)
        가. 개인구분 코드
         (1) 개인과세사업자 특정동 구별 없이 01부터 79까지를 순차적으로 부여
         (2) 개인면세사업자 산업구분없이 90부터 99까지를 순차적으로 부여
         (3) 소득세법 제1조 제3항에 해당하는 법인이 아닌 종교 단체 …89
         (4) 소득세법 제1조 제3항에 해당하는 자로서 "ⓒ"이외의 자(아파트관리사무소 등) 및 영 제7조 제6항의 규정에 의하여 등록한 다단계 판매업자 …80

        나. 법인성격코드:법인에 대하여는 성격별 코드를 구분하여 사용
         (1) 영리법인의 본점 …81.86
         (2) 비영리법인의 본점 및 지점(법인격 없는 사단, 재단, 기타단체중 법인으로 보는 단체를 포함) …82
         (3) 국가, 지방자치단체, 지방자치단체조합 … 83
         (4) 외국법인의 본·지점 및 연락사무소 … 84
         (5) 영리법인의 지점 …85


       3. 일련번호코드(4자리) 과세사업자(일반·간이·특례), 면세사업자, 법인사업자별로 등록 또는 지정일자순으로
          사용 가능한 번호를 0001~9999로 부여한다. 다만, 비영리법인의 본·지점은 등록 또는 지정일자순으로 0001~5999로 부여하고,
          국세기본법 제13조 제2항의 규정에 의하여 법인으로 보는 단체는 6000~9999로 부여함

       4. 검증번호(1위) 전산시스템에 의하여 사업자등록번호의 오류여부를 검증하기 위하여 부여된 특정숫자이다.
          ③ 폐업 후 재개업의 경우에도 종전의 사업자 등록번호를 변경 없이 사용한다. 다만, 2개 이상의
             사업자등록번호를 가진 사업자가 폐업하고 추후 사업자등록을 신청하는 경우에는 사업자등록 신청일로부터 1년이 경과한
             등록번호 중 가장 최근에 폐업한 사업장의 사업자등록번호부터 소급하여 순차적으로 부여함
             이 경우 공동사업자에게 부여하였던 사업자등록번호는 재사용하지 아니함

       사업자 등록번호의 의미
       사업자 번호는 000 - 00 - 00000 으로 되어 있는데
       처음 3자리는 지역을 의미
           서울,경기청 100
           중구청 200
           대전청 300
           광주청 400
           대구청 500
           부산청 600

       두번째 2자리는
           개인,법인,면세,비영리를 구분

           01~80 은 개인사업자
           81 영리법인
           82 비영리법인
           83 학교법인,지자체
           84 외국법인
           85 지점법인
           86 서울경기의 영리법인
           90~99 개인면세사업(쌀, 고기,어물,치과, 의원등)

       셋째 5자리는 일련 번호를 의미
    ******************************************************************************************** */
    function biz_num_f
        (pi_biz_num                    in     varchar2               -- 사업자번호
        ) return boolean
    is
        l_biz_num                      varchar2(30) default null;
        l_base_digit                   number       default null;
        l_chk_digit                    number       default null;
    begin
        -- 데이터 검증
        if pi_biz_num is null or length(l_biz_num) != 10 then
            return null;
        end if;

        -- 숫자만 추출
        select regexp_replace(regexp_replace(trim(lower(pi_biz_num)), '[^a-z,A-Z,0-9]', ''), '[[:space:]]{1,}', ' ')
          into l_biz_num
          from dual;
          
        -- 예외처리(테스트를 위하여 한시적으로 사용)
        if l_biz_num like '111%' then
            return true;
        end if;

        -- 사업자번호 체크
        select bn.base_digit
              ,mod(bn.a1*1 + bn.a2*3 + bn.a3*7 + bn.a4*1 + bn.a5*3 + bn.a6*7 + bn.a7*1 + bn.a8*3 + bn.a9*5 + trunc((bn.a9*5)/10, 0), 10) as chk_digit
          into l_base_digit
              ,l_chk_digit
          from (
                select l_biz_num
                      ,substr(l_biz_num, 1, 1)  a1
                      ,substr(l_biz_num, 2, 1)  a2
                      ,substr(l_biz_num, 3, 1)  a3
                      ,substr(l_biz_num, 4, 1)  a4
                      ,substr(l_biz_num, 5, 1)  a5
                      ,substr(l_biz_num, 6, 1)  a6
                      ,substr(l_biz_num, 7, 1)  a7
                      ,substr(l_biz_num, 8, 1)  a8
                      ,substr(l_biz_num, 9, 1)  a9
                      ,substr(l_biz_num, 10, 1) base_digit --유효성 체크자리? ?
                  from dual
               ) bn
           where 1=1;

        -- 사업자번호 체크
        if l_chk_digit = 0 then
            if l_chk_digit = l_base_digit then
                 return true;
            else return false;
            end if;

        else
            if 10 - l_chk_digit = l_base_digit then
                 return true;
            else return false;
            end if;

        end if;
    end biz_num_f;

    /* ********************************************************************************************
       * 사 용  목 적 : 다국어 데이터 업데이트 검증 함수
       * 생 성  일 자 : 2024-02-01
       * 생   성   자 : Admin 
    ******************************************************************************************** */
    function upd_lang_value
        (pi_sys_lang_cd                in     varchar2               -- 시스템언어코드
        ,pi_lang_cd                    in     varchar2               -- 언어코드
        ,pi_value                      in     varchar2               -- 항목의값
        ) return varchar2
    is
    begin
        -- 데이터 검증
        if pi_value is null or upper(pi_sys_lang_cd) = upper(pi_lang_cd) then
             return pi_value;
        else return null;
        end if;        
    end upd_lang_value;

    /* ********************************************************************************************
       * 사 용  목 적 : 마스크 형식을 적용하는 함수
       * 생 성  일 자 : 2024-02-01
       * 생   성   자 : Admin 
    ******************************************************************************************** */
    function mask_f
        (pi_mask_type                  in     varchar2               -- 마스크유형
        ,pi_text_value                 in     varchar2               -- 값
        ) return varchar2
    is
        l_mask_type                    varchar2(50)  default upper(pi_mask_type);
        l_text_value                   varchar2(200) default replace(trim(pi_text_value), '-', '');
    begin
        -- 값이 없으면 리턴
        if l_text_value is null then
            return null;
        end if;
        
        -- 주민번호
        if l_mask_type = 'PER_SSN' then
             return substr(l_text_value, 1, 6) || '-' || substr(l_text_value, 7, 7);
             
        -- 법인번호(284911-0138303)
        elsif l_mask_type = 'corp_num' then
             return substr(l_text_value, 1, 6) || '-' || substr(l_text_value, 7, 7);
             
        -- 사업자번호(101-81-55262)
        elsif l_mask_type = 'biz_num' then
             return substr(l_text_value, 1, 3) || '-' || substr(l_text_value, 4, 2) || '-' || substr(l_text_value, 6, 5);
             
        else return pi_text_value;
        end if;        
    end mask_f;

END sys_valid_api;