Skip to content

Shipping Pricebook

Overview

The Shipping Pricebook applet is where an e-commerce or logistics administrator defines conditional shipping charges: a Shipping Pricebook is a named container, and each Shipping Priceset inside it says who qualifies (entity type, member class, member label, company, branch, delivery region, date range), which items in the cart it looks at (items, categories, code or name patterns, with minimum quantity, minimum amount and weight bands) and what is charged (a Standard Shipping Fee, a Handling Fee and a Fuel Surcharge, each with a price source, an operator and a value).

The applet only maintains this master data. The rules are applied by one consumer: the CP Commerce storefront. At checkout the shopper picks a shipping price book as the Shipping method, the storefront evaluates its price sets in the browser and writes the resulting fee as a line for the website’s shipping-fee service item on the shopping cart. Nothing in the ERP back office (POS, sales documents, the Java backend) evaluates shipping price books.

Where it fits

DirectionAppletRelationship
UpstreamDoc Item MaintenanceItems, item categories and pricing schemes referenced by line rules and treatments; item weight and dimensions feed the weight bands; the SERVICE item that carries the fee
UpstreamOrganizationCompanies and branches for Company / Branch rules
UpstreamCustomer MaintenanceEntity types (customer / supplier / employee) matched by Entity Type rules
UpstreamMembership AdminMember classes and member labels for the member rules
ConsumerCP Commerce AdminWebsite settings that switch the shipping-fee process on, choose the Shipping Pricebook option, the default price book and the shipping-fee item
ConsumerShopping CartThe storefront writes the computed fee as a DRAFT-cart line; the cart converts to a Sales Order that carries it as a normal service line
SiblingPricebookSame rule / treatment design applied to discounts and points, on its own tables and with its own consumers

Screens and menus

The applet has two menu entries, Shipping Pricebook and Shipping Priceset, plus Settings and Personalization.

ScreenPathWhat it shows
Shipping Pricebook listingpricebookColumns Shipping Pricebook Code, Name, Description, Modified Date (sorted descending), Created Date, Status (read from the PRICE_BOOK_STATUS extension); server-side paging through shipping-pricebooks/query, deleted books excluded
Shipping Pricebook createShipping Pricebook → +Code, Name, Menu Icon, Status, Description
Shipping Pricebook editselect a rowTabs Details (code, name, menu icon, calculation logic, status, description, audit fields, Delete) and Pricing Set (the book’s price sets with Priority column, search, create and edit)
Shipping Priceset listingpricesetEvery price set of every price book, loaded client-side from shipping-pricebooks (no server paging): Code, Name, Description, Modified Date, Created Date, Status
Shipping Priceset createShipping Priceset → +Pricebook Name (searchable select), Code, Name, Priority Level, Status, Description
Shipping Priceset editselect a rowTabs Details, Rules - Doc Hdr, Rules - Multi Line, Rules - Single Line, Treatment
Add Rule+ on a Rules tabRule Type selector, then the type-specific form or selection grid
Settingsgear → SettingsMenu: Field Settings, Default Selection. Routes that exist without a menu entry: feature-visibility (the landing page of Settings), webhook, permission-set-listing, user-permission-listing, team-permission-listing, role-permission-listing
Personalizationgear → PersonalizationDefault Selection (branch / location; non-functional, see Configuration), Sidebar

There are two editors for a price set. The Shipping Priceset menu opens priceset-edit; the Pricing Set tab of a Shipping Pricebook opens the nested pricebook-edit-priceset. Unlike the Pricebook applet, both offer the same rule types and the same three treatments and save the same bl_fi_mst_shipping_price_book_line row.

Shipping Pricebook edit, Pricing Set tab, with the Create Shipping Priceset form open
Shipping Pricebook edit › Pricing Set: the nested Create Shipping Priceset form (Code, Name, Priority Level, Status, Description).
Shipping Priceset listing with the Create Shipping Priceset form open
Shipping Priceset menu › Create: the same form with a Pricebook Name selector in front.
Edit Shipping Priceset, Details tab
Edit Shipping Priceset › Details: code and price book are read-only, Priority Level and Status are editable, Delete at the bottom.

