Latest posts Visit blog

A cable is listed in metres in the catalogue, leaves the warehouse in 50-metre rings and is called off by the piece in purchasing. If someone orders 120 metres, the shop has to decide whether that turns into two rings, three rings or an error message. The decision is taken in three places at once - in the product master, in the cart and when the order is handed over to the ERP system - and in many projects it comes out differently in each place. This article separates unit of measure, pack size, minimum order quantity and interval, shows the fields a B2B shop provides for them, and sets out when a base price has to be shown alongside the total price.

Four quantity terms that do not mean the same thing

In everyday company language everything is called quantity. In the product master there are at least four different entries, and they answer four different questions. The content unit says what the article is measured in - metres, kilograms, pieces. The order unit says what it can be ordered in - ring, carton, pallet. The pack size says how many content units sit inside one order unit. And the minimum order quantity says how many order units are needed before an order comes about at all. Writing two of these four entries into the same field produces a shop that looks arithmetically sound and does not add up in the warehouse.

The BMEcat catalogue format, used by manufacturers and distributors to exchange product data, keeps this separation. It carries the order unit in the element ORDER_UNIT, the unit of the article in CONTENT_UNIT and the ratio between the two in NO_CU_PER_OU. The description in the standard also names the point where most conversion errors start: the price hangs on the order unit, not on the content unit. Anyone importing or exporting catalogues will recognise the field names and their meaning from the article on BMEcat and ETIM.

If this element is not stated, the price refers to the order unit given in the element ORDER_UNIT.

BMEcat 2005.2, element PRICE_QUANTITY, translated from the German specification

Half of the pricing logic of a B2B shop follows from that single sentence. If the article carries a price of 89 euro and the order unit is the ring, then the ring costs 89 euro, not the metre. If the price is meant to refer to a different quantity - to 100 metres instead of one ring, say - there is a separate field for it, the price quantity. Folding it into the price works up to the first scale; after that every report is off. How scales and customer-specific conditions come out of the ERP system cleanly is covered in the article on customer-specific prices from the ERP.

Four questions for every article

Before an article goes into the shop, four answers should be settled: what is the article measured in? What is it ordered in? How many units of measure sit in one order unit? And from how many order units does the shop accept an order? Only when these four answers sit separately in four fields can the fifth question be answered - what the price refers to. An article missing one of the four answers tends to produce a correction entry in the warehouse later on.

Where the conversion belongs in the product master

The conversion belongs in exactly one place: the product master. Every second place - a plugin in the cart, a script in the export, a rule in the price list - is a second truth that will diverge from the first at some point. In practice that means the article carries order unit, content unit, pack size, minimum quantity and interval as separate fields, and every downstream system reads them instead of recalculating them.

Where these fields are maintained is a question of the system landscape. If a PIM system holds the product data, they belong there and travel from there into the shop. If the truth comes from the ERP system, the path runs through the article interface. What matters is less which system wins than that the decision is taken once and written down. What has to be settled when introducing such a system is covered in the article on PIM implementation.

  • Content unit - what the article is measured in. In the catalogue format CONTENT_UNIT, described there as the unit of the product within one order unit.
  • Order unit - what is ordered in. In the catalogue format ORDER_UNIT, described as the unit in which the product can be ordered, and at the same time the reference for the price.
  • Pack size - how many content units one order unit contains. In the catalogue format NO_CU_PER_OU, described as the number of content units per order unit of the article.
  • Price quantity - which multiple or fraction of the order unit the price refers to. In the catalogue format PRICE_QUANTITY.
  • Minimum order quantity - from how many order units an order is accepted. In the catalogue format QUANTITY_MIN.
  • Interval - in which steps it can be ordered beyond that. In the catalogue format QUANTITY_INTERVAL.

A seventh field pays off as soon as the packaging changes with the quantity. The catalogue format provides a dedicated area describing how the packaging unit depends on the order quantity. The example in the standard is printer paper: the order unit is the pack, 5 packs become a carton, 50 packs an outer packaging, 500 packs a pallet. For the shop that is first of all a display question; for shipping and freight costs it is a costing question. What this means for bulky and heavy consignments is covered in the article on freight shipping.

One truth, one field

Every quantity entry has exactly one system of record and exactly one field. As soon as the same number can be maintained in two places, the question is no longer whether the two drift apart but when. A short reconciliation - which system owns which field, and who may change it - typically costs a morning and saves the later search for the place where 50 metres turned into 500.

Minimum quantity, interval and rounding up to the pack

Minimum order quantity and interval are often lumped together in daily work, but they do different things. The minimum quantity is the entry point: below it no order comes about. The interval is the step width above it; it says which quantities are admissible between the entry point and the maximum. The standard describes it as the statement of the interval in which the product can be ordered, and states explicitly that counting starts at the minimum order quantity.

