AP AI ERP Integration
Purpose
We need to investigate, design, and size the effort required to support ERP integration configuration and the new invoice workflow stages (Matching, Manual, and Filing) in AP AI so we can sequence delivery confidently and surface any architectural risks before sprint commitment.
Scope
The legacy application includes ERP/CRM integration configuration and a multi-stage invoice processing workflow. As part of the SaaS implementation, the following capabilities need to be scoped and designed before development begins:
- ERP Integration Configuration (backend & frontend): Provider selection and a request form for unsupported connectors
- Matching Stage: PO/Invoice comparison with mismatch visibility and user action paths
- Manual Stage: Manual override with notes, line item vouching, and action paths
- Filing Stage: Confirmation of ERP filing with action paths to Closed
Goals
- Identify integration touchpoints with the existing stage framework and Closed stage transition logic
- Surface any open questions around ERP connector architecture, data contracts, and permissions
- Deliver T-shirt size estimates (XS/S/M/L/XL/XXL) per functional area, broken down by UI, API/backend, and integration layer
T-Shirt Sizing Framework
1. ERP Integration Configuration
Overview
The ERP Integration Configuration page provides administrators with the ability to connect their ERP system to AP AI, manage email inboxes for invoice intake, and configure webhooks. This is accessed via the Connections tab in the settings area.
(image not available in export: /Users/karan.thelakkat@postman.com/Repos/fern-cla-main/Reference Material/images/ERP UI.png)
UI Components
Tabs
- Connections (active) — ERP, inbox, and webhook setup
- Features — Feature toggle configuration
- Workflow Configuration — Stage-level workflow settings
Inbox Monitoring Manager
- Monitored Inboxes / Blocked Senders toggle tabs
- Add Inbox button to subscribe new email inboxes
- Displays “No inboxes subscribed.” when empty
Integration Connections
- Displays the currently connected ERP (e.g., “Connected ERP: Epicor 21”)
- Shows connection details:
- ERP Base URL
- ERP Username
- Save Enabled flag
- Disconnect button to remove the active connection
- ERP dropdown — select ERP type (e.g., Epicor, SAP, NetSuite)
- Select provider dropdown — choose specific provider instance
- Request New Connector Support link — form/request for unsupported ERP connectors
Webhook Manager
- Add (+) button to register new webhooks
- Displays “No webhooks registered.” when empty
User Workflows
Connect a New ERP
- Navigate to Connections tab
- Select ERP type from dropdown
- Select provider from dropdown
- Enter connection credentials (URL, username, password/API key)
- Save connection
- Connection details appear in the Integration Connections card
Disconnect an ERP
- Click Disconnect on the active connection card
- Confirm disconnection
- Connection is removed
Request Unsupported Connector
- Click Request New Connector Support
- Fill out request form with ERP details
- Submit for review
Manage Inboxes
- Click Add Inbox to subscribe a new email inbox for invoice intake
- Toggle between Monitored Inboxes and Blocked Senders to manage
Existing Codebase Findings
The ERP integration layer already exists in common/erp/. Key findings:
- Connector abstraction (
abstract_connector.py): Defines theERPConnectorbase class with abstract methods:connect(),get_purchase_order(),get_receipts_by_po_number(),get_terms(),get_all_terms(),get_vendor(),get_all_vendors(),file_invoice() - Supported connectors (
connectors/__init__.py):epicor21,sageintacct,cla-mocked— mapped inconnector_mapping - Epicor 21 connector (
connectors/epicor21/epicor21.py): Fully implemented with token-based auth, PO retrieval (external + internal), receipts fetch, terms, vendors, and filing via XML-based voucher conversion - Sage Intacct connector (
connectors/sageintacct/connect2.py): Exists as a second real connector - ERP Service (
service.py):ERPServiceclass with TTL-cached connector instances per client (5 min TTL), exposesget_purchase_order(),get_receipts_by_po_number(),file_invoice() - Client config storage: Credentials stored in CosmosDB (
talaria.clientscontainer), encrypted per-client viaClientConfig.decrypt_connection("ERP") - Filing: Uses XML transaction sets to convert PO to voucher in Epicor via interactive UI server sessions
Existing API Routes (backend-api)
Existing ERP Connector Methods (Epicor 21)
T-Shirt Sizing (Revised)
Overall: M (3–5 days) — significantly reduced from L because the backend and integration layers already exist. Primary effort is the UI build.
Proposed User Stories
ERP-US-1: ERP Provider Selection UI
As an admin, I want to select an ERP type and provider from dropdowns so that I can configure my ERP connection.
- AC: ERP type dropdown populated from provider registry
- AC: Provider dropdown filters based on selected ERP type
- AC: Validation prevents saving without required fields
ERP-US-2: ERP Connection Management
As an admin, I want to connect and disconnect my ERP system so that AP AI can file invoices to my ERP.
- AC: Successful connection displays ERP name, URL, username, and save enabled status
- AC: Disconnect button removes the active connection after confirmation
- AC: Connection errors display meaningful error messages
ERP-US-3: ERP Connector Request Form
As an admin, I want to request support for an ERP not in the provider list so that my organization can still onboard.
- AC: Request form captures ERP name, version, and contact info
- AC: Submission confirms the request was received
ERP-US-4: Inbox Monitoring Manager
As an admin, I want to add and manage monitored email inboxes so that invoices are automatically ingested.
- AC: Add Inbox flow captures inbox configuration
- AC: Monitored Inboxes tab lists active subscriptions
- AC: Blocked Senders tab allows managing sender blocklist
ERP-US-5: Webhook Manager
As an admin, I want to register webhooks so that external systems are notified of invoice events.
- AC: Add button opens webhook configuration form
- AC: Registered webhooks displayed in list with edit/delete options
2. Matching Stage
Overview
The Matching Stage is the second stage in the invoice workflow (Intake → Matching → Manual → Filing → Closed). It performs an automated comparison between the Purchase Order (PO) and the submitted Invoice to identify mismatches in quantities, pricing, and line items. Users review discrepancies and decide how to proceed.
(image not available in export: /Users/karan.thelakkat@postman.com/Repos/fern-cla-main/Reference Material/images/Matching Stage.png)
UI Components
Workflow Breadcrumb
- Linear stage indicator: Intake → Matching → Manual → Filing → Closed
- Each stage shows a status icon (green check = complete, yellow warning = current with issues)
Error Banner
- Displays at the top when matching errors are detected
- Example: “Error — This invoice has matching errors”
Invoice Header
Side-by-Side Comparison
Left Panel — Purchase Order
- PO Number and Terms displayed at top
- Columns: Receipt #, Description, Qty, Unit Price, Amount
- Mismatched cells highlighted in red
Right Panel — Invoice
- Invoice Number and Terms displayed at top
- Terms dropdown (editable, e.g., Net 30)
- Columns: Description, Qty, Unit Price, Amount
- Mismatched cells highlighted in red
Mismatch Highlighting
- Cells with discrepancies between PO and Invoice are highlighted with a red background and dashed border
- Example: PO shows Qty 0 / 53.42
Action Buttons
User Workflows
Invoice with No Mismatches
- Invoice enters Matching stage automatically after Intake
- PO and Invoice line items are compared
- No mismatches found → all cells are clean
- User clicks Continue → Invoice advances to Filing stage (skips Manual)
Invoice with Mismatches
- Invoice enters Matching stage
- Error banner displays: “This invoice has matching errors”
- User reviews side-by-side comparison with red-highlighted cells
- User decides:
- Continue → Accept mismatches and advance (to Manual or Filing based on workflow config)
- Manual → Route to Manual stage for line-item-level review
- Reject → Reject the invoice entirely
- Rerun → Re-execute matching (e.g., if PO was updated in ERP)
Rerun Matching
- User updates PO data in ERP
- User clicks Rerun on the Matching stage
- System re-fetches PO data and re-runs comparison
- Updated results displayed
Existing Codebase Findings
- PO retrieval:
ERPService.get_purchase_order()andERPService.get_receipts_by_po_number()already exist and call the Epicor 21 API - Matching route:
PATCH /invoices/{invoiceID}/matcherexists ininvoice_v2.py— this is the endpoint for updating matching data - Stage transitions:
POST /invoices/{invoiceID}/stage/{viewedStage}handles stage changes (Continue, Reject, Manual routing) - Receipt fields: Epicor connector fetches:
receipt_number,po_number,po_line_number,unit_cost,extended_cost,qty_ordered,item_id,item_desc,receipt_line_unit_of_measure,qty_vouched,vendor_name - PO lookup: Tries external PO number first (
ExternalPoNo), then internal (PoNo) - Audit logging:
POST /databases/{db_name}/audit_loggingandGET /invoices/{invoice_id}/historyexist in the datastore API
T-Shirt Sizing (Revised)
Overall: M (3–5 days) — reduced from L because PO retrieval, stage transitions, and audit logging already exist.
Proposed User Stories
MATCH-US-1: PO/Invoice Side-by-Side Comparison
As a reviewer, I want to see the PO and Invoice line items side by side so that I can identify discrepancies.
- AC: PO data displayed on the left, Invoice data on the right
- AC: Line items aligned by matching logic (description/SKU)
- AC: Columns show Receipt #, Description, Qty, Unit Price, Amount
MATCH-US-2: Mismatch Highlighting
As a reviewer, I want to see mismatched cells highlighted in red so that discrepancies are immediately visible.
- AC: Cells where PO and Invoice values differ are highlighted
- AC: Mismatches include quantity, unit price, and amount differences
MATCH-US-3: Matching Error Banner
As a reviewer, I want to see a clear error message when the invoice has matching errors so that I know action is required.
- AC: Error banner appears at top of page when mismatches exist
- AC: Banner is hidden when no mismatches are detected
MATCH-US-4: Matching Stage Actions
As a reviewer, I want to choose between Rerun, Manual, Reject, and Continue so that I can route the invoice appropriately.
- AC: Rerun re-executes matching and refreshes results
- AC: Manual routes invoice to Manual stage
- AC: Reject moves invoice to rejected status with confirmation
- AC: Continue advances invoice to the next stage
MATCH-US-5: Rerun Matching
As a reviewer, I want to rerun the matching after a PO is updated so that I see the latest comparison.
- AC: Rerun fetches latest PO data from ERP
- AC: Comparison results are refreshed in the UI
- AC: Previous match results are replaced
3. Manual Stage
Overview
The Manual Stage is the third stage in the invoice workflow (Intake → Matching → Manual → Filing → Closed). It allows reviewers to manually override line item matching, vouch for invoice line items against PO receipts, add notes explaining adjustments, and approve or reject the invoice before it advances to Filing.
(image not available in export: /Users/karan.thelakkat@postman.com/Repos/fern-cla-main/Reference Material/images/Manual Stage.png)
UI Components
Workflow Breadcrumb
- Linear stage indicator: Intake → Matching → Manual → Filing → Closed
- Manual stage highlighted as current (green check on previous stages)
Invoice Header
Left Panel — PO / Receipt Data
- Terms displayed (e.g., Net 30)
- Vouch All? checkbox — bulk vouch all line items at once
- Table columns:
- Receipt #
- Item ID
- Item Description
- UOM (Unit of Measure)
- QTY (Rem) — remaining quantity on PO
- QTY (Inv) — quantity on invoice
- Unit Price
- Freight (Inv)
- Ext Cost
- Subtotal, Freight, and Total rows
- Displays “No results.” when no PO receipts are matched
Right Panel — Invoice Data
- Terms mapping displayed (e.g., “NET 30 DAYS mapped to Net 30”)
- Table columns:
- Prod Code
- Prod Description
- Qty
- Unit Price
- Ext Cost
- Subtotal, Freight, and Total rows
Manual Stage Notes
- Textarea: “Add notes about the manual adjustment…”
- Accept (green check) and Cancel (red X) buttons for the note
- Notes are saved as part of the manual review record
Action Buttons
User Workflows
Manual Review with Vouching
- Invoice arrives at Manual stage (from Matching or directly)
- Reviewer sees PO receipt data on the left, invoice data on the right
- Reviewer vouches individual line items or clicks Vouch All?
- Reviewer adds notes explaining any adjustments
- Reviewer clicks Approve → Invoice advances to Filing
Manual Review — No PO Match
- Invoice has no matching PO receipts (“No results.” on left panel)
- Reviewer reviews invoice data on the right
- Reviewer adds notes explaining the approval rationale
- Reviewer clicks Approve or Reject
Reject Invoice
- Reviewer determines the invoice cannot be approved
- Reviewer optionally adds notes
- Reviewer clicks Reject → Invoice is rejected
Existing Codebase Findings
- Manual route:
PATCH /invoices/{invoiceID}/manualexists ininvoice_v2.py— this handles vouching/manual stage updates - Vouching in ERP: The Epicor receipt data includes
receipt_line_vouch_completeandqty_vouchedfields — vouching is an ERP-level concept (marking receipt lines as verified against an invoice) - Terms mapping:
get_all_terms()returns a dict of{terms_id: terms_desc}from Epicor. The mapping shown in the UI (“NET 30 DAYS” → “Net 30”) is likely matching the invoice’s raw terms text to the ERP’sterms_descvalues. - Stage transitions: Same
POST /invoices/{invoiceID}/stage/{viewedStage}route handles Approve/Reject - Receipt fields available for vouching:
receipt_number,po_line_number,item_id,item_desc,unit_cost,extended_cost,qty_ordered,receipt_line_unit_of_measure,receipt_line_unit_quantity,qty_vouched
T-Shirt Sizing (Revised)
Overall: S–M (2–5 days) — reduced because the API route and ERP integration already exist. Primary effort is UI.
Proposed User Stories
MAN-US-1: Manual Review Layout
As a reviewer, I want to see PO receipt data alongside invoice data so that I can manually verify line items.
- AC: Left panel shows PO receipt details (Receipt #, Item ID, Description, UOM, quantities, pricing)
- AC: Right panel shows invoice line items (Prod Code, Description, Qty, Unit Price, Ext Cost)
- AC: Totals (Subtotal, Freight, Total) displayed on each side
MAN-US-2: Line Item Vouching
As a reviewer, I want to vouch individual invoice line items against PO receipts so that I can confirm they match.
- AC: Each line item has a vouch action
- AC: Vouched items are visually indicated
- AC: Vouch state is persisted
MAN-US-3: Vouch All
As a reviewer, I want to vouch all line items at once so that I can expedite review when everything matches.
- AC: “Vouch All?” checkbox vouches all line items
- AC: Unchecking removes vouch from all items
MAN-US-4: Manual Stage Notes
As a reviewer, I want to add notes explaining my manual adjustments so that there is an audit trail.
- AC: Textarea allows free-text notes
- AC: Save (check) and Cancel (X) buttons for note entry
- AC: Notes are persisted and visible in audit history
MAN-US-5: Approve / Reject Invoice
As a reviewer, I want to approve or reject the invoice so that it advances to Filing or is stopped.
- AC: Approve advances invoice to Filing stage
- AC: Reject moves invoice to rejected status with confirmation prompt
- AC: Both actions are audit-logged with timestamp and user
4. Filing Stage
Overview
The Filing Stage is the fourth and final active stage in the invoice workflow (Intake → Matching → Manual → Filing → Closed). It handles the submission of the approved invoice to the connected ERP system and confirms the filing status. Once filed successfully, the invoice transitions to Closed.
(image not available in export: /Users/karan.thelakkat@postman.com/Repos/fern-cla-main/Reference Material/images/Filling Stage.png)
UI Components
Workflow Breadcrumb
- Linear stage indicator: Intake → Matching → Manual → Filing → Closed
- All previous stages show green checks (completed)
Left Panel — Invoice Document Viewer
- Rendered image/PDF of the original invoice document
- Navigation controls:
- Previous / Next page arrows
- Page indicator (e.g., “1 of 1”)
- Zoom controls:
- Zoom in / Zoom out buttons
- Current zoom level displayed (e.g., “120%”)
- Copy / export buttons
Right Panel — Filing Status
- Success Banner: “Filed successfully!” (green highlight)
- Invoice Filing Status card:
- Confirmation message with timestamp: “Invoice filed to ERP on [date] @ [time]”
- Example: “Invoice filed to ERP on 03/05/2026 @ 12:15:55 AM.”
Action Buttons
User Workflows
Successful Filing
- Invoice arrives at Filing stage after Manual approval
- System automatically files the invoice to the connected ERP
- “Filed successfully!” banner and timestamp are displayed
- Reviewer verifies the filing details and original invoice document
- Reviewer clicks Continue → Invoice transitions to Closed
Filing Failure
- Invoice arrives at Filing stage
- ERP filing fails (connection error, validation error, etc.)
- Error status is displayed instead of success banner
- Reviewer can:
- Reject → Route back for re-review
- Retry filing (if supported)
Reject After Filing
- Reviewer notices an issue with the filed invoice
- Reviewer clicks Reject
- Invoice is returned to an earlier stage or rejected queue
Existing Codebase Findings
- Filing already implemented:
ERPConnector.file_invoice()→Epicor21Connector.file_invoice()iterates oversync_data.purchaseOrdersand callsconvert_to_voucher()for each PO - Filing mechanism: Uses Epicor’s interactive UI server sessions (XML-based). Creates a session, opens the “Convert PO to Voucher” window, populates tabs with invoice/PO data, and submits. This is not a REST API call — it automates the Epicor desktop UI via server-side sessions.
- SyncData model: The filing payload is a
SyncDataobject containing:invoiceID,purchaseOrders(dict ofSyncDataPurchaseOrderwith PO ID, invoice number/date, line items with quantities/prices/freight, subtotals, tax, surcharges, shipping) - XML transaction:
filing_xml.pybuilds XML with tabs: voucher info (Tab 1), accounts (Tab 2), terms (Tab 3), miscellaneous, line items (Tab 17), purchase accounts (Tab 18) - Filing errors: Custom
InvoiceFilingErrorexception raised on failure - DELETE_filing.py: Exists — suggests there’s logic to reverse/delete a filing
- Save enabled flag:
self.save_enabledis loaded from config but its usage in the filing flow needs confirmation - Mock ERP:
POST /{client_name}/invoice/fileexists in mock-services for testing
T-Shirt Sizing (Revised)
Overall: S–M (2–4 days) — significantly reduced because the entire filing pipeline (SyncData → XML → Epicor session) is already built.
Proposed User Stories
FILE-US-1: Invoice Document Viewer
As a reviewer, I want to view the original invoice document during Filing so that I can verify what was filed.
- AC: Invoice document rendered on the left panel
- AC: Zoom in/out and page navigation controls functional
- AC: Document is read-only at this stage
FILE-US-2: ERP Filing Execution
As the system, I want to file the approved invoice to the connected ERP so that the invoice is recorded in the customer’s financial system.
- AC: Invoice data is sent to the ERP via the configured connector
- AC: Filing timestamp is recorded
- AC: Success or failure status is returned and displayed
FILE-US-3: Filing Status Display
As a reviewer, I want to see the filing status and timestamp so that I know the invoice was successfully filed.
- AC: “Filed successfully!” banner displayed on success
- AC: Filing timestamp shown (date and time)
- AC: Error message displayed on failure
FILE-US-4: Continue to Closed
As a reviewer, I want to confirm the filing and close the invoice so that the workflow is complete.
- AC: Continue button transitions invoice to Closed status
- AC: Invoice is no longer editable after closing
- AC: Closed status is reflected in the workflow breadcrumb
FILE-US-5: Reject Filed Invoice
As a reviewer, I want to reject a filed invoice so that issues can be addressed before closing.
- AC: Reject button available even after successful filing
- AC: Confirmation prompt before rejection
- AC: Invoice routed to appropriate queue for re-review
5. Architectural Risks & Mitigations
6. Stage Transition Logic
Invoice Lifecycle Flow
There are 3 possible paths through the workflow. Every invoice starts at Intake. At each stage, the user picks an action that determines what happens next.
Path 1 — Happy Path (no mismatches)
Invoice matches cleanly. User clicks Continue at Matching (skips Manual), filing happens automatically, user clicks Continue to close.
Path 2 — Manual Review Required
Mismatches found or user wants to review. User clicks Manual, reviews and vouches line items, clicks Approve to file, then Continue to close.
Path 3 — Rejected (from any stage)
User clicks Reject at Matching, Manual, or Filing. Invoice moves to closed stage with rejected substatus. This is final — no re-entry.
Visual Summary
Transition Rules
Open Transition Questions
- Can an invoice skip Matching and go directly to Manual? (e.g., no PO on file)
- Can a Rejected invoice be re-opened and re-enter the workflow?
- Does “Reject” at Filing reverse the ERP filing, or is it an internal-only status change?
- Is Closed truly terminal, or can a Closed invoice be re-opened?
- Can the stage order be reconfigured per tenant (e.g., skip Manual entirely)?
7. Dependencies & Recommended Build Order
Dependency Map
Recommended Build Order
Cross-Cutting Dependencies
- Stage framework & breadcrumb — Shared component needed by all 3 stages. Build early in Phase 2.
- Audit logging — Used by Matching (Continue with mismatches), Manual (approve/reject + notes), and Filing (filing confirmation). Build as a shared service in Phase 1 or early Phase 2.
- Invoice document viewer — Used in Filing stage. Confirm if this exists from Intake or needs to be built. If new, start in Phase 3.
- Rejection flow — All stages support Reject. Define the rejection queue/status handling once and reuse.
8. Repository Design
Structure
The codebase follows a feature-based folder structure under a versioned v1/ root. Each feature is self-contained with its own route, controller, service, models/types, and co-located tests.
Conventions
Feature Folder Contents
Layer Responsibilities
Auth & Scopes
Auth scopes are defined per feature:
auth/scopes.py— defines permission scopes per feature (e.g.,ERP_CONFIG_WRITE,INVOICES_READ,INVOICES_APPROVE)auth/roles.py— maps roles to scope sets (e.g.,admin→ all scopes,reviewer→ read + approve)- Routes specify
valid_scopesin config and useauthenticate+authorizemiddleware
Middleware Stack (app.py startup)
Middleware initialization order:
- Logging — App Insights (production) or pretty console (development)
- App Configuration — Azure App Config or env vars via
config/app_config.py - Authentication — JWT validation middleware (dev HS256 / prod Azure AD RS256)
- Authorization decorators — Scope-based access control
- Request ID propagation —
X-Request-Idheader for correlation - CORS — Configured allowed origins, methods, headers
- Route registration — All feature routes registered via
routes/__init__.py - Startup — Server starts listening
Error Handling
errors/http_errors.py provides a factory for consistent error responses:
Testing
- Framework:
pytest - Location: Co-located with each feature under
tests/ - Naming:
test_<feature>_service.py(primary),test_<feature>_controller.py(optional) - Mocking:
pytest-mock/unittest.mockfor external clients (ERP, datastore) - Shared fixtures:
conftest.pyatsrc/root for test client, auth bypass, mock DB - Run all:
pytest src/ - Run feature:
pytest src/api/v1/matching/tests/ - Coverage:
pytest --cov=src/
Config (config/)
env.py— All environment variables with typed defaultsapp_config.py— Azure App Configuration integration for runtime feature flags and secrets
Router Registration (routes/init.py)
9. Assumptions
Summary — T-Shirt Sizing Overview
Total estimated effort: ~L (1–2 weeks) — significantly reduced from the original XL estimate because the ERP connector layer, filing pipeline, PO retrieval, receipt fetching, stage transitions, and audit logging already exist in the codebase. The primary effort is UI development across all four areas.
Acceptance Criteria (Spike)
- Designs are reviewed and accepted by the product owner prior to sprint commitment
- Each functional area has a documented T-shirt size estimate with rationale
- All open questions are answered or have an identified owner and resolution path
- The development team can decompose the spike output into sprint-ready user stories without requiring additional design sessions