[REF] stock_picking_batch_collect: rename and drop the aplicoop dependency

"custom" said nothing about what the module does. It is really about collecting
goods into baskets: the extra detailed-operation columns, the is_collected flag,
the Product Summary tab, the per-company validation restrictions and the
Basket Assembly operator view all serve that one job. Rename it accordingly.

Invert the dependency while at it. A generic warehouse addon was dragging in an
entire eCommerce application, and the whole coupling was a single field:
stock.move.line.home_delivery, related to picking_id.home_delivery. Everything
else was already duck-typed. website_sale_aplicoop now depends on this module
and injects its own consumer group columns into these views.

This removes duplicated logic rather than relocating it: stock.picking
.batch_consumer_group_id re-derived from sale_id a value aplicoop already stored
as stock.picking.consumer_group_id, and the duplicate carried no @api.depends,
so it never recomputed reliably. The batch transfers list now shows the stored
field, which is sortable and groupable.

The two aplicoop tests that probed information_schema for the res_company
batch_* columns can drop that guard: a real dependency guarantees them.

Renaming an addon is not something a migrations/ script can do, since a renamed
addon is a brand new module to Odoo and its migration scripts never run. A
pre_init_hook does it instead: it fires on install after the Python is imported
but before registry.load(), which is the window where remapping ir_model_data
makes Odoo reuse the existing tables and columns. is_collected, the summary line
table and the company settings all survive untouched.

Two details the hook has to get right:

- ir_model_constraint.module and ir_model_relation.module are integer FKs with
  ON DELETE CASCADE, so they must be repointed before the old module row is
  deleted or the bookkeeping goes with it.
- Deleting an ir_model_data row does not cascade to the record it points at.
  Artifacts handed over to aplicoop only need the xmlid dropped, but artifacts
  that disappear need the record deleted too, or the field survives as an orphan
  manual field and the view as a custom view referencing it.

Verified against a restored copy of the dev database: 50 xmlids moved, 19 summary
lines and 5 collected move lines preserved, no orphans, both test suites green,
and the module installs cleanly on a database without website_sale_aplicoop.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
GitHub Copilot 2026-08-27 14:26:47 +02:00
parent 704f0def1b
commit ef1283be7c
42 changed files with 926 additions and 709 deletions

View file

@ -189,9 +189,11 @@ addons-cm/
├── membership_monthly_invoicing/ # Factura mensual de membresía por socio (cron) ├── membership_monthly_invoicing/ # Factura mensual de membresía por socio (cron)
├── membership_expiry_reminder/ # Email recordatorio de renovación próxima ├── membership_expiry_reminder/ # Email recordatorio de renovación próxima
├── # --- Logística y contabilidad --- ├── # --- Logística y contabilidad ---
├── stock_picking_batch_custom/ # Batch picking: columnas extra + vista operario (Basket Assembly) ├── stock_picking_batch_collect/ # Batch picking: columnas extra + vista operario (Basket Assembly)
├── account_banking_mandate_batch/ # Crear/validar mandatos SEPA en bloque desde contactos ├── account_banking_mandate_batch/ # Crear/validar mandatos SEPA en bloque desde contactos
└── l10n_es_edi_tbai_reagyp_recibidas/ # Fix TicketBAI REAGYP facturas recibidas (19 → 02) ├── l10n_es_edi_tbai_reagyp_recibidas/ # Fix TicketBAI REAGYP facturas recibidas (19 → 02)
├── # --- UI de backend ---
└── web_list_striped/ # Efecto cebra en todas las listas del backend (sólo CSS)
```` ````
@ -233,7 +235,8 @@ addons-cm/
**Logística y contabilidad** **Logística y contabilidad**
- [stock_picking_batch_custom](../stock_picking_batch_custom/README.rst) - Columnas extra y vista operario para batch picking - [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 - [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) - [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)
@ -758,6 +761,10 @@ 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-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
extrae al nuevo addon `web_list_striped`. El renombrado en BD lo hace un `pre_init_hook`.
- **2026-06**: `stock_picking_batch_custom` — vista operario a pantalla completa (Basket Assembly), - **2026-06**: `stock_picking_batch_custom` — vista operario a pantalla completa (Basket Assembly),
ordenación de operaciones por categoría/producto/partner. ordenación de operaciones por categoría/producto/partner.
- **2026-02-18**: Refactor `product_main_seller` - Remover alias innecesario `default_supplier_id` - **2026-02-18**: Refactor `product_main_seller` - Remover alias innecesario `default_supplier_id`

View file

@ -27,8 +27,9 @@ Addons desarrollados por Criptomart para necesidades específicas del proyecto.
| [product_price_category_supplier](product_price_category_supplier/) | 18.0.1.0.0 | Categoría de precio por defecto en proveedor + actualización masiva de productos | | [product_price_category_supplier](product_price_category_supplier/) | 18.0.1.0.0 | Categoría de precio por defecto en proveedor + actualización masiva de productos |
| [product_pricelist_total_margin](product_pricelist_total_margin/) | 18.0.1.2.0 | Margen aditivo (no compuesto) en tarifas encadenadas, con límites globales | | [product_pricelist_total_margin](product_pricelist_total_margin/) | 18.0.1.2.0 | Margen aditivo (no compuesto) en tarifas encadenadas, con límites globales |
| [product_sale_price_from_pricelist](product_sale_price_from_pricelist/) | 18.0.2.7.0 | Calcula precio de venta desde último precio de compra vía tarifa configurable | | [product_sale_price_from_pricelist](product_sale_price_from_pricelist/) | 18.0.2.7.0 | Calcula precio de venta desde último precio de compra vía tarifa configurable |
| [stock_picking_batch_custom](stock_picking_batch_custom/) | 18.0.1.0.0 | Columnas extra en operaciones detalladas de lotes: partner, categoría, recogido | | [stock_picking_batch_collect](stock_picking_batch_collect/) | 18.0.2.0.0 | Montaje de cestas en lotes: columnas extra, resumen por producto y vista operario |
| [website_sale_aplicoop](website_sale_aplicoop/) | 18.0.1.9.0 | Sistema de pedidos colaborativos para grupos de consumo (reemplazo de Aplicoop) | | [web_list_striped](web_list_striped/) | 18.0.1.0.0 | Efecto cebra y hover suave en todas las listas del backend (sólo CSS) |
| [website_sale_aplicoop](website_sale_aplicoop/) | 18.0.1.17.0 | Sistema de pedidos colaborativos para grupos de consumo (reemplazo de Aplicoop) |
## Dependencias entre addons custom ## Dependencias entre addons custom
@ -40,6 +41,12 @@ website_sale_aplicoop
└── product_main_seller └── product_main_seller
└── product_price_category_supplier └── product_price_category_supplier
└── product_price_category └── product_price_category
└── stock_picking_batch_collect
└── stock_move_manual_quantity
stock_picking_batch_collect
└── stock_move_manual_quantity
└── stock_picking_batch (Odoo core)
account_invoice_triple_discount_readonly account_invoice_triple_discount_readonly
└── account_invoice_triple_discount └── account_invoice_triple_discount

View file

@ -0,0 +1,127 @@
===========================
Stock Picking Batch Collect
===========================
Visión general
==============
Este módulo convierte un lote de picking en una hoja de trabajo para el operario
que monta las cestas: amplía las operaciones detalladas, añade un resumen por
producto y una vista a pantalla completa para el almacén.
- ``picking_partner_id`` (Partner del albarán) para que el personal de almacén
identifique rápido el cliente/proveedor.
- ``product_categ_id`` (Categoría de producto) para ordenar y agrupar. Las
líneas del lote se ordenan por categoría, producto y partner.
- ``product_default_code`` (Referencia interna) como columna opcional.
- ``is_collected`` (Recogido) como check manual en cada línea para marcar si se
ha recolectado.
- Nueva pestaña **Product Summary** con totales por producto (demandado, hecho,
pendiente), categoría y el check de recogido consolidado.
- Botón **Basket Assembly**: una vista de lista a pantalla completa, con
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.
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
puede desactivarlas desde el selector de columnas sin recargar la vista.
Si además está instalado ``website_sale_aplicoop``, ese módulo añade a estas
mismas vistas las columnas de grupo de consumo (**Consumer Group** y **Home
Delivery**). Este módulo no depende de él: funciona igual sin la parte de
eCommerce.
Instalación
===========
Actualizar o instalar el módulo:
::
docker-compose run --rm odoo odoo -d odoo --stop-after-init -u stock_picking_batch_collect
Este módulo sustituye a ``stock_picking_batch_custom``. Al instalarlo sobre una
base de datos que tuviera el módulo antiguo, un ``pre_init_hook`` adopta sus
datos (ver ``hooks.py``): se conservan las líneas recogidas, el resumen por
producto y la configuración por compañía.
Configuración
=============
Restricciones de validación
---------------------------
En **Inventory > Configuration > Settings**, bloque *Operations*, hay dos
ajustes por compañía:
- **Restricciones del resumen de productos**: exige que las líneas de la
pestaña *Product Summary* estén marcadas como recogidas para validar el lote.
Desactivado por defecto (el check es sólo informativo).
- **Restricciones de operaciones detalladas**: exige que las líneas de la
pestaña *Detailed Operations* estén marcadas como recogidas.
**Activado por defecto**: recién instalado el módulo, un lote no se puede
validar hasta marcar las líneas.
Cada restricción tiene un alcance:
- *Sólo procesadas*: se comprueban únicamente las líneas con cantidad hecha
mayor que cero (por defecto).
- *Todas*: se comprueban todas las líneas del lote, procesadas o no.
Columnas
--------
Las columnas están visibles por defecto. Para ajustarlas:
- Abrir un **Lote de picking**.
- Ir a la pestaña **Detailed Operations**.
- Abrir el **selector de columnas** y activar o desactivar *Partner*,
*Product Category*, *Product Code* o *Collected* según necesidad.
Uso
===
1. Accede a **Inventory > Operations > Batch Transfers** y abre un lote.
2. Pestaña **Detailed Operations**: usa el selector de columnas para ajustar:
- **Partner** (``picking_partner_id``) para ver el cliente/proveedor.
- **Product Category** (``product_categ_id``) para ordenar/agrupación por categoría.
- **Collected** (``is_collected``) para marcar manualmente líneas recolectadas.
3. Pestaña **Product Summary**: consulta los totales por producto (demandado,
hecho y pendiente) y marca el check de recogido consolidado si corresponde.
4. Con el lote **en progreso**, el botón **Basket Assembly** abre la vista de
operario: la misma lista de líneas a pantalla completa, con la cantidad en
grande y el check *Collected* como interruptor táctil. Está pensada para
trabajar desde una tablet mientras se montan las cestas.
5. Ordena o agrupa por categoría en cualquiera de las vistas según convenga.
6. La cantidad que teclea el operario (el peso real de la balanza) queda fijada:
se marca como *Picked* y ni el planificador ni la validación de otros
albaranes vuelven a modificarla. Marcar **Collected** protege igualmente la
cantidad de la línea. Ver ``stock_move_manual_quantity``.
7. Al validar el lote, según la configuración de la compañía, se comprueba que
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.
Contribuidores
==============
* Criptomart
Créditos
========
Autor
-----
* Criptomart
Financiador
-----------
* Elika Bilbo

View file

@ -0,0 +1,2 @@
from . import models # noqa: F401
from .hooks import pre_init_hook # noqa: F401

View file

@ -1,10 +1,10 @@
# Copyright 2026 Criptomart # Copyright 2026 Criptomart
# 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 Custom", "name": "Stock Picking Batch Collect",
"version": "18.0.1.0.0", "version": "18.0.2.0.0",
"category": "Warehouse", "category": "Warehouse",
"summary": "Extra columns for batch detailed operations", "summary": "Collect batch operations: operator view, extra columns and product summary",
"author": "Odoo Community Association (OCA), Criptomart", "author": "Odoo Community Association (OCA), Criptomart",
"maintainers": ["Criptomart"], "maintainers": ["Criptomart"],
"website": "https://github.com/Criptomart", "website": "https://github.com/Criptomart",
@ -14,9 +14,6 @@
# re-reserved by the scheduler. # re-reserved by the scheduler.
"stock_move_manual_quantity", "stock_move_manual_quantity",
"stock_picking_batch", "stock_picking_batch",
# Ensure our related fields to sale/picking (home_delivery, pickup_slot_label)
# are available by depending on the Aplicoop website_sale extension.
"website_sale_aplicoop",
], ],
"data": [ "data": [
"security/ir.model.access.csv", "security/ir.model.access.csv",
@ -25,7 +22,10 @@
], ],
"assets": { "assets": {
"web.assets_backend": [ "web.assets_backend": [
"stock_picking_batch_custom/static/src/css/stock_picking_batch.css", "stock_picking_batch_collect/static/src/css/stock_picking_batch.css",
], ],
}, },
# Adopts the data of the former `stock_picking_batch_custom` when upgrading
# a database where that module was installed. See `hooks.py`.
"pre_init_hook": "pre_init_hook",
} }

