삼자대조 자동화: 결제 보류를 위한 테이블 및 워크플로우
PO, 수령, 송장의 수량과 가격이 일치할 때까지 결제를 보류하는 방법을 다루는 실용적인 테이블 설계와 시각적 워크플로우로 삼자대조 자동화를 배우세요.

삼자대조가 실제로 해결하는 문제
삼자대조 자동화는 단순합니다: 주문한 것(PO)과 실제 받은 것(수령 기록), 그리고 공급업체가 청구한 송장 내용이 일치할 때만 송금합니다. 세 문서는 구매 주문서(PO), 수령 기록(Receipt), 공급업체 송장입니다.
이 확인이 없으면, 계정과금(AP)은 한 문서에만 의존해 잘못되거나 불완전한 상태로 지불할 수 있습니다. 공급업체가 실제로 전달된 수량보다 더 많이 청구하거나 합의된 가격과 다른 가격을 쓰거나 이메일 스레드에서 새로 보이는 중복 송장을 보낼 수 있습니다.
이런 실패는 처음에는 극적으로 보이지 않습니다. 작은 새는 구멍처럼 나타납니다: 같은 품목이 두 번 청구되거나, 배송이 몇 개 부족하거나, 승인되지 않은 가격 인상, 또는 불필요하게 청구된 운임 등. 시간이 지나면 그런 작은 실수들이 실제 비용으로 쌓입니다.
목표는 단순히 "송장 승인" 버튼을 누르는 것이 아닙니다. 핵심 필드(보통 수량, 단가, 합계)가 PO, 수령, 송장 간에 일치할 때까지 결제를 차단하는 것입니다. 일치하지 않으면 송장이 이메일 속으로 사라져서는 안 됩니다. 명확한 사유 코드와 차이가 있는 정확한 필드가 포함된 예외 큐로 들어가야 합니다.
삼자대조는 팀 간의 역할도 명확히 나눕니다. 조달(Procurement)은 무엇을 주문했는지(조건과 가격)를 관리하고, 수령(Receiving)은 무엇이 도착했는지(수량과 날짜)를 확인하며, 재무(Finance)는 무엇을 지불할지(송장 검토 및 해제)를 통제합니다.
초기 기대치를 설정하세요: 이것은 프로세스와 데이터 문제이지 단순한 승인 버튼 문제가 아닙니다. PO 라인이 모호하거나, 수령이 기록되지 않거나, 송장이 PO 라인에 연결되지 않으면 자동화가 문제를 해결해주지 못합니다.
문서와 역할: PO, 수령, 송장, 그리고 누가 무엇을 소유하는가
삼자대조는 각 문서에 분명한 소유자가 있을 때만 제대로 작동합니다. "누가 무엇을 갱신하는가"가 불명확하면 시스템은 좋은 결제를 차단하거나 나쁜 결제를 통과시킬 것입니다.
실용적인 소유 모델은 다음과 같습니다:
- 요청자(Requester)가 구매 요청을 만들고 필요성을 확인합니다.
- 조달팀(Procurement)이 PO(공급업체, 가격, 조건)를 생성하고 유지합니다.
- 창고/수령자(또는 서비스 오너)가 수령 또는 수락을 게시합니다.
- AP/재무가 송장을 기록하고 결제를 통제합니다.
각 문서에는 매칭이 추측이 되지 않도록 최소 필드 세트가 필요합니다.
**PO (구매 주문서)**에는 공급업체 ID, PO 번호, 라인 아이템(SKU 또는 서비스), 주문 수량, 단가, 통화, 세금 규칙, 결제 조건이 필요합니다.
**수령(Receipt)**에는 PO 참조, 수령 날짜, PO 라인별 수령 수량, 수령자 정보가 필요합니다. 서비스의 경우에는 수락으로 처리하고 승인자를 기록하세요.
**송장(Invoice)**에는 공급업체 송장 번호, 송장 날짜, PO 참조(또는 PO를 안전하게 찾을 방법), 라인 세부 정보(수량, 단가), 세금/운임, 합계가 필요합니다.
또한 매칭이 언제 실행될지 결정하세요. 한 번만 실행되어서는 안 됩니다. 현실이 바뀔 때마다 트리거해야 합니다:
- 송장이 캡처될 때(지금 바로 지급 또는 보류를 결정할 수 있도록).
- 수령이 게시될 때(보류 중인 송장이 결제 가능으로 전환될 수 있도록).
- PO가 변경될 때(열려 있는 송장들을 재확인하도록).
부분 수령과 다수의 송장은 정상입니다. PO 라인이 세 번에 걸쳐 도착하고 두 건의 송장으로 청구될 수 있습니다. 논리는 문서 하나만 비교하는 것이 아니라 PO 라인별로 누적 수령량과 누적 청구량을 비교해야 합니다.
구축 전에 결정할 규칙들
테이블이나 워크플로우 단계를 건드리기 전에 전체 시스템을 좌우할 규칙들에 합의하세요. 모호한 규칙은 예측 가능한 실패를 만듭니다: 시스템이 너무 많이 차단해 사람들이 이를 우회하거나, 너무 적게 차단해 잘못된 송장이 여전히 지불됩니다.
매칭 수준을 선택하세요. 헤더(문서 합계)만 비교하면 설정은 쉬워 보이지만 부분 배송, 백오더, 운임 라인, 또는 혼합 세율에서 빠르게 깨집니다. 라인 수준 매칭은 설정에 시간이 더 걸리지만 안전한 기본값입니다. 같은 PO 라인, 그 수량, 단가를 PO/수령/송장 간에 비교하기 때문입니다.
강제 차단(하드 블록) vs 경고를 정의하세요. 하드 블록은 문제가 해결될 때까지 결제가 진행될 수 없음을 의미합니다. 경고는 송장이 진행될 수 있지만 누군가가 위험을 인지해야 함을 의미합니다.
일반적인 시작점:
- 하드 블록: 청구된 수량이 수령된 수량을 초과(상품의 경우).
- 하드 블록: 단가가 허용 오차를 넘어 PO 단가를 초과.
- 경고: 작은 반올림 차이.
- 경고: 별도로 코드화된 예상되는 세금 또는 운임 차이.
허용오차 규칙을 명확히 유지하세요. 방식(퍼센트, 절대 금액, 또는 둘 중 큰 값)을 정의하고 누가 소유하는지 정하세요. 예: 라인당 +/- 1% 또는 +/- $5 허용, 재무만 감사 노트와 함께 허용오차를 변경할 수 있도록.
작고 공유된 상태 집합을 사용하세요. 팀별 커스텀 상태를 피하세요. 깔끔한 집합은 보통 충분합니다: Matched, Hold, Exception, Approved. "Hold"는 결제가 차단되었음을 의미합니다. "Exception"은 사람이 검토해야 함을 의미합니다. "Approved"는 명시된 사람이 불일치를 수락하고 이유를 기록했음을 의미합니다.
데이터 모델: 필요한 테이블(및 이유)
삼자대조 자동화는 데이터 모델이 PO 라인, 수령된 것, 청구된 것을 연결할 수 있을 때만 작동합니다. 모든 송장 라인은 특정 PO 라인에 매칭 가능해야 하고(또는 명확히 비-PO로 표시), 모든 수령 라인은 해당 PO 라인의 잔여 수량을 감소시켜야 합니다.
핵심 구매 테이블부터 시작하세요:
- Vendors: 공급업체별 한 행(이름, 조건, 세금 정보).
- ItemsServices: 선택적이지만 일관성에 도움(SKU, 설명, 단위).
- PurchaseOrders: PO 헤더(vendor_id, currency, requested_by, status).
- PO_Lines: 매칭의 중심(po_id, item_id/description, ordered_qty, unit_price).
수령은 자체 기록이 필요합니다. "영수증"이 단순한 확인이라도, 무엇이 언제 도착했는지 증명할 수 있도록 송장과 분리해서 보관하세요:
- Receipts: 영수증 헤더(vendor_id, received_date, location, status).
- Receipt_Lines: 각 라인이 PO 라인을 참조(receipt_id, po_line_id, received_qty, notes).
송장(인보이싱)은 수령을 반영합니다. 공급업체가 청구한 것을 라인 수준으로 저장하고 해당 PO 라인에 연결하세요:
- Invoices: 송장 헤더(vendor_id, invoice_number, invoice_date, due_date, status).
- Invoice_Lines: (invoice_id, po_line_id when applicable, invoiced_qty, unit_price, tax, line_total).
마지막으로, 워크플로우가 차단할 수 있는 결제 지향 레코드를 만드세요. 일부 팀은 이를 bill, payment request, pay run item 등으로 부릅니다:
- PaymentRequests (또는 Bills): invoice_id에 연결되고 payment_hold(true/false) 및 hold_reason을 포함합니다.
감사와 깔끔한 예외 처리를 위해 헤더들(PO, 수령, 송장, 결제)에 일관된 라이프사이클 필드를 추가하세요: status, created_at/created_by, approved_at/approved_by, posted_at, 그리고(선택적으로) import용 source_document_id.
매칭을 신뢰할 수 있게 하는 주요 필드와 관계
매칭은 모든 문서가 동일한 라인 아이템으로 추적될 때 가장 잘 작동합니다. 즉, 안정적인 ID, 깔끔한 링크, 라인에서 재계산 가능한 합계가 필요합니다.
각 테이블에 내부적으로 안정적인 ID와 사람들이 검색하는 외부 번호를 모두 갖추세요:
- PO 헤더: po_id, po_number, vendor_id, currency, status, po_date
- PO 라인: po_line_id, po_id, item_id or description, ordered_qty, unit_price, tax_rate, line_total
- 수령: receipt_id, receipt_number, vendor_id, received_date; receipt_line_id, receipt_id, po_line_id, received_qty
- 송장: invoice_id, vendor_id, vendor_invoice_number, invoice_date, currency, subtotal, tax_total, total; invoice_line_id, invoice_id, po_line_id, qty, unit_price, tax_amount, line_total
- 공급업체 및 품목: vendor_id, payment_terms, default_currency; item_id, uom, tax_code
가장 중요한 연결은 라인 수준입니다:
- invoice_line.po_line_id는 PO 라인을 가리켜야 합니다.
- receipt_line.po_line_id도 동일한 PO 라인을 가리켜야 합니다.
이로써 수량과 가격을 추측 없이 비교할 수 있습니다.
부분 처리를 다루려면 PO 라인별 누적 합계를 계산하세요: received_qty(수령 라인의 합) 및 invoiced_qty(송장 라인의 합). 그런 다음 remaining_qty = ordered_qty - received_qty 및 open_to_invoice_qty = received_qty - invoiced_qty를 계산하세요. 이 값들은 송장이 선행인지 지연인지 과청구인지 한눈에 보여줍니다.
PO가 변경될 때 이력을 덮어쓰지 마세요. PO 개정 번호를 저장하고 오래된 PO 라인을 보관(active flag)하거나 변경 로그(who changed what, when, old value, new value)를 기록하세요.
중복 및 잘못된 조인 방지를 위한 기본 가드레일을 추가하세요:
- Unique (vendor_id, vendor_invoice_number)
- Unique receipt_number and po_number
- Not null on currency, quantities, and unit_price
- Check constraints like qty >= 0 and unit_price >= 0
- Foreign keys from invoice_line and receipt_line to po_line
단계별 워크플로우: 송장 접수부터 결제 보류까지
삼자대조 자동화는 보통 세 가지 진입점이 있습니다: 송장이 도착(이메일, 업로드, EDI), 수령이 게시, 또는 PO가 변경(가격, 수량, 상태). 워크플로우는 이들 중 어느 것이든 반응해야 보류 중인 송장이 누락된 부분이 채워지면 즉시 해제될 수 있습니다.
1) 먼저 송장의 기본을 검증하세요. 공급업체가 활성 상태인지, PO가 존재하는지, 통화가 PO와 일치하는지, 합계가 내부적으로 일관되는지(라인 합계가 더해져 총계가 맞는지, 세금이 합리적인지, 음수 수량이 아닌지 등)를 확인하세요. 실패하면 송장을 명확한 사유와 함께 바로 Hold로 보내세요.
2) 헤더뿐 아니라 라인별로 매칭하세요. 각 송장 라인에 대해 관련 PO 라인과 현재까지의 수령 합계를 찾고 비교하세요:
- 청구된 수량 vs 수령된 수량(또는 이미 청구된 것을 뺀 수령량)
- 송장 단가 vs PO의 단가
- 허용오차 규칙
- PO 라인이 아직 청구 가능한지 여부
3) 상태를 설정하고 차단을 시행하세요. 일반적인 패턴:
- Matched: 모든 라인이 검사를 통과하고 열린 예외가 없음.
- Hold: 최소 하나의 라인이 실패하거나 필요한 데이터가 누락됨.
Hold가 설정되면 결제 런이 준수해야 하는 payment hold 레코드를 생성하세요. 홀드는 송장과 분리해 보관해 홀드를 추가·해제·교체해도 송장 이력이 변경되지 않도록 하세요.
4) 재무가 신뢰할 수 있는 사유 코드를 기록하세요. 자유 텍스트형 홀드만 피하세요. PRICE_OVER_TOLERANCE, QTY_NOT_RECEIVED, PO_CLOSED, VENDOR_MISMATCH, CURRENCY_MISMATCH 같은 코드와 짧은 메모를 함께 사용하세요.
재무용 예외 큐 설계(무엇을 저장하고 무엇을 보여줄지)
예외 큐는 매칭을 실제로 활용 가능하게 만드는 곳입니다. 재무는 결정에 필요한 맥락을 충분히 보고 깔끔한 감사 기록을 남길 수 있어야 합니다.
일반적인 접근법은 ExceptionCases 같은 전용 테이블을 두는 것입니다. 각 행은 차단된 한 건의 송장(또는 송장 라인)을 나타내고 송장, PO, 수령 레코드를 참조합니다. 매칭 엔진은 여기에서 읽기 전용으로 두고 큐는 결정과 문서화 용도로만 사용하세요.
ExceptionCases에 저장할 항목
무엇이 잘못되었는지, 그 규모는 어느 정도인지, 누가 담당인지, 다음 단계는 무엇인지 저장하세요:
- Type(누락된 수령, 가격 차이, 수량 차이, PO 미발견, 중복 송장)
- Severity(info, warning, block)와 사용자 친화적 사유
- Owner(개인 또는 팀)와 상태(open, waiting on vendor, waiting on warehouse, resolved, overridden)
- 정렬 가능한 숫자형 분산 스냅샷(송장 금액, 매칭 금액, 가격 차이, 수량 차이)
- SLA 필드(기한, 에스컬레이션 플래그, reassigned_at, reassignment_reason)
또한 협업 및 감사 데이터를 저장하세요: 댓글(작성자, 타임스탬프)과 첨부파일 메타데이터(파일명, 유형, 업로더, 업로드 시간). 파일이 다른 곳에 있어도 메타데이터는 케이스에 있어야 이력이 완전합니다.
재무가 봐야 할 것(그리고 할 수 있는 것)
큐 뷰는 간결한 작업 목록이어야 합니다: 공급업체, 송장 번호, 예외 유형, 심각도, 금액, 기한, 담당자, 그리고 명확한 "차단 사유" 메시지.
케이스를 열면 좌우 비교 요약을 보여주세요: PO 라인, 수령 수량, 송장 라인, 그리고 실패한 정확한 필드.
동작은 제한적이고 안전해야 합니다:
- 수령 요청(수령 부서로 라우팅, 상태를 waiting으로 설정)
- 크레딧 메모 요청(공급업체로 라우팅, 예상 조정 기록)
- 오버라이드 승인(사유 필요, 승인자와 타임스탬프 캡처)
- 재할당(담당자 업데이트, 재할당 이력 보존)
- 해결로 종료(변경 후 매칭이 통과된 경우만)
예: 8개가 수령되었지만 10개가 청구된 송장은 블록됩니다. 재무는 수정된 송장을 요청하거나 수령된 8개에 대해 오버라이드를 승인하고 나머지 2개는 보류 상태로 둘 수 있습니다.
현실적인 예: 부분 수령과 불일치 송장
구매자가 품목 A 100개를 개당 $10.00에 주문했습니다. PO 합계는 $1,000입니다. 이틀 후 창고가 80개 수령을 게시했습니다.
그런데 송장이 100개에 대해 $10.00으로 도착했습니다. 매칭은 주문량이 아니라 수령된 양과 송장을 비교해야 합니다.
해당 라인에서는:
- 주문: 100개
- 수령: 80개
- 청구: 100개
- 매칭된 수량: min(Received, Invoiced) = 80개
- 미매칭 수량: Invoiced - Matched = 20개
송장은 20개에 대한 수령이 없어 "보류(On hold)"가 됩니다. 재무는 명확한 사유(수량 차이: +20)와 주요 수치를 나란히 보여주는 케이스를 봅니다.
알림은 보통 가장 빠르게 문제를 해결할 수 있는 사람에게 가야 합니다: 보통 수령자(수령이 누락되었는지 확인)와 구매자(선적 부족인지 확인)입니다.
나머지 20개가 도착하면 창고가 두 번째 수령(20개)을 게시합니다. 시스템은 매칭을 재실행해 수령이 100이 되고 미매칭이 0이 되어 송장이 Matched로 바뀌고 보류가 해제됩니다.
이제 가격 차이를 추가하면, 공급업체가 100개를 $10.50로 청구하면 수량은 맞지만 가격이 다릅니다. 예상 결과: 송장을 보류하고 "Price variance: +$0.50/unit (+$50 total)" 같은 사유로 라우팅합니다.
삼자대조 워크플로우를 망치는 흔한 실수들
대부분의 매칭 실패는 수학 문제가 아닙니다. 약한 데이터 링크와 게시 문서에 대한 느슨한 통제가 원인입니다.
송장 합계만으로 매칭하는 것. 문서 합계는 괜찮아 보여도 한 라인이 과대 청구되었거나 부족할 수 있습니다. 라인 수준 매칭을 하고 무엇이 차이날 수 있는지(보통 운임)와 차이나서는 안 되는 것(수령 수량과 단가)을 명확히 하세요.
한 PO당 한 번의 수령과 한 번의 송장을 전제로 하는 것. 실제 구매에는 분할 배송과 부분 청구가 포함됩니다. 동일 PO 라인에 여러 수령과 여러 송장을 지원하고 라인별로 남은 개수를 추적하세요.
게시된 수령이나 송장을 흔적 없이 수정할 수 있게 하는 것. 누군가가 나중에 수량을 조용히 변경할 수 있으면 매칭은 증거가 되지 않습니다. 게시된 레코드는 잠그고 조정 문서를 통해 수정해 이력을 보존하세요.
중복 방지 누락. 동일 공급업체 송장 번호가 두 번 입력되거나 같은 PDF가 다른 사람이 다시 업로드되는 경우가 있습니다. 초기에 중복 방지(공급업체 + 송장 번호, 선택적으로 날짜/금액)를 추가하고 중복이 감지되면 명확한 메시지를 보여주세요.
모호한 예외 사유. 재무는 추측해서는 안 됩니다. 가격 불일치, 수량 불일치, 수령 누락, 중복 의심, PO 미발견, 공급업체 불일치 같은 사유 코드를 사용해 깔끔하게 라우팅하세요.
결제 차단을 켜기 전 빠른 체크리스트
결제 차단은 매칭이 리포트가 아닌 통제가 되는 순간입니다. 기본이 튼튼하지 않으면 재무에 소음이 생기고 공급업체에 대한 지연 결제가 발생합니다.
작동 방식이 다른 소량의 송장들을 테스트하세요: 클린 매치, 부분 수령, 가격 변경, 세금 차이 등. 어떤 것도 깔끔하게 매치되지 않으면 먼저 데이터와 규칙을 수정하세요.
체크리스트:
- 참조 완전성: 모든 송장에 공급업체와 PO 참조가 있고, 각 송장 라인이 특정 PO 라인에 매핑될 수 있는지(단순히 "PO 총합"이 아닌지). 공급업체가 PO 헤더 번호만 보냈을 때 어떻게 처리할지 결정하세요.
- 수학적 일관성: 수량, 단가, 합계가 언제나 같은 방식으로 재계산됩니다. 세금, 운임, 할인, 반올림(예: 라인별 반올림 vs 합계에서만 반올림)을 명확히 하세요.
- 상태가 충분히 빨리 차단하는가: 결제 요청이나 지불 레코드가 생성되기 전에 "on hold"를 설정하세요.
- 구조화된 예외: 모든 보류는 사유 코드와 담당자(AP, 구매자, 수령자)를 저장합니다. 보류가 영원히 방치되지 않도록 기한을 설정하세요.
- 실제 감사 추적: 오버라이드는 누가 언제 무엇을 승인했는지(원래 값 포함)를 기록합니다. 편집을 허용하면 변경 전후 값을 기록하세요.
다음 단계: 프로세트를 파일럿하고 시각적으로 구축하세요
삼자대조 자동화를 통제처럼 다루세요: 작은 범위에서 작동을 입증한 다음 확대하세요.
감시하기 쉬운 파일럿부터 시작하세요. 하나의 사업부, 깨끗한 송장을 보내는 소수의 공급업체 그룹, 또는 단일 품목 카테고리를 선택하세요. 처음에는 규칙을 엄격하게 유지(정확한 수량과 가격 일치)해 데이터 품질 문제가 빨리 드러나게 하세요.
성공을 측정할 간단한 재무 뷰를 만드세요: 주당 보류 건수, 상위 사유 코드, 보류에서 해제까지 소요 시간, 실제 불일치였던 보류 비율, 반복적으로 예외를 발생시키는 공급업체.
빠르게 프로토타입을 만들고 싶다면 노코드 플랫폼이 도움이 됩니다. 테이블, 매칭 규칙, 라우팅을 코드 없이 모델링할 수 있기 때문입니다. 예를 들어 AppMaster (appmaster.io)에서는 PO, 수령, 송장, 예외 테이블을 구축하고 시각적 비즈니스 프로세스에서 보류 로직을 연결해 동일한 규칙이 모든 트리거에서 실행되게 할 수 있습니다.
파일럿 그룹의 실제 송장(부분 수령과 일반적인 공급업체 실수 포함)으로 테스트하세요. 패턴을 확인한 뒤에만 매칭 키를 조정하고 작은 허용오차를 추가하세요. 보류가 합리적으로 보이고 해제 시간이 개선되면 범위를 확장하고 더 풍부한 규칙(세금과 운임 처리, 단위 변환, 분할 배송)을 추가하되 핵심 통제는 유지하세요: 매칭이 통과될 때까지 결제는 해제되지 않습니다.


