You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@ofbiz.apache.org by Tomek <to...@wp.pl> on 2026/06/16 10:45:30 UTC
InventoryItem UomId ignored and incorrect ATP reduction on Purchase/Sales Order flow
Hi everyone,
I am facing an issue with UoM (Unit of Measure) handling in OFBiz and
would appreciate some guidance.
Here is my setup and the steps to reproduce the issue:
1. I created a test product and configured it with:
- Quantity Included: 250
- Quantity Uom Id: Grams (wt_g)
2. In the Suppliers tab, I added a supplier and set their supplier UoM
to Kilograms (wt_kg).
3. I created a Purchase Order (PO) from this supplier, who sells the
item in wt_kg.
4. I received the shipment for this PO, which automatically created an
InventoryItem.
Problem:
The uomId field in the newly created InventoryItem was not populated (it
is null).
Next, I simulated a sales order for this test product. After adding the
product to the order and approving it, the system decreased the
Available To Promise (ATP) on the aforementioned InventoryItem by exactly 1.
This issue persists even if I manually update the uomId field to wt_kg
directly in the InventoryItem.
Questions:
1. Why does OFBiz seem to ignore the Units of Measure in this scenario?
2. Shouldn't the sales order reduce the ATP value by 0.25 instead of 1,
given the product configuration?
Any insights on what might be missing or if this is an out-of-the-box
limitation would be highly appreciated.
Thanks in advance!
Re: InventoryItem UomId ignored and incorrect ATP reduction on Purchase/Sales Order flow
Posted by Tomek <to...@wp.pl>.
Hi,
I think I now have enough information to solve this problem, and I'm
confident I can take it from here.
Thank you very much for your help and for taking the time to explain
everything so clearly. I really appreciate it.
Best regards,
Tomek
W dniu 30.06.2026 o 14:18, Aditi Patel pisze:
> Hi Tomek,
>
> Both notes are right.
>
> 1. Yes, post a -7 and a +7000 rather than editing the existing row. That's
> how
> InventoryItemDetail is meant to work: it's append-only (the entity even
> re-sums all
> diff rows into the totals on each insert), so the original +7 stays for
> audit and the
> item lands at 7000. Just apply the -7 / +7000 to all three diffs (QOH, ATP,
> accounting), not only QOH, or the totals drift apart.
>
> One catch on cost: that rollup only sums quantities, not
> InventoryItem.unitCost. So
> set the /1000 cost on the item itself via updateInventoryItem, in the same
> call where
> you set uomId.
>
> 2. Correct: uomId is a field on InventoryItem, and Product.quantityUomId is
> the
> pre-configured target unit (g) the SECA reads for the conversion. Keep the
> earlier
> guard so you only convert when the item's uomId still differs from it.
>
> Best regards,
> Aditi
>
> On Tue, Jun 30, 2026 05:34 PM, Tomek <to...@wp.pl> wrote:
>
>>> On the split: you don't need to create a new InventoryItem yourself.
>>> prepareInventoryTransfer already handles that. A partial transfer clones
>> a
>>> new item
>>> for the moved quantity and reduces the source; a full transfer just moves
>>> the
>>> original. So by the time completeInventoryTransfer runs you already have
>> a
>>> single
>>> item (InventoryTransfer.inventoryItemId) at the destination, with the
>>> quantity moved
>>> 1:1. Your SECA just converts that item in place: add an
>> InventoryItemDetail
>>> with the
>>> converted values (convertUom, x1000 for kg -> g, inverse on unitCost) and
>>> set uomId
>>> to Product.quantityUomId. No second item, and no zeroed-out leftover to
>>> keep around
>>> for history, since the InventoryTransfer record already is the history.
>>
>> Hi,
>>
>> Thanks for the detailed breakdown of the completeInventoryTransfer
>> mechanism and how prepareInventoryTransfer handles the item splitting.
>> That makes a lot of sense. However, I have two quick notes regarding the
>> actual conversion logic, as these technical details are quite important
>> in OFBiz.
>>
>> 1. The InventoryItemDetail and quantity summation issue
>>
>> Let's say we transfer 7 kg. Once the transfer completes, the system
>> automatically creates an InventoryItemDetail record with a quantity of
>> +7. If my SECA simply inserts another InventoryItemDetail with +7000
>> (grams) and the recalculated unitCost, the resulting quantity on hand
>> would become 7007 g instead of 7000 g.
>>
>> Since I would prefer not to modify existing InventoryItemDetail records
>> in order to preserve a clean audit trail, I think the safest approach
>> would be to create two additional InventoryItemDetail records within the
>> SECA:
>>
>> The first InventoryItemDetail with a quantity of -7, effectively
>> reversing the original movement.
>> A second InventoryItemDetail with a quantity of +7000 and the
>> recalculated unitCost (divided by 1000).
>>
>> This would preserve the full history while leaving the final inventory
>> quantity at 7000 g.
>>
>> Would you recommend this approach, or did you have a different
>> implementation in mind for handling the InventoryItemDetail records?
>>
>> 2. Updating the uomId
>>
>> When you mentioned "set uomId to Product.quantityUomId", I assume you
>> meant updating the uomId field on the InventoryItem, correct?
>>
>> I am also assuming that Product.quantityUomId is already configured on
>> the product beforehand (for example, set to grams), and that this is how
>> the SECA determines the target unit for the conversion.
>>
>> Let me know what you think of this approach.
>>
>> Best regards,
>> Tomek
>>
>>
Re: InventoryItem UomId ignored and incorrect ATP reduction on Purchase/Sales Order flow
Posted by Aditi Patel <ad...@hotwax.co>.
Hi Tomek,
Both notes are right.
1. Yes, post a -7 and a +7000 rather than editing the existing row. That's
how
InventoryItemDetail is meant to work: it's append-only (the entity even
re-sums all
diff rows into the totals on each insert), so the original +7 stays for
audit and the
item lands at 7000. Just apply the -7 / +7000 to all three diffs (QOH, ATP,
accounting), not only QOH, or the totals drift apart.
One catch on cost: that rollup only sums quantities, not
InventoryItem.unitCost. So
set the /1000 cost on the item itself via updateInventoryItem, in the same
call where
you set uomId.
2. Correct: uomId is a field on InventoryItem, and Product.quantityUomId is
the
pre-configured target unit (g) the SECA reads for the conversion. Keep the
earlier
guard so you only convert when the item's uomId still differs from it.
Best regards,
Aditi
On Tue, Jun 30, 2026 05:34 PM, Tomek <to...@wp.pl> wrote:
>
> > On the split: you don't need to create a new InventoryItem yourself.
> > prepareInventoryTransfer already handles that. A partial transfer clones
> a
> > new item
> > for the moved quantity and reduces the source; a full transfer just moves
> > the
> > original. So by the time completeInventoryTransfer runs you already have
> a
> > single
> > item (InventoryTransfer.inventoryItemId) at the destination, with the
> > quantity moved
> > 1:1. Your SECA just converts that item in place: add an
> InventoryItemDetail
> > with the
> > converted values (convertUom, x1000 for kg -> g, inverse on unitCost) and
> > set uomId
> > to Product.quantityUomId. No second item, and no zeroed-out leftover to
> > keep around
> > for history, since the InventoryTransfer record already is the history.
>
>
> Hi,
>
> Thanks for the detailed breakdown of the completeInventoryTransfer
> mechanism and how prepareInventoryTransfer handles the item splitting.
> That makes a lot of sense. However, I have two quick notes regarding the
> actual conversion logic, as these technical details are quite important
> in OFBiz.
>
> 1. The InventoryItemDetail and quantity summation issue
>
> Let's say we transfer 7 kg. Once the transfer completes, the system
> automatically creates an InventoryItemDetail record with a quantity of
> +7. If my SECA simply inserts another InventoryItemDetail with +7000
> (grams) and the recalculated unitCost, the resulting quantity on hand
> would become 7007 g instead of 7000 g.
>
> Since I would prefer not to modify existing InventoryItemDetail records
> in order to preserve a clean audit trail, I think the safest approach
> would be to create two additional InventoryItemDetail records within the
> SECA:
>
> The first InventoryItemDetail with a quantity of -7, effectively
> reversing the original movement.
> A second InventoryItemDetail with a quantity of +7000 and the
> recalculated unitCost (divided by 1000).
>
> This would preserve the full history while leaving the final inventory
> quantity at 7000 g.
>
> Would you recommend this approach, or did you have a different
> implementation in mind for handling the InventoryItemDetail records?
>
> 2. Updating the uomId
>
> When you mentioned "set uomId to Product.quantityUomId", I assume you
> meant updating the uomId field on the InventoryItem, correct?
>
> I am also assuming that Product.quantityUomId is already configured on
> the product beforehand (for example, set to grams), and that this is how
> the SECA determines the target unit for the conversion.
>
> Let me know what you think of this approach.
>
> Best regards,
> Tomek
>
>
Re: InventoryItem UomId ignored and incorrect ATP reduction on Purchase/Sales Order flow
Posted by Tomek <to...@wp.pl>.
> On the split: you don't need to create a new InventoryItem yourself.
> prepareInventoryTransfer already handles that. A partial transfer clones a
> new item
> for the moved quantity and reduces the source; a full transfer just moves
> the
> original. So by the time completeInventoryTransfer runs you already have a
> single
> item (InventoryTransfer.inventoryItemId) at the destination, with the
> quantity moved
> 1:1. Your SECA just converts that item in place: add an InventoryItemDetail
> with the
> converted values (convertUom, x1000 for kg -> g, inverse on unitCost) and
> set uomId
> to Product.quantityUomId. No second item, and no zeroed-out leftover to
> keep around
> for history, since the InventoryTransfer record already is the history.
Hi,
Thanks for the detailed breakdown of the completeInventoryTransfer
mechanism and how prepareInventoryTransfer handles the item splitting.
That makes a lot of sense. However, I have two quick notes regarding the
actual conversion logic, as these technical details are quite important
in OFBiz.
1. The InventoryItemDetail and quantity summation issue
Let's say we transfer 7 kg. Once the transfer completes, the system
automatically creates an InventoryItemDetail record with a quantity of
+7. If my SECA simply inserts another InventoryItemDetail with +7000
(grams) and the recalculated unitCost, the resulting quantity on hand
would become 7007 g instead of 7000 g.
Since I would prefer not to modify existing InventoryItemDetail records
in order to preserve a clean audit trail, I think the safest approach
would be to create two additional InventoryItemDetail records within the
SECA:
The first InventoryItemDetail with a quantity of -7, effectively
reversing the original movement.
A second InventoryItemDetail with a quantity of +7000 and the
recalculated unitCost (divided by 1000).
This would preserve the full history while leaving the final inventory
quantity at 7000 g.
Would you recommend this approach, or did you have a different
implementation in mind for handling the InventoryItemDetail records?
2. Updating the uomId
When you mentioned "set uomId to Product.quantityUomId", I assume you
meant updating the uomId field on the InventoryItem, correct?
I am also assuming that Product.quantityUomId is already configured on
the product beforehand (for example, set to grams), and that this is how
the SECA determines the target unit for the conversion.
Let me know what you think of this approach.
Best regards,
Tomek
Re: InventoryItem UomId ignored and incorrect ATP reduction on Purchase/Sales Order flow
Posted by Aditi Patel <ad...@hotwax.co>.
Hi Tomek,
Yes, a SECA on the transfer is the right approach, but hook it on
completeInventoryTransfer rather than createInventoryTransfer.
createInventoryTransfer doesn't move anything itself: on invoke it triggers
prepareInventoryTransfer, and on commit (when the status is IXF_COMPLETE) it
triggers completeInventoryTransfer, which is where the stock actually lands
at the
destination. Hooking there also covers the two-step "create now, complete
later"
transfer, since that path runs completeInventoryTransfer too.
On the split: you don't need to create a new InventoryItem yourself.
prepareInventoryTransfer already handles that. A partial transfer clones a
new item
for the moved quantity and reduces the source; a full transfer just moves
the
original. So by the time completeInventoryTransfer runs you already have a
single
item (InventoryTransfer.inventoryItemId) at the destination, with the
quantity moved
1:1. Your SECA just converts that item in place: add an InventoryItemDetail
with the
converted values (convertUom, x1000 for kg -> g, inverse on unitCost) and
set uomId
to Product.quantityUomId. No second item, and no zeroed-out leftover to
keep around
for history, since the InventoryTransfer record already is the history.
And yes, I meant Inventory Items -> Transfer, not Stock Moves. Stock Moves
(processPhysicalStockMove) only shifts stock between locations within the
same
facility for picking, so it isn't the right place for this and, as you saw,
it's
harder to hook cleanly.
One thing to watch: only run the conversion when the item's uomId still
differs from
Product.quantityUomId, so a later facility-to-facility transfer of
already-converted
stock doesn't get multiplied again.
Best regards,
Aditi
On Fri, Jun 19, 2026 02:18 AM, Tomek <to...@wp.pl> wrote:
> Hi,
>
> I want to make sure I fully understand your suggestion. Are you
> proposing that I create a SECA rule triggered after the
> createInventoryTransfer service?
>
> At that point, an InventoryTransfer record is created and linked to the
> InventoryItem. If I follow this path, does my SECA service need to
> update the existing InventoryItem's UOM and unit cost, or should it
> split/create a new InventoryItem with the converted values (since a
> standard transfer usually moves the quantity 1:1 without changing the
> math)?
>
> From a UI perspective, my workflow would be: after receiving the
> purchase order, I go to the "Inventory Items" tab and click "Transfer".
> Once the transfer form is submitted, createInventoryTransfer runs,
> followed by my SECA service. Am I on the right track?
>
> I am asking because in the OFBiz UI, there is also a "Stock moves" tab.
> That functionality triggers services that create new InventoryItems
> under the hood, and it seems harder to intercept and modify them cleanly
> compared to a standard transfer. Which of these two OOTB UI flows did
> you have in mind for this architecture?
>
> Best regards,
> Tomek
>
> W dniu 18.06.2026 o 13:51, Aditi Patel pisze:
> > Hi Tomek,
> >
> > The SECA instinct is good — reacting to service events rather than
> editing
> > receiveInventoryProduct is the right way to stay upgrade-safe. But before
> > you build two services, I’d gently push back on where you’re putting the
> > conversion, because doing it at receipt time is what creates most of the
> > complexity you’re now having to engineer around.
> >
> > I suggested converting at the stock move rather than at receipt because
> the
> > two events answer different business questions:
> >
> > - The receipt has to reconcile against the supplier invoice. OFBiz
> > generates purchase invoicing from ShipmentReceipt quantities, so the
> > receipt, the PO, and the AP invoice all need to stay in the
> supplier’s unit
> > (kg). If you convert at receipt, the inventory no longer sits in the
> unit
> > your supplier billed you in, and the receipt no longer cleanly
> matches the
> > invoice you’re paying.
> > - The stock move into the warehouse is where the goods become your
> own
> > on-hand to sell. That’s the natural and auditable point to switch
> into your
> > stocking unit (g), because nothing upstream depends on it anymore.
> >
> > Your two-SECA design essentially recreates that switch at receipt, and
> the
> > cost shows up in the very parts you’re already working around:
> >
> > - The “keep the old InventoryItem for history” step is the tell.
> You’re
> > left with a zeroed-out kg item sitting next to the real g item, and
> every
> > ATP rollup, cycle count, and inventory report then has to know to
> ignore
> > it. At the stock move there’s no orphan — the quantity simply
> transfers and
> > lands in the new unit.
> > - The updateProduct trigger worries me most. Letting an admin edit
> > Product.quantityUomId silently re-value stock you already own is an
> > accounting event, not a form save. If there are reservations against
> that
> > stock, the balances won’t reconcile, and you’d have no audit trail.
> I’d
> > drop that path entirely and treat a UoM change on stocked product as
> a
> > deliberate physical adjustment.
> >
> >
> > So I’d still steer you toward the stock move: keep PO → receipt →
> > InventoryItem all in kg, then put a single small service on the inventory
> > transfer that calls convertUom (kg → g via UomConversion), records the
> > on-hand in g, and stamps uomId. One conversion, one auditable point, no
> > orphans, and the invoice reconciliation stays clean.
> >
> > The one part of your design I’d keep regardless is stamping uomId from
> the
> > SupplierProduct on the freshly received item — that’s a nice touch and
> > makes the kg stage explicit. Just resolve the supplier from the receipt
> or
> > order context rather than from the bare InventoryItem, since
> > createInventoryItem on its own won’t reliably know it’s part of a
> receipt.
> >
> > Best regards,
> > Aditi
> >
> > On Thu, Jun 18, 2026 at 2:39 PM Tomek <to...@wp.pl> wrote:
> >
> >> Hi,
> >>
> >> Thank you for proposing this solution. If I understand correctly, you
> >> are suggesting to receive the goods (using the receiveInventoryProduct
> >> service) and then somehow automatically perform the unit conversion
> >> during the transfer order from the UI level?
> >>
> >> You mentioned that it is not advisable to modify data inside the
> >> receiveInventoryProduct service. What do you think about using SECA
> >> (Service ECA) rules instead? Rather than modifying the data within
> >> receiveInventoryProduct itself, we could perform the conversion right
> >> after this service executes. My concept relies on two additional ECA
> >> services. The first one would be triggered after the createInventoryItem
> >> service completes, and the second one after the receiveInventoryProduct
> >> service completes.
> >>
> >> The first service (called after createInventoryItem) checks if the
> >> InventoryItem is linked to a supplier and if its uomId == null. If so,
> >> it sets the uomId based on the SupplierProduct's UOM. This ensures that
> >> the InventoryItem stores the supplier's unit of measure.
> >>
> >> The second service (called after receiveInventoryProduct) would perform
> >> the following steps:
> >>
> >> 1. Retrieve all InventoryItems that meet the following requirements:
> >> - are linked to the given product
> >> - have a UOM different from Product.quantityUomId
> >> - the fields quantityOnHandTotal != 0 OR availableToPromiseTotal != 0 OR
> >> accountingQuantityTotal != 0
> >>
> >> If I sell the product in the same unit of measure as the supplier, this
> >> InventoryItem list should be empty. Otherwise, usually one InventoryItem
> >> element will appear (we could also trigger this ECA service after the
> >> updateProduct service to detect if the Product.quantityUomId value has
> >> changed — in that case, the number of elements on the InventoryItem list
> >> would be greater).
> >>
> >> 2. For each InventoryItem element from the list created in step one:
> >> - create an InventoryItemDetail that resets quantityOnHandTotal,
> >> availableToPromiseTotal, and accountingQuantityTotal to zero in the
> >> original InventoryItem.
> >> - calculate the new quantityOnHandTotal, availableToPromiseTotal,
> >> accountingQuantityTotal, and unitCost based on the original values (unit
> >> conversion). For instance, when converting from WT_kg to WT_g, each of
> >> these values would be multiplied by 1000, except for the cost, which
> >> would be divided by 1000 (I would use the convertUom service you
> >> mentioned earlier for this). This would result in new variables:
> >> newQuantityOnHandTotal, newAvailableToPromiseTotal,
> >> newAccountingQuantityTotal, and newUnitCost.
> >> - create a new InventoryItem, set its uomId field to
> >> Product.quantityUomId, and then add a new InventoryItemDetail record
> >> (quantityOnHandDiff = newQuantityOnHandTotal, availableToPromiseDiff =
> >> newAvailableToPromiseTotal, accountingQuantityDiff =
> >> newAccountingQuantityTotal, unitCost = newUnitCost) linked to this new
> >> InventoryItem.
> >>
> >> The outcome of the above algorithm will be the creation of a new
> >> InventoryItem based on the desired units of measure. The old
> >> InventoryItem will be kept purely for informational/historical purposes
> >> (it will no longer contain any available products).
> >>
> >> What do you think about this approach?
> >>
> >> Best regards,
> >> Tomek
> >>
> >> W dniu 16.06.2026 o 17:38, Aditi Patel pisze:
> >>> Hi Tomek,
> >>>
> >>> Glad the earlier note helped. Here is how I would suggest handling UoM
> >>> across the lifecycle.
> >>>
> >>> The cleanest pattern is to keep the purchasing side in the supplier's
> >> unit
> >>> and switch to your stocking unit only when goods enter the warehouse.
> The
> >>> PO carries the supplier product's UoM (copied from SupplierProduct,
> e.g.
> >>> kg), the shipment is received in that same UoM, and the InventoryItem
> is
> >>> created in the UoM from the ShipmentReceipt. When you then move that
> >> stock
> >>> into the warehouse, you convert using the SupplierProduct and Product
> >> UoMs
> >>> and stock it in the Product's UoM (g).
> >>>
> >>> PO (kg) -> Receipt (kg) -> InventoryItem (kg) -> Stock move to
> warehouse,
> >>> convert kg -> g -> On-hand and sales in g
> >>>
> >>> So the PO lifecycle stays in the supplier product's UoM and the
> stocking
> >> is
> >>> in the product's UoM, with the conversion happening at the stock move.
> >>> Receiving in the PO's unit also keeps a clean match between the PO, the
> >>> receipt, and the supplier invoice (OFBiz generates purchase invoicing
> >> from
> >>> ShipmentReceipt quantities), so AP reconciliation and unit cost stay
> >>> accurate.
> >>>
> >>> On your questions:
> >>>
> >>> 1. The data model does support UoM management at the inventory level,
> and
> >>> InventoryItem.uomId is part of that - I have seen it used across
> various
> >>> inventory flows, including receiving, to record the unit an item is
> held
> >>> in. Just keep in mind the core ATP/QOH and reservation logic does not
> >> read
> >>> it out of the box, so it labels the unit rather than driving the
> >> conversion
> >>> on its own.
> >>>
> >>> 2. There is no single enforced "stocking UoM" field - inventory is
> >>> effectively 1 unit = 1. By convention the stocking unit lives on
> >>> Product.quantityUomId, the supplier's unit on
> >>> SupplierProduct.quantityUomId, and the conversion factor (wt_kg ->
> wt_g =
> >>> 1000) in the UomConversion entity that convertUom reads.
> >>>
> >>> 3. Rather than converting inside receiveInventoryProduct, I would do it
> >> at
> >>> the stock move into the warehouse: a small service (for example in a
> >>> hot-deploy component, around the inventory transfer / stock move) that
> >>> calls convertUom using the SupplierProduct and Product UoMs, records
> the
> >>> on-hand in g, and stamps InventoryItem.uomId. Everything downstream
> then
> >>> stays consistent.
> >>>
> >>> If at any point the UoM management or the conversions are not behaving
> as
> >>> expected, feel free to reach out - happy to help.
> >>>
> >>> Best regards,
> >>> Aditi
> >>>
> >>> On Tue, Jun 16, 2026 08:17 PM, Tomek <to...@wp.pl> wrote:
> >>>
> >>>> Hi,
> >>>>
> >>>> Thank you very much for your response.
> >>>>
> >>>> Indeed, this issue can be managed by:
> >>>> - multiplying the quantity by 1000 and dividing the cost by 1000
> during
> >>>> the purchase order receipt,
> >>>> - multiplying the quantity by 1000 and dividing the cost by 1000 at
> the
> >>>> stage of purchase order creation.
> >>>>
> >>>> This works and is actually a viable solution, but it makes me wonder:
> >>>> what is the purpose of the uomId field in InventoryItem then? Is it
> used
> >>>> anywhere at all? Is it a legacy remnant or perhaps a placeholder
> >>>> designed for future process customization?
> >>>>
> >>>> Let's assume I would like to automatically convert units from the
> >>>> supplier's purchase unit to my own preferred unit. For instance, I
> store
> >>>> Product X in my warehouse in grams, but the supplier sells it in
> >>>> kilograms. I would like this conversion to happen automatically.
> >>>>
> >>>> With that in mind, I have a couple of questions:
> >>>>
> >>>> 1. Where should I define my internal stocking unit (the UoM for
> products
> >>>> stored in my own warehouse)?
> >>>> 2. What would be the best way to handle this conversion? Should I
> >>>> override the receiveInventoryProduct service, or is there a better,
> more
> >>>> recommended approach?
> >>>>
> >>>> Best regards,
> >>>> Tomek
> >>>>
> >>>> W dniu 16.06.2026 o 13:06, Aditi Patel pisze:
> >>>>> Hi,
> >>>>>
> >>>>> Thanks for the clear write-up and reproduction steps! The good news
> is
> >>>> that
> >>>>> nothing is broken here. What you are seeing is OFBiz working as
> >> designed:
> >>>>> it does not perform automatic unit-of-measure conversion across the
> >>>>> purchase -> inventory -> sales flow.
> >>>>>
> >>>>> A few things that explain both observations:
> >>>>>
> >>>>> - Inventory is counted in stocking units, not by weight. ATP and QOH
> >> are
> >>>>> plain numeric quantities with no associated UoM, and reservation
> simply
> >>>>> subtracts the ordered quantity. That is why selling 1 reduces ATP by
> >>>>> exactly 1 rather than 0.25.
> >>>>> - receiveInventoryProduct does not copy Product.quantityUomId or the
> >>>>> SupplierProduct UoM onto InventoryItem.uomId, so it is left null. And
> >>>> even
> >>>>> when you set it manually, the reservation logic never reads it, so
> the
> >>>> math
> >>>>> is unchanged.
> >>>>> - Product.quantityIncluded / quantityUomId are descriptive packaging
> >>>>> metadata, not conversion factors applied to inventory or orders.
> >>>>>
> >>>>> So both behaviors are expected rather than a bug. If you need to buy
> in
> >>>> one
> >>>>> unit and stock or sell in another, the cleanest options are:
> >>>>>
> >>>>> - Normalize everything to a single stocking UoM and convert at
> receipt
> >>>>> time, e.g. receive the 1 kg PO line as quantityAccepted = 1000 and
> keep
> >>>> the
> >>>>> product stocked in grams; or
> >>>>> - Add your own conversion using the convertUom service together with
> >> the
> >>>>> UomConversion entity in framework/common.
> >>>>>
> >>>>> Hope this helps clear things up, and happy to elaborate on any of the
> >>>> above.
> >>>>> Best regards,
> >>>>> Aditi Patel
> >>>>>
> >>>>> On Tue, Jun 16, 2026 04:15 PM, Tomek <to...@wp.pl> wrote:
> >>>>>
> >>>>>> Hi everyone,
> >>>>>>
> >>>>>> I am facing an issue with UoM (Unit of Measure) handling in OFBiz
> and
> >>>>>> would appreciate some guidance.
> >>>>>>
> >>>>>> Here is my setup and the steps to reproduce the issue:
> >>>>>>
> >>>>>> 1. I created a test product and configured it with:
> >>>>>> - Quantity Included: 250
> >>>>>> - Quantity Uom Id: Grams (wt_g)
> >>>>>>
> >>>>>> 2. In the Suppliers tab, I added a supplier and set their supplier
> UoM
> >>>>>> to Kilograms (wt_kg).
> >>>>>>
> >>>>>> 3. I created a Purchase Order (PO) from this supplier, who sells the
> >>>>>> item in wt_kg.
> >>>>>>
> >>>>>> 4. I received the shipment for this PO, which automatically created
> an
> >>>>>> InventoryItem.
> >>>>>>
> >>>>>> Problem:
> >>>>>>
> >>>>>> The uomId field in the newly created InventoryItem was not populated
> >> (it
> >>>>>> is null).
> >>>>>>
> >>>>>> Next, I simulated a sales order for this test product. After adding
> >> the
> >>>>>> product to the order and approving it, the system decreased the
> >>>>>> Available To Promise (ATP) on the aforementioned InventoryItem by
> >>>> exactly
> >>>>>> 1.
> >>>>>>
> >>>>>> This issue persists even if I manually update the uomId field to
> wt_kg
> >>>>>> directly in the InventoryItem.
> >>>>>>
> >>>>>> Questions:
> >>>>>>
> >>>>>> 1. Why does OFBiz seem to ignore the Units of Measure in this
> >> scenario?
> >>>>>> 2. Shouldn't the sales order reduce the ATP value by 0.25 instead of
> >> 1,
> >>>>>> given the product configuration?
> >>>>>>
> >>>>>> Any insights on what might be missing or if this is an
> out-of-the-box
> >>>>>> limitation would be highly appreciated.
> >>>>>>
> >>>>>> Thanks in advance!
> >>>>>>
> >>>>>>
>
Re: InventoryItem UomId ignored and incorrect ATP reduction on Purchase/Sales Order flow
Posted by Tomek <to...@wp.pl>.
Hi,
I want to make sure I fully understand your suggestion. Are you
proposing that I create a SECA rule triggered after the
createInventoryTransfer service?
At that point, an InventoryTransfer record is created and linked to the
InventoryItem. If I follow this path, does my SECA service need to
update the existing InventoryItem's UOM and unit cost, or should it
split/create a new InventoryItem with the converted values (since a
standard transfer usually moves the quantity 1:1 without changing the math)?
From a UI perspective, my workflow would be: after receiving the
purchase order, I go to the "Inventory Items" tab and click "Transfer".
Once the transfer form is submitted, createInventoryTransfer runs,
followed by my SECA service. Am I on the right track?
I am asking because in the OFBiz UI, there is also a "Stock moves" tab.
That functionality triggers services that create new InventoryItems
under the hood, and it seems harder to intercept and modify them cleanly
compared to a standard transfer. Which of these two OOTB UI flows did
you have in mind for this architecture?
Best regards,
Tomek
W dniu 18.06.2026 o 13:51, Aditi Patel pisze:
> Hi Tomek,
>
> The SECA instinct is good — reacting to service events rather than editing
> receiveInventoryProduct is the right way to stay upgrade-safe. But before
> you build two services, I’d gently push back on where you’re putting the
> conversion, because doing it at receipt time is what creates most of the
> complexity you’re now having to engineer around.
>
> I suggested converting at the stock move rather than at receipt because the
> two events answer different business questions:
>
> - The receipt has to reconcile against the supplier invoice. OFBiz
> generates purchase invoicing from ShipmentReceipt quantities, so the
> receipt, the PO, and the AP invoice all need to stay in the supplier’s unit
> (kg). If you convert at receipt, the inventory no longer sits in the unit
> your supplier billed you in, and the receipt no longer cleanly matches the
> invoice you’re paying.
> - The stock move into the warehouse is where the goods become your own
> on-hand to sell. That’s the natural and auditable point to switch into your
> stocking unit (g), because nothing upstream depends on it anymore.
>
> Your two-SECA design essentially recreates that switch at receipt, and the
> cost shows up in the very parts you’re already working around:
>
> - The “keep the old InventoryItem for history” step is the tell. You’re
> left with a zeroed-out kg item sitting next to the real g item, and every
> ATP rollup, cycle count, and inventory report then has to know to ignore
> it. At the stock move there’s no orphan — the quantity simply transfers and
> lands in the new unit.
> - The updateProduct trigger worries me most. Letting an admin edit
> Product.quantityUomId silently re-value stock you already own is an
> accounting event, not a form save. If there are reservations against that
> stock, the balances won’t reconcile, and you’d have no audit trail. I’d
> drop that path entirely and treat a UoM change on stocked product as a
> deliberate physical adjustment.
>
>
> So I’d still steer you toward the stock move: keep PO → receipt →
> InventoryItem all in kg, then put a single small service on the inventory
> transfer that calls convertUom (kg → g via UomConversion), records the
> on-hand in g, and stamps uomId. One conversion, one auditable point, no
> orphans, and the invoice reconciliation stays clean.
>
> The one part of your design I’d keep regardless is stamping uomId from the
> SupplierProduct on the freshly received item — that’s a nice touch and
> makes the kg stage explicit. Just resolve the supplier from the receipt or
> order context rather than from the bare InventoryItem, since
> createInventoryItem on its own won’t reliably know it’s part of a receipt.
>
> Best regards,
> Aditi
>
> On Thu, Jun 18, 2026 at 2:39 PM Tomek <to...@wp.pl> wrote:
>
>> Hi,
>>
>> Thank you for proposing this solution. If I understand correctly, you
>> are suggesting to receive the goods (using the receiveInventoryProduct
>> service) and then somehow automatically perform the unit conversion
>> during the transfer order from the UI level?
>>
>> You mentioned that it is not advisable to modify data inside the
>> receiveInventoryProduct service. What do you think about using SECA
>> (Service ECA) rules instead? Rather than modifying the data within
>> receiveInventoryProduct itself, we could perform the conversion right
>> after this service executes. My concept relies on two additional ECA
>> services. The first one would be triggered after the createInventoryItem
>> service completes, and the second one after the receiveInventoryProduct
>> service completes.
>>
>> The first service (called after createInventoryItem) checks if the
>> InventoryItem is linked to a supplier and if its uomId == null. If so,
>> it sets the uomId based on the SupplierProduct's UOM. This ensures that
>> the InventoryItem stores the supplier's unit of measure.
>>
>> The second service (called after receiveInventoryProduct) would perform
>> the following steps:
>>
>> 1. Retrieve all InventoryItems that meet the following requirements:
>> - are linked to the given product
>> - have a UOM different from Product.quantityUomId
>> - the fields quantityOnHandTotal != 0 OR availableToPromiseTotal != 0 OR
>> accountingQuantityTotal != 0
>>
>> If I sell the product in the same unit of measure as the supplier, this
>> InventoryItem list should be empty. Otherwise, usually one InventoryItem
>> element will appear (we could also trigger this ECA service after the
>> updateProduct service to detect if the Product.quantityUomId value has
>> changed — in that case, the number of elements on the InventoryItem list
>> would be greater).
>>
>> 2. For each InventoryItem element from the list created in step one:
>> - create an InventoryItemDetail that resets quantityOnHandTotal,
>> availableToPromiseTotal, and accountingQuantityTotal to zero in the
>> original InventoryItem.
>> - calculate the new quantityOnHandTotal, availableToPromiseTotal,
>> accountingQuantityTotal, and unitCost based on the original values (unit
>> conversion). For instance, when converting from WT_kg to WT_g, each of
>> these values would be multiplied by 1000, except for the cost, which
>> would be divided by 1000 (I would use the convertUom service you
>> mentioned earlier for this). This would result in new variables:
>> newQuantityOnHandTotal, newAvailableToPromiseTotal,
>> newAccountingQuantityTotal, and newUnitCost.
>> - create a new InventoryItem, set its uomId field to
>> Product.quantityUomId, and then add a new InventoryItemDetail record
>> (quantityOnHandDiff = newQuantityOnHandTotal, availableToPromiseDiff =
>> newAvailableToPromiseTotal, accountingQuantityDiff =
>> newAccountingQuantityTotal, unitCost = newUnitCost) linked to this new
>> InventoryItem.
>>
>> The outcome of the above algorithm will be the creation of a new
>> InventoryItem based on the desired units of measure. The old
>> InventoryItem will be kept purely for informational/historical purposes
>> (it will no longer contain any available products).
>>
>> What do you think about this approach?
>>
>> Best regards,
>> Tomek
>>
>> W dniu 16.06.2026 o 17:38, Aditi Patel pisze:
>>> Hi Tomek,
>>>
>>> Glad the earlier note helped. Here is how I would suggest handling UoM
>>> across the lifecycle.
>>>
>>> The cleanest pattern is to keep the purchasing side in the supplier's
>> unit
>>> and switch to your stocking unit only when goods enter the warehouse. The
>>> PO carries the supplier product's UoM (copied from SupplierProduct, e.g.
>>> kg), the shipment is received in that same UoM, and the InventoryItem is
>>> created in the UoM from the ShipmentReceipt. When you then move that
>> stock
>>> into the warehouse, you convert using the SupplierProduct and Product
>> UoMs
>>> and stock it in the Product's UoM (g).
>>>
>>> PO (kg) -> Receipt (kg) -> InventoryItem (kg) -> Stock move to warehouse,
>>> convert kg -> g -> On-hand and sales in g
>>>
>>> So the PO lifecycle stays in the supplier product's UoM and the stocking
>> is
>>> in the product's UoM, with the conversion happening at the stock move.
>>> Receiving in the PO's unit also keeps a clean match between the PO, the
>>> receipt, and the supplier invoice (OFBiz generates purchase invoicing
>> from
>>> ShipmentReceipt quantities), so AP reconciliation and unit cost stay
>>> accurate.
>>>
>>> On your questions:
>>>
>>> 1. The data model does support UoM management at the inventory level, and
>>> InventoryItem.uomId is part of that - I have seen it used across various
>>> inventory flows, including receiving, to record the unit an item is held
>>> in. Just keep in mind the core ATP/QOH and reservation logic does not
>> read
>>> it out of the box, so it labels the unit rather than driving the
>> conversion
>>> on its own.
>>>
>>> 2. There is no single enforced "stocking UoM" field - inventory is
>>> effectively 1 unit = 1. By convention the stocking unit lives on
>>> Product.quantityUomId, the supplier's unit on
>>> SupplierProduct.quantityUomId, and the conversion factor (wt_kg -> wt_g =
>>> 1000) in the UomConversion entity that convertUom reads.
>>>
>>> 3. Rather than converting inside receiveInventoryProduct, I would do it
>> at
>>> the stock move into the warehouse: a small service (for example in a
>>> hot-deploy component, around the inventory transfer / stock move) that
>>> calls convertUom using the SupplierProduct and Product UoMs, records the
>>> on-hand in g, and stamps InventoryItem.uomId. Everything downstream then
>>> stays consistent.
>>>
>>> If at any point the UoM management or the conversions are not behaving as
>>> expected, feel free to reach out - happy to help.
>>>
>>> Best regards,
>>> Aditi
>>>
>>> On Tue, Jun 16, 2026 08:17 PM, Tomek <to...@wp.pl> wrote:
>>>
>>>> Hi,
>>>>
>>>> Thank you very much for your response.
>>>>
>>>> Indeed, this issue can be managed by:
>>>> - multiplying the quantity by 1000 and dividing the cost by 1000 during
>>>> the purchase order receipt,
>>>> - multiplying the quantity by 1000 and dividing the cost by 1000 at the
>>>> stage of purchase order creation.
>>>>
>>>> This works and is actually a viable solution, but it makes me wonder:
>>>> what is the purpose of the uomId field in InventoryItem then? Is it used
>>>> anywhere at all? Is it a legacy remnant or perhaps a placeholder
>>>> designed for future process customization?
>>>>
>>>> Let's assume I would like to automatically convert units from the
>>>> supplier's purchase unit to my own preferred unit. For instance, I store
>>>> Product X in my warehouse in grams, but the supplier sells it in
>>>> kilograms. I would like this conversion to happen automatically.
>>>>
>>>> With that in mind, I have a couple of questions:
>>>>
>>>> 1. Where should I define my internal stocking unit (the UoM for products
>>>> stored in my own warehouse)?
>>>> 2. What would be the best way to handle this conversion? Should I
>>>> override the receiveInventoryProduct service, or is there a better, more
>>>> recommended approach?
>>>>
>>>> Best regards,
>>>> Tomek
>>>>
>>>> W dniu 16.06.2026 o 13:06, Aditi Patel pisze:
>>>>> Hi,
>>>>>
>>>>> Thanks for the clear write-up and reproduction steps! The good news is
>>>> that
>>>>> nothing is broken here. What you are seeing is OFBiz working as
>> designed:
>>>>> it does not perform automatic unit-of-measure conversion across the
>>>>> purchase -> inventory -> sales flow.
>>>>>
>>>>> A few things that explain both observations:
>>>>>
>>>>> - Inventory is counted in stocking units, not by weight. ATP and QOH
>> are
>>>>> plain numeric quantities with no associated UoM, and reservation simply
>>>>> subtracts the ordered quantity. That is why selling 1 reduces ATP by
>>>>> exactly 1 rather than 0.25.
>>>>> - receiveInventoryProduct does not copy Product.quantityUomId or the
>>>>> SupplierProduct UoM onto InventoryItem.uomId, so it is left null. And
>>>> even
>>>>> when you set it manually, the reservation logic never reads it, so the
>>>> math
>>>>> is unchanged.
>>>>> - Product.quantityIncluded / quantityUomId are descriptive packaging
>>>>> metadata, not conversion factors applied to inventory or orders.
>>>>>
>>>>> So both behaviors are expected rather than a bug. If you need to buy in
>>>> one
>>>>> unit and stock or sell in another, the cleanest options are:
>>>>>
>>>>> - Normalize everything to a single stocking UoM and convert at receipt
>>>>> time, e.g. receive the 1 kg PO line as quantityAccepted = 1000 and keep
>>>> the
>>>>> product stocked in grams; or
>>>>> - Add your own conversion using the convertUom service together with
>> the
>>>>> UomConversion entity in framework/common.
>>>>>
>>>>> Hope this helps clear things up, and happy to elaborate on any of the
>>>> above.
>>>>> Best regards,
>>>>> Aditi Patel
>>>>>
>>>>> On Tue, Jun 16, 2026 04:15 PM, Tomek <to...@wp.pl> wrote:
>>>>>
>>>>>> Hi everyone,
>>>>>>
>>>>>> I am facing an issue with UoM (Unit of Measure) handling in OFBiz and
>>>>>> would appreciate some guidance.
>>>>>>
>>>>>> Here is my setup and the steps to reproduce the issue:
>>>>>>
>>>>>> 1. I created a test product and configured it with:
>>>>>> - Quantity Included: 250
>>>>>> - Quantity Uom Id: Grams (wt_g)
>>>>>>
>>>>>> 2. In the Suppliers tab, I added a supplier and set their supplier UoM
>>>>>> to Kilograms (wt_kg).
>>>>>>
>>>>>> 3. I created a Purchase Order (PO) from this supplier, who sells the
>>>>>> item in wt_kg.
>>>>>>
>>>>>> 4. I received the shipment for this PO, which automatically created an
>>>>>> InventoryItem.
>>>>>>
>>>>>> Problem:
>>>>>>
>>>>>> The uomId field in the newly created InventoryItem was not populated
>> (it
>>>>>> is null).
>>>>>>
>>>>>> Next, I simulated a sales order for this test product. After adding
>> the
>>>>>> product to the order and approving it, the system decreased the
>>>>>> Available To Promise (ATP) on the aforementioned InventoryItem by
>>>> exactly
>>>>>> 1.
>>>>>>
>>>>>> This issue persists even if I manually update the uomId field to wt_kg
>>>>>> directly in the InventoryItem.
>>>>>>
>>>>>> Questions:
>>>>>>
>>>>>> 1. Why does OFBiz seem to ignore the Units of Measure in this
>> scenario?
>>>>>> 2. Shouldn't the sales order reduce the ATP value by 0.25 instead of
>> 1,
>>>>>> given the product configuration?
>>>>>>
>>>>>> Any insights on what might be missing or if this is an out-of-the-box
>>>>>> limitation would be highly appreciated.
>>>>>>
>>>>>> Thanks in advance!
>>>>>>
>>>>>>
Re: InventoryItem UomId ignored and incorrect ATP reduction on Purchase/Sales Order flow
Posted by Aditi Patel <ad...@hotwax.co>.
Hi Tomek,
The SECA instinct is good — reacting to service events rather than editing
receiveInventoryProduct is the right way to stay upgrade-safe. But before
you build two services, I’d gently push back on where you’re putting the
conversion, because doing it at receipt time is what creates most of the
complexity you’re now having to engineer around.
I suggested converting at the stock move rather than at receipt because the
two events answer different business questions:
- The receipt has to reconcile against the supplier invoice. OFBiz
generates purchase invoicing from ShipmentReceipt quantities, so the
receipt, the PO, and the AP invoice all need to stay in the supplier’s unit
(kg). If you convert at receipt, the inventory no longer sits in the unit
your supplier billed you in, and the receipt no longer cleanly matches the
invoice you’re paying.
- The stock move into the warehouse is where the goods become your own
on-hand to sell. That’s the natural and auditable point to switch into your
stocking unit (g), because nothing upstream depends on it anymore.
Your two-SECA design essentially recreates that switch at receipt, and the
cost shows up in the very parts you’re already working around:
- The “keep the old InventoryItem for history” step is the tell. You’re
left with a zeroed-out kg item sitting next to the real g item, and every
ATP rollup, cycle count, and inventory report then has to know to ignore
it. At the stock move there’s no orphan — the quantity simply transfers and
lands in the new unit.
- The updateProduct trigger worries me most. Letting an admin edit
Product.quantityUomId silently re-value stock you already own is an
accounting event, not a form save. If there are reservations against that
stock, the balances won’t reconcile, and you’d have no audit trail. I’d
drop that path entirely and treat a UoM change on stocked product as a
deliberate physical adjustment.
So I’d still steer you toward the stock move: keep PO → receipt →
InventoryItem all in kg, then put a single small service on the inventory
transfer that calls convertUom (kg → g via UomConversion), records the
on-hand in g, and stamps uomId. One conversion, one auditable point, no
orphans, and the invoice reconciliation stays clean.
The one part of your design I’d keep regardless is stamping uomId from the
SupplierProduct on the freshly received item — that’s a nice touch and
makes the kg stage explicit. Just resolve the supplier from the receipt or
order context rather than from the bare InventoryItem, since
createInventoryItem on its own won’t reliably know it’s part of a receipt.
Best regards,
Aditi
On Thu, Jun 18, 2026 at 2:39 PM Tomek <to...@wp.pl> wrote:
> Hi,
>
> Thank you for proposing this solution. If I understand correctly, you
> are suggesting to receive the goods (using the receiveInventoryProduct
> service) and then somehow automatically perform the unit conversion
> during the transfer order from the UI level?
>
> You mentioned that it is not advisable to modify data inside the
> receiveInventoryProduct service. What do you think about using SECA
> (Service ECA) rules instead? Rather than modifying the data within
> receiveInventoryProduct itself, we could perform the conversion right
> after this service executes. My concept relies on two additional ECA
> services. The first one would be triggered after the createInventoryItem
> service completes, and the second one after the receiveInventoryProduct
> service completes.
>
> The first service (called after createInventoryItem) checks if the
> InventoryItem is linked to a supplier and if its uomId == null. If so,
> it sets the uomId based on the SupplierProduct's UOM. This ensures that
> the InventoryItem stores the supplier's unit of measure.
>
> The second service (called after receiveInventoryProduct) would perform
> the following steps:
>
> 1. Retrieve all InventoryItems that meet the following requirements:
> - are linked to the given product
> - have a UOM different from Product.quantityUomId
> - the fields quantityOnHandTotal != 0 OR availableToPromiseTotal != 0 OR
> accountingQuantityTotal != 0
>
> If I sell the product in the same unit of measure as the supplier, this
> InventoryItem list should be empty. Otherwise, usually one InventoryItem
> element will appear (we could also trigger this ECA service after the
> updateProduct service to detect if the Product.quantityUomId value has
> changed — in that case, the number of elements on the InventoryItem list
> would be greater).
>
> 2. For each InventoryItem element from the list created in step one:
> - create an InventoryItemDetail that resets quantityOnHandTotal,
> availableToPromiseTotal, and accountingQuantityTotal to zero in the
> original InventoryItem.
> - calculate the new quantityOnHandTotal, availableToPromiseTotal,
> accountingQuantityTotal, and unitCost based on the original values (unit
> conversion). For instance, when converting from WT_kg to WT_g, each of
> these values would be multiplied by 1000, except for the cost, which
> would be divided by 1000 (I would use the convertUom service you
> mentioned earlier for this). This would result in new variables:
> newQuantityOnHandTotal, newAvailableToPromiseTotal,
> newAccountingQuantityTotal, and newUnitCost.
> - create a new InventoryItem, set its uomId field to
> Product.quantityUomId, and then add a new InventoryItemDetail record
> (quantityOnHandDiff = newQuantityOnHandTotal, availableToPromiseDiff =
> newAvailableToPromiseTotal, accountingQuantityDiff =
> newAccountingQuantityTotal, unitCost = newUnitCost) linked to this new
> InventoryItem.
>
> The outcome of the above algorithm will be the creation of a new
> InventoryItem based on the desired units of measure. The old
> InventoryItem will be kept purely for informational/historical purposes
> (it will no longer contain any available products).
>
> What do you think about this approach?
>
> Best regards,
> Tomek
>
> W dniu 16.06.2026 o 17:38, Aditi Patel pisze:
> > Hi Tomek,
> >
> > Glad the earlier note helped. Here is how I would suggest handling UoM
> > across the lifecycle.
> >
> > The cleanest pattern is to keep the purchasing side in the supplier's
> unit
> > and switch to your stocking unit only when goods enter the warehouse. The
> > PO carries the supplier product's UoM (copied from SupplierProduct, e.g.
> > kg), the shipment is received in that same UoM, and the InventoryItem is
> > created in the UoM from the ShipmentReceipt. When you then move that
> stock
> > into the warehouse, you convert using the SupplierProduct and Product
> UoMs
> > and stock it in the Product's UoM (g).
> >
> > PO (kg) -> Receipt (kg) -> InventoryItem (kg) -> Stock move to warehouse,
> > convert kg -> g -> On-hand and sales in g
> >
> > So the PO lifecycle stays in the supplier product's UoM and the stocking
> is
> > in the product's UoM, with the conversion happening at the stock move.
> > Receiving in the PO's unit also keeps a clean match between the PO, the
> > receipt, and the supplier invoice (OFBiz generates purchase invoicing
> from
> > ShipmentReceipt quantities), so AP reconciliation and unit cost stay
> > accurate.
> >
> > On your questions:
> >
> > 1. The data model does support UoM management at the inventory level, and
> > InventoryItem.uomId is part of that - I have seen it used across various
> > inventory flows, including receiving, to record the unit an item is held
> > in. Just keep in mind the core ATP/QOH and reservation logic does not
> read
> > it out of the box, so it labels the unit rather than driving the
> conversion
> > on its own.
> >
> > 2. There is no single enforced "stocking UoM" field - inventory is
> > effectively 1 unit = 1. By convention the stocking unit lives on
> > Product.quantityUomId, the supplier's unit on
> > SupplierProduct.quantityUomId, and the conversion factor (wt_kg -> wt_g =
> > 1000) in the UomConversion entity that convertUom reads.
> >
> > 3. Rather than converting inside receiveInventoryProduct, I would do it
> at
> > the stock move into the warehouse: a small service (for example in a
> > hot-deploy component, around the inventory transfer / stock move) that
> > calls convertUom using the SupplierProduct and Product UoMs, records the
> > on-hand in g, and stamps InventoryItem.uomId. Everything downstream then
> > stays consistent.
> >
> > If at any point the UoM management or the conversions are not behaving as
> > expected, feel free to reach out - happy to help.
> >
> > Best regards,
> > Aditi
> >
> > On Tue, Jun 16, 2026 08:17 PM, Tomek <to...@wp.pl> wrote:
> >
> >> Hi,
> >>
> >> Thank you very much for your response.
> >>
> >> Indeed, this issue can be managed by:
> >> - multiplying the quantity by 1000 and dividing the cost by 1000 during
> >> the purchase order receipt,
> >> - multiplying the quantity by 1000 and dividing the cost by 1000 at the
> >> stage of purchase order creation.
> >>
> >> This works and is actually a viable solution, but it makes me wonder:
> >> what is the purpose of the uomId field in InventoryItem then? Is it used
> >> anywhere at all? Is it a legacy remnant or perhaps a placeholder
> >> designed for future process customization?
> >>
> >> Let's assume I would like to automatically convert units from the
> >> supplier's purchase unit to my own preferred unit. For instance, I store
> >> Product X in my warehouse in grams, but the supplier sells it in
> >> kilograms. I would like this conversion to happen automatically.
> >>
> >> With that in mind, I have a couple of questions:
> >>
> >> 1. Where should I define my internal stocking unit (the UoM for products
> >> stored in my own warehouse)?
> >> 2. What would be the best way to handle this conversion? Should I
> >> override the receiveInventoryProduct service, or is there a better, more
> >> recommended approach?
> >>
> >> Best regards,
> >> Tomek
> >>
> >> W dniu 16.06.2026 o 13:06, Aditi Patel pisze:
> >>> Hi,
> >>>
> >>> Thanks for the clear write-up and reproduction steps! The good news is
> >> that
> >>> nothing is broken here. What you are seeing is OFBiz working as
> designed:
> >>> it does not perform automatic unit-of-measure conversion across the
> >>> purchase -> inventory -> sales flow.
> >>>
> >>> A few things that explain both observations:
> >>>
> >>> - Inventory is counted in stocking units, not by weight. ATP and QOH
> are
> >>> plain numeric quantities with no associated UoM, and reservation simply
> >>> subtracts the ordered quantity. That is why selling 1 reduces ATP by
> >>> exactly 1 rather than 0.25.
> >>> - receiveInventoryProduct does not copy Product.quantityUomId or the
> >>> SupplierProduct UoM onto InventoryItem.uomId, so it is left null. And
> >> even
> >>> when you set it manually, the reservation logic never reads it, so the
> >> math
> >>> is unchanged.
> >>> - Product.quantityIncluded / quantityUomId are descriptive packaging
> >>> metadata, not conversion factors applied to inventory or orders.
> >>>
> >>> So both behaviors are expected rather than a bug. If you need to buy in
> >> one
> >>> unit and stock or sell in another, the cleanest options are:
> >>>
> >>> - Normalize everything to a single stocking UoM and convert at receipt
> >>> time, e.g. receive the 1 kg PO line as quantityAccepted = 1000 and keep
> >> the
> >>> product stocked in grams; or
> >>> - Add your own conversion using the convertUom service together with
> the
> >>> UomConversion entity in framework/common.
> >>>
> >>> Hope this helps clear things up, and happy to elaborate on any of the
> >> above.
> >>> Best regards,
> >>> Aditi Patel
> >>>
> >>> On Tue, Jun 16, 2026 04:15 PM, Tomek <to...@wp.pl> wrote:
> >>>
> >>>> Hi everyone,
> >>>>
> >>>> I am facing an issue with UoM (Unit of Measure) handling in OFBiz and
> >>>> would appreciate some guidance.
> >>>>
> >>>> Here is my setup and the steps to reproduce the issue:
> >>>>
> >>>> 1. I created a test product and configured it with:
> >>>> - Quantity Included: 250
> >>>> - Quantity Uom Id: Grams (wt_g)
> >>>>
> >>>> 2. In the Suppliers tab, I added a supplier and set their supplier UoM
> >>>> to Kilograms (wt_kg).
> >>>>
> >>>> 3. I created a Purchase Order (PO) from this supplier, who sells the
> >>>> item in wt_kg.
> >>>>
> >>>> 4. I received the shipment for this PO, which automatically created an
> >>>> InventoryItem.
> >>>>
> >>>> Problem:
> >>>>
> >>>> The uomId field in the newly created InventoryItem was not populated
> (it
> >>>> is null).
> >>>>
> >>>> Next, I simulated a sales order for this test product. After adding
> the
> >>>> product to the order and approving it, the system decreased the
> >>>> Available To Promise (ATP) on the aforementioned InventoryItem by
> >> exactly
> >>>> 1.
> >>>>
> >>>> This issue persists even if I manually update the uomId field to wt_kg
> >>>> directly in the InventoryItem.
> >>>>
> >>>> Questions:
> >>>>
> >>>> 1. Why does OFBiz seem to ignore the Units of Measure in this
> scenario?
> >>>>
> >>>> 2. Shouldn't the sales order reduce the ATP value by 0.25 instead of
> 1,
> >>>> given the product configuration?
> >>>>
> >>>> Any insights on what might be missing or if this is an out-of-the-box
> >>>> limitation would be highly appreciated.
> >>>>
> >>>> Thanks in advance!
> >>>>
> >>>>
>
Re: InventoryItem UomId ignored and incorrect ATP reduction on Purchase/Sales Order flow
Posted by Tomek <to...@wp.pl>.
Hi,
Thank you for proposing this solution. If I understand correctly, you
are suggesting to receive the goods (using the receiveInventoryProduct
service) and then somehow automatically perform the unit conversion
during the transfer order from the UI level?
You mentioned that it is not advisable to modify data inside the
receiveInventoryProduct service. What do you think about using SECA
(Service ECA) rules instead? Rather than modifying the data within
receiveInventoryProduct itself, we could perform the conversion right
after this service executes. My concept relies on two additional ECA
services. The first one would be triggered after the createInventoryItem
service completes, and the second one after the receiveInventoryProduct
service completes.
The first service (called after createInventoryItem) checks if the
InventoryItem is linked to a supplier and if its uomId == null. If so,
it sets the uomId based on the SupplierProduct's UOM. This ensures that
the InventoryItem stores the supplier's unit of measure.
The second service (called after receiveInventoryProduct) would perform
the following steps:
1. Retrieve all InventoryItems that meet the following requirements:
- are linked to the given product
- have a UOM different from Product.quantityUomId
- the fields quantityOnHandTotal != 0 OR availableToPromiseTotal != 0 OR
accountingQuantityTotal != 0
If I sell the product in the same unit of measure as the supplier, this
InventoryItem list should be empty. Otherwise, usually one InventoryItem
element will appear (we could also trigger this ECA service after the
updateProduct service to detect if the Product.quantityUomId value has
changed — in that case, the number of elements on the InventoryItem list
would be greater).
2. For each InventoryItem element from the list created in step one:
- create an InventoryItemDetail that resets quantityOnHandTotal,
availableToPromiseTotal, and accountingQuantityTotal to zero in the
original InventoryItem.
- calculate the new quantityOnHandTotal, availableToPromiseTotal,
accountingQuantityTotal, and unitCost based on the original values (unit
conversion). For instance, when converting from WT_kg to WT_g, each of
these values would be multiplied by 1000, except for the cost, which
would be divided by 1000 (I would use the convertUom service you
mentioned earlier for this). This would result in new variables:
newQuantityOnHandTotal, newAvailableToPromiseTotal,
newAccountingQuantityTotal, and newUnitCost.
- create a new InventoryItem, set its uomId field to
Product.quantityUomId, and then add a new InventoryItemDetail record
(quantityOnHandDiff = newQuantityOnHandTotal, availableToPromiseDiff =
newAvailableToPromiseTotal, accountingQuantityDiff =
newAccountingQuantityTotal, unitCost = newUnitCost) linked to this new
InventoryItem.
The outcome of the above algorithm will be the creation of a new
InventoryItem based on the desired units of measure. The old
InventoryItem will be kept purely for informational/historical purposes
(it will no longer contain any available products).
What do you think about this approach?
Best regards,
Tomek
W dniu 16.06.2026 o 17:38, Aditi Patel pisze:
> Hi Tomek,
>
> Glad the earlier note helped. Here is how I would suggest handling UoM
> across the lifecycle.
>
> The cleanest pattern is to keep the purchasing side in the supplier's unit
> and switch to your stocking unit only when goods enter the warehouse. The
> PO carries the supplier product's UoM (copied from SupplierProduct, e.g.
> kg), the shipment is received in that same UoM, and the InventoryItem is
> created in the UoM from the ShipmentReceipt. When you then move that stock
> into the warehouse, you convert using the SupplierProduct and Product UoMs
> and stock it in the Product's UoM (g).
>
> PO (kg) -> Receipt (kg) -> InventoryItem (kg) -> Stock move to warehouse,
> convert kg -> g -> On-hand and sales in g
>
> So the PO lifecycle stays in the supplier product's UoM and the stocking is
> in the product's UoM, with the conversion happening at the stock move.
> Receiving in the PO's unit also keeps a clean match between the PO, the
> receipt, and the supplier invoice (OFBiz generates purchase invoicing from
> ShipmentReceipt quantities), so AP reconciliation and unit cost stay
> accurate.
>
> On your questions:
>
> 1. The data model does support UoM management at the inventory level, and
> InventoryItem.uomId is part of that - I have seen it used across various
> inventory flows, including receiving, to record the unit an item is held
> in. Just keep in mind the core ATP/QOH and reservation logic does not read
> it out of the box, so it labels the unit rather than driving the conversion
> on its own.
>
> 2. There is no single enforced "stocking UoM" field - inventory is
> effectively 1 unit = 1. By convention the stocking unit lives on
> Product.quantityUomId, the supplier's unit on
> SupplierProduct.quantityUomId, and the conversion factor (wt_kg -> wt_g =
> 1000) in the UomConversion entity that convertUom reads.
>
> 3. Rather than converting inside receiveInventoryProduct, I would do it at
> the stock move into the warehouse: a small service (for example in a
> hot-deploy component, around the inventory transfer / stock move) that
> calls convertUom using the SupplierProduct and Product UoMs, records the
> on-hand in g, and stamps InventoryItem.uomId. Everything downstream then
> stays consistent.
>
> If at any point the UoM management or the conversions are not behaving as
> expected, feel free to reach out - happy to help.
>
> Best regards,
> Aditi
>
> On Tue, Jun 16, 2026 08:17 PM, Tomek <to...@wp.pl> wrote:
>
>> Hi,
>>
>> Thank you very much for your response.
>>
>> Indeed, this issue can be managed by:
>> - multiplying the quantity by 1000 and dividing the cost by 1000 during
>> the purchase order receipt,
>> - multiplying the quantity by 1000 and dividing the cost by 1000 at the
>> stage of purchase order creation.
>>
>> This works and is actually a viable solution, but it makes me wonder:
>> what is the purpose of the uomId field in InventoryItem then? Is it used
>> anywhere at all? Is it a legacy remnant or perhaps a placeholder
>> designed for future process customization?
>>
>> Let's assume I would like to automatically convert units from the
>> supplier's purchase unit to my own preferred unit. For instance, I store
>> Product X in my warehouse in grams, but the supplier sells it in
>> kilograms. I would like this conversion to happen automatically.
>>
>> With that in mind, I have a couple of questions:
>>
>> 1. Where should I define my internal stocking unit (the UoM for products
>> stored in my own warehouse)?
>> 2. What would be the best way to handle this conversion? Should I
>> override the receiveInventoryProduct service, or is there a better, more
>> recommended approach?
>>
>> Best regards,
>> Tomek
>>
>> W dniu 16.06.2026 o 13:06, Aditi Patel pisze:
>>> Hi,
>>>
>>> Thanks for the clear write-up and reproduction steps! The good news is
>> that
>>> nothing is broken here. What you are seeing is OFBiz working as designed:
>>> it does not perform automatic unit-of-measure conversion across the
>>> purchase -> inventory -> sales flow.
>>>
>>> A few things that explain both observations:
>>>
>>> - Inventory is counted in stocking units, not by weight. ATP and QOH are
>>> plain numeric quantities with no associated UoM, and reservation simply
>>> subtracts the ordered quantity. That is why selling 1 reduces ATP by
>>> exactly 1 rather than 0.25.
>>> - receiveInventoryProduct does not copy Product.quantityUomId or the
>>> SupplierProduct UoM onto InventoryItem.uomId, so it is left null. And
>> even
>>> when you set it manually, the reservation logic never reads it, so the
>> math
>>> is unchanged.
>>> - Product.quantityIncluded / quantityUomId are descriptive packaging
>>> metadata, not conversion factors applied to inventory or orders.
>>>
>>> So both behaviors are expected rather than a bug. If you need to buy in
>> one
>>> unit and stock or sell in another, the cleanest options are:
>>>
>>> - Normalize everything to a single stocking UoM and convert at receipt
>>> time, e.g. receive the 1 kg PO line as quantityAccepted = 1000 and keep
>> the
>>> product stocked in grams; or
>>> - Add your own conversion using the convertUom service together with the
>>> UomConversion entity in framework/common.
>>>
>>> Hope this helps clear things up, and happy to elaborate on any of the
>> above.
>>> Best regards,
>>> Aditi Patel
>>>
>>> On Tue, Jun 16, 2026 04:15 PM, Tomek <to...@wp.pl> wrote:
>>>
>>>> Hi everyone,
>>>>
>>>> I am facing an issue with UoM (Unit of Measure) handling in OFBiz and
>>>> would appreciate some guidance.
>>>>
>>>> Here is my setup and the steps to reproduce the issue:
>>>>
>>>> 1. I created a test product and configured it with:
>>>> - Quantity Included: 250
>>>> - Quantity Uom Id: Grams (wt_g)
>>>>
>>>> 2. In the Suppliers tab, I added a supplier and set their supplier UoM
>>>> to Kilograms (wt_kg).
>>>>
>>>> 3. I created a Purchase Order (PO) from this supplier, who sells the
>>>> item in wt_kg.
>>>>
>>>> 4. I received the shipment for this PO, which automatically created an
>>>> InventoryItem.
>>>>
>>>> Problem:
>>>>
>>>> The uomId field in the newly created InventoryItem was not populated (it
>>>> is null).
>>>>
>>>> Next, I simulated a sales order for this test product. After adding the
>>>> product to the order and approving it, the system decreased the
>>>> Available To Promise (ATP) on the aforementioned InventoryItem by
>> exactly
>>>> 1.
>>>>
>>>> This issue persists even if I manually update the uomId field to wt_kg
>>>> directly in the InventoryItem.
>>>>
>>>> Questions:
>>>>
>>>> 1. Why does OFBiz seem to ignore the Units of Measure in this scenario?
>>>>
>>>> 2. Shouldn't the sales order reduce the ATP value by 0.25 instead of 1,
>>>> given the product configuration?
>>>>
>>>> Any insights on what might be missing or if this is an out-of-the-box
>>>> limitation would be highly appreciated.
>>>>
>>>> Thanks in advance!
>>>>
>>>>
Re: InventoryItem UomId ignored and incorrect ATP reduction on Purchase/Sales Order flow
Posted by Aditi Patel <ad...@hotwax.co>.
Hi Tomek,
Glad the earlier note helped. Here is how I would suggest handling UoM
across the lifecycle.
The cleanest pattern is to keep the purchasing side in the supplier's unit
and switch to your stocking unit only when goods enter the warehouse. The
PO carries the supplier product's UoM (copied from SupplierProduct, e.g.
kg), the shipment is received in that same UoM, and the InventoryItem is
created in the UoM from the ShipmentReceipt. When you then move that stock
into the warehouse, you convert using the SupplierProduct and Product UoMs
and stock it in the Product's UoM (g).
PO (kg) -> Receipt (kg) -> InventoryItem (kg) -> Stock move to warehouse,
convert kg -> g -> On-hand and sales in g
So the PO lifecycle stays in the supplier product's UoM and the stocking is
in the product's UoM, with the conversion happening at the stock move.
Receiving in the PO's unit also keeps a clean match between the PO, the
receipt, and the supplier invoice (OFBiz generates purchase invoicing from
ShipmentReceipt quantities), so AP reconciliation and unit cost stay
accurate.
On your questions:
1. The data model does support UoM management at the inventory level, and
InventoryItem.uomId is part of that - I have seen it used across various
inventory flows, including receiving, to record the unit an item is held
in. Just keep in mind the core ATP/QOH and reservation logic does not read
it out of the box, so it labels the unit rather than driving the conversion
on its own.
2. There is no single enforced "stocking UoM" field - inventory is
effectively 1 unit = 1. By convention the stocking unit lives on
Product.quantityUomId, the supplier's unit on
SupplierProduct.quantityUomId, and the conversion factor (wt_kg -> wt_g =
1000) in the UomConversion entity that convertUom reads.
3. Rather than converting inside receiveInventoryProduct, I would do it at
the stock move into the warehouse: a small service (for example in a
hot-deploy component, around the inventory transfer / stock move) that
calls convertUom using the SupplierProduct and Product UoMs, records the
on-hand in g, and stamps InventoryItem.uomId. Everything downstream then
stays consistent.
If at any point the UoM management or the conversions are not behaving as
expected, feel free to reach out - happy to help.
Best regards,
Aditi
On Tue, Jun 16, 2026 08:17 PM, Tomek <to...@wp.pl> wrote:
> Hi,
>
> Thank you very much for your response.
>
> Indeed, this issue can be managed by:
> - multiplying the quantity by 1000 and dividing the cost by 1000 during
> the purchase order receipt,
> - multiplying the quantity by 1000 and dividing the cost by 1000 at the
> stage of purchase order creation.
>
> This works and is actually a viable solution, but it makes me wonder:
> what is the purpose of the uomId field in InventoryItem then? Is it used
> anywhere at all? Is it a legacy remnant or perhaps a placeholder
> designed for future process customization?
>
> Let's assume I would like to automatically convert units from the
> supplier's purchase unit to my own preferred unit. For instance, I store
> Product X in my warehouse in grams, but the supplier sells it in
> kilograms. I would like this conversion to happen automatically.
>
> With that in mind, I have a couple of questions:
>
> 1. Where should I define my internal stocking unit (the UoM for products
> stored in my own warehouse)?
> 2. What would be the best way to handle this conversion? Should I
> override the receiveInventoryProduct service, or is there a better, more
> recommended approach?
>
> Best regards,
> Tomek
>
> W dniu 16.06.2026 o 13:06, Aditi Patel pisze:
> > Hi,
> >
> > Thanks for the clear write-up and reproduction steps! The good news is
> that
> > nothing is broken here. What you are seeing is OFBiz working as designed:
> > it does not perform automatic unit-of-measure conversion across the
> > purchase -> inventory -> sales flow.
> >
> > A few things that explain both observations:
> >
> > - Inventory is counted in stocking units, not by weight. ATP and QOH are
> > plain numeric quantities with no associated UoM, and reservation simply
> > subtracts the ordered quantity. That is why selling 1 reduces ATP by
> > exactly 1 rather than 0.25.
> > - receiveInventoryProduct does not copy Product.quantityUomId or the
> > SupplierProduct UoM onto InventoryItem.uomId, so it is left null. And
> even
> > when you set it manually, the reservation logic never reads it, so the
> math
> > is unchanged.
> > - Product.quantityIncluded / quantityUomId are descriptive packaging
> > metadata, not conversion factors applied to inventory or orders.
> >
> > So both behaviors are expected rather than a bug. If you need to buy in
> one
> > unit and stock or sell in another, the cleanest options are:
> >
> > - Normalize everything to a single stocking UoM and convert at receipt
> > time, e.g. receive the 1 kg PO line as quantityAccepted = 1000 and keep
> the
> > product stocked in grams; or
> > - Add your own conversion using the convertUom service together with the
> > UomConversion entity in framework/common.
> >
> > Hope this helps clear things up, and happy to elaborate on any of the
> above.
> >
> > Best regards,
> > Aditi Patel
> >
> > On Tue, Jun 16, 2026 04:15 PM, Tomek <to...@wp.pl> wrote:
> >
> >> Hi everyone,
> >>
> >> I am facing an issue with UoM (Unit of Measure) handling in OFBiz and
> >> would appreciate some guidance.
> >>
> >> Here is my setup and the steps to reproduce the issue:
> >>
> >> 1. I created a test product and configured it with:
> >> - Quantity Included: 250
> >> - Quantity Uom Id: Grams (wt_g)
> >>
> >> 2. In the Suppliers tab, I added a supplier and set their supplier UoM
> >> to Kilograms (wt_kg).
> >>
> >> 3. I created a Purchase Order (PO) from this supplier, who sells the
> >> item in wt_kg.
> >>
> >> 4. I received the shipment for this PO, which automatically created an
> >> InventoryItem.
> >>
> >> Problem:
> >>
> >> The uomId field in the newly created InventoryItem was not populated (it
> >> is null).
> >>
> >> Next, I simulated a sales order for this test product. After adding the
> >> product to the order and approving it, the system decreased the
> >> Available To Promise (ATP) on the aforementioned InventoryItem by
> exactly
> >> 1.
> >>
> >> This issue persists even if I manually update the uomId field to wt_kg
> >> directly in the InventoryItem.
> >>
> >> Questions:
> >>
> >> 1. Why does OFBiz seem to ignore the Units of Measure in this scenario?
> >>
> >> 2. Shouldn't the sales order reduce the ATP value by 0.25 instead of 1,
> >> given the product configuration?
> >>
> >> Any insights on what might be missing or if this is an out-of-the-box
> >> limitation would be highly appreciated.
> >>
> >> Thanks in advance!
> >>
> >>
>
Re: InventoryItem UomId ignored and incorrect ATP reduction on Purchase/Sales Order flow
Posted by Tomek <to...@wp.pl>.
Hi,
Thank you very much for your response.
Indeed, this issue can be managed by:
- multiplying the quantity by 1000 and dividing the cost by 1000 during
the purchase order receipt,
- multiplying the quantity by 1000 and dividing the cost by 1000 at the
stage of purchase order creation.
This works and is actually a viable solution, but it makes me wonder:
what is the purpose of the uomId field in InventoryItem then? Is it used
anywhere at all? Is it a legacy remnant or perhaps a placeholder
designed for future process customization?
Let's assume I would like to automatically convert units from the
supplier's purchase unit to my own preferred unit. For instance, I store
Product X in my warehouse in grams, but the supplier sells it in
kilograms. I would like this conversion to happen automatically.
With that in mind, I have a couple of questions:
1. Where should I define my internal stocking unit (the UoM for products
stored in my own warehouse)?
2. What would be the best way to handle this conversion? Should I
override the receiveInventoryProduct service, or is there a better, more
recommended approach?
Best regards,
Tomek
W dniu 16.06.2026 o 13:06, Aditi Patel pisze:
> Hi,
>
> Thanks for the clear write-up and reproduction steps! The good news is that
> nothing is broken here. What you are seeing is OFBiz working as designed:
> it does not perform automatic unit-of-measure conversion across the
> purchase -> inventory -> sales flow.
>
> A few things that explain both observations:
>
> - Inventory is counted in stocking units, not by weight. ATP and QOH are
> plain numeric quantities with no associated UoM, and reservation simply
> subtracts the ordered quantity. That is why selling 1 reduces ATP by
> exactly 1 rather than 0.25.
> - receiveInventoryProduct does not copy Product.quantityUomId or the
> SupplierProduct UoM onto InventoryItem.uomId, so it is left null. And even
> when you set it manually, the reservation logic never reads it, so the math
> is unchanged.
> - Product.quantityIncluded / quantityUomId are descriptive packaging
> metadata, not conversion factors applied to inventory or orders.
>
> So both behaviors are expected rather than a bug. If you need to buy in one
> unit and stock or sell in another, the cleanest options are:
>
> - Normalize everything to a single stocking UoM and convert at receipt
> time, e.g. receive the 1 kg PO line as quantityAccepted = 1000 and keep the
> product stocked in grams; or
> - Add your own conversion using the convertUom service together with the
> UomConversion entity in framework/common.
>
> Hope this helps clear things up, and happy to elaborate on any of the above.
>
> Best regards,
> Aditi Patel
>
> On Tue, Jun 16, 2026 04:15 PM, Tomek <to...@wp.pl> wrote:
>
>> Hi everyone,
>>
>> I am facing an issue with UoM (Unit of Measure) handling in OFBiz and
>> would appreciate some guidance.
>>
>> Here is my setup and the steps to reproduce the issue:
>>
>> 1. I created a test product and configured it with:
>> - Quantity Included: 250
>> - Quantity Uom Id: Grams (wt_g)
>>
>> 2. In the Suppliers tab, I added a supplier and set their supplier UoM
>> to Kilograms (wt_kg).
>>
>> 3. I created a Purchase Order (PO) from this supplier, who sells the
>> item in wt_kg.
>>
>> 4. I received the shipment for this PO, which automatically created an
>> InventoryItem.
>>
>> Problem:
>>
>> The uomId field in the newly created InventoryItem was not populated (it
>> is null).
>>
>> Next, I simulated a sales order for this test product. After adding the
>> product to the order and approving it, the system decreased the
>> Available To Promise (ATP) on the aforementioned InventoryItem by exactly
>> 1.
>>
>> This issue persists even if I manually update the uomId field to wt_kg
>> directly in the InventoryItem.
>>
>> Questions:
>>
>> 1. Why does OFBiz seem to ignore the Units of Measure in this scenario?
>>
>> 2. Shouldn't the sales order reduce the ATP value by 0.25 instead of 1,
>> given the product configuration?
>>
>> Any insights on what might be missing or if this is an out-of-the-box
>> limitation would be highly appreciated.
>>
>> Thanks in advance!
>>
>>
Re: InventoryItem UomId ignored and incorrect ATP reduction on Purchase/Sales Order flow
Posted by Aditi Patel <ad...@hotwax.co>.
Hi,
Thanks for the clear write-up and reproduction steps! The good news is that
nothing is broken here. What you are seeing is OFBiz working as designed:
it does not perform automatic unit-of-measure conversion across the
purchase -> inventory -> sales flow.
A few things that explain both observations:
- Inventory is counted in stocking units, not by weight. ATP and QOH are
plain numeric quantities with no associated UoM, and reservation simply
subtracts the ordered quantity. That is why selling 1 reduces ATP by
exactly 1 rather than 0.25.
- receiveInventoryProduct does not copy Product.quantityUomId or the
SupplierProduct UoM onto InventoryItem.uomId, so it is left null. And even
when you set it manually, the reservation logic never reads it, so the math
is unchanged.
- Product.quantityIncluded / quantityUomId are descriptive packaging
metadata, not conversion factors applied to inventory or orders.
So both behaviors are expected rather than a bug. If you need to buy in one
unit and stock or sell in another, the cleanest options are:
- Normalize everything to a single stocking UoM and convert at receipt
time, e.g. receive the 1 kg PO line as quantityAccepted = 1000 and keep the
product stocked in grams; or
- Add your own conversion using the convertUom service together with the
UomConversion entity in framework/common.
Hope this helps clear things up, and happy to elaborate on any of the above.
Best regards,
Aditi Patel
On Tue, Jun 16, 2026 04:15 PM, Tomek <to...@wp.pl> wrote:
> Hi everyone,
>
> I am facing an issue with UoM (Unit of Measure) handling in OFBiz and
> would appreciate some guidance.
>
> Here is my setup and the steps to reproduce the issue:
>
> 1. I created a test product and configured it with:
> - Quantity Included: 250
> - Quantity Uom Id: Grams (wt_g)
>
> 2. In the Suppliers tab, I added a supplier and set their supplier UoM
> to Kilograms (wt_kg).
>
> 3. I created a Purchase Order (PO) from this supplier, who sells the
> item in wt_kg.
>
> 4. I received the shipment for this PO, which automatically created an
> InventoryItem.
>
> Problem:
>
> The uomId field in the newly created InventoryItem was not populated (it
> is null).
>
> Next, I simulated a sales order for this test product. After adding the
> product to the order and approving it, the system decreased the
> Available To Promise (ATP) on the aforementioned InventoryItem by exactly
> 1.
>
> This issue persists even if I manually update the uomId field to wt_kg
> directly in the InventoryItem.
>
> Questions:
>
> 1. Why does OFBiz seem to ignore the Units of Measure in this scenario?
>
> 2. Shouldn't the sales order reduce the ATP value by 0.25 instead of 1,
> given the product configuration?
>
> Any insights on what might be missing or if this is an out-of-the-box
> limitation would be highly appreciated.
>
> Thanks in advance!
>
>