View file

@ -0,0 +1,117 @@
# Copyright 2026 Criptomart
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
_logger = logging.getLogger(__name__)
OLD_MODULE = "stock_picking_batch_custom"
NEW_MODULE = "stock_picking_batch_collect"
# Fields handed over to `website_sale_aplicoop`, which declares the very same
# ones. Dropping just the xmlid is enough and is what we want: Odoo matches the
# existing row again by (model, name) and re-registers it under aplicoop's
# ownership later in the same run (aplicoop depends on us, so it loads after
# us). Both are non-stored, so no column is touched.
HANDED_OVER = (
"field_stock_move_line__home_delivery",
"field_stock_move_line__consumer_group_id",
)
# Artifacts that disappear for good, because aplicoop already stores the same
# value as `stock.picking.consumer_group_id`. Here the record itself has to go
# too, not only the xmlid: deleting an `ir_model_data` row does not cascade, so
# the field would survive as an orphan manual field and the view as a custom
# view still pointing at it. Mapped as table -> xmlids.
DROPPED = {
"ir_model_fields": ("field_stock_picking__batch_consumer_group_id",),
"ir_ui_view": ("view_stock_picking_batch_picking_tree_consumer_group",),
}
def pre_init_hook(env):
"""Adopt the database records of the former ``stock_picking_batch_custom``.
A renamed addon is a brand new module for Odoo, so a versioned
``migrations/`` script would never run. This hook does instead, on install,
after the Python is imported but before ``registry.load()`` and
``init_models()``: remapping ``ir_model_data`` in that window makes Odoo
reuse the existing tables and columns instead of creating new ones, so
``stock_move_line.is_collected``, the ``stock_picking_batch_summary_line``
table and the ``res_company.batch_*`` settings all survive untouched.
A no-op on a database where the old module was never installed.
"""
cr = env.cr
cr.execute("SELECT id FROM ir_module_module WHERE name = %s", (OLD_MODULE,))
old = cr.fetchone()
if not old:
return
old_id = old[0]
cr.execute("SELECT id FROM ir_module_module WHERE name = %s", (NEW_MODULE,))
new = cr.fetchone()
if not new:
# Should not happen: the module list is refreshed before installing.
_logger.warning("%s: no module row to adopt %s into", NEW_MODULE, OLD_MODULE)
return
new_id = new[0]
_logger.info(
"Adopting %s (id=%s) as %s (id=%s)", OLD_MODULE, old_id, NEW_MODULE, new_id
)
# 1. Hand every xmlid over to the new module name.
cr.execute(
"UPDATE ir_model_data SET module = %s WHERE module = %s",
(NEW_MODULE, OLD_MODULE),
)
_logger.info("Moved %s xmlids to %s", cr.rowcount, NEW_MODULE)
# 2. Give back what is no longer ours, so aplicoop can claim it.
cr.execute(
"DELETE FROM ir_model_data WHERE module = %s AND name IN %s",
(NEW_MODULE, HANDED_OVER),
)
# 3. Drop for good what neither module defines any more, record included.
for table, xmlids in DROPPED.items():
cr.execute(
"DELETE FROM %s WHERE id IN ("
" SELECT res_id FROM ir_model_data"
" WHERE module = %%s AND name IN %%s"
")" % table,
(NEW_MODULE, xmlids),
)
if cr.rowcount:
_logger.info("Dropped %s obsolete row(s) from %s", cr.rowcount, table)
cr.execute(
"DELETE FROM ir_model_data WHERE module = %s AND name IN %s",
(NEW_MODULE, tuple(name for names in DROPPED.values() for name in names)),
)
# 4. `ir_model_constraint.module` and `ir_model_relation.module` are integer
# FKs to `ir_module_module` with ON DELETE CASCADE: they must be
# repointed *before* the old row goes away, or the bookkeeping for our
# SQL constraints is silently destroyed with it.
cr.execute(
"UPDATE ir_model_constraint SET module = %s WHERE module = %s",
(new_id, old_id),
)
cr.execute(
"UPDATE ir_model_relation SET module = %s WHERE module = %s",
(new_id, old_id),
)
# 5. Drop the dependency rows, both ours and any pointing at the old name.
cr.execute(
"DELETE FROM ir_module_module_dependency WHERE module_id = %s OR name = %s",
(old_id, OLD_MODULE),
)
# 6. Finally the module row itself. We delete the *old* one and keep the
# new one: the loader already holds the new row's id in memory, so
# renaming the old row in place would leave Odoo writing to a record
# that no longer exists.
cr.execute("DELETE FROM ir_module_module WHERE id = %s", (old_id,))