Configuration

Before you can use it

  • A website with the shipping-fee process switched on in CP Commerce Admin → Website Edit → Details: tick Enable Shipping Fee Process, choose Shipping Fee Options = Shipping Pricebook, pick the Default Shipping Price Book Code and the Item Code for Shipping Fee. Without the item the storefront computes no line (the fee shows as RM 0.00); without the option the storefront runs the delivery-charge path instead (see Settings in other applets).
  • A SERVICE item for the fee in Doc Item Maintenance (txn_type SERVICE). Its GL and tax settings decide how the fee posts once the cart becomes a sales order.
  • Items and categories exist in Doc Item Maintenance for item / category rules; pricing schemes exist if a treatment uses Price Source = Pricing Scheme (the Treatment tab lists the schemes of the PRICING_SCHEME_ITEM list).
  • Companies and branches exist in Organization for Company / Branch rules; member classes and labels exist in Membership Admin for the member rules.
  • Delivery regions with a State value for Delivery Region rules — the storefront matches the shopper’s shipping-address state against the region’s State (see Lifecycle).
  • Tenant permissions. Every applet endpoint checks API_TNT_DM_ERP_SHIPPING_PRICE_BOOK_OWNER / ADMIN or the matching CREATE / UPDATE / DELETE / READ code (TntErpPermissions L371-383; ShippingPriceBookPackageController L56-215). The storefront does not need any of them: it reads through shipping-pricebooks/website-ep/{websiteHdrGuid}/query, an anonymous tenant endpoint that only validates the website guid (controller L219-245).

Applet settings

Settings are applet-local in layout only: app.routing.ts routes settings/field-settings and settings/default-selection to the applet’s own components, and the shared FieldConfigurationComponent in blg-shared-utilities is not routed (gates.py has no controls for ShippingPricebookApplet). None of the applet’s own screens is functional:

  • Field Settings is a static template — eight slide toggles (Lines Settings: Unit Discount, SST/VAT/GST, WHT, Blanket Order; Department Settings: Segment, G/L Dimension, Profit Center, Project) with no form binding, a SAVE button with no click handler and a component class with no logic (field-configuration.component.html, .ts). They are rendered but neither declared, persisted nor consumed.
  • Default Selection renders Default Branch and Default Location. The component writes each change into this.appletContainer.bl_applet_exts, but appletContainer is never assigned (there is no subscription to appletSettings$, and the routed host <app-settings> neither binds that input nor listens to save; the shared SettingsComponent.onSaveDefault is commented out). Changing a value throws in the browser console and nothing is saved; no code in the applet reads DEFAULT_BRANCH or DEFAULT_LOCATION.
  • Personalization → Default Selection has the same defect (personal-default-settings.component.ts L31-38 commented out).

No exposed, working control found (routes and settings components checked at commit 7894b78, 2026-09-02).

Settings in other applets that control this applet

SettingWhere it is setEffect on shipping price books
Enable Shipping Fee ProcessCP Commerce Admin → Website Edit → DetailsMaster switch; when off the storefront never calculates a shipping fee
Shipping Fee Options (Shipping Pricebook / Delivery Charges / Delivery Charges by Country / Delivery Charges by Region)same screenOnly Shipping Pricebook uses this applet. The storefront branches on useDeliveryChargeItem: delivery-charge options call the server-side loginEntityGenerateDeliveryChargesDocLine, the price book option runs the client-side engine described under Lifecycle
Default Shipping Price Book Code (website extension SYS_AKN_WEB_CP_COMMERCE_SHIPPING_PRICEBOOK)same screen, shown for the Shipping Pricebook optionThe price book pre-selected as Shipping method at checkout (selectActivePricebook: the shopper’s choice, else this default)
Item Code for Shipping Fee (SYS_AKN_WEB_CP_COMMERCE_SHIPPING_SERVICE_ITEM)same screenThe SERVICE item the computed fee is written against (quantity 1). With no item the storefront adds no line and shows RM 0.00
Pick-up in store (website content flag selectPickupStoreEnabled)website configurationAdds a synthetic “PICK UP IN STORE” entry (code PICKUP_STORE, guid DEFAULT_UUID) to the Shipping method list; choosing it skips the shipping address and the fee
Item property free_shippingitem master data used by the storefrontLines whose item carries item_property_json.free_shipping are left out of the item / category data fetched for rule evaluation

