Pannonia Distribution Kft.

Procurement Process Exploration — PROC-001 Detailed Discovery
2026-02-28
Workflows
6
W1 — W4b
Weekly Manual Hours
32
hrs / week
Annual Cost
~50K
EUR / year
AI Agents
3
Parser + Evaluator + Negotiator
Systems
4
Gmail + PostgreSQL + LiteLLM + SAP
Current Manual Process
Manual procurement lifecycle as observed during the Phase 0 workshop. All steps are human-driven with email, Excel, and Word. No automation, no audit trail, no historical data.
Weekly Hours
32
Error Rate (quote parsing)
8%
FTEs
1.5
Annual Cost
~50K EUR
Bottleneck Scoring
# Process Dept Frequency Hrs/Wk People Error Rate Pain Score Tools
1 Supplier quote collection & parsing Procurement Ongoing 8 1 8% 22 Gmail + Excel
2 Quote evaluation & comparison Procurement ~10/week 5 2 19 Excel
3 Demand intake & approval Ops / Procurement ~15/week 4 2 17 Email + Excel
4 Price negotiation Procurement ~5/week 6 1 16 Email
5 RFQ creation & distribution Procurement ~10/week 6 1 14 Word + Email
6 Final approval & PO creation Procurement / Finance ~10/week 3 2 13 Email + SAP
TOTAL 32 ~1.5 FTE ~49,920 EUR/yr
Key Pain Points
  • 1. Quote parsing — multi-language emails (HU/EN/DE), inconsistent formats, 8% error rate, 8 hrs/week
  • 2. No audit trail — approvals happen in email threads, no traceable chain for auditors, compliance risk
  • 3. Unstructured negotiation — no price guardrails, no concession tracking, manual language switching
  • 4. No historical data — supplier performance not tracked, same evaluation mistakes repeated
  • 5. Cascading delays — missed approval emails delay entire procurement chain by days, causing stockouts
Manual Process Flow
01

Demand intake & approval

Manual email chains for approval. No audit trail. Approvals lost in inbox.

4 hrs/wk 2 people Pain: 17
Email + Excel
Manual
02

RFQ creation & distribution

Copy-paste from demand into Word template. Sent individually per supplier. Must translate to HU/EN/DE.

6 hrs/wk 1 person Pain: 14
Word + Email
Manual
03

Supplier quote collection & parsing

Biggest pain. Manually copying prices from emails/PDFs into comparison spreadsheet. 8% error rate.

8 hrs/wk 1 person 8% errors Pain: 22
Gmail + Excel
Manual
04

Quote evaluation & comparison

Manual scoring in spreadsheet. No historical supplier data. Subjective decisions.

5 hrs/wk 2 people Pain: 19
Excel
Manual
05

Price negotiation

Time-consuming back-and-forth. No negotiation history. Must write in supplier language (HU/EN/DE).

6 hrs/wk 1 person Pain: 16
Email
Manual
06

Final approval & PO creation

Another approval round via email. Manual SAP entry for PO. Delays cascade to stockouts.

3 hrs/wk 2 people Pain: 13
Email + SAP
Manual
End-to-End Procurement Automation
Fully automated procurement lifecycle: demand intake, approval, RFQ distribution to suppliers, AI-powered quote parsing (HU/EN/DE), weighted evaluation with historical supplier data, multi-round negotiation with guardrails, and final approval. Email-based approvals, complete audit trail.
Weekly Hours
32
Error Rate
8%
Complexity
AI-Agentic
Score
26/30
State Machine
DEMAND_RECEIVED
PENDING_APPROVAL
APPROVED
RFQ_SENT
COLLECTING_RESPONSES
EVALUATING
NEGOTIATING
COLLECTING_RESPONSES
PENDING_FINAL_APPROVAL
COMPLETED
REJECTED
Can occur at PENDING_APPROVAL or PENDING_FINAL_APPROVAL
Systems & Integrations
Gmail
Send/receive: RFQs, approvals, negotiations, supplier responses
OAuth2 API
PostgreSQL 16
State management, audit trail, configuration
Direct connection
LiteLLM + Claude
3 AI agents: email parsing, evaluation, negotiation
Claude Sonnet 4
SAP Business One
PO creation (future — currently stub)
REST API (planned)
Automation Outlook
65%
20%
15%
Fully automated AI + human review Human decision required
Timeout Rules
StateTimeoutAction
PENDING_APPROVAL168h (7 days)Token expires, admin notified
COLLECTING_RESPONSES72h (3 days)Proceed with available quotes
NEGOTIATING72h per roundProceed with last offer
PENDING_FINAL_APPROVAL168h (7 days)Token expires, admin notified
Rollout Plan
PhasePeriodDescription
Shadow modeWeek 1-2Automation runs, human verifies 100% of outputs
Assisted modeWeek 3-4Auto-proceed for confidence ≥ 0.95, human reviews remainder
Autonomous modeMonth 2+Full automation with 5-10% weekly audit sample
W1: Demand Intake + W2: Approval Callback
External system submits demand via webhook. System validates, generates approval token, sends approval email with approve/reject buttons. Human clicks link, system validates token, updates status, and triggers RFQ distribution on approval.
W1 Steps
9
W2 Steps
8
Token Expiry
7 days
W1: Demand Intake Flow
01

