Merge pull request '[IMP] stock_picking_batch_collect: cantidad demandada en las líneas de movimiento' (#22) from 18.0-imp-stock_picking_batch_collect-demand into 18.0
Reviewed-on: #22
This commit is contained in:
commit
8a029464eb
11 changed files with 93 additions and 1 deletions
2
.github/copilot-instructions.md
vendored
2
.github/copilot-instructions.md
vendored
|
|
@ -761,6 +761,8 @@ last_purchase_price_compute_type != "manual_update" # Para auto-cálculo
|
||||||
`product_pricelist_total_margin`, `product_origin_char`, `l10n_es_edi_tbai_reagyp_recibidas`.
|
`product_pricelist_total_margin`, `product_origin_char`, `l10n_es_edi_tbai_reagyp_recibidas`.
|
||||||
`product_origin` (OCA) sustituido por `product_origin_char` (custom).
|
`product_origin` (OCA) sustituido por `product_origin_char` (custom).
|
||||||
- **2026-06-04**: `product_sale_price_from_pricelist` aplica descuentos de proveedor desde `supplierinfo`.
|
- **2026-06-04**: `product_sale_price_from_pricelist` aplica descuentos de proveedor desde `supplierinfo`.
|
||||||
|
- **2026-10-10**: `stock_picking_batch_collect` (v18.0.2.2.0) — columna de cantidad demandada en
|
||||||
|
las listas de líneas de movimiento (operaciones detalladas de lote y albarán, vista operario).
|
||||||
- **2026-10-04**: `stock_picking_batch_collect` (v18.0.2.1.0) — checks de recogido en albaranes
|
- **2026-10-04**: `stock_picking_batch_collect` (v18.0.2.1.0) — checks de recogido en albaranes
|
||||||
sueltos (activables por tipo de operación), columna de cantidad pedida en la venta (depende de
|
sueltos (activables por tipo de operación), columna de cantidad pedida en la venta (depende de
|
||||||
`sale_stock`) e informe *Albaranes* del lote.
|
`sale_stock`) e informe *Albaranes* del lote.
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,11 @@ producto y una vista a pantalla completa para el almacén.
|
||||||
comparar lo pedido con lo preparado en la misma pantalla. Está en las
|
comparar lo pedido con lo preparado en la misma pantalla. Está en las
|
||||||
operaciones detalladas, la vista de operario, la pestaña *Operations* y el
|
operaciones detalladas, la vista de operario, la pestaña *Operations* y el
|
||||||
resumen por producto del lote, y en el albarán.
|
resumen por producto del lote, y en el albarán.
|
||||||
|
- Columna **Cantidad demandada** (``move_demand_qty``), de sólo lectura, en las
|
||||||
|
listas de líneas de movimiento, que no la traen de serie: las operaciones
|
||||||
|
detalladas del lote y del albarán y la vista de operario. Es la demanda del
|
||||||
|
movimiento completo, así que se repite en cada línea de un movimiento
|
||||||
|
repartido en varias (lotes, ubicaciones).
|
||||||
- Informe **Albaranes** en el lote: todos sus albaranes de entrega en un PDF.
|
- Informe **Albaranes** en el lote: todos sus albaranes de entrega en un PDF.
|
||||||
|
|
||||||
Las columnas se añaden con ``optional="show"`` en la vista de líneas del lote
|
Las columnas se añaden con ``optional="show"`` en la vista de líneas del lote
|
||||||
|
|
@ -136,6 +141,8 @@ Uso
|
||||||
9. La columna **Cantidad pedida** muestra lo que pidió el cliente, frente a la
|
9. La columna **Cantidad pedida** muestra lo que pidió el cliente, frente a la
|
||||||
demanda (ya ajustada al peso) y la cantidad preparada. En el resumen por
|
demanda (ya ajustada al peso) y la cantidad preparada. En el resumen por
|
||||||
producto del lote es la suma de los pedidos.
|
producto del lote es la suma de los pedidos.
|
||||||
|
La columna **Cantidad demandada** está junto a ella en todas las vistas,
|
||||||
|
también en la vista de operario.
|
||||||
|
|
||||||
10. **Imprimir > Albaranes** en el lote genera un único PDF con el albarán de
|
10. **Imprimir > Albaranes** en el lote genera un único PDF con el albarán de
|
||||||
entrega de cada uno de sus traslados (salvo los cancelados), ordenados por
|
entrega de cada uno de sus traslados (salvo los cancelados), ordenados por
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
{ # noqa: B018
|
{ # noqa: B018
|
||||||
"name": "Stock Picking Batch Collect",
|
"name": "Stock Picking Batch Collect",
|
||||||
"version": "18.0.2.1.0",
|
"version": "18.0.2.2.0",
|
||||||
"category": "Warehouse",
|
"category": "Warehouse",
|
||||||
"summary": "Collect batch operations: operator view, extra columns and product summary",
|
"summary": "Collect batch operations: operator view, extra columns and product summary",
|
||||||
"author": "Odoo Community Association (OCA), Criptomart",
|
"author": "Odoo Community Association (OCA), Criptomart",
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,7 @@ msgid "Created on"
|
||||||
msgstr "Creado el"
|
msgstr "Creado el"
|
||||||
|
|
||||||
#. module: stock_picking_batch_collect
|
#. module: stock_picking_batch_collect
|
||||||
|
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_move_line__move_demand_qty
|
||||||
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__qty_demanded
|
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__qty_demanded
|
||||||
msgid "Demanded Quantity"
|
msgid "Demanded Quantity"
|
||||||
msgstr "Cantidad demandada"
|
msgstr "Cantidad demandada"
|
||||||
|
|
@ -282,3 +283,8 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Hay que marcar como recogidas las operaciones de %(picking)s antes de validarlo.\n"
|
"Hay que marcar como recogidas las operaciones de %(picking)s antes de validarlo.\n"
|
||||||
"Productos pendientes: %(products)s"
|
"Productos pendientes: %(products)s"
|
||||||
|
|
||||||
|
#. module: stock_picking_batch_collect
|
||||||
|
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.view_move_line_batch_operator
|
||||||
|
msgid "Demand"
|
||||||
|
msgstr "Demanda"
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ msgid "Created on"
|
||||||
msgstr "Noiz sortua"
|
msgstr "Noiz sortua"
|
||||||
|
|
||||||
#. module: stock_picking_batch_collect
|
#. module: stock_picking_batch_collect
|
||||||
|
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_move_line__move_demand_qty
|
||||||
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__qty_demanded
|
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__qty_demanded
|
||||||
msgid "Demanded Quantity"
|
msgid "Demanded Quantity"
|
||||||
msgstr "Eskatutako kantitatea"
|
msgstr "Eskatutako kantitatea"
|
||||||
|
|
@ -282,3 +283,8 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"%(picking)s balidatu aurretik, bere eragiketak jasota gisa markatu behar dira.\n"
|
"%(picking)s balidatu aurretik, bere eragiketak jasota gisa markatu behar dira.\n"
|
||||||
"Zain dauden produktuak: %(products)s"
|
"Zain dauden produktuak: %(products)s"
|
||||||
|
|
||||||
|
#. module: stock_picking_batch_collect
|
||||||
|
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.view_move_line_batch_operator
|
||||||
|
msgid "Demand"
|
||||||
|
msgstr "Eskaria"
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,11 @@ class StockMoveLine(models.Model):
|
||||||
digits="Product Unit of Measure",
|
digits="Product Unit of Measure",
|
||||||
compute="_compute_sale_ordered_qty",
|
compute="_compute_sale_ordered_qty",
|
||||||
)
|
)
|
||||||
|
move_demand_qty = fields.Float(
|
||||||
|
string="Demanded Quantity",
|
||||||
|
digits="Product Unit of Measure",
|
||||||
|
compute="_compute_move_demand_qty",
|
||||||
|
)
|
||||||
|
|
||||||
@api.depends("move_id.sale_ordered_qty", "move_id.product_uom", "product_uom_id")
|
@api.depends("move_id.sale_ordered_qty", "move_id.product_uom", "product_uom_id")
|
||||||
def _compute_sale_ordered_qty(self):
|
def _compute_sale_ordered_qty(self):
|
||||||
|
|
@ -53,6 +58,18 @@ class StockMoveLine(models.Model):
|
||||||
else:
|
else:
|
||||||
line.sale_ordered_qty = 0.0
|
line.sale_ordered_qty = 0.0
|
||||||
|
|
||||||
|
@api.depends("move_id.product_uom_qty", "move_id.product_uom", "product_uom_id")
|
||||||
|
def _compute_move_demand_qty(self):
|
||||||
|
"""The demand of the whole move: every line of a split move shows it."""
|
||||||
|
for line in self:
|
||||||
|
move = line.move_id
|
||||||
|
if move.product_uom and line.product_uom_id:
|
||||||
|
line.move_demand_qty = move.product_uom._compute_quantity(
|
||||||
|
move.product_uom_qty, line.product_uom_id, round=False
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
line.move_demand_qty = 0.0
|
||||||
|
|
||||||
def write(self, vals):
|
def write(self, vals):
|
||||||
res = super().write(vals)
|
res = super().write(vals)
|
||||||
if vals.get("is_collected"):
|
if vals.get("is_collected"):
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,11 @@ producto y una vista a pantalla completa para el almacén.
|
||||||
comparar lo pedido con lo preparado en la misma pantalla. Está en las
|
comparar lo pedido con lo preparado en la misma pantalla. Está en las
|
||||||
operaciones detalladas, la vista de operario, la pestaña *Operations* y el
|
operaciones detalladas, la vista de operario, la pestaña *Operations* y el
|
||||||
resumen por producto del lote, y en el albarán.
|
resumen por producto del lote, y en el albarán.
|
||||||
|
- Columna **Cantidad demandada** (``move_demand_qty``), de sólo lectura, en las
|
||||||
|
listas de líneas de movimiento, que no la traen de serie: las operaciones
|
||||||
|
detalladas del lote y del albarán y la vista de operario. Es la demanda del
|
||||||
|
movimiento completo, así que se repite en cada línea de un movimiento
|
||||||
|
repartido en varias (lotes, ubicaciones).
|
||||||
- Informe **Albaranes** en el lote: todos sus albaranes de entrega en un PDF.
|
- Informe **Albaranes** en el lote: todos sus albaranes de entrega en un PDF.
|
||||||
|
|
||||||
Las columnas se añaden con ``optional="show"`` en la vista de líneas del lote
|
Las columnas se añaden con ``optional="show"`` en la vista de líneas del lote
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,8 @@ Uso
|
||||||
9. La columna **Cantidad pedida** muestra lo que pidió el cliente, frente a la
|
9. La columna **Cantidad pedida** muestra lo que pidió el cliente, frente a la
|
||||||
demanda (ya ajustada al peso) y la cantidad preparada. En el resumen por
|
demanda (ya ajustada al peso) y la cantidad preparada. En el resumen por
|
||||||
producto del lote es la suma de los pedidos.
|
producto del lote es la suma de los pedidos.
|
||||||
|
La columna **Cantidad demandada** está junto a ella en todas las vistas,
|
||||||
|
también en la vista de operario.
|
||||||
|
|
||||||
10. **Imprimir > Albaranes** en el lote genera un único PDF con el albarán de
|
10. **Imprimir > Albaranes** en el lote genera un único PDF con el albarán de
|
||||||
entrega de cada uno de sus traslados (salvo los cancelados), ordenados por
|
entrega de cada uno de sus traslados (salvo los cancelados), ordenados por
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,50 @@ class TestPickingCollected(TransactionCase):
|
||||||
self.assertEqual(move.sale_ordered_qty, 2.0)
|
self.assertEqual(move.sale_ordered_qty, 2.0)
|
||||||
self.assertEqual(move.move_line_ids.sale_ordered_qty, 2.0)
|
self.assertEqual(move.move_line_ids.sale_ordered_qty, 2.0)
|
||||||
|
|
||||||
|
def test_move_line_demand_follows_the_move(self):
|
||||||
|
picking = self._create_sale_picking(2.0)
|
||||||
|
move = picking.move_ids
|
||||||
|
line = move.move_line_ids
|
||||||
|
|
||||||
|
self.assertEqual(line.move_demand_qty, 2.0)
|
||||||
|
|
||||||
|
gram = self.env.ref("uom.product_uom_gram")
|
||||||
|
line.product_uom_id = gram
|
||||||
|
self.assertEqual(line.move_demand_qty, 2000.0)
|
||||||
|
|
||||||
|
move.product_uom_qty = 3.0
|
||||||
|
self.assertEqual(line.move_demand_qty, 3000.0)
|
||||||
|
|
||||||
|
def test_move_line_demand_without_sale(self):
|
||||||
|
"""Unlike the ordered quantity, the demand needs no sale order."""
|
||||||
|
picking = self.env["stock.picking"].create(
|
||||||
|
{
|
||||||
|
"picking_type_id": self.picking_type_out.id,
|
||||||
|
"location_id": self.stock_location.id,
|
||||||
|
"location_dest_id": self.env.ref("stock.stock_location_customers").id,
|
||||||
|
"move_ids": [
|
||||||
|
Command.create(
|
||||||
|
{
|
||||||
|
"name": self.product.name,
|
||||||
|
"product_id": self.product.id,
|
||||||
|
"product_uom_qty": 4.0,
|
||||||
|
"product_uom": self.product.uom_id.id,
|
||||||
|
"location_id": self.stock_location.id,
|
||||||
|
"location_dest_id": self.env.ref(
|
||||||
|
"stock.stock_location_customers"
|
||||||
|
).id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
picking.action_confirm()
|
||||||
|
picking.action_assign()
|
||||||
|
line = picking.move_ids.move_line_ids
|
||||||
|
|
||||||
|
self.assertEqual(line.move_demand_qty, 4.0)
|
||||||
|
self.assertEqual(line.sale_ordered_qty, 0.0)
|
||||||
|
|
||||||
def test_batch_summary_ordered_quantity(self):
|
def test_batch_summary_ordered_quantity(self):
|
||||||
pickings = self._create_sale_picking(2.0) | self._create_sale_picking(3.0)
|
pickings = self._create_sale_picking(2.0) | self._create_sale_picking(3.0)
|
||||||
batch = self.env["stock.picking.batch"].create(
|
batch = self.env["stock.picking.batch"].create(
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
<field name="reference" readonly="1" optional="hide"/>
|
<field name="reference" readonly="1" optional="hide"/>
|
||||||
<field name="picking_partner_id" readonly="1" optional="show"/>
|
<field name="picking_partner_id" readonly="1" optional="show"/>
|
||||||
<field name="sale_ordered_qty" string="Ordered" readonly="1" optional="show"/>
|
<field name="sale_ordered_qty" string="Ordered" readonly="1" optional="show"/>
|
||||||
|
<field name="move_demand_qty" string="Demand" readonly="1" optional="show"/>
|
||||||
<field name="quantity" string="Cant."/>
|
<field name="quantity" string="Cant."/>
|
||||||
<!-- Loaded so `_onchange_quantity_manual` reaches the server. -->
|
<!-- Loaded so `_onchange_quantity_manual` reaches the server. -->
|
||||||
<field name="picked" column_invisible="True"/>
|
<field name="picked" column_invisible="True"/>
|
||||||
|
|
@ -82,6 +83,7 @@
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='quantity']" position="before">
|
<xpath expr="//field[@name='quantity']" position="before">
|
||||||
<field name="sale_ordered_qty" readonly="1" optional="show"/>
|
<field name="sale_ordered_qty" readonly="1" optional="show"/>
|
||||||
|
<field name="move_demand_qty" readonly="1" optional="show"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='quantity']" position="after">
|
<xpath expr="//field[@name='quantity']" position="after">
|
||||||
<!-- Loaded so `_onchange_quantity_manual` reaches the server. -->
|
<!-- Loaded so `_onchange_quantity_manual` reaches the server. -->
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
<xpath expr="//field[@name='quantity']" position="before">
|
<xpath expr="//field[@name='quantity']" position="before">
|
||||||
<field name="sale_ordered_qty" readonly="1" optional="show"
|
<field name="sale_ordered_qty" readonly="1" optional="show"
|
||||||
column_invisible="context.get('picking_code') == 'incoming'"/>
|
column_invisible="context.get('picking_code') == 'incoming'"/>
|
||||||
|
<field name="move_demand_qty" readonly="1" optional="show"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='quantity']" position="after">
|
<xpath expr="//field[@name='quantity']" position="after">
|
||||||
<field name="is_collected" widget="boolean_toggle" optional="show"
|
<field name="is_collected" widget="boolean_toggle" optional="show"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue