SAP 매입송장 중복 지급 후보 점검 — 거래처·금액·전기일로 겹치는 송장을 먼저 가른다
같은 거래처에 같은 금액, 날짜만 다른 송장 두 장 — 이중 지급 전에 걸러냅니다
매입송장은 같은 거래처에서 비슷한 시기에 비슷한 금액으로 여러 건 들어오는 일이 흔합니다. 문제는 그 중 일부가 이미 등록된 송장의 재입력이거나, 참조번호만 살짝 다르게 붙인 중복 건일 때입니다. 건별로 눈으로 훑어서는 좀처럼 드러나지 않고, 지급이 두 번 나간 뒤에야 알게 되는 경우도 있습니다.
표준 매입송장 라인아이템 구조를 그대로 이어받아, 거래처·회사코드·금액이 같은 송장 쌍을 자동으로 찾아 참조번호 일치 여부와 전기일 차이로 위험도를 매기는 화면을 OpenUI5로 확장했습니다. 판정 결과는 "점검 필요"·"확인 필요"로만 표시해 담당자가 직접 경위를 확인하도록 안내합니다. 실제 구동 화면 3종을 함께 공개합니다.
SAP 표준 기능을 그대로 이어받은 부분
- 매입송장 원천 — 표준 회계전표 라인아이템 구조(거래처·금액·참조번호)를 그대로 활용
- 표준 화면 — 거래처별 회선항목 조회(FBL1N) · 송장 검증(MIRO)
| 항목 | 내용 |
|---|---|
| 업무 영역 | 재무회계(FI) · 내부통제 |
| 관련 대상 영역 | - (내부통제 · 중복지급 점검) |
| Namespace | zui5.dupcheck |
| 셸 구조 | 조회조건 영역(우측 조회) + 매입송장 내역 + 중복 지급 후보, 상세 Dialog |
| 화면 수 | 조회 화면 1개 + 상세 다이얼로그 |
| SAP 표준 T-code | FBL1N, MIRO |
| 성격 | 조회·대사형 — 중복 여부의 최종 확인은 회사·감사인 몫 |
| UI 테마 | sap_horizon 단일 적용 |
실제 화면 3종 둘러보기
회사코드·회계연도·거래처·전기일 구간을 넣고 조회하면 매입송장 내역과 중복 지급 후보가 함께 뜹니다 → 후보 목록의 행을 클릭하면 판정 근거가 다이얼로그로 열립니다.
아래는 실제로 앱을 실행해 기능을 눌러 가며 캡처한 화면입니다. 이미지를 클릭하면 원본 크기로 확대됩니다.
조작 방법
- 회사코드 · 회계연도 · 거래처 · 전기일(From/To)를 지정합니다.
- 거래처·회계연도 입력 필드에서 Enter 키를 누르거나 조회조건 영역 오른쪽 끝의 조회 버튼을 누르면 재조회됩니다. 초기화 버튼은 조건을 기본값으로 되돌립니다.
- 회사코드를 "전체"로 두면 회사코드 조건 없이 조회합니다.
- 중복 지급 후보 목록의 행을 클릭하면 상세 다이얼로그가 열립니다.
중복 판정 로직
같은 회사코드·거래처·금액을 가진 매입송장 두 건을 짝지어 참조번호 일치 여부와 전기일 차이로 위험도를 판정합니다.
| 위험도 | 판정 조건 | 사용자 조치 |
|---|---|---|
| A(고위험) | 거래처·참조번호·금액이 모두 동일하고 문서번호만 다름 | 우선 점검 대상 — 동일 송장 이중 입력 가능성 확인 |
| B(중위험) | 거래처·금액이 동일하고 전기일 차이가 3일 이내(참조번호는 다름) | 참조번호 오기재 가능성 포함 확인 |
| C(참고) | 거래처·금액이 동일하나 전기일 차이가 4~30일 | 우연 일치 가능성이 있어 참고용으로 확인 |
이 화면이 대신 정하지 않는 것
거래처·금액이 같다고 해서 곧바로 중복으로 단정하지 않습니다. 분할 발주나 정상적인 반복 거래처럼 정당한 사유가 있을 수 있어, 최종 판단은 회사와 감사인이 합니다. 이 화면은 그 판단이 필요한 후보를 가려내는 점검 도구입니다.
판정 처리 단계
| 단계 | 내용 |
|---|---|
| 1단계 | 조회조건(회사코드·회계연도·거래처·전기일 구간)으로 매입송장 라인아이템을 조회 |
| 2단계 | 같은 거래처·같은 회사코드·같은 금액 조합을 모두 짝지어 비교(자기 자신은 제외) |
| 3단계 | 참조번호 일치 여부와 전기일 차이(일)로 A/B/C 위험도를 판정 |
| 4단계 | 판정된 후보를 위험도·일자차 순으로 정렬해 표시 |
| 5단계 | 티어별 건수를 집계해 요약 카드에 반영, 합계건수 항등식을 전수 검증 |
조회조건
| 필드 | 필수 | 설명 |
|---|---|---|
| 회사코드 | 선택 | 전체/1000/2000(전체 선택 시 조건 미전달) |
| 회계연도 | 필수 | 4자리 연도 |
| 거래처 | 선택 | 거래처코드 조회, 비우면 전체 |
| 전기일(From/To) | 선택 | 전기일 구간, Enter 키로 바로 조회 |
결과 컬럼
| 컬럼 | 설명 |
|---|---|
| 회사코드·회계연도·문서번호·거래처 | 매입송장 라인아이템 기본 정보 |
| 참조번호·전기일·문서일·금액·통화 | 대사에 쓰이는 핵심 항목 |
| 지급상태·지급문서 | 미지급/지급완료 여부와 지급 문서번호 |
| 후보ID·문서번호1/2·참조번호1/2 | 중복 지급 후보 페어 식별 정보 |
| 일자차(일)·위험도·점검결과 | 판정 근거와 위험도, 점검 필요/확인 필요 |
SAP 표준 기능 매핑
| SAP 표준 T-code | 연관 기능 |
|---|---|
FBL1N | 거래처별 회선항목 조회 |
MIRO | 매입송장 검증(등록) |
분석 지표 정의표
| 지표 | 정의 | 산출 방식 |
|---|---|---|
| DateDiffDays | 비교 대상 두 송장 전기일의 절대 차이(일) | ABS(전기일1 - 전기일2) |
| MatchTier | 중복 위험도 구간(A/B/C) | 참조번호 일치 여부 + 전기일 차이 기준 판정 |
도입 시 확인이 필요한 부분
위험도 구간의 구체적인 일수 기준은 회사의 매입 통제 정책에 맞춰 조정할 수 있습니다.
참고 CDS 뷰
운영 서비스로 연결할 때를 가정해 새로 스케치한 조회 뷰 예시입니다(운영 반영 시 권한 체크를 추가해야 합니다).
define view I_ApInvoiceItemSketch
as select from bseg as Item
inner join bkpf as Header
on Header.bukrs = Item.bukrs
and Header.belnr = Item.belnr
and Header.gjahr = Item.gjahr
{
key Item.bukrs as CompanyCode,
key Item.gjahr as FiscalYear,
key Item.belnr as DocNo,
key Item.buzei as ItemNo,
Item.lifnr as VendorNo,
Item.xblnr as InvoiceRef,
Header.budat as PostingDate,
Item.wrbtr as Amount
}
// 중복 후보 판정은 이 조회 결과를 거래처·회사코드·금액 기준으로 대사해 산출
OpenUI5 구성
| 기능 | 사용 컨트롤 |
|---|---|
| 화면 골격 | sap.m.Page + 조회조건 Panel + 매입송장/후보 목록 |
| 조회조건 | sap.m.Select · sap.m.Input · sap.m.DatePicker — 우측 끝에 조회 버튼, Enter 키로 즉시 재조회 |
| 결과 목록 | sap.m.Table — 행 클릭 시 상세 다이얼로그 |
| 상세 | sap.m.Dialog — 선택 후보의 판정 근거 표시 |
| 공통 처리 | 전역 오류 처리기(ErrorHandler) |
서비스 경로는 manifest.json 의 dataSources 에 상대 경로로 선언한 OData 모델을 그대로
바인딩하며, 조회조건은 sap.ui.model.Filter 로 조립해 $filter 로만 전달합니다. 회사코드를
"전체"로 둘 때는 필터를 아예 생성하지 않습니다.
파일 구성
| 경로 | 역할 |
|---|---|
index.html | OpenUI5 부트스트랩 — sap_horizon |
Component.js | 컴포넌트 초기화, 전역 오류 처리기 연결 |
manifest.json | 앱 디스크립터 — zui5.dupcheck · OData dataSources · ko 로케일 |
view/Main.view.xml | 조회조건 + 매입송장 내역 + 중복 지급 후보 |
view/DetailDialog.fragment.xml | 후보 상세 다이얼로그 |
controller/Main.controller.js | 조회·필터 조립·다이얼로그 로직 |
controller/BaseController.js | 공통 처리(CSV 다운로드 등) |
model/ErrorHandler.js | 전역 오류 처리 |
model/formatter.js | 금액·위험도·점검상태 서식 |
i18n/i18n_ko.properties | ko 로케일 리소스 |
검증 환경 구성 상세는 이 글에서 다루지 않습니다. 운영 전환 시에는 화면과 판정 로직은 그대로 두고 데이터 계층만 실제 서비스 호출에 맞추면 됩니다.
검증 결과
화면 구성에 쓴 데이터는 티어별 건수 합계 = 중복 후보 총건수 관계가 항상 성립하도록 구성했습니다.
| 검증 항목 | 결과 |
|---|---|
| 대사식 전수 검증(A건수+B건수+C건수 = 중복후보 총건수) | 통과(불일치 0건) |
| 거래처가 다른데 금액만 같은 오탐 방지 케이스 제외 확인 | 확인 |
| 표시 금지 검사 — 커스텀 프로그램ID·앱 식별자·출처 표현 검출 | 0건 |
| 화면 렌더링 — 실브라우저에서 조회 → 후보 목록 → 행 클릭 상세까지 실동작 후 캡처 | 3/3 |
| 조회 버튼 위치 · sap_horizon 테마 적용 · Enter 키 조회 | 확인 |
| OData 계약 — 동사 경로 미사용, $filter·$orderby 로만 조회조건 전달 | 확인 |
거래처·송장 데이터는 모두 검증용으로 구성한 가상 데이터입니다.
자주 묻는 질문
이 화면은 어느 범위에 적용하나요?
회사코드·회계연도·거래처를 지정해 조회한 매입송장 라인아이템을 대상으로 하며, 조회조건에 걸리는 범위 안에서 짝을 지어 중복 지급 후보를 가려냅니다.
위험도(A/B/C)는 무엇을 기준으로 나누나요?
거래처·참조번호·금액이 모두 같고 문서번호만 다르면 A, 거래처·금액이 같고 전기일 차이가 3일 이내면 B, 전기일 차이가 4~30일이면 참고용인 C로 구분합니다.
이 화면이 자동으로 지급을 막아주나요?
아니요. 이 화면은 중복 지급 후보를 가려내는 조회·점검 도구이며, 실제 중복 여부에 대한 최종 판단과 조치는 회사와 감사인이 수행합니다.
화면의 수치는 실시간 SAP 데이터인가요?
실제 운영 화면은 OData 서비스를 통해 조회합니다. 이 글에 표시된 수치와 캡처는 검증용 샘플 데이터이며 실제 업무 데이터가 아닙니다.