Skip to content

VMS POC — Extraction Analysis & Implementation Plan

Visual Marking Systems — Proof of Concept Date: 2026-02-19


Visual Marking Systems (VMS) is a label/decal manufacturer in Twinsburg, Ohio. They receive purchase orders from industrial customers and generate quotes from their “Enterprise” MIS system.

Workflow: Customer sends PO → VMS user validates in Ordermatic review page → Ordermatic submits to Enterprise MIS → Enterprise MIS creates one quote per line item (not per PO). This is the target pattern for the quote_splitting_enabled feature flag.

Eval scope: 7 inbound customer POs are the extraction eval targets. 12 outbound VMS quotes are stored as reference material only (they show what the ERP output should look like). Key finding: several extraction patterns require custom prompt_config to handle correctly — no code changes needed for extraction. The quote splitting UX is gated behind quote_splitting_enabled in Flagsmith.


DocumentCustomerItemsComplexityKey Challenges
PO-2512929Gradall Industries3 (same part)ComplexScheduled/blanket PO — same part 82173070 with 3 different due dates (02/19, 03/25, 04/22). Current “consolidate” prompt would merge these.
purchaseorder_101572_3013_109729Facil NA de Mexico1ComplexInternational PO. European number format (22.500,00 = 22,500). Price per 1000 units. Dual part numbers (customer LL00736ADD = VMS 3518910C2).
PO 11372 VMSActivities Press1SimpleVendor Stock No (162474:01) and Job number (M28168). Ship-to is VMS itself.
S16661Urschel Laboratories1SimpleStandard single-item PO. Part# 098141.
PO-0000024812J. Sterling Industries5MediumCanadian company (HST tax). Revision levels (AA.0, A.0, B.0). No vendor item numbers filled in.
PO1101011Nelsen Corporation2MediumDual part numbers: customer Item ID (MYLAR LABEL-BT-LEHIGH-23175) + VMS Part No (23175BT-VLV). Different due dates per line (02/20, 03/12).
po_pdf_0926554087Supply Technologies3MediumCustomer part numbers (4XH478351 etc) with VMS numbers embedded in descriptions (“Hyster Yale - 1627004”). Pack size info (PACK 25).

Outbound Quotes (12 documents) — Reference Only

Section titled “Outbound Quotes (12 documents) — Reference Only”

All from VMS Enterprise system. These are NOT extraction input documents — they are VMS’s output quotes generated after a PO is approved through Ordermatic. They are stored as reference material to document expected ERP output fields and format.

PO → Quote mapping (quote splitting pattern):

Source POOutput QuotesSplit Pattern
PO-2512929 (Gradall)Gradall quote 1/2/3.pdf1 quote per line item
purchaseorder_101572 (Facil)Facil Quote.pdf1 quote for whole order
PO-0000024812 (J. Sterling)J. Sterling Quote.pdf1 quote for all 5 items
po_pdf_0926554087 (Supply Tech)Supply Technologies Quote 1/2/3.pdf1 quote per line item
PO1101011 (Nelsen)Nelsen Quote 1/2.pdf1 quote per line item
S16661 (Urschel)Urschel Laboratories Quote.pdf1 quote for 1 item
PO 11372 VMS (Activities Press)Activities Press Quote.pdf1 quote for 1 item

1. Company Context Flip

VMS is the SELLER receiving POs, not a buyer/distributor. The prompt’s {{company_name}} context needs to identify VMS as the vendor so the SENDING company is correctly extracted as the customer. Straightforward via prompt_config.company_info.

2. Dual Part Numbers

4 of 7 POs have both customer AND VMS part numbers. Current item_ids array captures all IDs but doesn’t distinguish which is the customer’s vs vendor’s. For the POC, we handle this via prompt instructions: “Place the customer’s part number FIRST in item_ids, then the VMS/vendor part number SECOND.”

Where VMS part numbers appear varies by customer:

  • Gradall: VENDOR ITEM # column
  • Facil: Your part no.: field
  • Nelsen: Part No.: below Item ID
  • Supply Technologies: embedded in description after company name (“Hyster Yale - 1627004”)
  • Activities Press: Vendor Stock No. column
  • J. Sterling: Vendor Item Number column (empty on their PO)

3. Scheduled/Blanket POs

Gradall PO has the same part (82173070) on 3 lines with different due dates. The current prompt says “Single order: Consolidate all items into one order” which would INCORRECTLY merge these. Fix: Replace with “Each line item is a separate order_items entry, even if the same part appears multiple times.”

4. Per-Line Due Dates

Gradall (3 different dates), Nelsen (2 different dates). Current schema has order_date at order level only. For POC: instruct extractor to put due dates in item_description (“Due: YYYY-MM-DD”). Long-term: add due_date field to OrderItem schema.

5. European Number Formatting

Facil uses period as thousands separator, comma as decimal (22.500,00 = 22,500). Price is “90,00 USD per 1000 ea” = $0.09/unit. Prompt must instruct conversion to standard US format.