View file

@ -0,0 +1,235 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_picking_batch_collect
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 18.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-05-21 13:18+0000\n"
"PO-Revision-Date: 2026-05-21 13:18+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: stock_picking_batch_collect
#: model:ir.model.fields.selection,name:stock_picking_batch_collect.selection__res_company__batch_detailed_restriction_scope__all
msgid "All detailed lines"
msgstr "Todas las líneas detalladas"
#. module: stock_picking_batch_collect
#: model:ir.model.fields.selection,name:stock_picking_batch_collect.selection__res_company__batch_summary_restriction_scope__all
msgid "All summary products"
msgstr "Todos los productos del resumen"
#. module: stock_picking_batch_collect
#: model:ir.model,name:stock_picking_batch_collect.model_stock_backorder_confirmation
msgid "Backorder Confirmation"
msgstr "Confirmación de entrega parcial"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__batch_id
msgid "Batch"
msgstr "Lote"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking__batch_consumer_group_id
msgid "Batch Consumer Group"
msgstr "Grupo de consumidores del lote"
#. module: stock_picking_batch_collect
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.res_config_settings_view_form_inherit_batch_custom
msgid "Batch Detailed Operations Restriction"
msgstr "Restricción de operaciones detalladas del lote"
#. module: stock_picking_batch_collect
#: model:ir.model,name:stock_picking_batch_collect.model_stock_picking_batch_summary_line
msgid "Batch Product Summary Line"
msgstr "Línea de resumen de productos del lote"
#. module: stock_picking_batch_collect
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.res_config_settings_view_form_inherit_batch_custom
msgid "Batch Product Summary Restriction"
msgstr "Restricción del resumen de productos del lote"
#. module: stock_picking_batch_collect
#: model:ir.model,name:stock_picking_batch_collect.model_stock_picking_batch
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_line__is_collected
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__is_collected
msgid "Collected"
msgstr "Recogido"
#. module: stock_picking_batch_collect
#: model:ir.model,name:stock_picking_batch_collect.model_res_company
msgid "Companies"
msgstr "Compañías"
#. module: stock_picking_batch_collect
#: model:ir.model,name:stock_picking_batch_collect.model_res_config_settings
msgid "Config Settings"
msgstr "Ajustes de configuración"
#. module: stock_picking_batch_collect
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.res_config_settings_view_form_inherit_batch_custom
msgid "Configuración de restricciones para la pestaña Operaciones Detalladas."
msgstr ""
"Configuración de restricciones para la pestaña Operaciones Detalladas."
#. module: stock_picking_batch_collect
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.res_config_settings_view_form_inherit_batch_custom
msgid "Configuración de restricciones para la pestaña Product Summary."
msgstr "Configuración de restricciones para la pestaña Resumen de productos."
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_move_line__consumer_group_id
msgid "Consumer Group"
msgstr "Grupo de consumidores"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__create_uid
msgid "Created by"
msgstr "Creado por"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__create_date
msgid "Created on"
msgstr "Creado el"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__qty_demanded
msgid "Demanded Quantity"
msgstr "Cantidad demandada"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_res_company__batch_detailed_restriction_scope
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_res_config_settings__batch_detailed_restriction_scope
msgid "Detailed Operations Restriction Scope"
msgstr "Ámbito de restricción de operaciones detalladas"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__display_name
msgid "Display Name"
msgstr "Nombre mostrado"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__qty_done
msgid "Done Quantity"
msgstr "Cantidad hecha"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_res_company__batch_detailed_restriction_enabled
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_res_config_settings__batch_detailed_restriction_enabled
msgid "Enforce Detailed Operations Restriction"
msgstr "Aplicar restricción de operaciones detalladas"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_res_company__batch_summary_restriction_enabled
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_res_config_settings__batch_summary_restriction_enabled
msgid "Enforce Product Summary Restriction"
msgstr "Aplicar restricción del resumen de productos"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_move_line__home_delivery
msgid "Home Delivery"
msgstr "Entrega a domicilio"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__id
msgid "ID"
msgstr "ID"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__write_uid
msgid "Last Updated by"
msgstr "Última actualización por"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__write_date
msgid "Last Updated on"
msgstr "Última actualización el"
#. module: stock_picking_batch_collect
#: model:ir.model.fields.selection,name:stock_picking_batch_collect.selection__res_company__batch_detailed_restriction_scope__processed
msgid "Only processed lines"
msgstr "Solo líneas procesadas"
#. module: stock_picking_batch_collect
#: model:ir.model.fields.selection,name:stock_picking_batch_collect.selection__res_company__batch_summary_restriction_scope__processed
msgid "Only processed products"
msgstr "Solo productos procesados"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__qty_pending
msgid "Pending Quantity"
msgstr "Cantidad pendiente"
#. module: stock_picking_batch_collect
#. odoo-python
#: code:addons/stock_picking_batch_collect/models/stock_picking_batch.py:0
msgid "Pending products: %(products)s"
msgstr "Productos pendientes: %(products)s"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__product_id
msgid "Product"
msgstr "Producto"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__product_categ_id
msgid "Product Category"
msgstr "Categoría de producto"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_move_line__product_categ_id
msgid "Product Category (Batch)"
msgstr "Categoría de producto (lote)"
#. module: stock_picking_batch_collect
#: model:ir.model,name:stock_picking_batch_collect.model_stock_move_line
msgid "Product Moves (Stock Move Line)"
msgstr "Movimientos de producto (línea de movimiento de stock)"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch__summary_line_ids
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.view_stock_picking_batch_form_inherit_summary
msgid "Product Summary"
msgstr "Resumen de productos"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_res_company__batch_summary_restriction_scope
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_res_config_settings__batch_summary_restriction_scope
msgid "Product Summary Restriction Scope"
msgstr "Ámbito de restricción del resumen de productos"
#. module: stock_picking_batch_collect
#: model:ir.model.constraint,message:stock_picking_batch_collect.constraint_stock_picking_batch_summary_line_product_required
msgid "Product is required for summary lines."
msgstr "El producto es obligatorio en las líneas de resumen."
#. module: stock_picking_batch_collect
#: model:ir.model,name:stock_picking_batch_collect.model_stock_picking
msgid "Transfer"
msgstr "Traslado"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__product_uom_id
msgid "Unit of Measure"
msgstr "Unidad de medida"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,help:stock_picking_batch_collect.field_stock_move_line__home_delivery
msgid "Whether this picking includes home delivery (from sale order)"
msgstr "Si este albarán incluye entrega a domicilio (del pedido de venta)"
#. module: stock_picking_batch_collect
#: 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"

View file