Feature visibility / permissions

No client-side permission definitions are seeded for this applet (bl_applet_client_side_perm_dfn has no rows for ShippingPricebookApplet, checked 2026-09-05), so the Feature Visibility screen and the role / team / user permission listings under Settings have nothing applet-specific to gate. Access is decided by the tenant permissions listed under Before you can use it; the API returns not authorised when none of them is assigned.

Fields

Code and name inputs on the create forms accept letters, digits, space, hyphen and underscore only (blockSpecialChar), are upper-cased and trimmed on save, and are limited to 255 characters.

Shipping Pricebook — create

FieldMeaningRequiredNotes / validation
Shipping Pricebook CodeUnique identifier of the bookYesImmutable after creation (read-only on edit). The backend does not check uniqueness (ShippingPriceBookDataConsistencyObject validates guid, revision, status and hdr_guid links only)
Shipping Pricebook NameDisplay name; what the shopper sees as the Shipping methodYesStored upper-cased
Menu IconIcon shown next to the shipping method in the storefrontNoIonicon name, stored as property_json.icon
StatusActive / InactiveYesDefault Active. Stored as extension PRICE_BOOK_STATUS, not as the header status column — see Lifecycle for the consequence
DescriptionFree textNoMax 255 characters

Shipping Pricebook — edit › Details

FieldMeaningRequiredNotes / validation
Pricebook CodeAs createdRead-only
Pricebook NameDisplay nameYesSave is disabled until the form is touched
Menu IconAs aboveNo
Calculation LogicHow the storefront picks among matching price setsNoOptions Sequential Match, Amount Lowest, Amount Highest, Points Reward Highest / Lowest, Points Redeem Highest / Lowest (Options.firstMatchOptions, stored as extension FIRST_MATCH). The storefront treats every value as Sequential Match — see Lifecycle
StatusActive / InactiveNoExtension PRICE_BOOK_STATUS
DescriptionFree textNoCharacter counter, no limit on edit
Created By / Date, Modified By / DateAuditRead-only; the By fields resolve the subject to its e-mail login principal
DeleteSoft-deletes the bookBackend sets status DELETED on header, extensions and lines (ShippingPriceBookUow.deleteDbTableDao.delete with deletePermanent = false)

Shipping Priceset — create

FieldMeaningRequiredNotes / validation
Pricebook NameParent book (menu form only; the nested form shows it read-only)YesSearchable select over all books returned by shipping-pricebooks
Shipping Priceset CodeIdentifier within the bookYesImmutable after creation; not checked for uniqueness
Shipping Priceset NameDisplay nameYes
Priority LevelEvaluation order at checkoutYesNumber; lower value is evaluated first. Stored as property_json.priority_line
StatusActive / InactiveYesDefault Active; stored as property_json.status
DescriptionFree textNoMax 255 characters

Creating a price set appends a line to the book with three empty rule groups (hdr_doc_filter, multi_line_doc_filter, single_line_doc_filter, each top_level_logic = AND, negation_logic = FALSE, rules = []) and an empty treatment_json.treatment array, and PUTs the whole book.

Shipping Priceset — Rules tabs