Receive webhook

POST /webhook/demand-intake — accept JSON with demand details

n8n Webhook
Auto
02

Validate required fields

item_name, quantity, unit, urgency, department, requester_name, requester_email, supplier_category

Code node
Decision
03

Generate demand ID

Sequential: DEM-YYYY-NNNN (e.g., DEM-2026-0001)

PostgreSQL
Auto
04

Insert demand + approval token

Create record with status=DEMAND_RECEIVED, generate 64-char hex token

PostgreSQL
Auto
05

Audit log: demand_received

Log creation event with full demand details

PostgreSQL
Auto
06

Render approval email

Jinja2 template with item details, estimated cost, approve/reject buttons

Jinja2
Auto
07

Send approval email

Subject: "[Approval Required] DEM-2026-0001 — A4 Copy Paper"

Gmail
Auto
08

Update status: PENDING_APPROVAL

Demand now awaits human click on approve/reject link

PostgreSQL
Auto
09

Return HTTP 200

Response: { status: "ok", demand_id: "DEM-2026-0001", next_status: "PENDING_APPROVAL" }

Webhook
Auto
W2: Approval Callback Flow
01

Human clicks approve/reject link

GET /webhook/approval?token=abc...&action=approve|reject

Browser
Human
02

Validate token format

Must be 64-char hex, action must be approve or reject

Code node
Decision
03

Lookup token in database

Match against approval_token OR final_approval_token

PostgreSQL
Auto
04

Validate: found, not expired, correct status

Token expiry: 168h. Detect initial vs. final approval type.

Code node
Decision
05

Apply decision

Update status: APPROVED / REJECTED / FINAL_APPROVED. Clear used token.

PostgreSQL
Auto
06

Audit log: approval_decision

Actor: human, action type, approval type (initial/final)

PostgreSQL
Auto
07

Return HTML confirmation

Friendly confirmation page with demand summary

Code node
Auto
08

Trigger downstream

Initial approve → POST /webhook/rfq-send. Final approve → PO_CREATED → COMPLETED.

HTTP Request
Decision
W3a: RFQ Send + W3b: Monitor & Parse
Distribute RFQ emails to matching suppliers in their preferred language (HU/EN/DE). Monitor inbox for responses, parse with AI agent (AGT-P01), store quotes, and trigger evaluation when all responses collected or deadline passes.
RFQ Deadline
72 hrs
Languages
HU/EN/DE
Poll Interval
60s
W3a: RFQ Distribution Flow
01

Receive trigger from W2

POST /webhook/rfq-send with demand_id

Webhook
Auto
02

Load demand details

Python subprocess: load_demand.py

PostgreSQL
Auto
03

Query matching suppliers

Filter by supplier_category, active=true

PostgreSQL
Auto
04

Set RFQ deadline (NOW + 72h)

Update status: RFQ_SENT

PostgreSQL
Auto
05

Render RFQ emails per supplier

Jinja2 templates: hu.html, en.html, de.html — subject includes [RFQ-{demand_id}]

Jinja2
Auto
06

Send RFQ emails (loop over suppliers)

SplitInBatches → Gmail Send per supplier

Gmail
Auto
07

Log each RFQ sent

Audit: supplier name, email, language, deadline

PostgreSQL
Auto
W3b: Response Monitor & Parse Flow
01

Gmail trigger — poll every 60s

Filter: subject contains "[RFQ-"

Gmail
Trigger
02

Extract demand ID from subject

Regex: /\[RFQ-(DEM-\d{4}-\d{4})\]/i

Code node
Auto
03

Identify supplier

Match sender email to suppliers table (demo: extract [supplier_id:N] footer)

PostgreSQL
Auto
04

Parse email with AGT-P01

AI extracts: response_type, items[], prices, delivery, terms, confidence

Claude Sonnet 4
AI Agent
05

Route by confidence

≥0.90: auto-accept | 0.70-0.89: flag review | <0.70: dead letter

Code node
Decision
06

Store parsed quote

Insert into quotes table with round number, dedup by Gmail Message-ID

PostgreSQL
Auto
07

Check collection completeness

All suppliers responded OR deadline passed?

PostgreSQL
Decision
08

If complete: trigger W4a Evaluate

Set status EVALUATING, POST /webhook/evaluate