@ -0,0 +1,235 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_picking_batch_collect
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 18.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-05-21 13:21+0000\n"
"PO-Revision-Date: 2026-05-21 13:21+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: eu\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: stock_picking_batch_collect
#: model:ir.model.fields.selection,name:stock_picking_batch_collect.selection__res_company__batch_detailed_restriction_scope__all
msgid "All detailed lines"
msgstr "Lerro xehatu guztiak"
#. module: stock_picking_batch_collect
#: model:ir.model.fields.selection,name:stock_picking_batch_collect.selection__res_company__batch_summary_restriction_scope__all
msgid "All summary products"
msgstr "Laburpeneko produktu guztiak"
#. module: stock_picking_batch_collect
#: model:ir.model,name:stock_picking_batch_collect.model_stock_backorder_confirmation
msgid "Backorder Confirmation"
msgstr "Eskaeraren informazioa"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__batch_id
msgid "Batch"
msgstr "Lotea"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking__batch_consumer_group_id
msgid "Batch Consumer Group"
msgstr "Loteko kontsumitzaile taldea"
#. module: stock_picking_batch_collect
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.res_config_settings_view_form_inherit_batch_custom
msgid "Batch Detailed Operations Restriction"
msgstr "Loteko eragiketa xehatuen murrizketa"
#. module: stock_picking_batch_collect
#: model:ir.model,name:stock_picking_batch_collect.model_stock_picking_batch_summary_line
msgid "Batch Product Summary Line"
msgstr "Loteko produktuen laburpen-lerroa"
#. module: stock_picking_batch_collect
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.res_config_settings_view_form_inherit_batch_custom
msgid "Batch Product Summary Restriction"
msgstr "Loteko produktuen laburpenaren murrizketa"
#. module: stock_picking_batch_collect
#: model:ir.model,name:stock_picking_batch_collect.model_stock_picking_batch
msgid "Batch Transfer"
msgstr "Lote-transferentzia"
#. module: stock_picking_batch_collect
#: 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"
msgstr "Jasota"
#. module: stock_picking_batch_collect
#: model:ir.model,name:stock_picking_batch_collect.model_res_company
msgid "Companies"
msgstr "Enpresak"
#. module: stock_picking_batch_collect
#: model:ir.model,name:stock_picking_batch_collect.model_res_config_settings
msgid "Config Settings"
msgstr "Konfigurazio ezarpenak"
#. module: stock_picking_batch_collect
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.res_config_settings_view_form_inherit_batch_custom
msgid "Configuración de restricciones para la pestaña Operaciones Detalladas."
msgstr "Eragiketa xehatuak fitxarako murrizketen konfigurazioa."
#. module: stock_picking_batch_collect
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.res_config_settings_view_form_inherit_batch_custom
msgid "Configuración de restricciones para la pestaña Product Summary."
msgstr "Produktuen laburpena fitxarako murrizketen konfigurazioa."
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_move_line__consumer_group_id
msgid "Consumer Group"
msgstr "Kontsumitzaile taldea"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__create_uid
msgid "Created by"
msgstr "Nork sortua"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__create_date
msgid "Created on"
msgstr "Noiz sortua"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__qty_demanded
msgid "Demanded Quantity"
msgstr "Eskatutako kantitatea"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_res_company__batch_detailed_restriction_scope
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_res_config_settings__batch_detailed_restriction_scope
msgid "Detailed Operations Restriction Scope"
msgstr "Eragiketa xehatuen murrizketaren irismena"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__display_name
msgid "Display Name"
msgstr "Bistaratzeko izena"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__qty_done
msgid "Done Quantity"
msgstr "Egindako kantitatea"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_res_company__batch_detailed_restriction_enabled
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_res_config_settings__batch_detailed_restriction_enabled
msgid "Enforce Detailed Operations Restriction"
msgstr "Eragiketa xehatuen murrizketa aplikatu"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_res_company__batch_summary_restriction_enabled
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_res_config_settings__batch_summary_restriction_enabled
msgid "Enforce Product Summary Restriction"
msgstr "Produktuen laburpenaren murrizketa aplikatu"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_move_line__home_delivery
msgid "Home Delivery"
msgstr "Etxez etxeko entrega"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__id
msgid "ID"
msgstr "ID"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__write_uid
msgid "Last Updated by"
msgstr "Azken eguneratzailea"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__write_date
msgid "Last Updated on"
msgstr "Azken eguneratzea"
#. module: stock_picking_batch_collect
#: model:ir.model.fields.selection,name:stock_picking_batch_collect.selection__res_company__batch_detailed_restriction_scope__processed
msgid "Only processed lines"
msgstr "Prozesatutako lerroak soilik"
#. module: stock_picking_batch_collect
#: model:ir.model.fields.selection,name:stock_picking_batch_collect.selection__res_company__batch_summary_restriction_scope__processed
msgid "Only processed products"
msgstr "Prozesatutako produktuak soilik"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__qty_pending
msgid "Pending Quantity"
msgstr "Zain dagoen kantitatea"
#. module: stock_picking_batch_collect
#. odoo-python
#: code:addons/stock_picking_batch_collect/models/stock_picking_batch.py:0
msgid "Pending products: %(products)s"
msgstr "Zain dauden produktuak: %(products)s"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__product_id
msgid "Product"
msgstr "Produktua"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__product_categ_id
msgid "Product Category"
msgstr "Produktu-kategoria"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_move_line__product_categ_id
msgid "Product Category (Batch)"
msgstr "Produktu-kategoria (lotea)"
#. module: stock_picking_batch_collect
#: model:ir.model,name:stock_picking_batch_collect.model_stock_move_line
msgid "Product Moves (Stock Move Line)"
msgstr "Produktuen mugimenduak (stock mugimenduaren lerroa)"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch__summary_line_ids
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.view_stock_picking_batch_form_inherit_summary
msgid "Product Summary"
msgstr "Produktuen laburpena"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_res_company__batch_summary_restriction_scope
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_res_config_settings__batch_summary_restriction_scope
msgid "Product Summary Restriction Scope"
msgstr "Produktuen laburpenaren murrizketaren irismena"
#. module: stock_picking_batch_collect
#: model:ir.model.constraint,message:stock_picking_batch_collect.constraint_stock_picking_batch_summary_line_product_required
msgid "Product is required for summary lines."
msgstr "Produktua derrigorrezkoa da laburpen-lerroetan."
#. module: stock_picking_batch_collect
#: model:ir.model,name:stock_picking_batch_collect.model_stock_picking
msgid "Transfer"
msgstr "Transferentzia"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,field_description:stock_picking_batch_collect.field_stock_picking_batch_summary_line__product_uom_id
msgid "Unit of Measure"
msgstr "Neurri-unitatea"
#. module: stock_picking_batch_collect
#: model:ir.model.fields,help:stock_picking_batch_collect.field_stock_move_line__home_delivery
msgid "Whether this picking includes home delivery (from sale order)"
msgstr ""
"Albaran honek etxez etxeko entrega barne hartzen duen (salmenta-eskaeratik)"
#. module: stock_picking_batch_collect
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_collect.view_stock_picking_batch_form_inherit_summary
msgid "Basket Assembly"
msgstr "Saskien Prestaketa"

View file

@ -1,6 +1,6 @@
from . import res_company # noqa: F401 from . import res_company # noqa: F401
from . import res_config_settings # noqa: F401 from . import res_config_settings # noqa: F401
from . import stock_move_line # noqa: F401
from . import stock_backorder_confirmation # noqa: F401 from . import stock_backorder_confirmation # noqa: F401
from . import stock_move_line # noqa: F401
from . import stock_picking # noqa: F401 from . import stock_picking # noqa: F401
from . import stock_picking_batch # noqa: F401 from . import stock_picking_batch # noqa: F401

View file

@ -1,7 +1,6 @@
# Copyright 2026 Criptomart # Copyright 2026 Criptomart
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api
from odoo import fields from odoo import fields
from odoo import models from odoo import models
@ -36,17 +35,6 @@ class StockMoveLine(models.Model):
copy=False, copy=False,
) )
home_delivery = fields.Boolean(
related="picking_id.home_delivery",
readonly=True,
)
consumer_group_id = fields.Many2one(
comodel_name="res.partner",
compute="_compute_consumer_group_id",
readonly=True,
)
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"):
@ -61,12 +49,3 @@ class StockMoveLine(models.Model):
lines.picked = True lines.picked = True
lines._freeze_manual_quantity(align_demand=False) lines._freeze_manual_quantity(align_demand=False)
return res return res
@api.depends("picking_id")
def _compute_consumer_group_id(self):
for line in self:
picking = line.picking_id
if picking:
line.consumer_group_id = picking.batch_consumer_group_id
else:
line.consumer_group_id = False

View file

@ -1,28 +1,12 @@
# Copyright 2026 Criptomart # Copyright 2026 Criptomart
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields
from odoo import models from odoo import models
class StockPicking(models.Model): class StockPicking(models.Model):
_inherit = "stock.picking" _inherit = "stock.picking"
batch_consumer_group_id = fields.Many2one(
comodel_name="res.partner",
compute="_compute_batch_consumer_group_id",
readonly=True,
string="Batch Consumer Group",
)
def _compute_batch_consumer_group_id(self):
for picking in self:
sale = picking.sale_id if "sale_id" in picking._fields else False
if sale and "consumer_group_id" in sale._fields:
picking.batch_consumer_group_id = sale.consumer_group_id
else:
picking.batch_consumer_group_id = False
def _pre_action_done_hook(self): def _pre_action_done_hook(self):
"""Run collected checks only after Odoo resolves backorders. """Run collected checks only after Odoo resolves backorders.

View file

