Metadata-Version: 2.1
Name: odoo-addon-stock_secondary_unit
Version: 18.0.1.2.1
Requires-Python: >=3.10
Requires-Dist: odoo-addon-product_secondary_unit==18.0.*
Requires-Dist: odoo==18.0.*
Summary: Get product quantities in a secondary unit
Home-page: https://github.com/OCA/stock-logistics-warehouse
License: AGPL-3
Author: Tecnativa, Odoo Community Association (OCA)
Author-email: support@odoo-community.org
Classifier: Programming Language :: Python
Classifier: Framework :: Odoo
Classifier: Framework :: Odoo :: 18.0
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
Classifier: Development Status :: 5 - Production/Stable
Description-Content-Type: text/x-rst

.. image:: https://odoo-community.org/readme-banner-image
   :target: https://odoo-community.org/get-involved?utm_source=readme
   :alt: Odoo Community Association

====================
Stock Secondary Unit
====================

.. 
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   !! This file is generated by oca-gen-addon-readme !!
   !! changes will be overwritten.                   !!
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
   !! source digest: sha256:c2ff0a770178ee022af7eb81a3aa7732d3da682f714808518375977db8f3bfb3
   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png
    :target: https://odoo-community.org/page/development-status
    :alt: Production/Stable
.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png
    :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
    :alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fstock--logistics--warehouse-lightgray.png?logo=github
    :target: https://github.com/OCA/stock-logistics-warehouse/tree/18.0/stock_secondary_unit
    :alt: OCA/stock-logistics-warehouse
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
    :target: https://translation.odoo-community.org/projects/stock-logistics-warehouse-18-0/stock-logistics-warehouse-18-0-stock_secondary_unit
    :alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
    :target: https://runboat.odoo-community.org/builds?repo=OCA/stock-logistics-warehouse&target_branch=18.0
    :alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module lets a product be tracked, throughout the whole stock flow,
in a **secondary unit of measure** alongside its normal one - typically
a count (pieces, boxes) next to a product that is actually measured by
weight or volume. A classic case: fish sold by weight, but an order is
placed for "40 pieces" because each of a fixed number of guests gets
exactly one - the real weight per piece varies, but the piece count must
travel through the whole warehouse route exactly as ordered.

It builds on ``product_secondary_unit``'s per-product configuration (the
conversion factor, and the ``dependency_type`` that decides how the two
quantities relate to each other) and extends it to ``stock.move`` and
``stock.move.line``, so a secondary quantity can be demanded on a
transfer, counted on its operations, and shown on delivery documents -
not just converted once on the product form.

**Two independent secondary-unit settings live on the product:**

- ``secondary_uom_ids`` / the sale-facing secondary unit (from
  ``product_secondary_unit``) - the one that ends up on ``stock.move`` /
  ``stock.move.line`` records for an actual transfer.
- ``stock_secondary_uom_id`` ("Second unit for inventory", added by this
  module) - purely for the **on-hand quantity display**: pick one of the
  product's secondary units and a "Secondary Unit" smart button appears
  on the product form next to "On Hand", showing the current stock
  quantity converted into it. This is read-only, informational, and
  independent of whatever secondary unit an individual move ends up
  using.

**Why ``dependency_type`` matters here in particular:** a stock move's
``product_uom_qty`` (demand) and a move line's ``quantity`` (what was
actually done) are two different fields with different needs:

- ``dependent``: the secondary quantity is always a factor conversion of
  the primary one, in both directions - fine for informational units
  where nothing needs to survive an inexact conversion.
- ``independent``: the secondary quantity is entered on its own and
  never recomputed from the primary one, and vice versa - used when the
  two units don't relate to each other at all.
- ``secondary_priority``: the primary quantity is *estimated* from the
  secondary one (like ``dependent``), but the secondary one is *never*
  recomputed back from the primary (like ``independent``) - this is the
  one built for the fish-by-weight/pieces-by-count case: pieces are the
  real order, weight is only ever a convenience estimate derived from
  them, and must never silently drift because of how much something
  happened to weigh.

For ``independent`` and ``secondary_priority`` (together, the
"count-preserving" types), the module makes sure the secondary quantity
survives every stock operation exactly, instead of being silently
re-derived from the primary quantity and losing precision or meaning:

- **Splitting a move for a backorder** carries over exactly what's left
  of the secondary demand (e.g. 40 pieces demanded, 30 actually picked
  -> the backorder is for exactly 10 pieces, never a weight-based
  guess), and keeps the original move's own secondary quantity in sync
  with what was actually processed.
- **Merging moves back together** (e.g. two operations for the same
  product ending up as one line, or a backorder's pushed leg merging
  back into an already-existing move) sums the secondary quantities the
  same way core sums the primary one - core has no notion of this field
  at all, so without this the count would silently be lost on every
  merge.
- **A negative move (e.g. a decreased sale order line) absorbed into -
  or absorbing - an existing one** rebalances the secondary quantity the
  same way core rebalances the primary one for that specific code path,
  which is separate from the ordinary merge above. When the negative
  move is bigger than the pending demand, the remaining return gets a
  positive secondary quantity, as core only flips the primary one.
- **A pull-chain procurement** (e.g. a 2-step reception, or an internal
  make-to-order replenishment) carries the secondary unit forward into
  the next move it creates, the same way the primary quantity already
  does.
- **``secondary_uom_qty_done``**, a new aggregate field on
  ``stock.move``, mirrors what core's own ``quantity`` field does for
  the primary unit: it sums what was actually counted across the move's
  lines, so other code needing "how many pieces were actually done"
  doesn't have to re-derive that sum ad hoc every time.

**Table of contents**

.. contents::
   :local:

Usage
=====

Displaying stock on hand in a secondary unit
--------------------------------------------

1. On a product, go to *Inventory tab > Secondary unit* and choose which
   of the product's configured secondary units should be used for the
   on-hand display ("Second unit for inventory").
2. A "Secondary Unit" smart button appears on the product form (next to
   "On Hand"), showing the current stock quantity converted into that
   unit. This is purely informational: it does not affect any transfer.

Demanding and counting a secondary quantity on a transfer
---------------------------------------------------------

1. On a transfer's operations (the move lines list, or a move's own
   detail form when *Detailed Operations* is enabled), the *Secondary
   Qty* and its unit are editable columns/fields (needs the "Units of
   Measure" feature enabled, ``uom.group_uom``).
2. What happens when the secondary quantity is entered depends on the
   product's secondary unit ``dependency_type``:

   - ``dependent``: entering either quantity recomputes the other
     through the conversion factor.
   - ``independent`` / ``secondary_priority``: the secondary quantity is
     entered on its own; for ``secondary_priority`` the primary quantity
     is estimated from it, but never the other way round once a
     secondary quantity has actually been set.

Validating a transfer that doesn't match the secondary demand exactly
---------------------------------------------------------------------

For a count-preserving secondary unit (``independent`` or
``secondary_priority``), if what was actually counted is less than
demanded and a backorder gets created:

- The backorder is created for **exactly** what's left of the secondary
  demand (e.g. 40 pieces demanded, 30 counted -> the backorder demands
  exactly 10 pieces) - never a proportional estimate derived from
  whatever the primary quantity (e.g. weight) happened to be.
- The original, now-done transfer keeps its secondary quantity in sync
  with what was actually counted, not the original demand.

If instead more was counted than demanded, the move's own demand is left
untouched by this module alone; reconciling that difference is out of
scope for this module.

Decreasing the demand of a confirmed transfer
---------------------------------------------

When the quantity of a confirmed sale order line is decreased, core
creates a move with a negative quantity and merges it into the pending
one. For a count-preserving secondary unit, the surviving move's
secondary quantity reflects the net effect of the decrease, not just
whatever it already had before. If the decrease is bigger than the
pending demand, the remaining quantity becomes a return whose secondary
quantity is positive too.

Chained transfers (multi-step routes, make-to-order replenishment)
------------------------------------------------------------------

When a transfer is part of a pull chain (e.g. the "Input -> Stock" leg
of a 2-step reception, or an internal make-to-order move), whatever
secondary unit and quantity is set on it is carried forward into the
next transfer created for that chain - the destination move doesn't
start without one.

Delivery documents
------------------

The delivery slip report shows the secondary quantity and unit next to
the primary one for every line, both for a picking still being processed
and once it is done.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/stock-logistics-warehouse/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/stock-logistics-warehouse/issues/new?body=module:%20stock_secondary_unit%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* Tecnativa

Contributors
------------

- `Tecnativa <https://www.tecnativa.com>`__

  - Carlos Dauden
  - Sergio Teruel
  - Carlos Roca

- Kitti Upariphutthiphong <kittiu@ecosoft.co.th>
- Pimolnat Suntian <pimolnats@ecosoft.co.th>
- Alan Ramos <alan.ramos@jarsa.com.mx>

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
   :alt: Odoo Community Association
   :target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/stock-logistics-warehouse <https://github.com/OCA/stock-logistics-warehouse/tree/18.0/stock_secondary_unit>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
