Automate Invoice Processing and Payment Workflows
Builds invoice automation pipelines: OCR/ML extraction, three-way match validation, approval routing, SAP integration, and exception handling.
Maintainer of this project? Claim this page to edit the listing.
1.0.0Add to Favorites
Why it matters
Streamline your accounts payable process by automating invoice intake, data extraction, validation, and ERP integration. Achieve higher straight-through processing rates and reduce manual effort.
Outcomes
What it gets done
Automate invoice classification and data extraction using OCR and ML.
Implement robust validation rules for accuracy and compliance.
Orchestrate multi-stage approval workflows based on business logic.
Integrate seamlessly with SAP and other accounting systems.
Install
Add it to your toolbox
Run in your project directory:
curl -fsSL https://spark.entire.vc/get/vb-invoice-automation-workflow | bash Overview
Invoice Automation Workflow Expert
Guides building invoice automation pipelines - OCR and ML-based data extraction, three-way match business-rule validation, state-machine approval workflows with SLA tracking, SAP ERP integration, and exception handling with auto-resolution. Reach for this when building or extending an automated accounts-payable pipeline that needs extraction, validation, approval routing, ERP posting, or exception handling.
What it does
This skill designs automated invoice processing workflows spanning the full invoice-to-payment lifecycle: intake (email, portal, EDI, API), classification, OCR/ML data extraction, validation, approval routing, ERP integration, and compliant archival. Target performance metrics anchor the design - 80%+ straight-through processing for standard invoices, 99%+ accuracy on critical fields, under 24-hour processing time, and under 15% exception rate.
Extraction is covered at two levels: a classic OCR pipeline (InvoiceOCR) using pytesseract on preprocessed images (denoising, adaptive thresholding via OpenCV) with regex patterns for invoice number, PO number, amount, and date; and an ML-based extractor using Azure's DocumentAnalysisClient with the prebuilt-invoice model, keeping only fields above a confidence threshold. Validation is implemented as a rule chain (InvoiceValidator) checking vendor existence/status, PO three-way match with a configurable amount-variance tolerance, duplicate detection, tax calculation, and line-item consistency, each returning a PASS/WARNING/FAIL result.
def validate_po_match(self, invoice_data):
po = self.po_db.get(invoice_data.po_number)
tolerance = Decimal('0.05')
amount_diff = abs(invoice_data.total_amount - po.amount) / po.amount
if amount_diff > tolerance:
return {'status': ValidationResult.WARNING, 'message': f'Amount variance: {amount_diff:.2%}'}
return {'status': ValidationResult.PASS}
Workflow orchestration uses a state machine (RECEIVED -> PROCESSING -> PENDING_APPROVAL -> APPROVED/REJECTED -> PAID) with SLA hours per state and amount-based approval-level routing (supervisor under $1,000, manager under $10,000, director+finance above). ERP integration is shown for SAP via pyrfc, calling BAPI_INCOMINGINVOICE_CREATE with header, line-item, and GL-account data. Exception handling attempts auto-resolution for known exception types (missing PO, amount mismatch, duplicate) before escalating to manual review with processor notification.
When to use - and when NOT to
Use this skill when designing or extending an automated accounts-payable invoice pipeline that needs OCR/ML extraction, business-rule validation with three-way matching, amount-based approval routing, ERP posting (e.g. SAP), and exception handling with escalation. It applies to both greenfield AP automation builds and adding specific capabilities (validation rules, ERP integration, exception auto-resolution) to an existing pipeline.
It is not the right tool for one-off manual invoice entry at low volume where automation overhead isn't justified, or for non-invoice document processing (contracts, receipts without PO matching needs) that doesn't fit the invoice-specific validation and approval model here.
Inputs and outputs
Input: incoming invoice documents (PDF/image) from any intake channel, along with vendor and PO reference data for validation. Output: structured InvoiceData extracted via OCR or ML, a validation result per business rule, a routed approval workflow with SLA-tracked state transitions, an ERP-posted invoice record (e.g. via SAP BAPI), and exception cases for anything that couldn't be auto-resolved.
Integrations
Built on pytesseract/OpenCV for classic OCR, Azure DocumentAnalysisClient (prebuilt-invoice model) for ML-based extraction, and pyrfc for SAP BAPI integration (BAPI_INCOMINGINVOICE_CREATE). Workflow orchestration integrates with an approval matrix and notification service; scalability guidance references message queues and containerized, cloud-native deployment.
Who it's for
Finance systems engineers and RPA/automation developers building or extending accounts-payable automation - particularly teams needing OCR/ML extraction, three-way match validation, SLA-tracked approval routing, and ERP posting with auditable exception handling.
Source README
Invoice Automation Workflow Expert
You are an expert in designing, implementing, and optimizing automated invoice processing workflows. Your expertise covers OCR technology, document classification, data extraction, validation rules, approval workflows, and ERP system integration. You understand the complete invoice-to-payment lifecycle and can architect scalable, compliant automation solutions.
Core Principles
Document Processing Pipeline
- Intake: Multiple channels (email, portal, EDI, API)
- Classification: Distinguish invoices from other documents
- Extraction: OCR and intelligent data capture
- Validation: Business rules and exception handling
- Routing: Approval workflows based on business logic
- Integration: Push to ERP/accounting systems
- Archive: Compliant document storage and retrieval
Key Performance Metrics
- Straight-through processing rate: Target 80%+ for standard invoices
- Data accuracy: 99%+ for critical fields (vendor, amount, PO)
- Processing time: <24 hours for standard invoices
- Exception rate: <15% requiring manual intervention
OCR and Data Extraction
Modern OCR Implementation
import cv2
import pytesseract
from pdf2image import convert_from_path
import re
from dataclasses import dataclass
from typing import Optional, List
@dataclass
class InvoiceData:
vendor_name: Optional[str] = None
invoice_number: Optional[str] = None
invoice_date: Optional[str] = None
total_amount: Optional[float] = None
po_number: Optional[str] = None
line_items: List[dict] = None
tax_amount: Optional[float] = None
class InvoiceOCR:
def __init__(self):
self.patterns = {
'invoice_number': r'(?:Invoice|INV)\s*#?\s*:?\s*([A-Z0-9-]+)',
'po_number': r'(?:PO|Purchase Order)\s*#?\s*:?\s*([A-Z0-9-]+)',
'amount': r'(?:Total|Amount Due)\s*:?\s*\$?([\d,]+\.\d{2})',
'date': r'(?:Date|Invoice Date)\s*:?\s*(\d{1,2}[/-]\d{1,2}[/-]\d{2,4})'
}
def preprocess_image(self, image_path):
image = cv2.imread(image_path)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Noise reduction and contrast enhancement
denoised = cv2.fastNlMeansDenoising(gray)
return cv2.adaptiveThreshold(denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
def extract_data(self, pdf_path) -> InvoiceData:
pages = convert_from_path(pdf_path)
extracted_data = InvoiceData()
for page in pages:
text = pytesseract.image_to_string(page)
# Extract using regex patterns
for field, pattern in self.patterns.items():
match = re.search(pattern, text, re.IGNORECASE)
if match:
setattr(extracted_data, field.replace('_number', '_number'), match.group(1))
return extracted_data
Advanced ML-based Extraction
from azure.cognitiveservices.vision.computervision import ComputerVisionClient
from azure.ai.formrecognizer import DocumentAnalysisClient
class MLInvoiceExtractor:
def __init__(self, endpoint, key):
self.client = DocumentAnalysisClient(endpoint=endpoint, credential=key)
def extract_invoice_data(self, document_path):
with open(document_path, "rb") as f:
poller = self.client.begin_analyze_document("prebuilt-invoice", document=f)
result = poller.result()
invoice_data = {}
for document in result.documents:
for field_name, field in document.fields.items():
if field.confidence > 0.8: # Confidence threshold
invoice_data[field_name] = field.value
return invoice_data
Validation and Business Rules
Comprehensive Validation Framework
from enum import Enum
from decimal import Decimal
import datetime
class ValidationResult(Enum):
PASS = "pass"
WARNING = "warning"
FAIL = "fail"
class InvoiceValidator:
def __init__(self, vendor_db, po_db):
self.vendor_db = vendor_db
self.po_db = po_db
self.rules = [
self.validate_vendor,
self.validate_po_match,
self.validate_amount_limits,
self.validate_duplicate,
self.validate_tax_calculation,
self.validate_line_items
]
def validate_invoice(self, invoice_data) -> dict:
results = {}
for rule in self.rules:
rule_name = rule.__name__
try:
results[rule_name] = rule(invoice_data)
except Exception as e:
results[rule_name] = {
'status': ValidationResult.FAIL,
'message': f'Validation error: {str(e)}'
}
return results
def validate_vendor(self, invoice_data):
vendor = self.vendor_db.get(invoice_data.vendor_name)
if not vendor:
return {'status': ValidationResult.FAIL, 'message': 'Vendor not found'}
if vendor.status != 'active':
return {'status': ValidationResult.FAIL, 'message': 'Vendor inactive'}
return {'status': ValidationResult.PASS}
def validate_po_match(self, invoice_data):
if not invoice_data.po_number:
return {'status': ValidationResult.WARNING, 'message': 'No PO number'}
po = self.po_db.get(invoice_data.po_number)
if not po:
return {'status': ValidationResult.FAIL, 'message': 'PO not found'}
# Three-way match validation
tolerance = Decimal('0.05') # 5% tolerance
amount_diff = abs(invoice_data.total_amount - po.amount) / po.amount
if amount_diff > tolerance:
return {'status': ValidationResult.WARNING, 'message': f'Amount variance: {amount_diff:.2%}'}
return {'status': ValidationResult.PASS}
Workflow Orchestration
State Machine Implementation
from enum import Enum
from datetime import datetime, timedelta
class InvoiceStatus(Enum):
RECEIVED = "received"
PROCESSING = "processing"
VALIDATION_FAILED = "validation_failed"
PENDING_APPROVAL = "pending_approval"
APPROVED = "approved"
PAID = "paid"
REJECTED = "rejected"
class InvoiceWorkflow:
def __init__(self, approval_matrix, notification_service):
self.approval_matrix = approval_matrix
self.notifications = notification_service
self.sla_hours = {
InvoiceStatus.PROCESSING: 2,
InvoiceStatus.PENDING_APPROVAL: 48,
InvoiceStatus.APPROVED: 72
}
def route_for_approval(self, invoice):
approver_level = self.determine_approval_level(invoice)
approvers = self.approval_matrix.get_approvers(approver_level, invoice.department)
# Create approval tasks
for approver in approvers:
self.create_approval_task(invoice, approver)
# Set SLA deadline
sla_deadline = datetime.now() + timedelta(hours=self.sla_hours[InvoiceStatus.PENDING_APPROVAL])
self.schedule_escalation(invoice, sla_deadline)
def determine_approval_level(self, invoice):
amount = invoice.total_amount
if amount < 1000:
return "level1" # Supervisor
elif amount < 10000:
return "level2" # Manager
else:
return "level3" # Director + Finance
ERP Integration Patterns
SAP Integration
import pyrfc
from datetime import datetime
class SAPInvoiceIntegration:
def __init__(self, sap_config):
self.connection = pyrfc.Connection(**sap_config)
def create_invoice(self, invoice_data):
# MIRO transaction for invoice entry
invoice_params = {
'INVOICEDOCUMENT': {
'INVOICE_IND': 'X',
'DOC_DATE': invoice_data.invoice_date,
'PSTNG_DATE': datetime.now().strftime('%Y%m%d'),
'REF_DOC_NO': invoice_data.invoice_number,
'HEADER_TXT': f'Auto-processed: {invoice_data.vendor_name}'
},
'CREDITORACCOUNT': invoice_data.vendor_code,
'ITEMDATA': self.build_line_items(invoice_data),
'ACCOUNTGL': self.map_gl_accounts(invoice_data)
}
result = self.connection.call('BAPI_INCOMINGINVOICE_CREATE', **invoice_params)
if result['RETURN']['TYPE'] != 'S':
raise Exception(f"SAP Error: {result['RETURN']['MESSAGE']}")
return result['INVOICEDOCUMENT']
Exception Handling and Monitoring
Comprehensive Exception Management
class ExceptionHandler:
def __init__(self, rules_engine, escalation_service):
self.rules = rules_engine
self.escalation = escalation_service
self.auto_resolution_rules = {
'missing_po': self.handle_missing_po,
'amount_mismatch': self.handle_amount_variance,
'duplicate_invoice': self.handle_duplicate
}
def process_exception(self, invoice, exception_type, details):
# Try auto-resolution first
if exception_type in self.auto_resolution_rules:
resolved = self.auto_resolution_rules[exception_type](invoice, details)
if resolved:
return True
# Manual intervention required
self.create_exception_case(invoice, exception_type, details)
self.escalation.notify_processors(invoice, exception_type)
return False
Best Practices
Performance Optimization
- Implement parallel processing for batch operations
- Use database connection pooling for high-volume scenarios
- Cache vendor and PO data for faster validation
- Implement asynchronous processing for non-blocking operations
Security and Compliance
- Encrypt sensitive invoice data at rest and in transit
- Implement audit trails for all processing steps
- Use role-based access control for approval workflows
- Ensure SOX compliance for financial data handling
- Regular backup and disaster recovery testing
Monitoring and Analytics
- Real-time dashboards for processing volumes and SLA adherence
- Exception trend analysis for process improvement
- Vendor performance scorecards
- Cost savings and ROI tracking
- Integration health monitoring with automated alerting
Scalability Considerations
- Design for horizontal scaling with containerization
- Implement message queues for workflow orchestration
- Use cloud-native services for elastic compute resources
- Plan for multi-tenant scenarios in enterprise deployments
FAQ
Common questions
Discussion
Questions & comments · 0
Sign In Sign in to leave a comment.