The difference becomes tangible in the examples given by the standard: an interval of 1 allows 5, 6, 7 boxes, an interval of 2 allows 4, 6, 8 boxes. Both configurations look similar in the form but lead to entirely different error messages when someone types 7. Anyone offering fast entry masks should enforce the rule there just as in the ordinary cart - which fits the article on quick order for regular customers.

EntryWhat it definesField in the catalogue formatEffect in the cart
Content unitwhat the article is measured inCONTENT_UNITdisplay of the total quantity in metres, litres or pieces
Order unitwhat is ordered in and what the price refers toORDER_UNITquantity field counts packs, not units of measure
Pack sizehow many content units one pack containsNO_CU_PER_OUconversion between the two displays
Price quantitywhich multiple of the order unit the price refers toPRICE_QUANTITYbasis of every line total
Minimum order quantityfrom which quantity an order comes aboutQUANTITY_MINlower bound of the quantity field
Intervalin which steps it is ordered beyond thatQUANTITY_INTERVALstep width of the quantity field

Rounding up to the next pack is none of these six entries but a rule that follows from them. It applies when a customer thinks in content units and the shop ships in order units. There are three workable answers: round up, reject, or offer a partial quantity. What tends to create trouble is the silent variant - accepting the wish, changing the quantity internally and displaying neither. A similar question arises for composed articles, covered in the article on product bundles and set articles.

Rounding up changes the price

Whoever orders 120 metres and receives three rings of 50 metres each pays for 150 metres. Rounding up is therefore not a display question but a change of price, and it belongs where it happens: in the quantity field itself, not first in the order confirmation. A note directly below the field has proved useful, naming the rounded quantity, the number of packs and the resulting line total together. Shipping costs then arise on the rounded quantity as well - what this means for costing is covered in the article on shipping cost models.

Base price: when it is due and when it is not

As soon as a shop sells by weight, volume, length or area, the question of the base price comes up. The German Price Indication Ordinance governs the indication of prices for goods or services by traders towards consumers (section 1(1) PAngV) - the scope is therefore tied to the notion of the consumer, and under section 2 point 9 PAngV a consumer is any natural person within the meaning of section 13 of the German Civil Code. A shop that supplies commercial buyers only and enforces this technically therefore sits outside that scope. A shop with a mixed audience does not.

Where the sale falls within the scope, section 4(1) PAngV requires the base price to be stated alongside the total price, unambiguously, clearly identifiable and easily legible. Under section 2 point 4 PAngV the base price is the price per unit of measure of a good including value added tax and other price components. Section 4(3) PAngV exempts certain goods from that duty; for a technical distributor these cases are the relevant ones:

  • Goods with a nominal weight or nominal volume of less than 10 grams or 10 millilitres (section 4(3) point 1 PAngV).
  • Goods containing different products that are not mixed or blended with each other - the assortment box case (section 4(3) point 2 PAngV).
  • Goods offered in the context of a service (section 4(3) point 4 PAngV).
  • Goods offered in beverage and food vending machines (section 4(3) point 5 PAngV).

Where the duty applies, section 5 PAngV sets the reference. The unit of measure for the base price is 1 kilogram, 1 litre, 1 cubic metre, 1 metre or 1 square metre of the good. For goods customarily supplied in quantities of 100 litres and more, 50 kilograms and more or 100 metres and more, the unit of measure corresponding to general commercial practice is used instead - in the cable trade that tends to be 100 metres rather than 1 metre. For the shop side that means the base price is calculated from price, price quantity and pack size instead of being maintained as a separate field. How this sits with discount displays is covered in the article on strikethrough prices and the PAngV.

Coding units instead of naming them

Ring, roll, pack, PU - a free-text field in an article table contains all of them, and no two systems understand the same thing by them. For machine exchange there is an agreed list: UN/CEFACT Recommendation 20 for units of measure, extended by the packaging codes of Recommendation 21, which are carried with an X in front. The version of this list published by Peppol carries the designation Recommendation 20, including Recommendation 21 codes - prefixed with X (UN/ECE) and the version Revision 11e. The same list sits behind the electronic invoice, so that order, delivery note and invoice can carry identical codes.

C62 - one

The code for the dimensionless counting unit. The list carries it with the addition Synonym: unit. In catalogues it typically appears where colloquial usage means pieces.

H87 - piece

The second code for piece counts, described in the list as a unit of count defining the number of pieces. Which of the two is used should be settled once per catalogue.

XPK - Package

A packaging code from Recommendation 21, described in the list briefly as standard packaging unit. For specific packs there are dedicated codes, for example XRG for the ring, XCT for the carton and XPX for the pallet.