6. Price-Per-Thousand

Facil prices at “90.00 USD per 1000 ea”. Actual unit_price should be 0.09. Prompt instruction: “Normalize unit_price to per-single-unit. If price is quoted per 100/1000/etc, divide accordingly.”

7. Revision Levels — J. Sterling POs have part revisions (AA.0, B.0). Capture in item_description.

8. Job/Reference Numbers — Activities Press has a “Job” column (M28168). Capture in item_description.

9. Quote Document Handling — VMS quotes are outbound. Extractor should recognize customer_name = the entity being quoted (not VMS), and quotation number = po_number.


  • Set company_info for VMS org (name, location, aliases)
  • Add detailed requirements and notes to handle VMS-specific patterns
  • Override the “consolidate” behavior via prompt instructions
  • No code changes required

If the POC validates well, add to Gemini response schema (schemas.py):

FieldTypeLocationPurpose
due_datestring, optionalOrderItemPer-line delivery date
customer_part_numberstring, optionalOrderItemExplicit customer reference
vendor_part_numberstring, optionalOrderItemExplicit vendor reference
unit_of_measurestring, optionalOrderItemEA, PACK, etc.
revisionstring, optionalOrderItemPart revision level

These would also need corresponding columns in extracted_order_items table and frontend display changes.


Full JSON stored in erp_connections.prompt_config for VMS:

File: scripts/poc-setup/vms-prompt-config.json

{
"company_info": {
"name": "Visual Marking Systems",
"location": "Twinsburg, Ohio",
"aliases": ["VMS", "Visual Marking Systems, Inc.", "vmsinc"]
},
"requirements": [
"CRITICAL: Each line item in a PO is a SEPARATE entry in order_items, even if the same part number appears multiple times with different due dates or delivery schedules. Do NOT consolidate duplicate part numbers into a single line item.",
"For dual part numbers: When a document shows both a customer part number AND a vendor/VMS part number, place the CUSTOMER's part number FIRST in item_ids array, then the VMS/vendor part number SECOND.",
"Always normalize unit_price to per-single-unit cost. If price is shown as 'per 100', 'per 1000', 'per M', divide accordingly.",
"Handle European number formatting: periods as thousands separators and commas as decimal points (e.g., '22.500,00' = 22500.00).",
"Capture per-line due dates in item_description when available (format: 'Due: YYYY-MM-DD'). order_date should be the PO issue date.",
"For VMS Quote documents: customer_name is the entity BEING QUOTED. Quotation Number goes in po_number.",
"Extract revision levels into item_description when present (format: 'Rev: [level]').",
"Extract Job numbers, reference numbers, and drawing numbers into item_description."
],
"notes": [
"VMS is the SELLER/VENDOR on inbound POs. The sending company is the CUSTOMER.",
"VMS part numbers appear in various fields: 'Vendor Item #', 'Vendor Stock No.', 'Part No.', 'Your part no.', or embedded in descriptions after company names.",
"Pack quantity notations like '(PACK 25)' are packaging info, NOT order quantity.",
"Some POs show Order/Recv/Due breakdowns — use 'Order' quantity.",
"Common VMS customers: Gradall, Supply Technologies, Facil NA, J. Sterling, Nelsen, Urschel, Activities Press."
]
}

Golden dataset created at packages/eval/test-data/golden-dataset/vms-golden-dataset.json.

  • 19 entries total (7 POs + 12 quotes)
  • 13 entries have full ground truth annotation
  • 6 entries are placeholders pending annotation (remaining quote documents)
  • Test PDFs stored at packages/eval/test-data/vms-documents/

Test scenarios covered: scheduled POs, dual part numbers, international formatting, European numbers, multi-item orders, price-per-thousand, pack quantities, multi-page documents.

Scoring priorities: customer_name accuracy, item_ids completeness (both customer + VMS parts captured), quantity accuracy, unit_price accuracy (especially price-per-thousand normalization).

Note: The 12 quote documents have testCategory: "reference" and shouldExtractOrders: false — they are skipped by the eval runner.


  • Create VMS org in Clerk (slug: vms-poc)
  • Add david+vms@ordermatic.co as admin
  • Create ERP connection with vms-prompt-config.json
  • Upload 19 test PDFs to R2 under vms-poc/ prefix
  • Run eval pipeline against golden dataset
  • Review extraction accuracy, iterate on prompt_config
  • Create Cleveland Kitchen org in Clerk (slug: cleveland-kitchen-poc)
  • Add david+cle@ordermatic.co as admin
  • Configure with cleveland-kitchen-prompt-config.json
  • Await example documents from Cleveland Kitchen for eval dataset

Run: npx tsx scripts/poc-setup/setup-poc-orgs.ts

Requires CLERK_SECRET_KEY and DATABASE_URL env vars. Creates both orgs, sends invitations, and inserts ERP connections with prompt_configs.