@ -231,7 +231,7 @@ class StockPickingBatch(models.Model):
"views": [ "views": [
( (
self.env.ref( self.env.ref(
"stock_picking_batch_custom.view_move_line_batch_operator" "stock_picking_batch_collect.view_move_line_batch_operator"
).id, ).id,
"list", "list",
) )

View file

@ -0,0 +1,32 @@
Configuración
=============
Restricciones de validación
---------------------------
En **Inventory > Configuration > Settings**, bloque *Operations*, hay dos
ajustes por compañía:
- **Restricciones del resumen de productos**: exige que las líneas de la
pestaña *Product Summary* estén marcadas como recogidas para validar el lote.
Desactivado por defecto (el check es sólo informativo).
- **Restricciones de operaciones detalladas**: exige que las líneas de la
pestaña *Detailed Operations* estén marcadas como recogidas.
**Activado por defecto**: recién instalado el módulo, un lote no se puede
validar hasta marcar las líneas.
Cada restricción tiene un alcance:
- *Sólo procesadas*: se comprueban únicamente las líneas con cantidad hecha
mayor que cero (por defecto).
- *Todas*: se comprueban todas las líneas del lote, procesadas o no.
Columnas
--------
Las columnas están visibles por defecto. Para ajustarlas:
- Abrir un **Lote de picking**.
- Ir a la pestaña **Detailed Operations**.
- Abrir el **selector de columnas** y activar o desactivar *Partner*,
*Product Category*, *Product Code* o *Collected* según necesidad.

View file

@ -0,0 +1,26 @@
Este módulo convierte un lote de picking en una hoja de trabajo para el operario
que monta las cestas: amplía las operaciones detalladas, añade un resumen por
producto y una vista a pantalla completa para el almacén.
- ``picking_partner_id`` (Partner del albarán) para que el personal de almacén
identifique rápido el cliente/proveedor.
- ``product_categ_id`` (Categoría de producto) para ordenar y agrupar. Las
líneas del lote se ordenan por categoría, producto y partner.
- ``product_default_code`` (Referencia interna) como columna opcional.
- ``is_collected`` (Recogido) como check manual en cada línea para marcar si se
ha recolectado.
- Nueva pestaña **Product Summary** con totales por producto (demandado, hecho,
pendiente), categoría y el check de recogido consolidado.
- Botón **Basket Assembly**: una vista de lista a pantalla completa, con
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.
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
puede desactivarlas desde el selector de columnas sin recargar la vista.
Si además está instalado ``website_sale_aplicoop``, ese módulo añade a estas
mismas vistas las columnas de grupo de consumo (**Consumer Group** y **Home
Delivery**). Este módulo no depende de él: funciona igual sin la parte de
eCommerce.

View file

@ -5,4 +5,4 @@ Actualizar o instalar el módulo:
:: ::
docker-compose run --rm odoo odoo -d odoo --stop-after-init -u stock_picking_batch_custom docker-compose run --rm odoo odoo -d odoo --stop-after-init -u stock_picking_batch_collect

View file

@ -2,7 +2,7 @@ Uso
=== ===
1. Accede a **Inventory > Operations > Batch Transfers** y abre un lote. 1. Accede a **Inventory > Operations > Batch Transfers** y abre un lote.
2. Pestaña **Detailed Operations**: usa el selector de columnas para activar: 2. Pestaña **Detailed Operations**: usa el selector de columnas para ajustar:
- **Partner** (``picking_partner_id``) para ver el cliente/proveedor. - **Partner** (``picking_partner_id``) para ver el cliente/proveedor.
- **Product Category** (``product_categ_id``) para ordenar/agrupación por categoría. - **Product Category** (``product_categ_id``) para ordenar/agrupación por categoría.
@ -11,9 +11,19 @@ Uso
3. Pestaña **Product Summary**: consulta los totales por producto (demandado, 3. Pestaña **Product Summary**: consulta los totales por producto (demandado,
hecho y pendiente) y marca el check de recogido consolidado si corresponde. hecho y pendiente) y marca el check de recogido consolidado si corresponde.
4. Ordena o agrupa por categoría en cualquiera de las vistas según convenga. 4. Con el lote **en progreso**, el botón **Basket Assembly** abre la vista de
operario: la misma lista de líneas a pantalla completa, con la cantidad en
grande y el check *Collected* como interruptor táctil. Está pensada para
trabajar desde una tablet mientras se montan las cestas.
5. La cantidad que teclea el operario (el peso real de la balanza) queda fijada: 5. Ordena o agrupa por categoría en cualquiera de las vistas según convenga.
6. La cantidad que teclea el operario (el peso real de la balanza) queda fijada:
se marca como *Picked* y ni el planificador ni la validación de otros se marca como *Picked* y ni el planificador ni la validación de otros
albaranes vuelven a modificarla. Marcar **Collected** protege igualmente la albaranes vuelven a modificarla. Marcar **Collected** protege igualmente la
cantidad de la línea. Ver ``stock_move_manual_quantity``. cantidad de la línea. Ver ``stock_move_manual_quantity``.
7. Al validar el lote, según la configuración de la compañía, se comprueba que
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.

View file

Before

Width:  |  Height:  |  Size: 111 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Before After
Before After

View file

@ -1,13 +1,3 @@
/* zebra striping for list views in this module (Odoo 18 selectors) */
table.o_list_table tbody tr.o_data_row:nth-child(even) td {
background-color: rgba(0, 0, 0, 0.03);
}
table.o_list_table tbody tr.o_data_row:hover td {
background-color: rgba(0, 0, 0, 0.045);
}
/* Widen the quantity column in detailed operations so it is easier to tap */ /* Widen the quantity column in detailed operations so it is easier to tap */
/* Note: arch class lands on the root <div> of the list controller, not <table> */ /* Note: arch class lands on the root <div> of the list controller, not <table> */
.o_batch_move_line_list th[data-name="quantity"], .o_batch_move_line_list th[data-name="quantity"],

View file

@ -30,8 +30,6 @@
context="{'display_default_code': False}"/> context="{'display_default_code': False}"/>
<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="home_delivery" readonly="1" widget="boolean_toggle" optional="show"/>
<field name="consumer_group_id" 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"/>
@ -54,23 +52,12 @@
</xpath> </xpath>
<xpath expr="//notebook/page[@name='page_detailed_operations']" position="after"> <xpath expr="//notebook/page[@name='page_detailed_operations']" position="after">
<page string="Product Summary" name="page_product_summary"> <page string="Product Summary" name="page_product_summary">
<field name="summary_line_ids" context="{'tree_view_ref': 'stock_picking_batch_custom.view_stock_picking_batch_summary_line_tree'}"/> <field name="summary_line_ids" context="{'tree_view_ref': 'stock_picking_batch_collect.view_stock_picking_batch_summary_line_tree'}"/>
</page> </page>
</xpath> </xpath>
</field> </field>
</record> </record>
<record id="view_stock_picking_batch_picking_tree_consumer_group" model="ir.ui.view">
<field name="name">stock.picking.batch.picking.tree.consumer.group</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock_picking_batch.stock_picking_view_batch_tree_ref"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='partner_id']" position="after">
<field name="batch_consumer_group_id" optional="show"/>
</xpath>
</field>
</record>
<record id="view_move_line_tree_inherit_batch_custom" model="ir.ui.view"> <record id="view_move_line_tree_inherit_batch_custom" model="ir.ui.view">
<field name="name">stock.move.line.list.batch.custom</field> <field name="name">stock.move.line.list.batch.custom</field>
<field name="model">stock.move.line</field> <field name="model">stock.move.line</field>
@ -89,8 +76,6 @@
<xpath expr="//field[@name='product_id']" position="after"> <xpath expr="//field[@name='product_id']" position="after">
<field name="picking_partner_id" readonly="1" optional="show"/> <field name="picking_partner_id" readonly="1" optional="show"/>
<field name="product_default_code" readonly="1" optional="hide"/> <field name="product_default_code" readonly="1" optional="hide"/>
<field name="home_delivery" readonly="1" widget="boolean_toggle" optional="show"/>
<field name="consumer_group_id" readonly="1" optional="show"/>
<field name="is_collected" widget="boolean_toggle" optional="show"/> <field name="is_collected" widget="boolean_toggle" optional="show"/>
</xpath> </xpath>
<xpath expr="//field[@name='quantity']" position="after"> <xpath expr="//field[@name='quantity']" position="after">
@ -115,5 +100,4 @@
</field> </field>
</record> </record>
<!-- assets: moved to manifest 'assets' declaration -->
</odoo> </odoo>

View file

@ -1,66 +0,0 @@
============================
Stock Picking Batch Custom
============================
Visión general
==============
Este módulo amplía las operaciones detalladas y añade un resumen por producto
en los lotes de picking:
- ``picking_partner_id`` (Partner del albarán) para identificar cliente/proveedor.
- ``product_categ_id`` (Categoría de producto) para ordenar y agrupar.
- ``is_collected`` (Recogido) como check manual en cada línea para marcar si se ha
recolectado.
- Nueva pestaña **Product Summary** con totales por producto (demandado, hecho,
pendiente), categoría y el check de recogido consolidado.
Instalación
===========
Actualizar o instalar el módulo:
::
docker-compose run --rm odoo odoo -d odoo --stop-after-init -u stock_picking_batch_custom
Configuración
=============
No requiere configuración adicional. Para usar las columnas:
- Abrir un **Lote de picking**.
- Ir a la pestaña **Detailed Operations**.
- Abrir el **selector de columnas** y activar *Partner*, *Product Category* y *Collected* según necesidad.
Uso
===
1. Accede a **Inventory > Operations > Batch Transfers** y abre un lote.
2. Pestaña **Detailed Operations**: usa el selector de columnas para activar:
- **Partner** (``picking_partner_id``) para ver el cliente/proveedor.
- **Product Category** (``product_categ_id``) para ordenar/agrupación por categoría.
- **Collected** (``is_collected``) para marcar manualmente líneas recolectadas.
3. Pestaña **Product Summary**: consulta los totales por producto (demandado,
hecho y pendiente) y marca el check de recogido consolidado si corresponde.
4. Ordena o agrupa por categoría en cualquiera de las vistas según convenga.
Contribuidores
==============
* Criptomart
Créditos
========
Autor
-----
* Criptomart
Financiador
-----------
* Elika Bilbo

View file

@ -1 +0,0 @@
from . import models # noqa: F401

View file

@ -1,235 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_picking_batch_custom
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 18.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-05-21 13:18+0000\n"
"PO-Revision-Date: 2026-05-21 13:18+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: stock_picking_batch_custom
#: model:ir.model.fields.selection,name:stock_picking_batch_custom.selection__res_company__batch_detailed_restriction_scope__all
msgid "All detailed lines"
msgstr "Todas las líneas detalladas"
#. module: stock_picking_batch_custom
#: model:ir.model.fields.selection,name:stock_picking_batch_custom.selection__res_company__batch_summary_restriction_scope__all
msgid "All summary products"
msgstr "Todos los productos del resumen"
#. module: stock_picking_batch_custom
#: model:ir.model,name:stock_picking_batch_custom.model_stock_backorder_confirmation
msgid "Backorder Confirmation"
msgstr "Confirmación de entrega parcial"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__batch_id
msgid "Batch"
msgstr "Lote"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking__batch_consumer_group_id
msgid "Batch Consumer Group"
msgstr "Grupo de consumidores del lote"
#. module: stock_picking_batch_custom
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_custom.res_config_settings_view_form_inherit_batch_custom
msgid "Batch Detailed Operations Restriction"
msgstr "Restricción de operaciones detalladas del lote"
#. module: stock_picking_batch_custom
#: model:ir.model,name:stock_picking_batch_custom.model_stock_picking_batch_summary_line
msgid "Batch Product Summary Line"
msgstr "Línea de resumen de productos del lote"
#. module: stock_picking_batch_custom
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_custom.res_config_settings_view_form_inherit_batch_custom
msgid "Batch Product Summary Restriction"
msgstr "Restricción del resumen de productos del lote"
#. module: stock_picking_batch_custom
#: model:ir.model,name:stock_picking_batch_custom.model_stock_picking_batch
msgid "Batch Transfer"
msgstr "Traslado por lote"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_move_line__is_collected
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__is_collected
msgid "Collected"
msgstr "Recogido"
#. module: stock_picking_batch_custom
#: model:ir.model,name:stock_picking_batch_custom.model_res_company
msgid "Companies"
msgstr "Compañías"
#. module: stock_picking_batch_custom
#: model:ir.model,name:stock_picking_batch_custom.model_res_config_settings
msgid "Config Settings"
msgstr "Ajustes de configuración"
#. module: stock_picking_batch_custom
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_custom.res_config_settings_view_form_inherit_batch_custom
msgid "Configuración de restricciones para la pestaña Operaciones Detalladas."
msgstr ""
"Configuración de restricciones para la pestaña Operaciones Detalladas."
#. module: stock_picking_batch_custom
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_custom.res_config_settings_view_form_inherit_batch_custom
msgid "Configuración de restricciones para la pestaña Product Summary."
msgstr "Configuración de restricciones para la pestaña Resumen de productos."
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_move_line__consumer_group_id
msgid "Consumer Group"
msgstr "Grupo de consumidores"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__create_uid
msgid "Created by"
msgstr "Creado por"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__create_date
msgid "Created on"
msgstr "Creado el"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__qty_demanded
msgid "Demanded Quantity"
msgstr "Cantidad demandada"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_res_company__batch_detailed_restriction_scope
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_res_config_settings__batch_detailed_restriction_scope
msgid "Detailed Operations Restriction Scope"
msgstr "Ámbito de restricción de operaciones detalladas"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__display_name
msgid "Display Name"
msgstr "Nombre mostrado"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__qty_done
msgid "Done Quantity"
msgstr "Cantidad hecha"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_res_company__batch_detailed_restriction_enabled
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_res_config_settings__batch_detailed_restriction_enabled
msgid "Enforce Detailed Operations Restriction"
msgstr "Aplicar restricción de operaciones detalladas"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_res_company__batch_summary_restriction_enabled
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_res_config_settings__batch_summary_restriction_enabled
msgid "Enforce Product Summary Restriction"
msgstr "Aplicar restricción del resumen de productos"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_move_line__home_delivery
msgid "Home Delivery"
msgstr "Entrega a domicilio"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__id
msgid "ID"
msgstr "ID"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__write_uid
msgid "Last Updated by"
msgstr "Última actualización por"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__write_date
msgid "Last Updated on"
msgstr "Última actualización el"
#. module: stock_picking_batch_custom
#: model:ir.model.fields.selection,name:stock_picking_batch_custom.selection__res_company__batch_detailed_restriction_scope__processed
msgid "Only processed lines"
msgstr "Solo líneas procesadas"
#. module: stock_picking_batch_custom
#: model:ir.model.fields.selection,name:stock_picking_batch_custom.selection__res_company__batch_summary_restriction_scope__processed
msgid "Only processed products"
msgstr "Solo productos procesados"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__qty_pending
msgid "Pending Quantity"
msgstr "Cantidad pendiente"
#. module: stock_picking_batch_custom
#. odoo-python
#: code:addons/stock_picking_batch_custom/models/stock_picking_batch.py:0
msgid "Pending products: %(products)s"
msgstr "Productos pendientes: %(products)s"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__product_id
msgid "Product"
msgstr "Producto"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__product_categ_id
msgid "Product Category"
msgstr "Categoría de producto"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_move_line__product_categ_id
msgid "Product Category (Batch)"
msgstr "Categoría de producto (lote)"
#. module: stock_picking_batch_custom
#: model:ir.model,name:stock_picking_batch_custom.model_stock_move_line
msgid "Product Moves (Stock Move Line)"
msgstr "Movimientos de producto (línea de movimiento de stock)"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch__summary_line_ids
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_custom.view_stock_picking_batch_form_inherit_summary
msgid "Product Summary"
msgstr "Resumen de productos"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_res_company__batch_summary_restriction_scope
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_res_config_settings__batch_summary_restriction_scope
msgid "Product Summary Restriction Scope"
msgstr "Ámbito de restricción del resumen de productos"
#. module: stock_picking_batch_custom
#: model:ir.model.constraint,message:stock_picking_batch_custom.constraint_stock_picking_batch_summary_line_product_required
msgid "Product is required for summary lines."
msgstr "El producto es obligatorio en las líneas de resumen."
#. module: stock_picking_batch_custom
#: model:ir.model,name:stock_picking_batch_custom.model_stock_picking
msgid "Transfer"
msgstr "Traslado"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__product_uom_id
msgid "Unit of Measure"
msgstr "Unidad de medida"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,help:stock_picking_batch_custom.field_stock_move_line__home_delivery
msgid "Whether this picking includes home delivery (from sale order)"
msgstr "Si este albarán incluye entrega a domicilio (del pedido de venta)"
#. module: stock_picking_batch_custom
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_custom.view_stock_picking_batch_form_inherit_summary
msgid "Basket Assembly"
msgstr "Montaje de Cestas"

View file

@ -1,235 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_picking_batch_custom
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 18.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-05-21 13:21+0000\n"
"PO-Revision-Date: 2026-05-21 13:21+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: eu\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: stock_picking_batch_custom
#: model:ir.model.fields.selection,name:stock_picking_batch_custom.selection__res_company__batch_detailed_restriction_scope__all
msgid "All detailed lines"
msgstr "Lerro xehatu guztiak"
#. module: stock_picking_batch_custom
#: model:ir.model.fields.selection,name:stock_picking_batch_custom.selection__res_company__batch_summary_restriction_scope__all
msgid "All summary products"
msgstr "Laburpeneko produktu guztiak"
#. module: stock_picking_batch_custom
#: model:ir.model,name:stock_picking_batch_custom.model_stock_backorder_confirmation
msgid "Backorder Confirmation"
msgstr "Eskaeraren informazioa"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__batch_id
msgid "Batch"
msgstr "Lotea"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking__batch_consumer_group_id
msgid "Batch Consumer Group"
msgstr "Loteko kontsumitzaile taldea"
#. module: stock_picking_batch_custom
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_custom.res_config_settings_view_form_inherit_batch_custom
msgid "Batch Detailed Operations Restriction"
msgstr "Loteko eragiketa xehatuen murrizketa"
#. module: stock_picking_batch_custom
#: model:ir.model,name:stock_picking_batch_custom.model_stock_picking_batch_summary_line
msgid "Batch Product Summary Line"
msgstr "Loteko produktuen laburpen-lerroa"
#. module: stock_picking_batch_custom
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_custom.res_config_settings_view_form_inherit_batch_custom
msgid "Batch Product Summary Restriction"
msgstr "Loteko produktuen laburpenaren murrizketa"
#. module: stock_picking_batch_custom
#: model:ir.model,name:stock_picking_batch_custom.model_stock_picking_batch
msgid "Batch Transfer"
msgstr "Lote-transferentzia"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_move_line__is_collected
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__is_collected
msgid "Collected"
msgstr "Jasota"
#. module: stock_picking_batch_custom
#: model:ir.model,name:stock_picking_batch_custom.model_res_company
msgid "Companies"
msgstr "Enpresak"
#. module: stock_picking_batch_custom
#: model:ir.model,name:stock_picking_batch_custom.model_res_config_settings
msgid "Config Settings"
msgstr "Konfigurazio ezarpenak"
#. module: stock_picking_batch_custom
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_custom.res_config_settings_view_form_inherit_batch_custom
msgid "Configuración de restricciones para la pestaña Operaciones Detalladas."
msgstr "Eragiketa xehatuak fitxarako murrizketen konfigurazioa."
#. module: stock_picking_batch_custom
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_custom.res_config_settings_view_form_inherit_batch_custom
msgid "Configuración de restricciones para la pestaña Product Summary."
msgstr "Produktuen laburpena fitxarako murrizketen konfigurazioa."
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_move_line__consumer_group_id
msgid "Consumer Group"
msgstr "Kontsumitzaile taldea"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__create_uid
msgid "Created by"
msgstr "Nork sortua"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__create_date
msgid "Created on"
msgstr "Noiz sortua"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__qty_demanded
msgid "Demanded Quantity"
msgstr "Eskatutako kantitatea"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_res_company__batch_detailed_restriction_scope
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_res_config_settings__batch_detailed_restriction_scope
msgid "Detailed Operations Restriction Scope"
msgstr "Eragiketa xehatuen murrizketaren irismena"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__display_name
msgid "Display Name"
msgstr "Bistaratzeko izena"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__qty_done
msgid "Done Quantity"
msgstr "Egindako kantitatea"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_res_company__batch_detailed_restriction_enabled
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_res_config_settings__batch_detailed_restriction_enabled
msgid "Enforce Detailed Operations Restriction"
msgstr "Eragiketa xehatuen murrizketa aplikatu"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_res_company__batch_summary_restriction_enabled
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_res_config_settings__batch_summary_restriction_enabled
msgid "Enforce Product Summary Restriction"
msgstr "Produktuen laburpenaren murrizketa aplikatu"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_move_line__home_delivery
msgid "Home Delivery"
msgstr "Etxez etxeko entrega"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__id
msgid "ID"
msgstr "ID"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__write_uid
msgid "Last Updated by"
msgstr "Azken eguneratzailea"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__write_date
msgid "Last Updated on"
msgstr "Azken eguneratzea"
#. module: stock_picking_batch_custom
#: model:ir.model.fields.selection,name:stock_picking_batch_custom.selection__res_company__batch_detailed_restriction_scope__processed
msgid "Only processed lines"
msgstr "Prozesatutako lerroak soilik"
#. module: stock_picking_batch_custom
#: model:ir.model.fields.selection,name:stock_picking_batch_custom.selection__res_company__batch_summary_restriction_scope__processed
msgid "Only processed products"
msgstr "Prozesatutako produktuak soilik"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__qty_pending
msgid "Pending Quantity"
msgstr "Zain dagoen kantitatea"
#. module: stock_picking_batch_custom
#. odoo-python
#: code:addons/stock_picking_batch_custom/models/stock_picking_batch.py:0
msgid "Pending products: %(products)s"
msgstr "Zain dauden produktuak: %(products)s"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__product_id
msgid "Product"
msgstr "Produktua"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__product_categ_id
msgid "Product Category"
msgstr "Produktu-kategoria"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_move_line__product_categ_id
msgid "Product Category (Batch)"
msgstr "Produktu-kategoria (lotea)"
#. module: stock_picking_batch_custom
#: model:ir.model,name:stock_picking_batch_custom.model_stock_move_line
msgid "Product Moves (Stock Move Line)"
msgstr "Produktuen mugimenduak (stock mugimenduaren lerroa)"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch__summary_line_ids
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_custom.view_stock_picking_batch_form_inherit_summary
msgid "Product Summary"
msgstr "Produktuen laburpena"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_res_company__batch_summary_restriction_scope
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_res_config_settings__batch_summary_restriction_scope
msgid "Product Summary Restriction Scope"
msgstr "Produktuen laburpenaren murrizketaren irismena"
#. module: stock_picking_batch_custom
#: model:ir.model.constraint,message:stock_picking_batch_custom.constraint_stock_picking_batch_summary_line_product_required
msgid "Product is required for summary lines."
msgstr "Produktua derrigorrezkoa da laburpen-lerroetan."
#. module: stock_picking_batch_custom
#: model:ir.model,name:stock_picking_batch_custom.model_stock_picking
msgid "Transfer"
msgstr "Transferentzia"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,field_description:stock_picking_batch_custom.field_stock_picking_batch_summary_line__product_uom_id
msgid "Unit of Measure"
msgstr "Neurri-unitatea"
#. module: stock_picking_batch_custom
#: model:ir.model.fields,help:stock_picking_batch_custom.field_stock_move_line__home_delivery
msgid "Whether this picking includes home delivery (from sale order)"
msgstr ""
"Albaran honek etxez etxeko entrega barne hartzen duen (salmenta-eskaeratik)"
#. module: stock_picking_batch_custom
#: model_terms:ir.ui.view,arch_db:stock_picking_batch_custom.view_stock_picking_batch_form_inherit_summary
msgid "Basket Assembly"
msgstr "Saskien Prestaketa"

View file

@ -1,8 +0,0 @@
Configuración
=============
No requiere configuración adicional. Para usar las columnas:
- Abrir un **Lote de picking**.
- Ir a la pestaña **Detailed Operations**.
- Abrir el **selector de columnas** y activar *Partner* y *Product Category* según necesidad.

View file

@ -1,14 +0,0 @@
Este módulo amplía las operaciones detalladas y añade un resumen por producto
en los lotes de picking:
- ``picking_partner_id`` (Partner del albarán) para que el personal de almacén
identifique rápido el cliente/proveedor.
- ``product_categ_id`` (Categoría de producto) para ordenar y agrupar.
- ``is_collected`` (Recogido) como check manual en cada línea para marcar si se
ha recolectado.
- Nueva pestaña **Product Summary** con totales por producto (demandado, hecho,
pendiente), categoría y el check de recogido consolidado.
Las columnas se añaden como ``optional="hide"`` en la vista de líneas del lote,
de modo que el usuario puede activarlas desde el selector de columnas sin
recargar la vista por defecto.

View file

@ -135,22 +135,36 @@ La página inicial renderiza la primera página server-side. El botón "Cargar m
| Cron | Frecuencia | Acción | | Cron | Frecuencia | Acción |
| ---- | ---------- | ------ | | ---- | ---------- | ------ |
| `_cron_confirm_group_orders` | Diario (medianoche) | Confirma sale.orders pasado el cutoff; crea lotes de picking agrupados por consumer_group + pickup_date | | `_cron_confirm_group_orders` | Diario (medianoche) | Confirma sale.orders pasado el cutoff; crea lotes de picking por pedido de grupo, uno por tipo de operación (`_create_picking_batches`) |
| `_cron_update_dates` | Diario | Recalcula `delivery_date` y `pickup_date` en órdenes activas | | `_cron_update_dates` | Diario | Recalcula `delivery_date` y `pickup_date` en órdenes activas |
## Dependencias ## Dependencias
Según `__manifest__.py`:
```text ```text
website_sale_aplicoop website_sale_aplicoop
├── website_sale (Odoo core) ├── website_sale (Odoo core)
├── website_sale_stock (Odoo core)
├── payment (Odoo core)
├── product (Odoo core)
├── sale (Odoo core) ├── sale (Odoo core)
├── product_main_seller (OCA) ├── stock (Odoo core)
├── product_sale_price_from_pricelist (custom) ├── account (Odoo core)
│ └── product_pricelist_total_margin (custom) ├── stock_picking_batch (Odoo core)
│ └── product_price_category (OCA) ├── stock_picking_batch_collect (custom)
└── stock_picking_batch_custom (custom) │ ├── stock_move_manual_quantity (custom)
│ └── stock_picking_batch (Odoo core)
├── product_get_price_helper (OCA)
└── l10n_es_partner (OCA)
``` ```
La dependencia sobre `stock_picking_batch_collect` es deliberada y va en este
sentido: ese addon es genérico de almacén y no sabe nada de grupos de consumo.
Es `website_sale_aplicoop` quien inyecta en sus vistas las columnas
**Consumer Group** y **Home Delivery** (ver `views/stock_picking_batch_views.xml`
y `models/stock_move_line_extension.py`).
## Instalación y actualización ## Instalación y actualización
```bash ```bash

View file

@ -3,7 +3,7 @@
{ # noqa: B018 { # noqa: B018
"name": "Website Sale - Aplicoop", "name": "Website Sale - Aplicoop",
"version": "18.0.1.16.0", "version": "18.0.1.17.0",
"category": "Website/Sale", "category": "Website/Sale",
"summary": "Modern replacement of legacy Aplicoop - Collaborative consumption group orders", "summary": "Modern replacement of legacy Aplicoop - Collaborative consumption group orders",
"author": "Odoo Community Association (OCA), Criptomart", "author": "Odoo Community Association (OCA), Criptomart",
@ -18,6 +18,9 @@
"sale", "sale",
"stock", "stock",
"stock_picking_batch", "stock_picking_batch",
# Owns the batch collect views into which we inject the consumer group
# columns (home_delivery, consumer_group_id).
"stock_picking_batch_collect",
"account", "account",
"product_get_price_helper", "product_get_price_helper",
"l10n_es_partner", "l10n_es_partner",
@ -43,6 +46,7 @@
"views/product_template_views.xml", "views/product_template_views.xml",
"views/sale_order_views.xml", "views/sale_order_views.xml",
"views/stock_picking_views.xml", "views/stock_picking_views.xml",
"views/stock_picking_batch_views.xml",
"views/portal_templates.xml", "views/portal_templates.xml",
"views/load_from_history_templates.xml", "views/load_from_history_templates.xml",
], ],

View file

@ -1,11 +1,12 @@
from . import group_order # noqa: F401 from . import group_order # noqa: F401
from . import group_order_slot # noqa: F401 from . import group_order_slot # noqa: F401
from . import js_translations # noqa: F401
from . import payment_transaction # noqa: F401 from . import payment_transaction # noqa: F401
from . import product_category_extension # noqa: F401 from . import product_category_extension # noqa: F401
from . import product_extension # noqa: F401 from . import product_extension # noqa: F401
from . import res_config_settings # noqa: F401 from . import res_config_settings # noqa: F401
from . import res_partner_extension # noqa: F401 from . import res_partner_extension # noqa: F401
from . import sale_order_extension # noqa: F401 from . import sale_order_extension # noqa: F401
from . import stock_move_line_extension # noqa: F401
from . import stock_picking_extension # noqa: F401 from . import stock_picking_extension # noqa: F401
from . import website # noqa: F401 from . import website # noqa: F401
from . import js_translations # noqa: F401

View file

@ -0,0 +1,28 @@
# Copyright 2026 Criptomart
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
from odoo import fields
from odoo import models
class StockMoveLine(models.Model):
"""Surface the consumer group data on the batch operation lines.
The picking already carries these values as stored related fields, so the
move line only has to hop one step further. Chaining off ``picking_id``
instead of re-deriving from ``sale_id`` keeps a single source of truth.
"""
_inherit = "stock.move.line"
home_delivery = fields.Boolean(
related="picking_id.home_delivery",
string="Home Delivery",
readonly=True,
)
consumer_group_id = fields.Many2one(
related="picking_id.consumer_group_id",
string="Consumer Group",
readonly=True,
)

View file

@ -14,39 +14,16 @@ class TestMultiCompanyGroupOrder(TransactionCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
# Crear dos compañías # Crear dos compañías. `stock_picking_batch_collect` es dependencia del
# módulo, así que los campos de restricción de lote siempre existen.
company_model = self.env["res.company"] company_model = self.env["res.company"]
# Compatibilidad con esquemas legacy: columna NOT NULL presente sin campo ORM.
self.env.cr.execute("""
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'res_company'
AND column_name IN ('batch_summary_restriction_scope', 'batch_detailed_restriction_scope')
""")
existing_columns = {row[0] for row in self.env.cr.fetchall()}
if (
"batch_summary_restriction_scope" in existing_columns
and "batch_summary_restriction_scope" not in company_model._fields
):
self.env.cr.execute(
"ALTER TABLE res_company ALTER COLUMN batch_summary_restriction_scope SET DEFAULT 'processed'"
)
if (
"batch_detailed_restriction_scope" in existing_columns
and "batch_detailed_restriction_scope" not in company_model._fields
):
self.env.cr.execute(
"ALTER TABLE res_company ALTER COLUMN batch_detailed_restriction_scope SET DEFAULT 'processed'"
)
def _company_vals(name): def _company_vals(name):
vals = {"name": name} return {
if "batch_summary_restriction_scope" in company_model._fields: "name": name,
vals["batch_summary_restriction_scope"] = "processed" "batch_summary_restriction_scope": "processed",
if "batch_detailed_restriction_scope" in company_model._fields: "batch_detailed_restriction_scope": "processed",
vals["batch_detailed_restriction_scope"] = "processed" }
return vals
self.company1 = company_model.create(_company_vals("Company 1")) self.company1 = company_model.create(_company_vals("Company 1"))
self.company2 = company_model.create(_company_vals("Company 2")) self.company2 = company_model.create(_company_vals("Company 2"))

View file

@ -14,39 +14,16 @@ class TestGroupOrderRecordRules(TransactionCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
# Crear dos compañías # Crear dos compañías. `stock_picking_batch_collect` es dependencia del
# módulo, así que los campos de restricción de lote siempre existen.
company_model = self.env["res.company"] company_model = self.env["res.company"]
# Compatibilidad con esquemas legacy: columna NOT NULL presente sin campo ORM.
self.env.cr.execute("""
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'res_company'
AND column_name IN ('batch_summary_restriction_scope', 'batch_detailed_restriction_scope')
""")
existing_columns = {row[0] for row in self.env.cr.fetchall()}
if (
"batch_summary_restriction_scope" in existing_columns
and "batch_summary_restriction_scope" not in company_model._fields
):
self.env.cr.execute(
"ALTER TABLE res_company ALTER COLUMN batch_summary_restriction_scope SET DEFAULT 'processed'"
)
if (
"batch_detailed_restriction_scope" in existing_columns
and "batch_detailed_restriction_scope" not in company_model._fields
):
self.env.cr.execute(
"ALTER TABLE res_company ALTER COLUMN batch_detailed_restriction_scope SET DEFAULT 'processed'"
)
def _company_vals(name): def _company_vals(name):
vals = {"name": name} return {
if "batch_summary_restriction_scope" in company_model._fields: "name": name,
vals["batch_summary_restriction_scope"] = "processed" "batch_summary_restriction_scope": "processed",
if "batch_detailed_restriction_scope" in company_model._fields: "batch_detailed_restriction_scope": "processed",
vals["batch_detailed_restriction_scope"] = "processed" }
return vals
self.company1 = company_model.create(_company_vals("Company 1")) self.company1 = company_model.create(_company_vals("Company 1"))
self.company2 = company_model.create(_company_vals("Company 2")) self.company2 = company_model.create(_company_vals("Company 2"))

View file

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Consumer group columns on the batch operator screen (Basket Assembly) -->
<record id="view_move_line_batch_operator_consumer_group" model="ir.ui.view">
<field name="name">stock.move.line.batch.operator.consumer.group</field>
<field name="model">stock.move.line</field>
<field name="inherit_id" ref="stock_picking_batch_collect.view_move_line_batch_operator"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='picking_partner_id']" position="after">
<field name="home_delivery" readonly="1" widget="boolean_toggle" optional="show"/>
<field name="consumer_group_id" readonly="1" optional="show"/>
</xpath>
</field>
</record>
<!-- Consumer group columns on the batch detailed operations list -->
<record id="view_move_line_tree_batch_consumer_group" model="ir.ui.view">
<field name="name">stock.move.line.list.batch.consumer.group</field>
<field name="model">stock.move.line</field>
<field name="inherit_id" ref="stock_picking_batch_collect.view_move_line_tree_inherit_batch_custom"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='product_default_code']" position="after">
<field name="home_delivery" readonly="1" widget="boolean_toggle" optional="show"/>
<field name="consumer_group_id" readonly="1" optional="show"/>
</xpath>
</field>
</record>
<!-- Consumer group on the transfers list of a batch -->
<record id="view_stock_picking_batch_picking_tree_consumer_group" model="ir.ui.view">
<field name="name">stock.picking.batch.picking.tree.consumer.group</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock_picking_batch.stock_picking_view_batch_tree_ref"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='partner_id']" position="after">
<field name="consumer_group_id" optional="show"/>
</xpath>
</field>
</record>
</odoo>