s4hana-create-pir
Create Purchasing Info Records on SAP S/4HANA Cloud Public. Verified production-ready against SAP S/4HANA Cloud Public Edition 2026-05-12 (PIR 5300000130 created via API; 119 prior bulk-migrated PIRs from 2026-05-05).
When to trigger
Verbs: create / post / add / generate / seed / maintain / onboard
Objects: PIR(s), purchasing info record(s), info record(s), supplier-material pricing
Counts: 1 to ~200 records.
Hard rules (never violate)
- Always do a 1-record live POST as a probe before bulk (≥3 records).
- Never invent IDs — verify Supplier exists on the target PurchOrg, Material has
ProcurementType=F, both exist in the target Plant.
- If a required field has no sensible default and the user didn't specify → ask once, then auto-pick.
- Scripts go in
<cwd>/.s4hana-tmp/create-pirs-<YYYYMMDD-HHMM>/. Never commit, never modify .env.
- POSTs are sequential with 200ms delay; halt on 3 consecutive failures.
Endpoint
- Service path:
/sap/opu/odata/sap/API_INFORECORD_PROCESS_SRV
- Entity sets:
A_PurchasingInfoRecord, A_PurgInfoRecdOrgPlantData
- Method: POST (deep-insert with
to_PurgInfoRecdOrgPlantData)
- Communication scenario:
SAP_COM_0102 — "Purchasing Info Record Integration"
Phases
Phase 0 — Setup check (MANDATORY, no exceptions)
Before any API call, before any tool use, do this check. Even if you already know credentials from earlier in the conversation — IGNORE that knowledge and re-check from scratch each invocation.
- Announce: tell the user "Checking for SAP credentials in
<current cwd>..."
- Check ONLY these two sources:
- A
.env file at ./.env (in the current working directory — NOT parent dirs, NOT ~/.env, NOT any memory file)
- Shell-exported env vars:
SAP_HOST AND SAP_AUTH_MODE both present
- If neither: auto-create
./.env from the bundled template (curl from https://raw.githubusercontent.com/ilia-inovaflow/s4hana-create-record-skills/main/.env.example), append .env to .gitignore if not already there, tell the user clearly what to fill in (auth mode + host + creds), and wait for them to say "ready" before making any API call. Never overwrite an existing .env.
- If credentials are present: report back to the user: "✓ Loaded credentials for
<host> in <auth-mode> mode. Proceeding with [task]."
Never use credentials from conversation memory, from another project's .env, or from any tenant the user previously worked with in a different session. Each project gets its own .env. See shared/setup-check.md for the full rationale and edge cases.
Cross-tenant migration notes
- Source PIR IDs do NOT carry forward — Cloud auto-assigns.
- For pair (supplier, material): both must exist in target with their PurchOrg/plant relationships established. If migrating from a source with different supplier/material pools, hash-pair them deterministically.
- 2026-05-05 migration: 109 PIRs created in one batch by hash-pairing 81+ SUPL suppliers against ~100 ProcurementType=F materials at plant 1010. Side-effect: 210 pricing condition records auto-generated.
Known error catalog
| Code |
Cause |
Fix |
ME/083 |
"Enter G/L Account" OR "Enter Standard Order Quantity" |
The PIR variant: add StandardPurchaseOrderQuantity to org-plant entity |
ME/092 |
Procurement type doesn't match (material is in-house E, but PIR needs F external) |
Filter materials to ProcurementType=F only |
06/321 |
Supplier does not exist in purchasing organization |
Extend supplier with A_SupplierPurchasingOrg row for the target PurchOrg first |
Property X is invalid |
Header has fields that belong on org-plant (e.g. PurchasingInfoRecordCategory) |
Move them into to_PurgInfoRecdOrgPlantData |
MM_PUR_PIR/xxx generic |
Check innererror.errordetails |
Specific field will be named |
Output structure
<cwd>/.s4hana-tmp/create-pirs-<YYYYMMDD-HHMM>/
├── eligible-pairs.json # (supplier, material) candidates after filtering
├── payloads.json
├── create-log.jsonl
├── results.json
└── verify-sample.json
Reference files
references/envelope-template.md — full schema with all optional fields
references/known-quirks.md — header vs org-plant fields, ProcurementType filter, supplier-purchorg requirement, side-effects
scripts/bulk-pir-poster.mjs — reference implementation
1---2name: s4hana-create-pir3description: Create Purchasing Info Records (PIRs) in SAP S/4HANA Cloud Public or on-prem private edition via OData V2 A_PurchasingInfoRecord deep-insert at API_INFORECORD_PROCESS_SRV. Use whenever the user wants to create, post, add, generate, seed, onboard, or maintain purchasing info records — phrases like "create PIRs for supplier X", "add info records", "seed PIR demo data", "maintain prices for these materials", "onboard supplier-material pricing", "make me a few PIRs". Handles header + org-plant deep-insert in one POST, master-data lookup (eligible materials with ProcurementType=F, suppliers with PurchOrg setup), idempotent bulk batches, and known constraints (ProcurementType F only, supplier must have A_SupplierPurchasingOrg row for the target PurchOrg, StandardPurchaseOrderQuantity mandatory, PurchasingInfoRecordCategory lives on org-plant entity NOT header). Do NOT use for PIR price-condition updates (separate entity), PIR deletion, or category 1/2 (subcontracting/consignment) PIRs (untested).4---56# s4hana-create-pir78Create Purchasing Info Records on SAP S/4HANA Cloud Public. **Verified production-ready against SAP S/4HANA Cloud Public Edition 2026-05-12 (PIR 5300000130 created via API; 119 prior bulk-migrated PIRs from 2026-05-05).**910## When to trigger11Verbs: create / post / add / generate / seed / maintain / onboard12Objects: PIR(s), purchasing info record(s), info record(s), supplier-material pricing13Counts: 1 to ~200 records.1415## Hard rules (never violate)161. Always do a 1-record live POST as a probe before bulk (≥3 records).172. Never invent IDs — verify Supplier exists on the target PurchOrg, Material has `ProcurementType=F`, both exist in the target Plant.183. If a required field has no sensible default and the user didn't specify → **ask once**, then auto-pick.194. Scripts go in `<cwd>/.s4hana-tmp/create-pirs-<YYYYMMDD-HHMM>/`. Never commit, never modify `.env`.205. POSTs are sequential with 200ms delay; halt on 3 consecutive failures.2122## Endpoint23- Service path: `/sap/opu/odata/sap/API_INFORECORD_PROCESS_SRV`24- Entity sets: `A_PurchasingInfoRecord`, `A_PurgInfoRecdOrgPlantData`25- Method: POST (deep-insert with `to_PurgInfoRecdOrgPlantData`)26- Communication scenario: `SAP_COM_0102` — "Purchasing Info Record Integration"2728## Phases2930## Phase 0 — Setup check (MANDATORY, no exceptions)3132**Before any API call, before any tool use, do this check. Even if you already know credentials from earlier in the conversation — IGNORE that knowledge and re-check from scratch each invocation.**33341. **Announce**: tell the user "Checking for SAP credentials in `<current cwd>`..."352. **Check ONLY these two sources:**36 - A `.env` file at `./.env` (in the current working directory — NOT parent dirs, NOT `~/.env`, NOT any memory file)37 - Shell-exported env vars: `SAP_HOST` AND `SAP_AUTH_MODE` both present383. **If neither**: auto-create `./.env` from the bundled template (curl from `https://raw.githubusercontent.com/ilia-inovaflow/s4hana-create-record-skills/main/.env.example`), append `.env` to `.gitignore` if not already there, tell the user clearly what to fill in (auth mode + host + creds), and **wait** for them to say "ready" before making any API call. Never overwrite an existing `.env`.394. **If credentials are present**: report back to the user: "✓ Loaded credentials for `<host>` in `<auth-mode>` mode. Proceeding with [task]."4041**Never use credentials from conversation memory, from another project's `.env`, or from any tenant the user previously worked with in a different session.** Each project gets its own `.env`. See [`shared/setup-check.md`](../../shared/setup-check.md) for the full rationale and edge cases.424344## Cross-tenant migration notes45- Source PIR IDs do NOT carry forward — Cloud auto-assigns.46- For pair (supplier, material): both must exist in target with their PurchOrg/plant relationships established. If migrating from a source with different supplier/material pools, hash-pair them deterministically.47- 2026-05-05 migration: 109 PIRs created in one batch by hash-pairing 81+ SUPL suppliers against ~100 ProcurementType=F materials at plant 1010. Side-effect: 210 pricing condition records auto-generated.4849## Known error catalog5051| Code | Cause | Fix |52|---|---|---|53| `ME/083` | "Enter G/L Account" OR "Enter Standard Order Quantity" | The PIR variant: add `StandardPurchaseOrderQuantity` to org-plant entity |54| `ME/092` | Procurement type doesn't match (material is in-house `E`, but PIR needs `F` external) | Filter materials to `ProcurementType=F` only |55| `06/321` | Supplier does not exist in purchasing organization | Extend supplier with `A_SupplierPurchasingOrg` row for the target PurchOrg first |56| `Property X is invalid` | Header has fields that belong on org-plant (e.g. `PurchasingInfoRecordCategory`) | Move them into `to_PurgInfoRecdOrgPlantData` |57| `MM_PUR_PIR/xxx` generic | Check `innererror.errordetails` | Specific field will be named |5859## Output structure60```61<cwd>/.s4hana-tmp/create-pirs-<YYYYMMDD-HHMM>/62├── eligible-pairs.json # (supplier, material) candidates after filtering63├── payloads.json64├── create-log.jsonl65├── results.json66└── verify-sample.json67```6869## Reference files70- `references/envelope-template.md` — full schema with all optional fields71- `references/known-quirks.md` — header vs org-plant fields, ProcurementType filter, supplier-purchorg requirement, side-effects72- `scripts/bulk-pir-poster.mjs` — reference implementation