MTR, KGM, LTR

Metre, kilogram and litre - codes for exactly those units of measure that section 5(1) PAngV provides for the base price. Carrying them in the product master allows the base price to be calculated instead of maintained.

The gain lies not in the list itself but in the unambiguity at the interfaces. A catalogue writing XRG says the same thing to every recipient; a catalogue writing ring says something different to every recipient. For orders triggered from the customer's procurement system this is not a nicety but the precondition for the line to be matched at all on the way back - see the article on punchout catalogues.

Three places in the ordering path where conversion happens

The conversion does not happen once but three times: when displaying the article, when adding to the cart and when handing the order over. A different number can arise in each of these places if the rule does not come from the same source. The sequence is fixed: the customer's wish arrives in content units or order units, is normalised to the order unit, checked against minimum quantity and interval, rounded up where necessary, and only then calculated.

Counting for this interval consistently starts at the stated minimum order quantity.

BMEcat 2005.2, element QUANTITY_INTERVAL, translated from the German specification

That sentence decides how rounding up works. With a minimum quantity of 4 and an interval of 2, 5 is not an admissible quantity and 6 is the next one. A cart that simply rounds to the next multiple of the interval arrives at 6 - which happens to be right here. With a minimum quantity of 5 and an interval of 2, the admissible values are 5, 7 and 9, and the same naive rounding delivers 6 and therefore a quantity the ERP system rejects. The stock behind it is also kept in order units - counting and its pitfalls fit the article on year-end stocktaking.

The same rule applies again when handing over to the ERP system, regardless of whether the order arrives through the cart, through a fast entry mask or through an interface. It therefore makes sense to keep the check as one function and call it from all three paths instead of rebuilding it in each one. Which systems play together here is shown by the overview of the integrations.

Rounding as one function that returns its decision

The core is short and still has a few edges. The function receives the wish, the pack size, the minimum quantity and the interval, and it returns not just a number but the decision: how many packs, how many content units, and whether it rounded up. Only with that additional information can the note in the form be produced without doing the calculation a second time. For implementations of this kind in an existing shop, programming is available.

packsize.php
<?php
// Wanted quantity in content units -> order quantity in order units.
// Minimum and interval are counted in order units (ORDER_UNIT).

function packQuantity(
    float $wantedContent,
    float $contentPerPack,
    float $minimumPacks,
    float $intervalPacks
): array {
    if ($contentPerPack <= 0 || $intervalPacks <= 0) {
        throw new InvalidArgumentException('Pack size and interval have to be positive.');
    }

    $raw = $wantedContent / $contentPerPack;

    // Counting starts at the minimum quantity, not at zero.
    $steps = $raw <= $minimumPacks
        ? 0
        : (int) ceil(($raw - $minimumPacks) / $intervalPacks - 1e-9);

    $packs = $minimumPacks + $steps * $intervalPacks;
    $content = $packs * $contentPerPack;

    return [
        'packs' => $packs,
        'content' => $content,
        'rounded' => abs($content - $wantedContent) > 1e-9,
    ];
}

// 120 m at 50 m per ring, minimum 1, interval 1
// gives 3 packs, 150 m of content, rounded up

The tolerance in the comparison is not cosmetic but necessary: dividing metres by rings means working with floating point numbers, and 120 divided by 50 does not in every case yield exactly 2.4. Without a tolerance the function occasionally rounds one step too far for a wish that sits exactly on an interval step. In systems working with fixed-precision decimals this disappears - and then the quantity should be carried there rather than as a floating point number.

Terminal
$ php packsize.php --wanted 120 --content 50 --min 1 --interval 1
packs=3 content=150 rounded=yes
$ php packsize.php --wanted 100 --content 50 --min 1 --interval 1
packs=2 content=100 rounded=no
$ xmllint --xpath '//PRODUCT_ORDER_DETAILS' catalogue.xml
<PRODUCT_ORDER_DETAILS> <ORDER_UNIT>XRG</ORDER_UNIT> <CONTENT_UNIT>MTR</CONTENT_UNIT> <NO_CU_PER_OU>50</NO_CU_PER_OU> <PRICE_QUANTITY>1</PRICE_QUANTITY> <QUANTITY_MIN>1</QUANTITY_MIN> <QUANTITY_INTERVAL>1</QUANTITY_INTERVAL> </PRODUCT_ORDER_DETAILS>

