A Bag Is Not a Unit of Mass: Version Packaging Conversions in Commodity Inventory
An inventory import contains 400 bags. The product master says one bag is 25 kg, so the system records ten tonnes. A later packaging change replaces that field with 50 kg. Rebuilding the same report now produces twenty tonnes without any goods moving.
The error is a mutable conversion rule attached to historical transactions.
This is a hypothetical inventory design. All pack sizes, identifiers and quantities below are synthetic; they are not Zenith Eclipse stock records or packaging offers.
Give the packing arrangement its own identity
A product identifier answers what material is involved. A pack-definition revision answers how a particular quantity was packaged. Record both on the movement, along with lot identity, package count and the kind of mass recorded.
Zenith Eclipse's dry pea packaging requirements distinguish product form, net weight, tolerance, material and loading configuration. Those are useful domain inputs for a pack definition. They do not make every sack of peas interchangeable.
Create immutable definitions such as PACK-A-R1 with nominal net kilograms per bag. A changed size creates another definition; it must not alter old movements. Scope definitions to the relevant product and packing arrangement, with approval evidence.
Do not encode gross mass, pallet tare or actual scale readings in the nominal net conversion. Preserve those as separate observations with their own provenance.
Make conversion refuse an indivisible result
The following helper calculates the whole-package count corresponding exactly to a requested nominal net mass. It deliberately refuses to round up or down.
from fractions import Fraction
def whole_packages(net_kg, nominal_kg_per_package):
if not isinstance(net_kg, Fraction):
raise TypeError("Expected exact rational mass")
if not isinstance(nominal_kg_per_package, Fraction):
raise TypeError("Expected exact rational pack size")
if net_kg < 0 or nominal_kg_per_package <= 0:
raise ValueError("Invalid mass or pack size")
count = net_kg / nominal_kg_per_package
if count.denominator != 1:
raise ValueError("Not a whole-package quantity")
return count.numerator
assert whole_packages(Fraction(1000), Fraction(25)) == 40
assert whole_packages(Fraction(1000), Fraction(50)) == 20
try:
whole_packages(Fraction(1001), Fraction(25))
except ValueError:
pass
else:
raise AssertionError("Fractional package was accepted")
Python's fractions documentation describes rational arithmetic and numerator/denominator construction. Build values from validated integers or decimal strings, not previously rounded binary floats. The application still needs bounded input lengths and quantity limits.
This is a planning conversion, not a weighing result. Forty nominal 25 kg bags do not prove that a scale measured exactly 1,000 kg.
Preserve two quantities when both matter
A receipt can contain 40 packages and an independently measured net mass. Retain both rather than recomputing one from the other. A discrepancy belongs in a review workflow tied to the contract and measurement evidence.
If an order requests 1,001 kg but stock is handled only in sealed 25 kg bags, the system should expose a choice for authorized review: change the requested quantity, permit a separately defined partial package, or use another packing arrangement. Silently rounding to 41 bags changes the commercial quantity.
A partial package needs its own state and measured remaining quantity. Calling it “0.4 bags” without identifying the original pack and handling state makes later reconciliation unreliable.
Treat repacking as a movement
Replacing 25 kg bags with 50 kg bags is not a master-data update. Record consumption of the source packages and creation of the destination packages, linking both to a repacking operation. Preserve any measured loss, residual material or unexplained discrepancy separately; do not force theoretical mass balance by inventing an adjustment.
Corrections should reference the original movement and retain the superseded values. Reports must resolve the pack revision stored on each transaction, never today's default.
Test mixed pack revisions in one lot, zero mass, invalid negative inputs, a nonintegral package count and an old report rerun after a new pack definition appears. The essential invariant is historical: a packaging change cannot rewrite yesterday's quantity.
About the publisher: Zenith Eclipse Co works across agricultural commodities, international logistics and machinery sourcing.
Comments
Join the discussionNo comments yet. Be the first to comment.