Purchase orders and invoice linkage (payableId)

Analyzes purchase orders and their link to invoices via payableId. Explains why payableId=null does not necessarily mean no invoice exists.

โ†“ Download skill (.md)
79/100ยท๐Ÿ” Ad hocยทExpertProcurementAP Manager
Budget & POsReconciliationget_purchase_orders

๐ŸŽฏ Skill purpose

Analyzes purchase orders and their link to invoices via payableId. Explains why payableId=null does not necessarily mean no invoice exists.

๐Ÿ“Š What it produces

POs with invoice linkage status, committed amount, and explanation of cases without payableId.

โšก Benefit

Before

Incorrect interpretation of payableId=null caused false missing invoice reports.

After

Correct understanding of PO-invoice linkage, zero false missing invoice detection.



# Instructions โ€” Purchase Orders (POs)

## โš ๏ธ payableId=null โ‰  "no invoice"

Each PO can have an `invoices[]` array with related invoices.
Each invoice has a `payableId` which can be:
- **UUID** โ†’ direct link to the payable (use `get_payable_by_id` for details)
- **null** โ†’ the invoice exists but cannot be resolved from its `requestId`

```json
// Invoice with payableId null โ€” the invoice exists but is not linked:
{
  "invoiceRequestId": "abc123",
  "invoiceNumber": "INV-001",
  "amount": { "amount": 150000, "currency": "EUR", "precision": 2 },
  "status": "paid",
  "payableId": null   โ† DO NOT conclude "no invoice"
}
```

โ†’ In case of `payableId=null`, use `invoiceRequestId` or `invoiceNumber` for manual reconciliation.

## โš ๏ธ Multi-currency POs: do not sum across currencies

POs can be denominated in EUR, USD, GBP, etc. The `amount`, `billedAmount`, `deliveredAmount` fields are in the PO's currency.
โ†’ Never add up POs in different currencies without conversion.
โ†’ Display separately by currency or convert explicitly.

Live example: FullStory PO in USD ($21,267.89), Oracle PO in EUR (30,000 EUR).

## Step 1 โ€” Active POs (status=open)

```json
{ "companyId": "...", "status": ["open"], "pageSize": 100 }
```

โ†’ Returns ongoing POs that can still accept invoices.
โ†’ `billingStatus: "lateInvoice"` โ†’ PO open but no invoice received recently.
โ†’ `billingStatus: "partiallyBilled"` โ†’ invoices received but budget not exhausted.

## Step 2 โ€” POs expiring soon

```json
{
  "companyId": "...",
  "endDateFrom": "YYYY-MM-DD",
  "endDateTo": "YYYY-MM-DD",
  "status": ["open"]
}
```

Example: POs expiring in the next 30 days = endDateFrom=today, endDateTo=today+30d.

## Step 3 โ€” Calculating consumed budget

For each PO:
```
committed_amount = amount (CURRENT committed amount in PO currency โ€” not the originally approved budget, which the tool does not return)
invoiced = billedAmount
delivered = deliveredAmount
net_of_vat = netAmount (net-of-VAT counterpart of amount; field absent when no net amount was declared โ€” never treat it as 0)

consumption_rate = billedAmount / amount ร— 100
remaining_budget = amount - billedAmount
```

โš ๏ธ A budget overrun cannot be detected here: `amount` may be realigned to `billedAmount`. Say the originally approved budget is not available rather than reporting "no overruns".

## Step 4 โ€” Accessing invoice details

For each PO with `invoices[]`:
1. If `payableId != null` โ†’ call `get_payable_by_id(payableId)` for full details
2. If `payableId == null` โ†’ note `invoiceNumber` + `invoiceRequestId` for manual reconciliation

## Live example (real data)

| PO | Description | Status | Amount | Invoiced |
|----|-------------|--------|--------|---------|
| Coworking Lyon | Coworking space | open | 26,026 EUR | 20,185 EUR (78%) |
| FullStory | SaaS subscription | open | $21,267 USD | $10,633 USD (50%) |
| Oracle | Annual subscription | open | 30,000 EUR | 0 EUR (0%) โ€” lateInvoice |
| Coworking Lyon 2 | Extension | open | 35,424 EUR | 5,904 EUR (17%) |

Note: `payableId=null` not visible in this demo dataset โ€” the risk is documented in the MCP spec but not testable here.

## Example prompt

- "Which POs expire in the next 30 days?" โ†’ endDateFrom/endDateTo + status=open
- "What is the consumption rate of our active POs?" โ†’ status=open + billedAmount/amount calculation
- "Find the invoices linked to the Oracle PO" โ†’ invoices[].payableId โ†’ get_payable_by_id

How to install this skill

/
  1. 1
    Download the file s28-purchase-orders-payable-id.md using the button above.
  2. 2
    Place the file in the .claude/ directory of your project (or ~/.claude/ for a global install).
    cp s28-purchase-orders-payable-id.md .claude/s28-purchase-orders-payable-id.md
  3. 3
    Use in Claude Code โ€” the skill is automatically discovered. Describe your need in natural language and Claude will apply the skill instructions.
๐Ÿ’ก Make sure the Spendesk MCP is configured in your .claude/settings.json with the tools get_purchase_orders.

Similar skills

โ˜… Top
95/100ยท๐Ÿ” Ad hocยทExpert

Audit what the MCP covers

Probes all available MCP tools, re-evaluates coverage of 50 persona use cases, detects new fields or tools, and regenerates the gap analysis report.

CFOControllerAP Manager
โ˜… Top
89/100ยท๐Ÿ” Ad hocยทIntermediate

Build a custom skill

Turns a precise business need into a brand-new tailored Claude skill, ready to use on the Spendesk MCP.

CFOControllerAP Manager
โ˜… Top
88/100ยท๐Ÿ” Ad hocยทBeginner

Discover the Spendesk MCP in two minutes

A guided, conversational tour of the Spendesk MCP with real calls on the user's own data, adapted to their persona.

CFOControllerAP Manager

Interested in AI Agent services or Custom Integrations?