HTTP Request
Auto
AI Confidence Routing (AGT-P01)
ConfidenceStatusAction
≥ 0.90successAuto-accepted, stored in quotes table
0.70 - 0.89low_confidenceStored but flagged: human_verified=false
< 0.70errorDead letter queue + admin notification
W4a: Evaluate + W4b: Negotiate
Calculate weighted scores (price 40%, delivery 20%, quality 25%, reliability 15%). AI evaluator (AGT-P02) provides risk assessment and negotiation recommendation. If negotiation needed: AI drafter (AGT-P03) creates counter-proposals with guardrails. Multi-round loop back through W3b for supplier replies.
Max Rounds
3
Auto-send
Rounds 1-2
Guardrails
5 rules
Scoring Formula
DimensionWeightFormula
Price40%MAX(0, 1 - (unit_price - min_price) / min_price) × 40
Delivery20%MAX(0, 1 - delivery_days / max_delivery) × 20
Quality25%historical_quality_score × 25
Reliability15%historical_ontime_rate × 15
Negotiation Decision Logic
ConditionAction
Any supplier price > max_acceptable_priceTrigger W4b: negotiate with those suppliers
All prices ≤ max_acceptable_priceSkip negotiation → send final approval email
Negotiation Guardrails (AGT-P03)
#RuleOn Violation
1proposed_price ≤ max_acceptable_priceBlock send
2Quantity unchangedBlock send
3Payment terms ≥ 14 daysBlock send
4Management disclaimer includedAuto-append
5Language matches supplier preferenceFlag for review
Auto-Send Rules
RoundActionRationale
Round 1-2Auto-send via GmailStandard counter-proposals, low risk
Round 3+Hold as draft, notify adminRequires human judgment to prevent over-negotiation
Multi-Round Negotiation Loop
W4a

Evaluate: should_negotiate?

AGT-P02 checks if any price exceeds max_acceptable_price

AGT-P02
Decision
W4b

Draft & send counter-proposals

AGT-P03 drafts, guardrails validate, send to flagged suppliers

AGT-P03
AI Agent
W3b

Monitor supplier replies (round N)

Same W3b flow, stores quotes with round=N

Gmail + AGT-P01
Auto
W4a

Re-evaluate with round N quotes

Negotiate again or proceed to final approval?

AGT-P02
Decision
AI Agents
Three specialized AI agents powered by Claude Sonnet 4, called through a centralized agent_runner.py abstraction via LiteLLM proxy. Each has defined input/output schemas, confidence thresholds, and fallback behavior.
Model
Claude Sonnet 4
Monthly LLM Cost
~€3.50
Agent Registry
Supplier Email Parser
AGT-P01
Extracts structured quote data from unstructured supplier emails in Hungarian, English, and German. Handles inline text, PDF attachments, and varying formats. Returns items, prices, delivery terms, and confidence score.
Temp: 0
Max tokens: 4096
Auto-accept: ≥0.90
Review: 0.70-0.89
Used by: W3b
Quote Evaluator
AGT-P02
Analyzes numerically scored quotes, provides qualitative risk assessment per supplier, and recommends whether to negotiate or accept. Returns supplier evaluations, overall recommendation, and negotiation targets with reasoning.
Temp: 0
Max tokens: 4096
Key decision: should_negotiate
Used by: W4a
Negotiation Drafter
AGT-P03
Drafts professional counter-proposal emails in the supplier's preferred language. Operates within hard guardrails (price ceiling, quantity lock, payment terms minimum). Must include management approval disclaimer in every email.
Temp: 0.3
Max tokens: 4096
Languages: HU/EN/DE
Used by: W4b
3-Layer Error Handling
LayerComponentHandles
Layer 1LiteLLM ProxyRate limits (2x retry), timeouts (60s), provider fallback
Layer 2agent_runner.pyMalformed JSON (retry with fix), schema validation, confidence routing
Layer 3n8n WorkflowsPer-step error branches, dead letter queue, admin email alerts
Agent Call Architecture
1

n8n Code node calls run_agent.py

Python subprocess with JSON on stdin: { agent_id, input_data, context }

n8n
Auto
2

agent_runner loads config from DB

Fetch agent_configs: model, temperature, prompt path, output schema, thresholds

PostgreSQL
Auto
3

Resolve prompt + append shared rules

Load prompt file + anti-hallucination.md + output-format.md

Filesystem
Auto
4

POST to LiteLLM /v1/chat/completions

OpenAI-compatible API on port 4000, routes to Claude Sonnet 4

LiteLLM
LLM Call
5

Validate response against schema

JSON parse, schema validation, confidence check, status assignment

agent_runner
Decision
6

Return AgentResult to n8n

{ status, data, confidence, reasoning, agent_id, model_used }

stdout
Auto