Two checks cover the most frequent errors. The first compares the units against each other for every article: an order unit identical to the content unit but carrying a pack size greater than one is as a rule a maintenance error. The second checks the catalogue export against the code list: every value in ORDER_UNIT and CONTENT_UNIT has to appear there, otherwise the recipient rejects the catalogue or reads it wrongly.

  • Order unit, content unit and pack size sit in three separate fields.
  • The price quantity is set wherever the price does not refer to one order unit.
  • Minimum quantity and interval count in order units, not in content units.
  • Rounding is visible in the quantity field before the line reaches the cart.
  • All unit codes come from the agreed list, not from free text.
  • The base price is calculated and not maintained as a separate field.
  • Fast entry and interface call the same check as the cart.

Handover to the ERP system and catalogue formats

In the end the order leaves the shop, and that is where it shows whether the separation has been kept up. What is handed over is the quantity in order units together with the code of the order unit; the content quantity can be derived from it and is not the field of record. Conversely the supplier's catalogue arrives with the same fields. A catalogue export omitting one of the two units forces the recipient to guess - and guessing turns out differently in different ERP systems.

  1. Quantity in order units, as an integer or with the precision stored on the article.
  2. Code of the order unit from the agreed list, not the display name.
  3. Pack size, so that the recipient can recalculate the content quantity.
  4. Price quantity and line price, so that the total can be checked without a query.
  5. Whether rounding took place, as a separate field rather than a comment in free text.

Where to start

The first step is not development but a count: how many articles actually have an order unit that differs from the content unit? In many assortments it is a small share, and that share carries most of the queries. For those articles the fields named above are filled in, then the rounding rule is built in, and only then is the display refined. Turning the sequence around means building a pretty display on top of data that cannot carry it.

The second step is the code list. Putting it into the product master once as a select list costs little and ends the free-text variants for good. The third step is checking the catalogue export against the same list, so that a maintenance error surfaces before it reaches the customer. After that the quantity logic is a data question and no longer a programming question - and that is the state in which an assortment can grow without every new article group needing a special rule of its own.

Sources and legal basis

This article draws on the German Price Indication Ordinance of 12 November 2021 in the version published on Gesetze im Internet, in particular on section 1(1), section 2 nos. 4 and 9, section 4(1) and (3) and section 5(1). The field descriptions for order unit, content unit, pack size, price quantity, minimum quantity and interval come from the BMEcat 2005.2 specification of BME e.V., element PRODUCT_ORDER_DETAILS. The unit and packaging codes come from UN/CEFACT Recommendation 20 including the codes of Recommendation 21 prefixed with X; the version used is the code list published by Peppol as part of Peppol BIS Billing 3.0 in version Revision 11e. The field names and codes named here refer to those versions; older and newer releases may differ. The article does not replace legal advice in an individual case.

The unit of measure - the content unit in the catalogue format - says what the article is measured in: metres, kilograms, pieces. The packaging or order unit says what it leaves the warehouse in: ring, carton, pallet. Both belong in separate fields, because a third field carries the ratio between them, the pack size. The price as a rule refers to the order unit; the BMEcat catalogue format states this explicitly.

The German Price Indication Ordinance governs the indication of prices by traders towards consumers (section 1(1) PAngV), and under section 2 point 9 PAngV a consumer is any natural person within the meaning of section 13 of the German Civil Code. A shop that supplies commercial buyers only and restricts access accordingly sits outside that scope. As soon as consumers can order too, section 4(1) PAngV applies. Because the distinction depends on the individual case, a legal review of your own site is advisable; this article does not replace it.

Under section 5(1) PAngV the unit of measure for the base price is 1 kilogram, 1 litre, 1 cubic metre, 1 metre or 1 square metre of the good. For goods customarily supplied in quantities of 100 metres and more, the unit of measure corresponding to general commercial practice takes its place. For cables and hoses that is typically a statement per 100 metres. The value is calculated from price, price quantity and pack size instead of being maintained as a separate field.

Technically yes, in terms of communication only visibly. Rounding up changes the quantity and with it the price, so it belongs where the buyer can still correct it: in the quantity field itself, not in the order confirmation. A note naming the rounded quantity, the number of packs and the line total together has proved useful. Anyone preferring to reject rather than round up should name the next admissible quantity in the message, otherwise the buyer will try values until one is accepted.

Values from UN/CEFACT Recommendation 20, extended by the packaging codes of Recommendation 21 prefixed with X. Common ones are MTR for metre, KGM for kilogram, LTR for litre, C62 or H87 for piece counts as well as XCT for carton, XRG for ring and XPX for pallet. More important than the choice in an individual case is settling it per catalogue: two codes for the same thing in the same data set cost the recipient as much work as free text.

The minimum quantity is the entry point, the interval the step width above it. The BMEcat specification states that counting for the interval starts at the stated minimum order quantity. With a minimum quantity of 5 and an interval of 2 the admissible values are therefore 5, 7 and 9, not 6 and 8. Both values count in order units. For an assessment of your own product master a conversation is enough to start with, see contact.