Condition Records ↔ SAP S/4HANA — Integration Q&A (Pull, Status, typedId)

Condition Records ↔ SAP S/4HANA — Integration Q&A

Answers compiled from Pricefx Confluence. The direction of the standard accelerator flow is Pricefx → SAP S/4HANA (prices are calculated in Pricefx, which is the source of truth, and synchronised out to SAP). A reverse path (SAP → Pricefx) exists for the case where someone edits conditions directly in SAP.

Primary sources


1. How should we structure our queries for the pull? (by ID range / create-update date / other?)

Neither ID range nor created/updated date. The Pricefx accelerator does not poll the condition-record table by ID window or by timestamp. It is event-triggered + status-driven, with paging:

  1. Trigger (event, not query). Pricefx fires a CONDITION_RECORD_CREATION_FINISHED event (the Price-List variant uses ITEM_APPROVED_PL) when a CR set is generated/approved. SAP Integration Suite listens on Pricefx RabbitMQ. The event carries the affected condition record set IDs and the source object typedId (Price List / Price Grid / Quote / Contract). So which records to pull is announced by the event — you don't scan for them.

  2. Fetch one batch at a time, filtered by integrationStatus. The "Get sales/purchasing price condition records from Pricefx" flow fetches one page of records from the condition record set, selecting records that have not yet been processed (i.e. filtered on the integrationStatus flag). Immediately after a batch is fetched it is flagged integrationStatus = 1 ("processing"), so the next page query cannot pick the same rows again.

  3. Loop until empty. The flow re-publishes a "fetch next page" message to JMS and repeats with the configured page size until no more records come back. (See "Splitter properties" / "Page size" / "Fetch next page receiver" params.)

  4. Optional business filters. The CR set is designed to carry a Source and Source Item ID attribute precisely so the integration can "filter for fetching records" and identify a record without relying on the composite key (see Pricefx Condition Record Setup).

Recommendation: key your pull off conditionRecordSetId + integrationStatus (unprocessed) + page size, optionally narrowed by Source/application — not by ID range or change date. The status flag is what gives you exactly-once, resumable batching; an ID/date window cannot (it would re-pull rows mid-flight and double-send to SAP).


2. How is the integration status field updated once a set of records is pulled?

In two stages, both performed through the Pricefx Integration Adapter "update" operation:

  • On pull (claim the rows): as soon as the first batch is fetched, "Update Processing Condition Records Status in Pricefx" sets integrationStatus to the "processing" value (e.g. 1). This is the mechanism that prevents the records from being fetched again while a batch is in flight (ties directly to Q1).

  • On completion (write the outcome): after SAP responds, "Update S4HANA Condition Records Results to Pricefx Condition Records" writes the final integration status plus the SAP results back onto the same records (via the "Update condition records to Pricefx" flow).

The actual numeric values for "processing" / "success" / "error" are project-defined and held in the flow's value mapping (per condition record set / table), not hard-coded by Pricefx.


3. How can we set integrationStatus to a success code once the data is loaded into SAP? (is it possible?)

Yes — this is exactly what the write-back leg does. After "Create sales/purchasing price condition records in SAP S4HANA" returns, the result is extracted and "Update S4HANA Condition Records Results to Pricefx Condition Records" updates the Pricefx records.

Mechanism — the Pricefx Integration Adapter "Update Condition Record" operation (SAP IS adapter doc):

  • Target = the condition record table; you may pass a last-updated timestamp to guard against concurrent overwrites.

  • Request body is a JSON array of { "id": <recordId>, "<field>": <value> } objects. Multiple records per call; all must carry the same field set. Example:

JSON
[
  { "id": 5, "integrationStatus": 7, "conditionRecordNumber": "...", "errorCode": "" },
  { "id": 6, "integrationStatus": 7, "conditionRecordNumber": "...", "errorCode": "" }
]
  • Response returns the IDs that failed to update.

So on a successful SAP load you write your chosen success code into integrationStatus and stash the SAP outcome in the result fields the CR set is set up to hold: Condition record number, Error Code, Free Text 1–3 (see Pricefx Condition Record Setup).

Failure / concurrency handling: if the SAP call errored, the error text (extracted by "Extract Error Message from Condition Record Response from SAP S4HANA") is written back instead. If the Pricefx write-back itself fails on a concurrent-update conflict, the flow resets the status to "processing" and the record is reprocessed. Failed create messages are parked on a JMS error queue ("Write errored price condition messages to error queue") and can be replayed ("Rerun errored price condition messages from error queue").

The success code is a number you define in the value mapping (the KB shows the same field being set with withSplicingOption().set("integrationStatus", 7) on the Pricefx side).


