diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
index 22d616b..0f33715 100644
--- a/.github/copilot-instructions.md
+++ b/.github/copilot-instructions.md
@@ -235,7 +235,7 @@ addons-cm/
**Logística y contabilidad**
-- [stock_picking_batch_collect](../stock_picking_batch_collect/README.rst) - Columnas extra, resumen por producto y vista operario para batch picking; checks de recogido también en albaranes sueltos, cantidad pedida en venta e informe con todos los albaranes del lote
+- [stock_picking_batch_collect](../stock_picking_batch_collect/README.rst) - Columnas extra, resumen por producto y vista operario para batch picking
- [web_list_striped](../web_list_striped/README.rst) - Efecto cebra en todas las listas del backend (sólo CSS)
- [account_banking_mandate_batch](../account_banking_mandate_batch/README.rst) - Creación masiva de mandatos SEPA desde contactos
- [l10n_es_edi_tbai_reagyp_recibidas](../l10n_es_edi_tbai_reagyp_recibidas/README.rst) - Fix TicketBAI REAGYP en facturas recibidas (clave régimen 19 → 02)
@@ -761,9 +761,6 @@ 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_origin` (OCA) sustituido por `product_origin_char` (custom).
- **2026-06-04**: `product_sale_price_from_pricelist` aplica descuentos de proveedor desde `supplierinfo`.
-- **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
- `sale_stock`) e informe *Albaranes* del lote.
- **2026-08-27**: `stock_picking_batch_custom` renombrado a `stock_picking_batch_collect`
(v18.0.2.0.0). Se invierte la dependencia: ya no depende de `website_sale_aplicoop`; es este
el que depende de él e inyecta las columnas de grupo de consumo. El efecto cebra global se
diff --git a/stock_picking_batch_collect/README.rst b/stock_picking_batch_collect/README.rst
index ab69239..75a70b6 100644
--- a/stock_picking_batch_collect/README.rst
+++ b/stock_picking_batch_collect/README.rst
@@ -21,15 +21,6 @@ producto y una vista a pantalla completa para el almacén.
cantidades grandes y controles táctiles, pensada para tablet en el almacén.
- Restricciones de validación configurables por compañía: el lote no se puede
validar hasta que las líneas estén marcadas como recogidas.
-- Los mismos checks en los albaranes sueltos (fuera de un lote), activables por
- tipo de operación.
-- Columna **Cantidad pedida** (``sale_ordered_qty``), de sólo lectura, con lo
- que pidió el cliente en el pedido de venta. Al teclear el peso real la demanda
- del movimiento se ajusta a lo pesado, así que esta columna es la que permite
- 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
- resumen por producto del lote, y en el albarán.
-- 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
(salvo ``product_default_code``, oculta por defecto), de modo que el usuario
@@ -77,17 +68,6 @@ Cada restricción tiene un alcance:
mayor que cero (por defecto).
- *Todas*: se comprueban todas las líneas del lote, procesadas o no.
-Albaranes fuera de un lote
---------------------------
-
-Para exigir los checks también en los albaranes sueltos, marcar **Exigir líneas
-recogidas** en el tipo de operación (**Inventory > Configuration > Operation
-Types**, p. ej. *Delivery Orders*). Viene desactivado: sin él, los albaranes
-sueltos de ese tipo se validan como siempre.
-
-Un albarán suelto no tiene resumen por producto, así que las dos restricciones
-comprueban sus líneas; si alguna usa el alcance *Todas*, se aplica ese.
-
Columnas
--------
@@ -128,19 +108,6 @@ Uso
La comprobación se ejecuta después de resolver el backorder, de modo que
sólo bloquea sobre las líneas que realmente se van a procesar.
-8. En un albarán suelto, la pestaña **Operations** tiene un check
- **Collected** por producto, que marca todas sus líneas; las operaciones
- detalladas lo tienen por línea. Si su tipo de operación lo exige, el
- albarán no se valida hasta marcarlos.
-
-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
- producto del lote es la suma de los pedidos.
-
-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
- cliente.
-
Contribuidores
==============
diff --git a/stock_picking_batch_collect/__init__.py b/stock_picking_batch_collect/__init__.py
index 7efee8a..4a5c3e3 100644
--- a/stock_picking_batch_collect/__init__.py
+++ b/stock_picking_batch_collect/__init__.py
@@ -1,3 +1,2 @@
from . import models # noqa: F401
-from . import report # noqa: F401
from .hooks import pre_init_hook # noqa: F401
diff --git a/stock_picking_batch_collect/__manifest__.py b/stock_picking_batch_collect/__manifest__.py
index ae2b5f3..7e61eac 100644
--- a/stock_picking_batch_collect/__manifest__.py
+++ b/stock_picking_batch_collect/__manifest__.py
@@ -2,7 +2,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{ # noqa: B018
"name": "Stock Picking Batch Collect",
- "version": "18.0.2.1.0",
+ "version": "18.0.2.0.0",
"category": "Warehouse",
"summary": "Collect batch operations: operator view, extra columns and product summary",
"author": "Odoo Community Association (OCA), Criptomart",
@@ -10,9 +10,6 @@
"website": "https://github.com/Criptomart",
"license": "AGPL-3",
"depends": [
- # The ordered quantity of the sale line, which the weighed demand
- # overwrites.
- "sale_stock",
# A quantity typed by the operator is the weighed one: it must not be
# re-reserved by the scheduler.
"stock_move_manual_quantity",
@@ -22,8 +19,6 @@
"security/ir.model.access.csv",
"views/res_config_settings_views.xml",
"views/stock_picking_batch_views.xml",
- "views/stock_picking_views.xml",
- "report/report_batch_deliveryslip.xml",
],
"assets": {
"web.assets_backend": [
diff --git a/stock_picking_batch_collect/i18n/es.po b/stock_picking_batch_collect/i18n/es.po
index 21f6002..4bad2cb 100644
--- a/stock_picking_batch_collect/i18n/es.po
+++ b/stock_picking_batch_collect/i18n/es.po
@@ -62,7 +62,6 @@ msgid "Batch Transfer"
msgstr "Traslado por lote"
#. module: stock_picking_batch_collect
-#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_move__is_collected
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_move_line__is_collected
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__is_collected
msgid "Collected"
@@ -234,51 +233,3 @@ msgstr "Si este albarán incluye entrega a domicilio (del pedido de venta)"
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.view_stock_picking_batch_form_inherit_summary
msgid "Basket Assembly"
msgstr "Montaje de Cestas"
-
-#. module: stock_picking_batch_collect
-#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_move__sale_ordered_qty
-#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_move_line__sale_ordered_qty
-#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__qty_ordered
-msgid "Ordered Quantity"
-msgstr "Cantidad pedida"
-
-#. module: stock_picking_batch_collect
-#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.view_move_line_batch_operator
-msgid "Ordered"
-msgstr "Pedido"
-
-#. module: stock_picking_batch_collect
-#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_type__collected_check_required
-msgid "Require Collected Lines"
-msgstr "Exigir líneas recogidas"
-
-#. module: stock_picking_batch_collect
-#: model:ir.model.fields,help:stock_picking_batch_collect.field_stock_picking_type__collected_check_required
-msgid ""
-"Transfers of this type that are not in a batch can only be validated once "
-"their lines are marked as collected, following the batch validation "
-"restrictions of the inventory settings."
-msgstr ""
-"Los albaranes de este tipo que no estén en un lote solo se pueden validar "
-"cuando sus líneas estén marcadas como recogidas, según las restricciones de "
-"validación de lotes de los ajustes de inventario."
-
-#. module: stock_picking_batch_collect
-#: model:ir.actions.report,name:stock_picking_batch_collect.action_report_batch_deliveryslip
-msgid "Delivery Slips"
-msgstr "Albaranes"
-
-#. module: stock_picking_batch_collect
-#: model:ir.model,name:stock_picking_batch_collect.model_report_stock_picking_batch_collect_report_batch_deliveryslip
-msgid "Batch Delivery Slips"
-msgstr "Albaranes del lote"
-
-#. module: stock_picking_batch_collect
-#: code:addons/stock_picking_batch_collect/models/stock_picking.py:0
-#, python-format
-msgid ""
-"You must mark the operations of %(picking)s as collected before validating it.\n"
-"Pending products: %(products)s"
-msgstr ""
-"Hay que marcar como recogidas las operaciones de %(picking)s antes de validarlo.\n"
-"Productos pendientes: %(products)s"
diff --git a/stock_picking_batch_collect/i18n/eu.po b/stock_picking_batch_collect/i18n/eu.po
index b0de814..62cd2c9 100644
--- a/stock_picking_batch_collect/i18n/eu.po
+++ b/stock_picking_batch_collect/i18n/eu.po
@@ -62,7 +62,6 @@ msgid "Batch Transfer"
msgstr "Lote-transferentzia"
#. module: stock_picking_batch_collect
-#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_move__is_collected
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_move_line__is_collected
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__is_collected
msgid "Collected"
@@ -234,51 +233,3 @@ msgstr ""
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.view_stock_picking_batch_form_inherit_summary
msgid "Basket Assembly"
msgstr "Saskien Prestaketa"
-
-#. module: stock_picking_batch_collect
-#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_move__sale_ordered_qty
-#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_move_line__sale_ordered_qty
-#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__qty_ordered
-msgid "Ordered Quantity"
-msgstr "Eskaeraren kantitatea"
-
-#. module: stock_picking_batch_collect
-#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.view_move_line_batch_operator
-msgid "Ordered"
-msgstr "Eskatua"
-
-#. module: stock_picking_batch_collect
-#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_type__collected_check_required
-msgid "Require Collected Lines"
-msgstr "Jasotako lerroak eskatu"
-
-#. module: stock_picking_batch_collect
-#: model:ir.model.fields,help:stock_picking_batch_collect.field_stock_picking_type__collected_check_required
-msgid ""
-"Transfers of this type that are not in a batch can only be validated once "
-"their lines are marked as collected, following the batch validation "
-"restrictions of the inventory settings."
-msgstr ""
-"Lote batean ez dauden mota honetako transferentziak beren lerroak jasota "
-"gisa markatuta daudenean bakarrik balida daitezke, inbentarioaren "
-"ezarpenetako loteen balidazio-murrizketen arabera."
-
-#. module: stock_picking_batch_collect
-#: model:ir.actions.report,name:stock_picking_batch_collect.action_report_batch_deliveryslip
-msgid "Delivery Slips"
-msgstr "Entrega-albaranak"
-
-#. module: stock_picking_batch_collect
-#: model:ir.model,name:stock_picking_batch_collect.model_report_stock_picking_batch_collect_report_batch_deliveryslip
-msgid "Batch Delivery Slips"
-msgstr "Loteko entrega-albaranak"
-
-#. module: stock_picking_batch_collect
-#: code:addons/stock_picking_batch_collect/models/stock_picking.py:0
-#, python-format
-msgid ""
-"You must mark the operations of %(picking)s as collected before validating it.\n"
-"Pending products: %(products)s"
-msgstr ""
-"%(picking)s balidatu aurretik, bere eragiketak jasota gisa markatu behar dira.\n"
-"Zain dauden produktuak: %(products)s"
diff --git a/stock_picking_batch_collect/migrations/18.0.2.1.0/post-migration.py b/stock_picking_batch_collect/migrations/18.0.2.1.0/post-migration.py
deleted file mode 100644
index d46ffbc..0000000
--- a/stock_picking_batch_collect/migrations/18.0.2.1.0/post-migration.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2026 Criptomart
-# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-
-from odoo import SUPERUSER_ID
-from odoo import api
-
-
-def migrate(cr, version):
- """Fill the new ordered quantity of the open batches' product summary."""
- env = api.Environment(cr, SUPERUSER_ID, {})
- batches = env["stock.picking.batch"].search(
- [("state", "in", ("draft", "in_progress"))]
- )
- env.add_to_compute(env["stock.picking.batch"]._fields["summary_line_ids"], batches)
- batches.flush_recordset(["summary_line_ids"])
diff --git a/stock_picking_batch_collect/models/__init__.py b/stock_picking_batch_collect/models/__init__.py
index 08ec35b..5b85812 100644
--- a/stock_picking_batch_collect/models/__init__.py
+++ b/stock_picking_batch_collect/models/__init__.py
@@ -1,8 +1,6 @@
from . import res_company # noqa: F401
from . import res_config_settings # noqa: F401
from . import stock_backorder_confirmation # noqa: F401
-from . import stock_move # noqa: F401
from . import stock_move_line # noqa: F401
from . import stock_picking # noqa: F401
from . import stock_picking_batch # noqa: F401
-from . import stock_picking_type # noqa: F401
diff --git a/stock_picking_batch_collect/models/stock_backorder_confirmation.py b/stock_picking_batch_collect/models/stock_backorder_confirmation.py
index 6c2067a..2236e4f 100644
--- a/stock_picking_batch_collect/models/stock_backorder_confirmation.py
+++ b/stock_picking_batch_collect/models/stock_backorder_confirmation.py
@@ -7,15 +7,17 @@ from odoo import models
class StockBackorderConfirmation(models.TransientModel):
_inherit = "stock.backorder.confirmation"
- def _check_collected_products(self):
- self.env["stock.picking"].browse(
+ def _check_batch_summary_lines(self):
+ pickings = self.env["stock.picking"].browse(
self.env.context.get("button_validate_picking_ids", [])
- )._check_collected_products()
+ )
+ for batch in pickings.batch_id:
+ batch._check_all_products_collected(pickings)
def process(self):
- self._check_collected_products()
+ self._check_batch_summary_lines()
return super().process()
def process_cancel_backorder(self):
- self._check_collected_products()
+ self._check_batch_summary_lines()
return super().process_cancel_backorder()
diff --git a/stock_picking_batch_collect/models/stock_move.py b/stock_picking_batch_collect/models/stock_move.py
deleted file mode 100644
index 14e4554..0000000
--- a/stock_picking_batch_collect/models/stock_move.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright 2026 Criptomart
-# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-
-from odoo import api
-from odoo import fields
-from odoo import models
-
-
-class StockMove(models.Model):
- _inherit = "stock.move"
-
- is_collected = fields.Boolean(
- string="Collected",
- compute="_compute_is_collected",
- inverse="_inverse_is_collected",
- )
- sale_ordered_qty = fields.Float(
- string="Ordered Quantity",
- digits="Product Unit of Measure",
- compute="_compute_sale_ordered_qty",
- )
-
- @api.depends("move_line_ids.is_collected")
- def _compute_is_collected(self):
- for move in self:
- lines = move.move_line_ids
- move.is_collected = bool(lines) and all(lines.mapped("is_collected"))
-
- def _inverse_is_collected(self):
- collected = self.filtered("is_collected")
- collected.move_line_ids.filtered(
- lambda line: not line.is_collected
- ).is_collected = True
- (self - collected).move_line_ids.filtered("is_collected").is_collected = False
-
- @api.depends(
- "product_id",
- "product_uom",
- "sale_line_id.product_id",
- "sale_line_id.product_uom",
- "sale_line_id.product_uom_qty",
- )
- def _compute_sale_ordered_qty(self):
- """What the customer ordered, which the weighed demand overwrites.
-
- Kit components carry the kit's sale line, whose quantity is not theirs.
- """
- for move in self:
- line = move.sale_line_id
- if line and line.product_id == move.product_id and move.product_uom:
- move.sale_ordered_qty = line.product_uom._compute_quantity(
- line.product_uom_qty, move.product_uom, round=False
- )
- else:
- move.sale_ordered_qty = 0.0
diff --git a/stock_picking_batch_collect/models/stock_move_line.py b/stock_picking_batch_collect/models/stock_move_line.py
index 012813f..c87320a 100644
--- a/stock_picking_batch_collect/models/stock_move_line.py
+++ b/stock_picking_batch_collect/models/stock_move_line.py
@@ -1,7 +1,6 @@
# Copyright 2026 Criptomart
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-from odoo import api
from odoo import fields
from odoo import models
@@ -36,23 +35,6 @@ class StockMoveLine(models.Model):
copy=False,
)
- sale_ordered_qty = fields.Float(
- string="Ordered Quantity",
- digits="Product Unit of Measure",
- compute="_compute_sale_ordered_qty",
- )
-
- @api.depends("move_id.sale_ordered_qty", "move_id.product_uom", "product_uom_id")
- def _compute_sale_ordered_qty(self):
- for line in self:
- move = line.move_id
- if move.sale_ordered_qty and line.product_uom_id:
- line.sale_ordered_qty = move.product_uom._compute_quantity(
- move.sale_ordered_qty, line.product_uom_id, round=False
- )
- else:
- line.sale_ordered_qty = 0.0
-
def write(self, vals):
res = super().write(vals)
if vals.get("is_collected"):
diff --git a/stock_picking_batch_collect/models/stock_picking.py b/stock_picking_batch_collect/models/stock_picking.py
index ed1b66a..1cb06ef 100644
--- a/stock_picking_batch_collect/models/stock_picking.py
+++ b/stock_picking_batch_collect/models/stock_picking.py
@@ -2,7 +2,6 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models
-from odoo.exceptions import UserError
class StockPicking(models.Model):
@@ -20,68 +19,21 @@ class StockPicking(models.Model):
if res is not True:
return res
- self._check_collected_products()
+ self._check_batch_collected_products()
return res
- def _get_open_move_lines(self, scope):
- """Move lines still to process; ``processed`` keeps those with quantity."""
- lines = self.move_line_ids.filtered(
- lambda line: line.move_id.state not in ("cancel", "done")
- and line.product_id
- )
- if scope == "processed":
- lines = lines.filtered(lambda line: line.move_id.quantity > 0)
- return lines
-
- def _get_not_collected_move_lines(self, scope):
- return self._get_open_move_lines(scope).filtered(
- lambda line: not line.is_collected
- )
-
- def _check_collected_products(self):
+ def _check_batch_collected_products(self):
for batch in self.batch_id:
batch_pickings = self.filtered(
lambda picking, batch=batch: picking.batch_id == batch
)
- if batch_pickings._get_open_move_lines("processed"):
- batch._check_all_products_collected(batch_pickings)
-
- loose_pickings = self.filtered(
- lambda picking: not picking.batch_id
- and picking.picking_type_id.collected_check_required
- )
- for picking in loose_pickings:
- if picking._get_open_move_lines("processed"):
- picking._check_picking_collected()
-
- def _check_picking_collected(self):
- """Apply the batch restrictions to a transfer outside a batch.
-
- A single transfer has no product summary: the toggle of its Operations
- tab collects every line of the product, so both restrictions check its
- move lines, with the widest scope enabled.
- """
- self.ensure_one()
- company = self.company_id
- scopes = set()
- if company.batch_detailed_restriction_enabled:
- scopes.add(company.batch_detailed_restriction_scope)
- if company.batch_summary_restriction_enabled:
- scopes.add(company.batch_summary_restriction_scope)
- if not scopes:
- return
- scope = "all" if "all" in scopes else "processed"
- not_collected = self._get_not_collected_move_lines(scope)
- if not not_collected:
- return
- product_names = ", ".join(
- sorted(set(not_collected.mapped("product_id.display_name")))
- )
- raise UserError(
- self.env._(
- "You must mark the operations of %(picking)s as collected "
- "before validating it.\nPending products: %(products)s",
- picking=self.name,
- products=product_names,
+ processed_move_lines = batch_pickings.move_line_ids.filtered(
+ lambda line: (
+ line.move_id.state not in ("cancel", "done")
+ and line.product_id
+ and line.move_id.quantity > 0
+ )
)
- )
+ if not processed_move_lines:
+ continue
+ batch._check_all_products_collected(batch_pickings)
diff --git a/stock_picking_batch_collect/models/stock_picking_batch.py b/stock_picking_batch_collect/models/stock_picking_batch.py
index d362c42..553796a 100644
--- a/stock_picking_batch_collect/models/stock_picking_batch.py
+++ b/stock_picking_batch_collect/models/stock_picking_batch.py
@@ -25,12 +25,10 @@ class StockPickingBatch(models.Model):
"move_line_ids.move_id.quantity",
"move_line_ids.move_id.product_uom",
"move_line_ids.move_id.state",
- "move_line_ids.move_id.sale_line_id.product_uom_qty",
)
def _compute_summary_line_ids(self):
"""Aggregate move quantities per product and keep collected flag.
- - Ordered: sale line quantity converted to product UoM, once per line.
- Demand: move.product_uom_qty converted to product UoM.
- Done: move.quantity converted to product UoM.
- Pending: demand - done.
@@ -51,7 +49,6 @@ class StockPickingBatch(models.Model):
}
# Use regular dict to avoid accidental creation of empty entries
aggregates = {}
- counted_sale_lines = set()
# Demand per move (count once per move)
for move in batch.move_ids:
@@ -66,22 +63,10 @@ class StockPickingBatch(models.Model):
aggregates[product.id] = {
"product_id": product.id,
"product_uom_id": product_uom.id,
- "qty_ordered": 0.0,
"qty_demanded": 0.0,
"qty_done": 0.0,
}
aggregates[product.id]["qty_demanded"] += demand
- if move.sale_ordered_qty and move.sale_line_id.id not in (
- counted_sale_lines
- ):
- counted_sale_lines.add(move.sale_line_id.id)
- aggregates[product.id][
- "qty_ordered"
- ] += move.product_uom._compute_quantity(
- move.sale_ordered_qty,
- product_uom,
- rounding_method="HALF-UP",
- )
# Done per move line
for line in batch.move_line_ids:
@@ -99,7 +84,6 @@ class StockPickingBatch(models.Model):
aggregates[product.id] = {
"product_id": product.id,
"product_uom_id": product_uom.id,
- "qty_ordered": 0.0,
"qty_demanded": 0.0,
"qty_done": 0.0,
}
@@ -124,7 +108,6 @@ class StockPickingBatch(models.Model):
existing_line.id,
{
"product_uom_id": values["product_uom_id"],
- "qty_ordered": values["qty_ordered"],
"qty_demanded": values["qty_demanded"],
"qty_done": values["qty_done"],
"is_collected": is_collected,
@@ -139,7 +122,6 @@ class StockPickingBatch(models.Model):
{
"product_id": values["product_id"],
"product_uom_id": values["product_uom_id"],
- "qty_ordered": values["qty_ordered"],
"qty_demanded": values["qty_demanded"],
"qty_done": values["qty_done"],
"is_collected": is_collected,
@@ -169,16 +151,30 @@ class StockPickingBatch(models.Model):
def _get_not_collected_summary_lines(self, batch_pickings, scope):
summary_lines = self.summary_line_ids
if scope == "processed":
- processed_products = batch_pickings._get_open_move_lines(
- "processed"
- ).product_id
+ processed_product_ids = set(
+ batch_pickings.move_line_ids.filtered(
+ lambda line: (
+ line.move_id.state not in ("cancel", "done")
+ and line.product_id
+ and line.move_id.quantity > 0
+ )
+ ).mapped("product_id.id")
+ )
summary_lines = summary_lines.filtered(
- lambda line: line.product_id in processed_products
+ lambda line: line.product_id.id in processed_product_ids
)
return summary_lines.filtered(lambda line: not line.is_collected)
def _get_not_collected_detailed_lines(self, batch_pickings, scope):
- return batch_pickings._get_not_collected_move_lines(scope)
+ detailed_lines = batch_pickings.move_line_ids.filtered(
+ lambda line: line.move_id.state not in ("cancel", "done")
+ and line.product_id
+ )
+ if scope == "processed":
+ detailed_lines = detailed_lines.filtered(
+ lambda line: line.move_id.quantity > 0
+ )
+ return detailed_lines.filtered(lambda line: not line.is_collected)
def _check_all_products_collected(self, pickings=None):
"""Validate collected restrictions based on tab configuration."""
@@ -289,11 +285,6 @@ class StockPickingBatchSummaryLine(models.Model):
string="Unit of Measure",
required=True,
)
- qty_ordered = fields.Float(
- string="Ordered Quantity",
- digits="Product Unit of Measure",
- default=0.0,
- )
qty_demanded = fields.Float(
string="Demanded Quantity",
digits="Product Unit of Measure",
diff --git a/stock_picking_batch_collect/models/stock_picking_type.py b/stock_picking_batch_collect/models/stock_picking_type.py
deleted file mode 100644
index 9b5ff5b..0000000
--- a/stock_picking_batch_collect/models/stock_picking_type.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2026 Criptomart
-# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-
-from odoo import fields
-from odoo import models
-
-
-class StockPickingType(models.Model):
- _inherit = "stock.picking.type"
-
- collected_check_required = fields.Boolean(
- string="Require Collected Lines",
- help="Transfers of this type that are not in a batch can only be "
- "validated once their lines are marked as collected, following the "
- "batch validation restrictions of the inventory settings.",
- )
diff --git a/stock_picking_batch_collect/readme/CONFIGURE.rst b/stock_picking_batch_collect/readme/CONFIGURE.rst
index 100fd1a..bda97fc 100644
--- a/stock_picking_batch_collect/readme/CONFIGURE.rst
+++ b/stock_picking_batch_collect/readme/CONFIGURE.rst
@@ -21,17 +21,6 @@ Cada restricción tiene un alcance:
mayor que cero (por defecto).
- *Todas*: se comprueban todas las líneas del lote, procesadas o no.
-Albaranes fuera de un lote
---------------------------
-
-Para exigir los checks también en los albaranes sueltos, marcar **Exigir líneas
-recogidas** en el tipo de operación (**Inventory > Configuration > Operation
-Types**, p. ej. *Delivery Orders*). Viene desactivado: sin él, los albaranes
-sueltos de ese tipo se validan como siempre.
-
-Un albarán suelto no tiene resumen por producto, así que las dos restricciones
-comprueban sus líneas; si alguna usa el alcance *Todas*, se aplica ese.
-
Columnas
--------
diff --git a/stock_picking_batch_collect/readme/DESCRIPTION.rst b/stock_picking_batch_collect/readme/DESCRIPTION.rst
index 74012d7..dc348e7 100644
--- a/stock_picking_batch_collect/readme/DESCRIPTION.rst
+++ b/stock_picking_batch_collect/readme/DESCRIPTION.rst
@@ -15,15 +15,6 @@ producto y una vista a pantalla completa para el almacén.
cantidades grandes y controles táctiles, pensada para tablet en el almacén.
- Restricciones de validación configurables por compañía: el lote no se puede
validar hasta que las líneas estén marcadas como recogidas.
-- Los mismos checks en los albaranes sueltos (fuera de un lote), activables por
- tipo de operación.
-- Columna **Cantidad pedida** (``sale_ordered_qty``), de sólo lectura, con lo
- que pidió el cliente en el pedido de venta. Al teclear el peso real la demanda
- del movimiento se ajusta a lo pesado, así que esta columna es la que permite
- 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
- resumen por producto del lote, y en el albarán.
-- 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
(salvo ``product_default_code``, oculta por defecto), de modo que el usuario
diff --git a/stock_picking_batch_collect/readme/USAGE.rst b/stock_picking_batch_collect/readme/USAGE.rst
index 8caafd5..73eea25 100644
--- a/stock_picking_batch_collect/readme/USAGE.rst
+++ b/stock_picking_batch_collect/readme/USAGE.rst
@@ -27,16 +27,3 @@ Uso
las líneas estén recogidas y se avisa con la lista de productos pendientes.
La comprobación se ejecuta después de resolver el backorder, de modo que
sólo bloquea sobre las líneas que realmente se van a procesar.
-
-8. En un albarán suelto, la pestaña **Operations** tiene un check
- **Collected** por producto, que marca todas sus líneas; las operaciones
- detalladas lo tienen por línea. Si su tipo de operación lo exige, el
- albarán no se valida hasta marcarlos.
-
-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
- producto del lote es la suma de los pedidos.
-
-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
- cliente.
diff --git a/stock_picking_batch_collect/report/__init__.py b/stock_picking_batch_collect/report/__init__.py
deleted file mode 100644
index dfbb06d..0000000
--- a/stock_picking_batch_collect/report/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from . import report_batch_deliveryslip # noqa: F401
diff --git a/stock_picking_batch_collect/report/report_batch_deliveryslip.py b/stock_picking_batch_collect/report/report_batch_deliveryslip.py
deleted file mode 100644
index c1e57f4..0000000
--- a/stock_picking_batch_collect/report/report_batch_deliveryslip.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# Copyright 2026 Criptomart
-# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-
-from odoo import api
-from odoo import models
-
-
-class ReportBatchDeliverySlip(models.AbstractModel):
- _name = "report.stock_picking_batch_collect.report_batch_deliveryslip"
- _description = "Batch Delivery Slips"
-
- @api.model
- def _get_report_values(self, docids, data=None):
- batches = self.env["stock.picking.batch"].browse(docids)
- pickings = self.env["stock.picking"]
- for batch in batches:
- pickings |= batch.picking_ids.filtered(
- lambda picking: picking.state != "cancel"
- ).sorted(lambda picking: (picking.partner_id.name or "", picking.name))
- return {
- "doc_ids": docids,
- "doc_model": "stock.picking.batch",
- "docs": batches,
- "pickings": pickings,
- }
diff --git a/stock_picking_batch_collect/report/report_batch_deliveryslip.xml b/stock_picking_batch_collect/report/report_batch_deliveryslip.xml
deleted file mode 100644
index 91b6a74..0000000
--- a/stock_picking_batch_collect/report/report_batch_deliveryslip.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
- Delivery Slips
- stock.picking.batch
- qweb-pdf
- stock_picking_batch_collect.report_batch_deliveryslip
- stock_picking_batch_collect.report_batch_deliveryslip
- 'Delivery Slips - %s' % object.name
-
- report
-
-
-
-
-
-
-
-
diff --git a/stock_picking_batch_collect/tests/__init__.py b/stock_picking_batch_collect/tests/__init__.py
index ba5d668..a586ed8 100644
--- a/stock_picking_batch_collect/tests/__init__.py
+++ b/stock_picking_batch_collect/tests/__init__.py
@@ -1,3 +1,2 @@
from . import test_batch_summary # noqa: F401
from . import test_collected_picked # noqa: F401
-from . import test_picking_collected # noqa: F401
diff --git a/stock_picking_batch_collect/tests/test_picking_collected.py b/stock_picking_batch_collect/tests/test_picking_collected.py
deleted file mode 100644
index 30bfbc3..0000000
--- a/stock_picking_batch_collect/tests/test_picking_collected.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# Copyright 2026 Criptomart
-# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-
-from odoo import Command
-from odoo.exceptions import UserError
-from odoo.tests import TransactionCase
-from odoo.tests import tagged
-
-
-@tagged("-at_install", "post_install")
-class TestPickingCollected(TransactionCase):
- """Collected checks and ordered quantities on transfers outside a batch."""
-
- @classmethod
- def setUpClass(cls):
- super().setUpClass()
- cls.stock_location = cls.env.ref("stock.stock_location_stock")
- cls.picking_type_out = cls.env.ref("stock.picking_type_out")
- cls.picking_type_out.collected_check_required = True
- cls.env.company.write(
- {
- "batch_detailed_restriction_enabled": True,
- "batch_detailed_restriction_scope": "processed",
- "batch_summary_restriction_enabled": False,
- }
- )
- kg = cls.env.ref("uom.product_uom_kgm")
- cls.product = cls.env["product.product"].create(
- {
- "name": "Collected Pears",
- "is_storable": True,
- "uom_id": kg.id,
- "uom_po_id": kg.id,
- }
- )
- cls.env["stock.quant"]._update_available_quantity(
- cls.product, cls.stock_location, 50.0
- )
- cls.partner = cls.env["res.partner"].create({"name": "Pear Lover"})
-
- def _create_sale_picking(self, qty=2.0):
- order = self.env["sale.order"].create(
- {
- "partner_id": self.partner.id,
- "order_line": [
- Command.create(
- {"product_id": self.product.id, "product_uom_qty": qty}
- )
- ],
- }
- )
- order.action_confirm()
- picking = order.picking_ids
- picking.action_assign()
- return picking
-
- def test_loose_picking_blocks_until_collected(self):
- picking = self._create_sale_picking()
-
- with self.assertRaisesRegex(UserError, self.product.display_name):
- picking.button_validate()
-
- picking.move_ids.is_collected = True
- picking.button_validate()
-
- self.assertEqual(picking.state, "done")
-
- def test_picking_type_without_check_is_not_blocked(self):
- self.picking_type_out.collected_check_required = False
- picking = self._create_sale_picking()
-
- picking.button_validate()
-
- self.assertEqual(picking.state, "done")
-
- def test_batch_picking_follows_the_batch_restriction(self):
- """The batch summary flag is not required by the loose transfer check."""
- self.env.company.batch_summary_restriction_enabled = True
- picking = self._create_sale_picking()
- batch = self.env["stock.picking.batch"].create(
- {"picking_ids": [Command.set(picking.ids)]}
- )
- batch.action_confirm()
- picking.move_ids.is_collected = True
-
- with self.assertRaisesRegex(UserError, "product summary"):
- batch.action_done()
-
- def test_collecting_the_move_collects_its_lines(self):
- picking = self._create_sale_picking()
- move = picking.move_ids
- self.assertFalse(move.is_collected)
-
- move.is_collected = True
-
- self.assertTrue(all(move.move_line_ids.mapped("is_collected")))
- self.assertTrue(move.picked)
-
- move.move_line_ids.is_collected = False
-
- self.assertFalse(move.is_collected)
-
- def test_ordered_quantity_survives_weighing(self):
- picking = self._create_sale_picking(2.0)
- move = picking.move_ids
-
- move.move_line_ids.write({"quantity": 1.5, "picked": True})
-
- self.assertEqual(move.product_uom_qty, 1.5)
- self.assertEqual(move.sale_ordered_qty, 2.0)
- self.assertEqual(move.move_line_ids.sale_ordered_qty, 2.0)
-
- def test_batch_summary_ordered_quantity(self):
- pickings = self._create_sale_picking(2.0) | self._create_sale_picking(3.0)
- batch = self.env["stock.picking.batch"].create(
- {"picking_ids": [Command.set(pickings.ids)]}
- )
- pickings[0].move_ids.move_line_ids.write({"quantity": 1.5, "picked": True})
-
- batch._compute_summary_line_ids()
-
- line = batch.summary_line_ids
- self.assertEqual(line.qty_ordered, 5.0)
- self.assertEqual(line.qty_demanded, 4.5)
-
- def test_report_prints_every_delivery_slip(self):
- pickings = self._create_sale_picking(2.0) | self._create_sale_picking(3.0)
- batch = self.env["stock.picking.batch"].create(
- {"picking_ids": [Command.set(pickings.ids)]}
- )
-
- html, _report_format = self.env["ir.actions.report"]._render_qweb_html(
- "stock_picking_batch_collect.report_batch_deliveryslip", batch.ids
- )
-
- for picking in pickings:
- self.assertIn(picking.name, html.decode())
diff --git a/stock_picking_batch_collect/views/stock_picking_batch_views.xml b/stock_picking_batch_collect/views/stock_picking_batch_views.xml
index 5918306..38c8d70 100644
--- a/stock_picking_batch_collect/views/stock_picking_batch_views.xml
+++ b/stock_picking_batch_collect/views/stock_picking_batch_views.xml
@@ -9,7 +9,6 @@
-
@@ -31,7 +30,6 @@
context="{'display_default_code': False}"/>
-
@@ -80,9 +78,6 @@
-
-
-
@@ -105,15 +100,4 @@
-
- stock_picking_batch.picking.move.list.collect
- stock.move
-
-
-
-
-
-
-
-
diff --git a/stock_picking_batch_collect/views/stock_picking_views.xml b/stock_picking_batch_collect/views/stock_picking_views.xml
deleted file mode 100644
index 80ef434..0000000
--- a/stock_picking_batch_collect/views/stock_picking_views.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-
-
-
- stock.picking.form.collect
- stock.picking
-
-
-
-
-
-
-
-
-
-
-
-
- stock.move.line.operations.list.collect
- stock.move.line
-
-
-
-
-
-
-
-
-
-
-
-
- stock.move.line.operations.list.popup.collect
- stock.move.line
-
-
-
-
-
-
-
-
-
- stock.picking.type.form.collect
- stock.picking.type
-
-
-
-
-
-
-
-