How to Create and Submit Quotes in Bulk

This article describes how to create and submit large numbers of Pricefx Quotes in a process driven by a Pricefx user inside the platform.

If you instead have a third-party system that needs to push quotes into Pricefx, the right approach is for that system to call the CLIC API directly via clicmanager.create/{type} followed by clicmanager.runjob/{typedId}/submit. The third-party system is already the orchestrator; routing those creations through a Pricefx-side bulk job would add a layer of indirection.

About this article — v1, with a v2 in the works. The pattern documented here is the current recommendation for bulk quote creation: a user-managed source table (Pricing Parameter) plus a CFS, with a Status column on the source giving per-row feedback. It works and scales, but the user has to come back and check the Status column, and there is no built-in import-level history or auditability.

The target v2 is a BulkImport Model Class that generalises this idea to any CLIC object type — Quote (Q), Contract / Agreement (CT), Rebate Agreement (RBA), and so on — through a single framework with thin per-type adapters. Each import becomes a first-class business object with file upload, up-front validation, an issue report the user reviews before processing, per-row outcomes with links to the created objects, and full audit (who imported what, when, with which result). When v2 lands, this CP+CFS path will be retired in favour of the Model Class. Until then, treat this article as the path of least resistance for projects that need bulk quote creation today.

Use a Calculated Field Set as the driver:

  1. The list of quotes to create lives in a source data table (e.g. a Pricing Parameter table with one row per quote).

  2. A CFS is configured against that table. The CFS framework iterates the rows for you; for each row it invokes a small CFS logic.

  3. The CFS logic assembles the minimal quote payload from the current row, persists the quote, and submits it. It does nothing else.

  4. The Quote Header Logic and Quote Item Logic — wired through a custom Quote Type — run as part of the submission, computing all outputs in the place the platform expects.

  5. The CFS framework writes each row's outcome (success / error) back to a status column on the source table, giving per-quote feedback without a separate logging table.

Parallelism and scaling

Because the per-row CFS logic is self-contained, the platform can run rows in parallel across calculation nodes and threads. This is enabled by the Allow distributed calculation toggle in the CFS configuration UI, and stored as shotgunModeEnabled: true in the CFS config JSON.

Separation of responsibilities

This pattern only scales if the responsibilities are kept clean. The two roles do not overlap:

Responsibility

The CFS bulk-creation logic

Quote Header and Quote Item logics

Decide which rows to process

Yes (driven by the CFS source / filter)

No

Persist the quote with required inputs

Yes — and only the required inputs

No

Set the quote type so the right logics run

Yes

No

Trigger submission

Yes

No

Master-data lookups (customer, product, segment, currency, ...)

No

Yes

Calculate prices, discounts, margins, totals

No

Yes

Validations, warnings, alerts, approval routing

No

Yes

Aggregations across line items

No

Yes (in the header post-phase)

The line is sharp on purpose. Anything that the Quote logics can reconstruct from master data should not be persisted by the bulk job; anything that is genuinely a deal parameter (e.g. an explicit quantity, a negotiated list price) is exactly what the bulk job persists.

Reference implementation

An importable Reusable Component named bulk-quote-create-and-submit demonstrates the pattern end-to-end — the source tables, the CFS, the per-row CFS logic, the custom Quote Type, and minimal sample Header and Item logics. See the component's README for endpoint names, payload shape, source-table column conventions, and configuration knobs. The current page deliberately stays at the functional level so the message survives changes in the underlying APIs.

What v2 will change

The Model Class-based v2 keeps the core principles described here — lean creation step, quote logics own the heavy lifting, parallel per-row processing — and improves the parts the CP+CFS path leaves rough:

  • Generic across CLIC types. One BulkImport Model Class handles Quote (Q), Contract / Agreement (CT), Rebate Agreement (RBA) and other CLIC types through thin per-type adapters. The CLIC endpoints (clicmanager.create/{type}, clicmanager.runjob/{typedId}/{action}) are uniform, so the heavy lifting is shared.

  • Up-front validation. The file the user uploads is parsed, schema-checked, and referentially validated before any object is created. The user sees an issue report and decides whether to fix the file or proceed with valid rows only.

  • End-to-end visibility. Each import is a Model Object the user can open: it shows counts, per-row outcomes, links to the created CLIC objects, and the validation report. No more "check the Status column an hour later".

  • Auditability by default. Who imported which file, when, with what outcome, is all attached to the Model Object's history — not spread across a Pricing Parameter table, a CFS run log, and Quote audit trails.

v2 is being designed; this article will be updated when the Model Class lands. Until then, the pattern documented above is the recommended one for bulk quote creation.

Relation to other guidance

The existing article How to Create a Quote from a Logic remains the reference for single-quote, dashboard-driven creation scenarios. The pattern documented here applies specifically to bulk creation — many quotes from a feed, a migration, or an integration — where the single-threaded approach hits scaling and timeout walls.