4. How is the condition record status field used (Expired / Invalidated / Superseded)?

This status is the Condition Record Item lifecycle status — completely separate from integrationStatus. Normal, current records are Active (the column is effectively blank/"Active"). The other values only ever appear when a record is moved to the History table (CRCIH) instead of being hard-deleted — and that only happens when superseding / history is enabled (withSplicingOption().setSupersedingOn(), or the LoadData supersedeRecords: true). Without superseding, the equivalent records are simply deleted, so you'd never see these statuses.

They distinguish why a record was retired:

Status

Set by

When it appears

Superseded (UI: common_superseded)

Overlap-resolution / splicing logic with superseding on

A newly approved CR overlaps an existing one. Instead of deleting the old row, it's moved to CRCIH and marked superseded. (v15.0+ — Condition Records Splicing Options)

Invalidated

conditionRecordHelper.invalidate(...) with superseding on

A CR is explicitly invalidated/removed from the active set by the CR creation logic; the old row lands in CRCIH marked invalidated. (v16.0+ — Delete or Invalidate Condition Records)

Expired (method-level status is shortened)

conditionRecordHelper.shortenValidTo(...)

A record's validity is end-dated earlier ("shortened from the right"). The original is moved to CRCIH; the KB calls this status shortened, which is what the UI surfaces as Expired. (v16.0+ — Shorten Condition Record Validity Interval)

Why this matters for the SAP integration: these are audit/history states. When you see them on a record it means a newer pricing action replaced, removed, or end-dated that condition — which is typically the trigger to propagate a delete/expire to SAP (e.g. revoking a price list creates a CR with a "deleted" intent that the Condition record deletion flow forwards to SAP). For a normal outbound pull you work with Active records; the historical statuses tell you what was retired and why.

Note the terminology seam: the KB method docs label the shorten case shortened, while the UI filter you're seeing groups it as Expired. If precise wording matters for your build, confirm the exact stored string in your partition's CRCIH table.


5. Logic behind the Type ID (typedId) — does the alphanumeric suffix ever change?

What's referred to as "Type ID" is Pricefx's standard typedId, and its format is:

<numericId>.<typeCode>

Real examples straight from the KB pages: 2.CRCI4, 77.CRCI1, 78.CRCI1, 770.CRCI1, 333.CRCIH1, 2.CRCIH4.

The numeric part:

  • A database-generated 64-bit Long, monotonically increasing, assigned per table (not globally) and never reused.

  • Max value is 9,223,372,036,854,775,807 (~9.2 quintillion). One million is trivially small — the number just keeps counting up; it does not roll the suffix.

The alpha suffix (typeCode):

  • CRCI<n> identifies which Condition Record Item table the row physically lives in, where n runs 1–12 (Pricefx partitions CR Items across tables CRCI1CRCI12; a CR set is stored in one of them based on its key structure — a CR holds 1–12 keys). See Parallel Writing to Condition Record Sets.

  • CRCIH<n> is the History table equivalent (same n), used when a record is superseded/invalidated/shortened (see Q4). That's the only "change" of suffix you'll see — an active ….CRCI4 row becoming a ….CRCIH4 history row.

So, directly answering the example:

  • The suffix is fixed by the table the record belongs to, not by the magnitude of the number. The 1,000,000th record in the CRCI3 table is exactly 1000000.CRCI3 — the CRCI3 part does not mutate as the counter grows.

  • The suffix differs only if the record sits in a different CRCI table (different set/key-count → CRCI1 vs CRCI3 vs …) or moves to history (CRCIH3).

  • Because the counter is per-table, you can legitimately see 2.CRCI4 and 2.CRCIH4 coexisting — same number, different tables.

To confirm which CRCI<n> table your condition record set maps to (and therefore the suffix your integration will see), check the set definition in Administration → Configuration → Condition Record Sets in the partition.


One-line summary per question

  1. Event-triggered + integrationStatus flag + paging — not ID range, not date.

  2. Set to "processing" on fetch, then to the final status on completion, both via the Pricefx Integration Adapter update op.

  3. Yes — post a JSON array of {id, integrationStatus: <successCode>, …results} to the adapter's Update Condition Record operation (success code is project-defined in value mapping).

  4. Lifecycle/history status (separate from integrationStatus): appears only with superseding/history on — Superseded (overlap), Invalidated (invalidate()), Expired/"shortened" (shortenValidTo()).

  5. typedId = <Long>.<CRCI n | CRCIH n>. Number is a per-table 64-bit counter; suffix is the table code and does not change with size → 1000000.CRCI3.