This feature enables organizations to:
The system handles both purchase requests (before purchase) and invoice approvals (after receipt).
Employees submit purchase requests through Orcha. The AI ensures complete information before routing to approval.
Submission Channels:
@orcha I need to buy...)When an employee initiates a purchase request, the LLM validates completeness and asks clarifying questions before submission.
Required Fields:
| Field | Description | AI Prompt if Missing |
|---|---|---|
description |
What is being purchased | "What exactly do you need to purchase?" |
amount |
Estimated cost | "What is the estimated cost?" |
supplier |
Vendor name | "Which supplier/vendor is this from?" |
justification |
Business reason | "Why do you need this? How does it benefit the team/project?" |
cost_center |
Budget allocation | "Which cost center should this be charged to?" |
department |
Requesting department | (Auto-detected from user profile, confirm if ambiguous) |
urgency |
Timeline | "When do you need this by? Is this urgent?" |
Optional Fields (AI may prompt based on context):
| Field | When AI Asks |
|---|---|
project |
If multiple active projects in department |
alternatives_considered |
For high-value requests (>€10k) |
recurring |
If description suggests subscription |
existing_contract |
If supplier already has relationship |
Example AI Conversation:
Employee: I need to buy some new laptops for the team
Orcha: I can help you submit a purchase request for laptops. Let me gather some details:
1. How many laptops do you need, and what specifications?
2. What is the estimated cost per laptop?
3. Which team members are these for?
4. When do you need them by?
5. Which cost center should this be charged to?
Employee: 5 MacBook Pros for the new engineers starting next month.
Around €2,500 each. Cost center is CC-ENG-001.
Orcha: Got it. I'll create a purchase request:
- 5x MacBook Pro laptops
- Total: €12,500
- Cost Center: CC-ENG-001 (Engineering)
- Needed by: Next month (new hire onboarding)
One more question: Are there any specific specs required (RAM, storage),
or should I note "standard developer configuration"?
Employee: 32GB RAM, 512GB SSD
Orcha: ✓ Purchase request PR-2026-0089 created and sent for approval.
Approver: Thomas Weber (Engineering Director)
Estimated approval time: 24-48 hours
I'll notify you when there's an update.
draft → pending_approval → approved → ordered → received → closed
↘ rejected (workflow ends, must create new PR)
↘ needs_info → (updated) → pending_approval
| State | Description |
|---|---|
draft |
Employee is still entering details |
pending_approval |
Awaiting approver action |
needs_info |
Approver requested more information |
approved |
Ready to order |
rejected |
Denied (with reason). Workflow ends. Requester must create new PR if needed |
ordered |
PO issued to supplier |
received |
Goods/services received |
closed |
Complete (invoice matched) |
For purchases with a contract period (e.g., annual SaaS license):
Example:
Jan 2026: PR approved for "Figma Annual License - €1,200/year"
Contract period: Jan 2026 - Dec 2026
Feb-Dec 2026: Monthly invoices (~€100/month) auto-matched, no approval needed
Dec 2026: Renewal notification sent
Jan 2027: New PR required for "Figma Annual License - Renewal 2027"
Goes through approval workflow again
The system tracks:
contract_start_date and contract_end_date on purchase requestis_recurring flagWhen an approver reviews a request, they see comprehensive budget information to make informed decisions.
Budget Summary Card:
┌─────────────────────────────────────────────────────────────────┐
│ Budget: CC-ENG-001 (Engineering) - Q1 2026 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Allocated Budget: €150,000.00 │
│ ───────────────────────────────────────────────────────── │
│ Invoices Received (paid/pending): - €67,500.00 │
│ Approved PRs (not yet invoiced): - €23,200.00 │
│ ───────────────────────────────────────────────────────── │
│ Committed Total: €90,700.00 │
│ ───────────────────────────────────────────────────────── │
│ Available Budget: €59,300.00 │
│ │
│ THIS REQUEST: - €12,500.00 │
│ ───────────────────────────────────────────────────────── │
│ Remaining After Approval: €46,800.00 ✓ │
│ │
│ Pending PRs (not yet approved): (€18,400.00) │
│ If all pending approved: €28,400.00 │
│ │
├─────────────────────────────────────────────────────────────────┤
│ ℹ️ Previous Period (Q4 2025): │
│ Unused budget that expired: €12,300.00 │
│ (No rollover - for reference only) │
└─────────────────────────────────────────────────────────────────┘
Note: Budget periods are strict (no rollover). The previous period's unused amount is shown for context only—it does not increase the current period's available budget.
When Budget is Not Configured:
If no budget has been defined for the cost center, show a placeholder that encourages configuration:
┌─────────────────────────────────────────────────────────────────┐
│ Budget: CC-ENG-001 (Engineering) - Q1 2026 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ⚠️ No budget configured for this cost center │
│ │
│ Without a budget, Orcha cannot show: │
│ • Available funds remaining │
│ • Budget impact of this request │
│ • Warnings when spending exceeds allocation │
│ │
│ To enable budget tracking: │
│ → Settings > Budgets > Upload Budget (Excel) │
│ │
└─────────────────────────────────────────────────────────────────┘
Budget Upload:
cost_center, period_start, period_end, allocated_amount, currency, owner_emailCommitted Spend:
Committed = Invoices Received + Approved PRs (not invoiced)
| Component | Description | Source |
|---|---|---|
| Invoices Received | Invoices posted to this cost center | Invoice table, status = received/paid |
| Approved PRs | Purchase requests approved but no invoice yet | PR table, status = approved/ordered |
Projected Spend:
Projected = Committed + Pending PRs (including this request)
| Component | Description | Source |
|---|---|---|
| Pending PRs | Purchase requests awaiting approval | PR table, status = pending_approval |
The system displays warnings based on budget impact:
| Condition | Warning Level | Display |
|---|---|---|
| Remaining > 20% of budget | None | Green checkmark |
| Remaining 10-20% of budget | Caution | Yellow warning |
| Remaining < 10% of budget | Warning | Orange alert |
| Would exceed budget | Critical | Red block with explanation |
| Would exceed + pending PRs also exceed | Critical+ | Red with note about queue |
Example Warning (Budget Exceeded):
┌─────────────────────────────────────────────────────────────────┐
│ ⚠️ BUDGET ALERT: This request would exceed the Q1 budget │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Available Budget: €8,500.00 │
│ This Request: €12,500.00 │
│ ───────────────────────────────────────────────────────── │
│ Over Budget By: €4,000.00 │
│ Percentage Over: 47% │
│ │
│ Options: │
│ • Approve with budget exception (requires Finance Director) │
│ • Request budget increase │
│ • Defer to Q2 │
│ • Reject with explanation │
│ │
└─────────────────────────────────────────────────────────────────┘
Budgets can be defined at different granularities:
| Period | Calculation Window |
|---|---|
| Monthly | Current calendar month |
| Quarterly | Current quarter (Q1=Jan-Mar, etc.) |
| Annual | Current fiscal year |
| Project-based | Project start to end date |
The system automatically selects the appropriate period based on cost center configuration.
Workflows are triggered by conditions on document attributes. All conditions in a workflow must match (AND logic). Multiple workflows can exist; priority determines which one applies.
Supported Condition Fields:
| Field | Operators | Example |
|---|---|---|
amount |
<, <=, >, >=, between |
amount >= 10000 AND amount < 50000 |
supplier.country |
=, in, not_in |
supplier.country IN (DE, AT, CH) |
supplier.legal_type |
=, in |
supplier.legal_type = GmbH |
supplier.name |
contains, starts_with, = |
supplier.name contains "Consulting" |
cost_center |
=, in, starts_with |
cost_center IN (CC-1001, CC-1002) |
department |
=, in |
department = Engineering |
document_type |
= |
document_type = invoice |
currency |
=, in |
currency = EUR |
has_po_match |
= |
has_po_match = false (invoice without PO) |
budget_impact |
=, > |
budget_impact > 0.8 (>80% of remaining) |
Condition Examples:
Workflow: "High-Value DACH Region"
Priority: 100
Conditions:
- amount >= 25000
- supplier.country IN (DE, AT, CH)
Workflow: "GmbH Supplier Standard"
Priority: 50
Conditions:
- supplier.legal_type = GmbH
- amount < 25000
Workflow: "Engineering Cost Center"
Priority: 75
Conditions:
- cost_center starts_with "CC-ENG"
- amount >= 5000
Workflow: "Budget Exception Required"
Priority: 200
Conditions:
- budget_impact > 1.0 (would exceed budget)
Each workflow contains ordered steps. A step defines:
Approver Types:
| Type | Description | Example |
|---|---|---|
user |
Specific person | anna.schmidt@company.com |
role |
Anyone with role | Finance Director |
dynamic:requester_manager |
Requester's direct manager | Resolved at runtime |
dynamic:cost_center_owner |
Owner of the document's cost center | Resolved at runtime |
dynamic:budget_owner |
Budget owner for category | Resolved at runtime |
dynamic:department_head |
Head of requester's department | Resolved at runtime |
Step Configuration Example:
steps:
- step: 1
name: "Department Head Approval"
approvers:
- type: dynamic:department_head
timeout_hours: 24
on_timeout: remind
- step: 2
name: "Finance Review"
approvers:
- type: role
value: "Finance Controller"
- type: role
value: "Finance Director"
require_all: false # Any one can approve
timeout_hours: 48
on_timeout: escalate
escalate_to:
- type: user
value: "cfo@company.com"
- step: 3
name: "Executive Sign-off"
approvers:
- type: user
value: "cfo@company.com"
- type: user
value: "ceo@company.com"
require_all: true # Both must approve
timeout_hours: 72
The Problem: A single purchase request might match multiple workflows. For example:
If a €15,000 request from a German supplier comes in, it matches all three workflows. Which one applies?
The Solution: Priority-based matching. Users assign explicit priority values (1-1000). Higher priority = evaluated first. The first matching workflow wins.
Workflow Selection Algorithm:
Example:
| Workflow | Priority | Conditions | Approvers |
|---|---|---|---|
| C: High-Value German Supplier | 100 | amount > €10k AND country = DE | Finance Director + Regional Manager |
| A: High-Value General | 50 | amount > €10k | Finance Director |
| B: German Supplier | 30 | country = DE | Regional Manager |
For a €15,000 request from Germany:
For a €15,000 request from France:
UI for Priority Management:
When a document enters the system (via OCR/extraction, manual entry, or purchase request), the AI automatically selects the appropriate workflow.
Document/Request Received
│
▼
┌─────────────────┐
│ Extract/Validate│ (supplier, amount, cost center, etc.)
│ Fields │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Calculate Budget│ (committed, projected, impact %)
│ Impact │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Match Workflows │ (evaluate conditions, respect priority)
└────────┬────────┘
│
▼
┌─────────────────┐
│ Resolve Dynamic │ (lookup requester manager, budget owner)
│ Approvers │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Create Approval │ (request with step 1 active)
│ Request │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Send to First │ (via configured channels)
│ Approvers │
└─────────────────┘
For edge cases where rule-based matching is insufficient, the AI can:
Setup:
Approval Request Message (with Budget Context):
┌─────────────────────────────────────────────────────────────────┐
│ 📋 Approval Request #PR-2026-0089 │
├─────────────────────────────────────────────────────────────────┤
│ Type: Purchase Request │
│ Description: 5x MacBook Pro laptops (32GB, 512GB) │
│ Supplier: Apple Inc. │
│ Amount: €12,500.00 │
│ Cost Center: CC-ENG-001 (Engineering) │
│ Requester: Sarah Mueller │
│ Justification: New hire onboarding - 5 engineers starting Feb │
├─────────────────────────────────────────────────────────────────┤
│ 💰 Budget Impact (Q1 2026): │
│ Available: €59,300 → After approval: €46,800 (31% remaining) │
│ Status: ✓ Within budget │
├─────────────────────────────────────────────────────────────────┤
│ Workflow: Engineering >€10k (Step 1 of 2) │
│ Your Action Required │
├─────────────────────────────────────────────────────────────────┤
│ [✓ Approve] [✗ Reject] [❓ Ask Question] [📄 View Details] │
└─────────────────────────────────────────────────────────────────┘
Query Commands: Users can ask Orcha via Slack:
@orcha what are my pending approvals? - List approvals waiting for this user@orcha show approval PR-2026-0089 - Show specific approval details@orcha what's the budget status for CC-ENG-001? - Show budget summary@orcha remind approvers for PR-2026-0089 - Send reminderApproval Email:
Emails contain the same complete information as Slack so approvers can make fast, informed decisions directly from email:
Subject: [Action Required] Approval Request PR-2026-0089 - €12,500
┌─────────────────────────────────────────────────────────────────┐
│ 📋 Approval Request #PR-2026-0089 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ REQUEST DETAILS │
│ ─────────────────────────────────────────────────────────── │
│ Type: Purchase Request │
│ Description: 5x MacBook Pro laptops (32GB RAM, 512GB SSD) │
│ Supplier: Apple Inc. (USA) │
│ Amount: €12,500.00 │
│ Cost Center: CC-ENG-001 (Engineering) │
│ Requester: Sarah Mueller │
│ Needed By: February 2026 │
│ │
│ JUSTIFICATION │
│ ─────────────────────────────────────────────────────────── │
│ New hire onboarding - 5 engineers starting in February. │
│ Standard developer configuration for the team. │
│ │
│ 💰 BUDGET IMPACT (Q1 2026) │
│ ─────────────────────────────────────────────────────────── │
│ Available Budget: €59,300.00 │
│ This Request: -€12,500.00 │
│ After Approval: €46,800.00 (31% remaining) ✓ │
│ │
│ Previous Period (Q4 2025): €12,300 unused (no rollover) │
│ │
│ WORKFLOW │
│ ─────────────────────────────────────────────────────────── │
│ Engineering >€10k (Step 1 of 2) │
│ Next Step: Finance Director approval │
│ │
├─────────────────────────────────────────────────────────────────┤
│ │
│ [ ✓ APPROVE ] [ ✗ REJECT ] [ ❓ ASK QUESTION ] │
│ │
│ (One-click buttons - no login required) │
│ │
└─────────────────────────────────────────────────────────────────┘
Email Features:
Query via Email: Users can email approvals@company.getorcha.com:
Full approval management in the web application (see Monitoring Dashboard section).
| Role | Permissions |
|---|---|
employee |
Submit PRs, view own requests, view approvals assigned to self |
approver |
All employee permissions + approve/reject assigned items |
budget_viewer |
View budget status for assigned cost centers |
finance_admin |
View all approvals in assigned cost centers/departments |
workflow_admin |
Create/edit/delete workflows, view all workflow analytics |
org_admin |
Full access to all approvals, all workflows, all analytics |
Document Visibility: A user can see an approval request if ANY of these apply:
finance_admin role for the document's cost centerorg_admin roleBudget Visibility:
budget_viewer sees summary for assigned cost centersfinance_admin and org_admin see all budgetsWhen a user asks "What are all open approvals?":
Response Example (non-admin):
You have 3 pending approvals:
1. PR-2026-0089 - €12,500 - MacBook Pros (awaiting your approval)
2. PR-2026-0092 - €3,200 - Office Supplies (you submitted, pending manager)
3. INV-2026-0051 - €8,900 - Cloud Services (awaiting your approval)
Response Example (org-admin):
Company-wide pending approvals: 47 total
By Age:
- < 24 hours: 23
- 24-48 hours: 15
- > 48 hours: 9 (attention needed)
Budget Alerts:
- 3 requests would exceed their cost center budget
- 5 requests would use >80% of remaining budget
Top pending by amount:
1. PR-2026-0078 - €125,000 - Enterprise Software (Step 2/3, waiting CFO)
2. PR-2026-0095 - €89,000 - Hardware (Step 1/2, waiting Dept Head)
...
Summary Cards:
Pending Approvals Table:
| Type | ID | Description | Amount | Requester | Budget Impact | Current Step | Waiting Since |
|---|---|---|---|---|---|---|---|
| PR | PR-2026-0089 | MacBook Pros | €12,500 | S. Mueller | 21% of remaining | 1/2 | 2 days |
| INV | INV-2026-0042 | SaaS License | €8,500 | T. Weber | 14% of remaining | 1/1 | 4 hours |
| PR | PR-2026-0091 | Server Hardware | €45,000 | A. Schmidt | ⚠️ Exceeds budget | 2/3 | 1 day |
Filters:
Cost Center Budget Summary:
| Cost Center | Q1 Budget | Committed | Pending | Available | Status |
|---|---|---|---|---|---|
| CC-ENG-001 | €150,000 | €90,700 | €18,400 | €59,300 | ✓ OK |
| CC-MKT-001 | €80,000 | €72,500 | €12,000 | €7,500 | ⚠️ 9% left |
| CC-OPS-001 | €50,000 | €48,200 | €8,500 | €1,800 | 🔴 Over if pending approved |
Real-time feed of approval actions:
10:42 - M. Schmidt approved PR-2026-0089 (€12,500) via Slack
10:38 - T. Weber submitted PR-2026-0115 (€8,200)
10:15 - A. Hoffmann rejected INV-2026-0048 (€3,100) - "Missing documentation"
09:55 - System escalated PR-2026-0039 to CFO (48h timeout)
09:30 - Budget alert: CC-MKT-001 at 91% utilization
-- Purchase Request
CREATE TABLE purchase_request (
request_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
org_id UUID NOT NULL REFERENCES organization(org_id),
request_number TEXT NOT NULL UNIQUE, -- PR-2026-0001
status TEXT NOT NULL DEFAULT 'draft'
CHECK (status IN ('draft', 'pending_approval', 'needs_info',
'approved', 'rejected', 'ordered', 'received', 'closed')),
requester_id UUID NOT NULL REFERENCES app_user(user_id),
description TEXT NOT NULL,
justification TEXT,
supplier_id UUID REFERENCES supplier(supplier_id),
supplier_name TEXT, -- Denormalized for display
estimated_amount NUMERIC(15,2) NOT NULL, -- Always in EUR (converted at submission)
original_amount NUMERIC(15,2), -- Original amount if submitted in different currency
original_currency TEXT, -- Original currency code (null if EUR)
exchange_rate NUMERIC(10,6), -- Rate used for conversion
cost_center TEXT NOT NULL,
department TEXT,
project TEXT,
urgency TEXT CHECK (urgency IN ('low', 'normal', 'high', 'critical')),
needed_by DATE,
-- Recurring purchase fields
is_recurring BOOLEAN DEFAULT false,
contract_start DATE, -- Start of contract period
contract_end DATE, -- End of contract period (triggers renewal reminder)
renewal_reminder_sent BOOLEAN DEFAULT false,
-- Metadata
metadata JSONB, -- Additional fields, attachments, etc.
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
submitted_at TIMESTAMPTZ,
approved_at TIMESTAMPTZ,
closed_at TIMESTAMPTZ
);
-- Budget Definition
CREATE TABLE budget (
budget_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
org_id UUID NOT NULL REFERENCES organization(org_id),
cost_center TEXT NOT NULL,
period_type TEXT NOT NULL CHECK (period_type IN ('monthly', 'quarterly', 'annual', 'project')),
period_start DATE NOT NULL,
period_end DATE NOT NULL,
allocated_amount NUMERIC(15,2) NOT NULL,
currency TEXT NOT NULL DEFAULT 'EUR',
owner_id UUID REFERENCES app_user(user_id),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (org_id, cost_center, period_start, period_end)
);
-- Supplier Master Data (Hybrid: auto-created from documents, requires verification)
CREATE TABLE supplier (
supplier_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
org_id UUID NOT NULL REFERENCES organization(org_id),
name TEXT NOT NULL,
legal_type TEXT, -- GmbH, AG, Ltd, Inc, etc.
country TEXT, -- ISO country code
tax_id TEXT,
address JSONB,
payment_terms TEXT,
is_preferred BOOLEAN DEFAULT false,
is_verified BOOLEAN DEFAULT false, -- Admin must verify before trusted
verified_by UUID REFERENCES app_user(user_id),
verified_at TIMESTAMPTZ,
source TEXT, -- 'manual', 'invoice_extraction', 'purchase_request'
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (org_id, name, country)
);
-- Workflow definition
CREATE TABLE approval_workflow (
workflow_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
org_id UUID NOT NULL REFERENCES organization(org_id),
name TEXT NOT NULL,
description TEXT,
document_type TEXT NOT NULL CHECK (document_type IN ('invoice', 'purchase_request')),
priority INTEGER NOT NULL DEFAULT 50,
active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_by UUID REFERENCES app_user(user_id)
);
-- Workflow conditions (multiple per workflow, AND logic)
CREATE TABLE approval_workflow_condition (
condition_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
workflow_id UUID NOT NULL REFERENCES approval_workflow(workflow_id) ON DELETE CASCADE,
field TEXT NOT NULL,
operator TEXT NOT NULL,
value JSONB NOT NULL,
sort_order INTEGER NOT NULL DEFAULT 0
);
-- Workflow steps (ordered)
CREATE TABLE approval_workflow_step (
step_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
workflow_id UUID NOT NULL REFERENCES approval_workflow(workflow_id) ON DELETE CASCADE,
step_number INTEGER NOT NULL,
name TEXT NOT NULL,
require_all BOOLEAN NOT NULL DEFAULT false,
timeout_hours INTEGER,
on_timeout TEXT CHECK (on_timeout IN ('remind', 'escalate', 'auto_approve')),
escalate_to_step UUID REFERENCES approval_workflow_step(step_id),
UNIQUE (workflow_id, step_number)
);
-- Approvers per step
CREATE TABLE approval_step_approver (
approver_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
step_id UUID NOT NULL REFERENCES approval_workflow_step(step_id) ON DELETE CASCADE,
approver_type TEXT NOT NULL,
approver_value TEXT,
sort_order INTEGER NOT NULL DEFAULT 0
);
-- Approval request (tracks approval progress for any document)
CREATE TABLE approval_request (
request_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
org_id UUID NOT NULL REFERENCES organization(org_id),
document_type TEXT NOT NULL,
document_id UUID NOT NULL, -- Reference to purchase_request or invoice
workflow_id UUID REFERENCES approval_workflow(workflow_id),
status TEXT NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending', 'approved', 'rejected', 'cancelled', 'expired')),
current_step INTEGER NOT NULL DEFAULT 1,
budget_snapshot JSONB, -- Snapshot of budget state at time of request
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
completed_at TIMESTAMPTZ
);
-- Individual approval actions
CREATE TABLE approval_action (
action_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
request_id UUID NOT NULL REFERENCES approval_request(request_id),
step_number INTEGER NOT NULL,
approver_id UUID NOT NULL REFERENCES app_user(user_id),
action TEXT NOT NULL CHECK (action IN ('approve', 'reject', 'delegate', 'request_info')),
comment TEXT,
channel TEXT,
delegate_to UUID REFERENCES app_user(user_id),
acted_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
-- Indexes
CREATE INDEX idx_purchase_request_org_status ON purchase_request(org_id, status);
CREATE INDEX idx_purchase_request_cost_center ON purchase_request(cost_center, status);
CREATE INDEX idx_budget_org_cost_center ON budget(org_id, cost_center, period_start);
CREATE INDEX idx_approval_request_document ON approval_request(document_type, document_id);
-- Get budget status for a cost center
WITH budget_period AS (
SELECT budget_id, allocated_amount
FROM budget
WHERE org_id = :org_id
AND cost_center = :cost_center
AND :date BETWEEN period_start AND period_end
),
invoices_received AS (
SELECT COALESCE(SUM(amount), 0) as total
FROM invoice
WHERE org_id = :org_id
AND cost_center = :cost_center
AND status IN ('received', 'paid', 'pending_payment')
AND invoice_date BETWEEN :period_start AND :period_end
),
approved_prs AS (
SELECT COALESCE(SUM(estimated_amount), 0) as total
FROM purchase_request
WHERE org_id = :org_id
AND cost_center = :cost_center
AND status IN ('approved', 'ordered')
AND approved_at BETWEEN :period_start AND :period_end
),
pending_prs AS (
SELECT COALESCE(SUM(estimated_amount), 0) as total
FROM purchase_request
WHERE org_id = :org_id
AND cost_center = :cost_center
AND status = 'pending_approval'
)
SELECT
bp.allocated_amount,
ir.total as invoices_received,
ap.total as approved_prs_not_invoiced,
(ir.total + ap.total) as committed,
(bp.allocated_amount - ir.total - ap.total) as available,
pp.total as pending_prs
FROM budget_period bp, invoices_received ir, approved_prs ap, pending_prs pp;
These decisions have been confirmed:
| Decision | Choice | Details |
|---|---|---|
| Supplier Management | Hybrid | Auto-create from documents, require admin verification before "trusted" |
| Budget Periods | Strict, no rollover | Budgets are strict per month/quarter. However, show previous period's unused amount to approver for context |
| PO-Invoice Matching | Asymmetric, zero tolerance on overage | Invoice ≤ PR: OK. Invoice > PR (any amount): Flag for review |
| Partial Approvals | Not supported | Approve or reject only. Requester must resubmit with different amount |
| After Rejection | Workflow ends | Requester must create a new PR from scratch (rejected PR is closed) |
| Recurring Purchases | Contract-period based | Approved for the contract period (e.g., 12-month license). No re-approval needed within period. Renewal/extension requires new approval |
| Delegation | Not supported | Approvers must act themselves. No delegation to others. Escalation to next step is the only alternative |
| Cost Center Matching | Exact match only | No wildcard/hierarchy support. Must list each cost center explicitly in workflow conditions |
| Multi-Currency | Convert at submission | Convert to base currency (EUR) when PR is submitted. Budget calculations use EUR |
| Audit Retention | Configurable | No specific requirement now. Make retention period configurable per organization |
These items are out of scope for initial implementation but noted for future:
Cost Center Hierarchy: Currently exact match only. Could add wildcard support (CC-ENG-* matches CC-ENG-001) if needed.
Multi-Currency Display: Currently all converted to EUR. Could show original currency alongside EUR conversion.
Approval Delegation: Currently not supported. Could add delegation with constraints (same department, vacation coverage, etc.)
Partial Approvals: Currently not supported. Could allow approvers to reduce amounts.
Mobile App: Slack/Email work on mobile, but dedicated app could improve experience.