Each Rules tab has Rules Logic (And / Ortop_level_logic) and Negation Logic (Enabled / Disablednegation_logic) for the whole group, a grid of Rule Name · Rule Type, and a + that opens Add Rule. Every rule form has a required Rule Name and its own Negation Logic. Rules are saved immediately by the rule form (a PUT of the book), independently of the SAVE button of the price set.

Rules - Doc Hdr tab with the Add Rule type list open
Rules - Doc Hdr: group logic on the left, the Rule Type list of the Add Rule column on the right.
TabRule TypeForm / pickerStored keys
Rules - Doc HdrValid Date RangePeriod Unit (Day(s) / Month(s) / Year(s)), Relative Period (number), Absolute Period From / To (date pickers)start_date, end_date, period
Rules - Doc HdrEntity TypeCheckboxes All Customer, All Supplier, All Employeerule_filter_values (entity type codes)
Rules - Doc HdrMember Class, Member LabelSelection grid of classes / labelsrule_filter_values (guids)
Rules - Doc HdrCompany, BranchSelection grid of companies / branchesrule_filter_values (guids)
Rules - Doc HdrDelivery RegionSelection grid Code · Delivery Region · State · Countryrule_filter_values (regions with state)
Rules - Multi Line, Rules - Single LineItem, Item CategoryMin Quantity, Min Amount (“measured against the selected items only, after discount”), Total Weight From / To, Total Volumetric Weight From / To, Divisor, then the item / category selection gridminQty, minAmt, totalWeightFrom, totalWeightTo, totalVolumetricWeightFrom, totalVolumetricWeightTo, volumetricWeightDivisor, rule_filter_values
Rules - Multi Line, Rules - Single LineItem Code Regex, Item Name Regex, Category Code Regex, Category Name RegexName and the regular expression, added to a listrule_filter_values (name / code pairs)
Rules - Multi Line tab with the Add Rule type list open
Rules - Multi Line: the six item and pattern rule types.
Rules - Single Line tab with the Add Rule type list open
Rules - Single Line offers the same six types; the storefront does not evaluate this tab (see Lifecycle).

Shipping Priceset — Treatment tab

Three independent blocks, each enabled by its checkbox: Standard Shipping Fee (STANDARD_SHIPPING_FEE), Handling Fee (HANDLING_FEE) and Fuel Surcharge (FUEL_SURCHARGE). Unticking a block removes its entry from treatment_json.treatment on save.

FieldMeaningRequiredNotes / validation
Price SourceThe cart figure the fee is derived fromNoBase Quantity (qty_base), Standard Amount (amount_std), Price Unit Cost (price_unit_cost), Net Amount (amount_net), Transaction Amount (amount_txn), Pricing Scheme (pricing_scheme)
OperatorThe arithmetic appliedNoMULTIPLY, ABSOLUTE, ADD, SUBTRACT
ValueThe number the operator usesNoNumeric input, no validation
Pricing SchemeShown only when Price Source = Pricing SchemeNoSchemes of the PRICING_SCHEME_ITEM list; stored as pricing_scheme (guid)
Auto apply to all child itemsStandard Shipping Fee block onlyNo“When a group item is selected in this priceset’s rules, also match every child item of that group in the cart”; stored as auto_apply_to_all_child_items and read while evaluating item rules
Treatment tab with the Price Source list open
Treatment: Standard Shipping Fee, Handling Fee and Fuel Surcharge, each with Price Source, Operator and Value.

Lifecycle and effects

What the applet writes. Every action is a full PUT of the price book container (shipping-pricebooks, ShippingPriceBookService.put): header, extensions and lines together. Price set Delete does not remove the line; it sets status and property_json.status to DELETED and PUTs. Price book Delete calls DELETE /{guid} and the backend soft-deletes header, extensions and lines. Update, delete and price set actions also POST an audit row to shipping-pricebooks/events (bl_fi_mst_shipping_price_book_event, txn_type SYS_APPLET, actions PRICE_BOOK_UPDATED, PRICE_BOOK_DELETED, PRICING_SET_CREATED, PRICE_SET_UPDATED, PRICE_SET_DELETED); the create effect builds its PRICE_BOOK_CREATED event inside an inner pipe that is never subscribed, so that event is never written.

Backend validation. ShippingPriceBookPackageService.create/update run ShippingPriceBookDataConsistencyObject: header guid present and (on create) not already existing, revision and status present, every extension and line with a guid, hdr_guid equal to the header guid, revision and status. Failures come back as Core2DataConsistencyException with codes such as SHIPPING_PRICEBOOK_HDR_OBJECT_GUID_ALREADY_EXISTS or SHIPPING_PRICEBOOK_LINE_OBJECT_HDR_GUID_DIFFERENT_FROM_PRICEBOOK_HDR_OBJECT_GUID. Nothing validates the rule or treatment JSON and nothing checks code uniqueness. The bl_fi_mst_shipping_price_book_rule_* tables, DCOs and controllers exist in the backend but no applet, storefront or admin code references them.

No posting. A shipping price book is master data: no server document type, no signums, no journal, no stock processor. The fee reaches the ledger only as an ordinary service-item line on the sales order the cart converts into, and posts by that item’s GL and tax configuration.

How the storefront applies it (the only consumer). All of this runs in the shopper’s browser (wavelet-cp-commerce, commit 247243251, 2026-09-03):

  1. Load. loadShippingPricebookInit$ calls the anonymous website endpoint asking for header status ACTIVE, ordered by created date. The applet’s Status field is the extension PRICE_BOOK_STATUS, which the storefront never reads, so an Inactive price book is still loaded and offered; only a deleted one disappears.
  2. Choose. The Shipping method block at checkout lists every loaded price book by name and icon (plus PICK UP IN STORE when enabled) with the website default pre-selected; selectActivePricebook = the shopper’s choice, else the website default.
  3. Qualify. ShippingManager sorts the book’s price sets by priority_line ascending (missing → last; ties keep API order), drops DELETED ones — Inactive price sets are still evaluated — and keeps those whose Doc Hdr rules and Multi Line rules both pass. The Single Line tab is never evaluated. Within a group, Rules Logic And / Or and Negation Logic are honoured.
  4. Select. selectPricesetBasedOnCalculationLogic always returns the first qualifying set. Calculation Logic on the book (FIRST_MATCH) is read but every value behaves as Sequential Match.
  5. Compute. Aggregate = Σ over all cart lines of the Standard Shipping Fee price source (qty_basequantity_base, amount_std, amount_net, amount_txn, price_unit_costunit_price_std). Each ticked treatment applies its operator to that same aggregate: MULTIPLY = aggregate × value, ABSOLUTE = value, ADD = aggregate + value, SUBTRACT = aggregate − value; an unticked treatment contributes 0. Fee = Standard + Handling + Fuel, rounded to two decimals. The Handling Fee and Fuel Surcharge blocks’ own Price Source is not used; Pricing Scheme as a price source reads a field that is not on the cart line and yields no usable number.
  6. Write. The fee becomes a quantity-1 line for the website’s shipping-fee item (addShippingDocLine; the previous shipping line is marked DELETED), the cart revision is checked, and the coupon engine is re-run so a free-shipping voucher can discount the line.

Rule coverage at checkout.

Rule TypeEvaluated as
Entity TypeCart entity has any of the selected types (containsEntity)
Member Class, Member LabelCart member’s class guid / label guids include any selected
Company, BranchCart company / branch guid equals any selected
Delivery RegionShipping address state equals (case-insensitive) the State of any selected region; region code, country and postcode are not compared
Item, Item Category, code / name regexesSelected items / categories / patterns present in the cart with minQty, minAmt (after discount, selected items only), total weight and volumetric weight bands; group items expand to child lines when Auto apply to all child items is on
Valid Date RangeMapped to a node with null start and end dates, so it always passes; with Negation Enabled it never passes. The dates and period entered in the applet are not used
Any item / category rule with nothing selectedEvaluates to false and, with the default And, disables the whole price set (a known gap noted in the mapper)

Related applets

  • Pricebook — the discount / sales-price / points sibling with the same rule and treatment design; its consumers (POS, sales documents, OCR) never read shipping price books.
  • CP Commerce Admin — owns the website switches that decide whether, with which price book and against which item the storefront charges shipping.
  • Shopping Cart — the fee is a line of the DRAFT cart; the coupon engine may discount it.
  • Doc Item Maintenance — the shipping-fee SERVICE item, the items and categories in line rules, the pricing schemes offered in the Treatment tab, and the weight / dimensions used by weight bands.
  • Organization — companies and branches for Company / Branch rules.
  • Membership Admin — member classes and labels for member rules.
  • Customer Maintenance — entity types for Entity Type rules.
  • Sales Order — receives the fee as a service line when the cart converts.

Troubleshooting

SymptomCauseFix
Checkout charges a fixed fee (e.g. RM 20) although the shopper does not match the rules you expected (gh:bigledger/wavelet-cp-commerce#57, #67)The first price set in priority_line order whose Doc Hdr and Multi Line rules pass wins; a price set with no rules always qualifies; Single Line rules are ignored; Inactive price sets are still evaluatedGive every price set a distinct Priority Level, put the most specific sets on the lowest numbers, move item conditions to the Multi Line tab, and delete (not deactivate) sets that must not apply
A price set never applies even though its rules look rightAn Item / Item Category / regex rule was saved with nothing selected; it evaluates to false and, under And, disables the whole setOpen the rule and delete it, or select items
Valid Date Range has no effect (promotion rate applies outside the dates, or never applies)The storefront evaluates the rule with null dates: it always passes, and with Negation Enabled never passesDo not rely on date rules for shipping; switch price sets manually, or deactivate the book
Delivery Region rule does not match an address in the right regionOnly the address state text is compared with the region’s State (case-insensitive); postcode, city and country are ignoredMake the region’s State exactly the value the storefront stores in the shipping address; create one region per state spelling
Handling Fee or Fuel Surcharge is calculated on the wrong baseBoth use the aggregate of the Standard Shipping Fee price source; their own Price Source is ignored. With Standard Shipping Fee unticked the aggregate is 0, so MULTIPLY gives 0 and ADD / ABSOLUTE give the bare valueTick Standard Shipping Fee and set its Price Source to the base you want for all three
Calculation Logic = Amount Lowest / Highest makes no differenceThe storefront always takes the first qualifying price set in priority orderOrder the price sets by Priority Level instead
An Inactive price book still appears as a shipping methodStatus is stored as the PRICE_BOOK_STATUS extension; the storefront filters on the header status columnDelete the book (soft delete) or remove it as website default and rename it; ask the product team about the extension / column mismatch
No Shipping method block, or fee always RM 0.00Website has Enable Shipping Fee Process off, Shipping Fee Options is not Shipping Pricebook, no Default Shipping Price Book Code, or no Item Code for Shipping Fee (no item → no line)Complete the website Details section in CP Commerce Admin
Price Source = Pricing Scheme gives no feeThe storefront reads pricing_scheme from the cart line, which carries no such numberUse Base Quantity, Standard / Net / Transaction Amount or Price Unit Cost; model tiers as several price sets
Old price sets carry duplicate treatment entriesAn earlier version of the save effect appended a second STANDARD_SHIPPING_FEE / HANDLING_FEE / FUEL_SURCHARGE entry whenever the set had exactly one treatmentOpen the price set and Save once: the current effect collapses duplicates, keeping the last entry per type
Default Selection throws or does not keep Branch / LocationThe settings component is not wired to the applet store (no container loaded, no save listener)Nothing to configure here; the applet reads no default branch or location
“Could not calculate the shipping fee because the cart kept changing”The cart revision changed while the fee was being computed; the storefront retries a bounded number of times and then gives upRetry checkout once the cart is stable

Related documentation

Last updated on