diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 0f33715..cb37e4b 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -189,11 +189,9 @@ addons-cm/ ├── membership_monthly_invoicing/ # Factura mensual de membresía por socio (cron) ├── membership_expiry_reminder/ # Email recordatorio de renovación próxima ├── # --- Logística y contabilidad --- -├── stock_picking_batch_collect/ # Batch picking: columnas extra + vista operario (Basket Assembly) +├── stock_picking_batch_custom/ # Batch picking: columnas extra + vista operario (Basket Assembly) ├── 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) -├── # --- UI de backend --- -└── web_list_striped/ # Efecto cebra en todas las listas del backend (sólo CSS) +└── l10n_es_edi_tbai_reagyp_recibidas/ # Fix TicketBAI REAGYP facturas recibidas (19 → 02) ```` @@ -235,8 +233,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 -- [web_list_striped](../web_list_striped/README.rst) - Efecto cebra en todas las listas del backend (sólo CSS) +- [stock_picking_batch_custom](../stock_picking_batch_custom/README.rst) - Columnas extra y vista operario para batch picking - [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,10 +758,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-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), ordenación de operaciones por categoría/producto/partner. - **2026-02-18**: Refactor `product_main_seller` - Remover alias innecesario `default_supplier_id` diff --git a/README.md b/README.md index 2a34a8b..8dbf2e0 100644 --- a/README.md +++ b/README.md @@ -27,9 +27,8 @@ 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_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 | -| [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 | -| [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) | +| [stock_picking_batch_custom](stock_picking_batch_custom/) | 18.0.1.0.0 | Columnas extra en operaciones detalladas de lotes: partner, categoría, recogido | +| [website_sale_aplicoop](website_sale_aplicoop/) | 18.0.1.9.0 | Sistema de pedidos colaborativos para grupos de consumo (reemplazo de Aplicoop) | ## Dependencias entre addons custom @@ -41,12 +40,6 @@ website_sale_aplicoop └── product_main_seller └── product_price_category_supplier └── 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 diff --git a/stock_move_manual_quantity/__init__.py b/stock_move_manual_quantity/__init__.py deleted file mode 100644 index 0650744..0000000 --- a/stock_move_manual_quantity/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import models diff --git a/stock_move_manual_quantity/__manifest__.py b/stock_move_manual_quantity/__manifest__.py deleted file mode 100644 index 43bf599..0000000 --- a/stock_move_manual_quantity/__manifest__.py +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2026 Criptomart -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -{ # noqa: B018 - "name": "Stock Move Manual Quantity", - "version": "18.0.1.0.0", - "category": "Warehouse", - "summary": "A hand-typed quantity is final: never re-reserved automatically", - "license": "AGPL-3", - "author": "Odoo Community Association (OCA), Criptomart", - "maintainers": ["Criptomart"], - "website": "https://git.criptomart.net/criptomart/addons-cm", - "depends": ["stock"], - "data": [ - "views/stock_move_line_views.xml", - ], -} diff --git a/stock_move_manual_quantity/models/__init__.py b/stock_move_manual_quantity/models/__init__.py deleted file mode 100644 index d7b52af..0000000 --- a/stock_move_manual_quantity/models/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from . import stock_move -from . import stock_move_line -from . import stock_picking diff --git a/stock_move_manual_quantity/models/stock_move.py b/stock_move_manual_quantity/models/stock_move.py deleted file mode 100644 index 9a82907..0000000 --- a/stock_move_manual_quantity/models/stock_move.py +++ /dev/null @@ -1,60 +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 -from odoo.tools import float_compare -from odoo.tools import float_is_zero - - -class StockMove(models.Model): - _inherit = "stock.move" - - @api.onchange("quantity") - def _onchange_quantity_manual(self): - """Mark the move as picked when a user types its quantity. - - Covers the ``Operations`` tab of a transfer, where the quantity is - edited on the move and ``_set_quantity`` spreads it to the lines. - """ - for move in self: - if move.state not in ("done", "cancel"): - move.picked = True - - def write(self, vals): - res = super().write(vals) - if "quantity" in vals and vals.get("picked"): - self._align_demand_to_manual_quantity() - return res - - def _align_demand_to_manual_quantity(self): - """Lower the demand of a move to the quantity a user typed by hand. - - A move whose quantity is below its demand goes back to - ``partially_available`` (``_recompute_state``), and that is precisely - what makes the scheduler reserve the difference again. Aligning the - demand keeps the move ``assigned`` and drops the backorder question for - a quantity that is final: a weighed product is never completed later. - - The demand is only ever lowered. Above it the move is already - ``assigned``, so nothing has to be touched. - """ - for move in self: - if move.state in ("draft", "done", "cancel") or move.is_inventory: - continue - if move.move_dest_ids: - # Chained moves: lowering the demand here would leave the next - # step of the route asking for more than this one delivers. - continue - rounding = move.product_uom.rounding - if float_is_zero(move.quantity, precision_rounding=rounding): - # Nothing was picked: leave the demand alone so the transfer - # still offers its usual backorder choice. - continue - if ( - float_compare( - move.quantity, move.product_uom_qty, precision_rounding=rounding - ) - < 0 - ): - move.product_uom_qty = move.quantity diff --git a/stock_move_manual_quantity/models/stock_move_line.py b/stock_move_manual_quantity/models/stock_move_line.py deleted file mode 100644 index b7c74d4..0000000 --- a/stock_move_manual_quantity/models/stock_move_line.py +++ /dev/null @@ -1,50 +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 StockMoveLine(models.Model): - _inherit = "stock.move.line" - - @api.onchange("quantity") - def _onchange_quantity_manual(self): - """A quantity typed by a user is the quantity physically handled. - - Onchanges only run from the user interface, never from the reservation - engine, so this marks the lines a person edited without freezing the - ones ``_action_assign`` reserves on its own. - """ - for line in self: - if line.state not in ("done", "cancel"): - line.picked = True - - def write(self, vals): - res = super().write(vals) - # `_onchange_quantity_manual` makes the interface send both fields in - # the same write, which is what tells a manual edit from a reservation. - if "quantity" in vals and vals.get("picked"): - self._freeze_manual_quantity() - return res - - def _freeze_manual_quantity(self, align_demand=True): - """Protect a hand-typed quantity from the reservation engine. - - ``_action_assign`` (run by the ``Procurement: run scheduler`` cron and - by ``_trigger_assign`` whenever another transfer of the same product is - validated) tops up every move that is not picked until it reaches its - demand, and ``_free_reservation`` steals quantities from move lines - that are not picked. Marking the whole move keeps both away from it. - """ - lines = self.filtered(lambda ml: ml.state not in ("done", "cancel")) - if not lines: - return - siblings = (lines.move_id.move_line_ids - lines).filtered( - lambda ml: not ml.picked and ml.state not in ("done", "cancel") - ) - if siblings: - # `_action_done` unlinks the non picked lines of a picked move. - siblings.picked = True - if align_demand: - lines.move_id._align_demand_to_manual_quantity() diff --git a/stock_move_manual_quantity/models/stock_picking.py b/stock_move_manual_quantity/models/stock_picking.py deleted file mode 100644 index d0641e3..0000000 --- a/stock_move_manual_quantity/models/stock_picking.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2026 Criptomart -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import models -from odoo.tools import float_is_zero - - -class StockPicking(models.Model): - _inherit = "stock.picking" - - def _pre_action_done_hook(self): - """Validate every line holding a quantity, picked by hand or not. - - Core only auto-picks a transfer when *no* move is picked yet, so as - soon as an operator freezes one weighed line the untouched ones would - be pushed to a backorder -- or cancelled, if the user answers "no - backorder" -- even though their goods are in the basket. Picking - everything that carries a quantity keeps the behaviour operators know. - """ - for picking in self.filtered(lambda p: p.state not in ("done", "cancel")): - moves = picking.move_ids.filtered( - lambda move: not move.picked - and not move.scrapped - and move.state not in ("done", "cancel") - and not float_is_zero( - move.quantity, precision_rounding=move.product_uom.rounding - ) - ) - if moves: - moves.picked = True - return super()._pre_action_done_hook() diff --git a/stock_move_manual_quantity/readme/CONFIGURE.rst b/stock_move_manual_quantity/readme/CONFIGURE.rst deleted file mode 100644 index 6a053eb..0000000 --- a/stock_move_manual_quantity/readme/CONFIGURE.rst +++ /dev/null @@ -1,2 +0,0 @@ -No configuration is required: the behaviour applies to every transfer as soon -as the module is installed. diff --git a/stock_move_manual_quantity/readme/CONTRIBUTORS.rst b/stock_move_manual_quantity/readme/CONTRIBUTORS.rst deleted file mode 100644 index ecd0958..0000000 --- a/stock_move_manual_quantity/readme/CONTRIBUTORS.rst +++ /dev/null @@ -1,3 +0,0 @@ -* `Criptomart `_: - - * Analysis of the reservation engine and implementation diff --git a/stock_move_manual_quantity/readme/CREDITS.rst b/stock_move_manual_quantity/readme/CREDITS.rst deleted file mode 100644 index d1ba675..0000000 --- a/stock_move_manual_quantity/readme/CREDITS.rst +++ /dev/null @@ -1,3 +0,0 @@ -**Authors:** - -* Criptomart diff --git a/stock_move_manual_quantity/readme/DESCRIPTION.rst b/stock_move_manual_quantity/readme/DESCRIPTION.rst deleted file mode 100644 index db47fe0..0000000 --- a/stock_move_manual_quantity/readme/DESCRIPTION.rst +++ /dev/null @@ -1,22 +0,0 @@ -When an operator types a quantity on a transfer line, that quantity is the one -that was physically handled: a bag of apples ordered as 1 kg that weighs -0.87 kg on the scale. - -Odoo, however, treats a quantity below the demand as an incomplete -*reservation*. The move goes back to ``partially_available`` and -``_action_assign`` tops it up again to the demanded quantity, either from the -``Procurement: run scheduler`` cron or from ``_trigger_assign``, which runs -every time another transfer of the same product is validated. A few hours -later the weighed 0.87 kg is back to 1 kg. Raising the quantity is never -reverted, because the move stays ``assigned`` and no longer matches those -domains. - -This module makes a hand-typed quantity final: - -* Editing a quantity from the interface marks the move as **picked**, which is - what keeps ``_action_assign`` and ``_free_reservation`` away from it. -* When the typed quantity is below the demand, the demand is lowered to match, - so the move stays ``assigned`` and no backorder is asked for a quantity that - will never be completed. -* Transfers still validate every line that carries a quantity, picked by hand - or not, so freezing one line never pushes the untouched ones to a backorder. diff --git a/stock_move_manual_quantity/readme/INSTALL.rst b/stock_move_manual_quantity/readme/INSTALL.rst deleted file mode 100644 index 5e1e1b9..0000000 --- a/stock_move_manual_quantity/readme/INSTALL.rst +++ /dev/null @@ -1,8 +0,0 @@ -To install this module, you need to: - -#. Update the Apps list -#. Install *Stock Move Manual Quantity* - -:: - - docker-compose run --rm odoo odoo -d odoo --stop-after-init -i stock_move_manual_quantity diff --git a/stock_move_manual_quantity/readme/USAGE.rst b/stock_move_manual_quantity/readme/USAGE.rst deleted file mode 100644 index eddf61f..0000000 --- a/stock_move_manual_quantity/readme/USAGE.rst +++ /dev/null @@ -1,23 +0,0 @@ -Nothing to configure: the behaviour applies to every transfer as soon as the -module is installed. - -**Weighing a line** - -#. Open the transfer (or the batch operator view) and type the real quantity, - for example 0.87 instead of the demanded 1. -#. The move is marked as picked and, because 0.87 is below the demand, the - demand becomes 0.87 too. The move stays *Ready*. -#. Neither the scheduler nor the validation of another transfer of the same - product will change that quantity again. - -**Notes** - -* The demand is only ever lowered, never raised: above the demand the move is - already fully reserved and nothing needs to be adjusted. -* A line left at zero keeps the standard behaviour, so the transfer still - offers its usual backorder choice for what was not delivered. -* Chained moves (multi-step routes) are only frozen, their demand is left - untouched so the next step of the route stays consistent. -* Lowering the demand is logged in the transfer chatter, and it is what the - sale order uses to know how much is still to deliver while the transfer is - not validated. diff --git a/stock_move_manual_quantity/tests/__init__.py b/stock_move_manual_quantity/tests/__init__.py deleted file mode 100644 index 9a3ccd6..0000000 --- a/stock_move_manual_quantity/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import test_manual_quantity diff --git a/stock_move_manual_quantity/tests/test_manual_quantity.py b/stock_move_manual_quantity/tests/test_manual_quantity.py deleted file mode 100644 index fe2d6a8..0000000 --- a/stock_move_manual_quantity/tests/test_manual_quantity.py +++ /dev/null @@ -1,184 +0,0 @@ -# Copyright 2026 Criptomart -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import Command -from odoo.tests import Form -from odoo.tests import TransactionCase -from odoo.tests import tagged - - -@tagged("-at_install", "post_install") -class TestManualQuantity(TransactionCase): - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.uom_kg = cls.env.ref("uom.product_uom_kgm") - cls.stock_location = cls.env.ref("stock.stock_location_stock") - cls.customer_location = cls.env.ref("stock.stock_location_customers") - cls.picking_type_out = cls.env.ref("stock.picking_type_out") - - cls.apples = cls.env["product.product"].create( - { - "name": "Apples", - "is_storable": True, - "uom_id": cls.uom_kg.id, - "uom_po_id": cls.uom_kg.id, - } - ) - cls.bread = cls.env["product.product"].create( - { - "name": "Bread", - "is_storable": True, - "uom_id": cls.uom_kg.id, - "uom_po_id": cls.uom_kg.id, - } - ) - for product in cls.apples | cls.bread: - cls.env["stock.quant"]._update_available_quantity( - product, cls.stock_location, 100.0 - ) - - # Helpers - - def _create_picking(self, products_qty): - """Create a confirmed and reserved delivery for ``{product: demand}``.""" - picking = self.env["stock.picking"].create( - { - "picking_type_id": self.picking_type_out.id, - "location_id": self.stock_location.id, - "location_dest_id": self.customer_location.id, - "move_ids": [ - Command.create( - { - "name": product.name, - "product_id": product.id, - "product_uom": product.uom_id.id, - "product_uom_qty": qty, - "location_id": self.stock_location.id, - "location_dest_id": self.customer_location.id, - } - ) - for product, qty in products_qty.items() - ], - } - ) - picking.action_confirm() - picking.action_assign() - return picking - - def _type_quantity(self, line, quantity): - """Reproduce what the web client sends when a user types a quantity. - - The onchange marks the line as picked, so both fields travel together - in the same write. - """ - edited = line.new(origin=line) - edited.quantity = quantity - edited._onchange_quantity_manual() - line.write({"quantity": quantity, "picked": edited.picked}) - - # Tests - - def test_onchange_marks_the_line_as_picked(self): - picking = self._create_picking({self.apples: 1.0}) - line = picking.move_ids.move_line_ids - - edited = line.new(origin=line) - edited.quantity = 0.87 - edited._onchange_quantity_manual() - - self.assertTrue(edited.picked) - - def test_reservation_does_not_restore_a_lowered_quantity(self): - picking = self._create_picking({self.apples: 1.0}) - move = picking.move_ids - self.assertEqual(move.quantity, 1.0) - - self._type_quantity(move.move_line_ids, 0.87) - - self.assertTrue(move.picked) - self.assertEqual(move.product_uom_qty, 0.87) - self.assertEqual(move.state, "assigned") - - # The two entry points that used to top the move back up to its demand. - move._action_assign() - self.env["procurement.group"].run_scheduler() - - self.assertEqual(move.quantity, 0.87) - self.assertEqual(move.move_line_ids.quantity, 0.87) - - def test_a_raised_quantity_keeps_its_demand(self): - picking = self._create_picking({self.apples: 1.0}) - move = picking.move_ids - - self._type_quantity(move.move_line_ids, 1.2) - - self.assertEqual(move.product_uom_qty, 1.0) - self.assertEqual(move.state, "assigned") - - move._action_assign() - - self.assertEqual(move.quantity, 1.2) - - def test_an_empty_line_keeps_its_demand(self): - """A line left at zero still offers the standard backorder choice.""" - picking = self._create_picking({self.apples: 1.0}) - move = picking.move_ids - - self._type_quantity(move.move_line_ids, 0.0) - - self.assertEqual(move.product_uom_qty, 1.0) - - def test_reserving_does_not_mark_moves_as_picked(self): - """Only a person marks a move as picked, never the reservation.""" - picking = self._create_picking({self.apples: 1.0}) - - picking.move_ids._action_assign() - self.env["procurement.group"].run_scheduler() - - self.assertFalse(picking.move_ids.picked) - self.assertFalse(picking.move_ids.move_line_ids.picked) - - def test_editing_the_move_quantity_freezes_it_too(self): - """The Operations tab of a transfer edits the quantity on the move.""" - picking = self._create_picking({self.apples: 1.0}) - move = picking.move_ids - - with Form(picking) as picking_form: - with picking_form.move_ids_without_package.edit(0) as move_form: - move_form.quantity = 0.87 - - self.assertTrue(move.picked) - self.assertEqual(move.product_uom_qty, 0.87) - - move._action_assign() - - self.assertEqual(move.quantity, 0.87) - - def test_untouched_lines_are_still_validated(self): - """Freezing one line must not push the others to a backorder.""" - picking = self._create_picking({self.apples: 1.0, self.bread: 2.0}) - apples_move = picking.move_ids.filtered( - lambda move: move.product_id == self.apples - ) - bread_move = picking.move_ids - apples_move - - self._type_quantity(apples_move.move_line_ids, 0.87) - picking.button_validate() - - self.assertEqual(picking.state, "done") - self.assertEqual(apples_move.quantity, 0.87) - self.assertEqual(bread_move.state, "done") - self.assertEqual(bread_move.quantity, 2.0) - self.assertFalse(picking.backorder_ids) - - def test_operation_views_load_the_picked_field(self): - """The client only sends back the fields present in the arch.""" - move_line = self.env["stock.move.line"] - for xml_id in ( - "stock.view_stock_move_line_operation_tree", - "stock.view_stock_move_line_detailed_operation_tree", - ): - with self.subTest(view=xml_id): - view = move_line.get_view(self.env.ref(xml_id).id, "list") - self.assertIn('name="picked"', view["arch"]) diff --git a/stock_move_manual_quantity/views/stock_move_line_views.xml b/stock_move_manual_quantity/views/stock_move_line_views.xml deleted file mode 100644 index 91b50b9..0000000 --- a/stock_move_manual_quantity/views/stock_move_line_views.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - stock.move.line.operations.manual.quantity - stock.move.line - - - - - - - - - - stock.move.line.detailed.operations.manual.quantity - stock.move.line - - - - - - - - diff --git a/stock_picking_batch_collect/README.rst b/stock_picking_batch_collect/README.rst deleted file mode 100644 index 75a70b6..0000000 --- a/stock_picking_batch_collect/README.rst +++ /dev/null @@ -1,127 +0,0 @@ -=========================== -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 diff --git a/stock_picking_batch_collect/__init__.py b/stock_picking_batch_collect/__init__.py deleted file mode 100644 index 4a5c3e3..0000000 --- a/stock_picking_batch_collect/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from . import models # 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 deleted file mode 100644 index 7e61eac..0000000 --- a/stock_picking_batch_collect/__manifest__.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2026 Criptomart -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -{ # noqa: B018 - "name": "Stock Picking Batch Collect", - "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", - "maintainers": ["Criptomart"], - "website": "https://github.com/Criptomart", - "license": "AGPL-3", - "depends": [ - # A quantity typed by the operator is the weighed one: it must not be - # re-reserved by the scheduler. - "stock_move_manual_quantity", - "stock_picking_batch", - ], - "data": [ - "security/ir.model.access.csv", - "views/res_config_settings_views.xml", - "views/stock_picking_batch_views.xml", - ], - "assets": { - "web.assets_backend": [ - "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", -} diff --git a/stock_picking_batch_collect/hooks.py b/stock_picking_batch_collect/hooks.py deleted file mode 100644 index 7dcdaf4..0000000 --- a/stock_picking_batch_collect/hooks.py +++ /dev/null @@ -1,117 +0,0 @@ -# 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,)) diff --git a/stock_picking_batch_collect/i18n/es.po b/stock_picking_batch_collect/i18n/es.po deleted file mode 100644 index 4bad2cb..0000000 --- a/stock_picking_batch_collect/i18n/es.po +++ /dev/null @@ -1,235 +0,0 @@ -# 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" diff --git a/stock_picking_batch_collect/i18n/eu.po b/stock_picking_batch_collect/i18n/eu.po deleted file mode 100644 index 62cd2c9..0000000 --- a/stock_picking_batch_collect/i18n/eu.po +++ /dev/null @@ -1,235 +0,0 @@ -# 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" diff --git a/stock_picking_batch_collect/readme/CONFIGURE.rst b/stock_picking_batch_collect/readme/CONFIGURE.rst deleted file mode 100644 index bda97fc..0000000 --- a/stock_picking_batch_collect/readme/CONFIGURE.rst +++ /dev/null @@ -1,32 +0,0 @@ -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. diff --git a/stock_picking_batch_collect/readme/DESCRIPTION.rst b/stock_picking_batch_collect/readme/DESCRIPTION.rst deleted file mode 100644 index dc348e7..0000000 --- a/stock_picking_batch_collect/readme/DESCRIPTION.rst +++ /dev/null @@ -1,26 +0,0 @@ -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. diff --git a/stock_picking_batch_collect/readme/USAGE.rst b/stock_picking_batch_collect/readme/USAGE.rst deleted file mode 100644 index 73eea25..0000000 --- a/stock_picking_batch_collect/readme/USAGE.rst +++ /dev/null @@ -1,29 +0,0 @@ -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. diff --git a/stock_picking_batch_collect/tests/__init__.py b/stock_picking_batch_collect/tests/__init__.py deleted file mode 100644 index a586ed8..0000000 --- a/stock_picking_batch_collect/tests/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from . import test_batch_summary # noqa: F401 -from . import test_collected_picked # noqa: F401 diff --git a/stock_picking_batch_collect/tests/test_collected_picked.py b/stock_picking_batch_collect/tests/test_collected_picked.py deleted file mode 100644 index c90176d..0000000 --- a/stock_picking_batch_collect/tests/test_collected_picked.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2026 Criptomart -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import Command -from odoo.tests import TransactionCase -from odoo.tests import tagged - - -@tagged("-at_install", "post_install") -class TestCollectedPicked(TransactionCase): - """Collecting a line protects its quantity from the reservation engine.""" - - @classmethod - def setUpClass(cls): - super().setUpClass() - cls.stock_location = cls.env.ref("stock.stock_location_stock") - cls.customer_location = cls.env.ref("stock.stock_location_customers") - cls.picking_type = cls.env.ref("stock.picking_type_out") - cls.product = cls.env["product.product"].create( - { - "name": "Collected Apples", - "is_storable": True, - "uom_id": cls.env.ref("uom.product_uom_kgm").id, - "uom_po_id": cls.env.ref("uom.product_uom_kgm").id, - } - ) - cls.env["stock.quant"]._update_available_quantity( - cls.product, cls.stock_location, 50.0 - ) - - def _create_picking(self, demand): - picking = self.env["stock.picking"].create( - { - "picking_type_id": self.picking_type.id, - "location_id": self.stock_location.id, - "location_dest_id": self.customer_location.id, - "move_ids": [ - Command.create( - { - "name": self.product.name, - "product_id": self.product.id, - "product_uom": self.product.uom_id.id, - "product_uom_qty": demand, - "location_id": self.stock_location.id, - "location_dest_id": self.customer_location.id, - } - ) - ], - } - ) - picking.action_confirm() - picking.action_assign() - return picking - - def test_collecting_a_line_marks_it_picked(self): - picking = self._create_picking(2.0) - line = picking.move_ids.move_line_ids - - line.is_collected = True - - self.assertTrue(line.picked) - self.assertTrue(picking.move_ids.picked) - - def test_collecting_a_line_keeps_its_demand(self): - """Only a hand-typed quantity lowers the demand, collecting does not.""" - picking = self._create_picking(2.0) - move = picking.move_ids - move.move_line_ids.write({"quantity": 1.5, "picked": True}) - - move.move_line_ids.is_collected = True - - self.assertEqual(move.product_uom_qty, 1.5) - self.assertTrue(move.picked) diff --git a/stock_picking_batch_custom/README.rst b/stock_picking_batch_custom/README.rst new file mode 100644 index 0000000..964a1a7 --- /dev/null +++ b/stock_picking_batch_custom/README.rst @@ -0,0 +1,66 @@ +============================ +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 diff --git a/stock_picking_batch_custom/__init__.py b/stock_picking_batch_custom/__init__.py new file mode 100644 index 0000000..ce9807d --- /dev/null +++ b/stock_picking_batch_custom/__init__.py @@ -0,0 +1 @@ +from . import models # noqa: F401 diff --git a/stock_picking_batch_custom/__manifest__.py b/stock_picking_batch_custom/__manifest__.py new file mode 100644 index 0000000..23d05c5 --- /dev/null +++ b/stock_picking_batch_custom/__manifest__.py @@ -0,0 +1,29 @@ +# Copyright 2026 Criptomart +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ # noqa: B018 + "name": "Stock Picking Batch Custom", + "version": "18.0.1.0.0", + "category": "Warehouse", + "summary": "Extra columns for batch detailed operations", + "author": "Odoo Community Association (OCA), Criptomart", + "maintainers": ["Criptomart"], + "website": "https://github.com/Criptomart", + "license": "AGPL-3", + "depends": [ + "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": [ + "security/ir.model.access.csv", + "views/res_config_settings_views.xml", + "views/stock_move_line_views.xml", + "views/stock_picking_batch_views.xml", + ], + "assets": { + "web.assets_backend": [ + "stock_picking_batch_custom/static/src/css/stock_picking_batch.css", + ], + }, +} diff --git a/stock_picking_batch_custom/i18n/es.po b/stock_picking_batch_custom/i18n/es.po new file mode 100644 index 0000000..e0a4108 --- /dev/null +++ b/stock_picking_batch_custom/i18n/es.po @@ -0,0 +1,235 @@ +# 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" diff --git a/stock_picking_batch_custom/i18n/eu.po b/stock_picking_batch_custom/i18n/eu.po new file mode 100644 index 0000000..82b3d93 --- /dev/null +++ b/stock_picking_batch_custom/i18n/eu.po @@ -0,0 +1,235 @@ +# 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" diff --git a/stock_picking_batch_collect/models/__init__.py b/stock_picking_batch_custom/models/__init__.py similarity index 100% rename from stock_picking_batch_collect/models/__init__.py rename to stock_picking_batch_custom/models/__init__.py index 5b85812..8be5195 100644 --- a/stock_picking_batch_collect/models/__init__.py +++ b/stock_picking_batch_custom/models/__init__.py @@ -1,6 +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_line # noqa: F401 +from . import stock_backorder_confirmation # noqa: F401 from . import stock_picking # noqa: F401 from . import stock_picking_batch # noqa: F401 diff --git a/stock_picking_batch_collect/models/res_company.py b/stock_picking_batch_custom/models/res_company.py similarity index 100% rename from stock_picking_batch_collect/models/res_company.py rename to stock_picking_batch_custom/models/res_company.py diff --git a/stock_picking_batch_collect/models/res_config_settings.py b/stock_picking_batch_custom/models/res_config_settings.py similarity index 100% rename from stock_picking_batch_collect/models/res_config_settings.py rename to stock_picking_batch_custom/models/res_config_settings.py diff --git a/stock_picking_batch_collect/models/stock_backorder_confirmation.py b/stock_picking_batch_custom/models/stock_backorder_confirmation.py similarity index 100% rename from stock_picking_batch_collect/models/stock_backorder_confirmation.py rename to stock_picking_batch_custom/models/stock_backorder_confirmation.py diff --git a/stock_picking_batch_collect/models/stock_move_line.py b/stock_picking_batch_custom/models/stock_move_line.py similarity index 57% rename from stock_picking_batch_collect/models/stock_move_line.py rename to stock_picking_batch_custom/models/stock_move_line.py index c87320a..bc75ed5 100644 --- a/stock_picking_batch_collect/models/stock_move_line.py +++ b/stock_picking_batch_custom/models/stock_move_line.py @@ -1,6 +1,7 @@ # 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 @@ -35,17 +36,22 @@ class StockMoveLine(models.Model): copy=False, ) - def write(self, vals): - res = super().write(vals) - if vals.get("is_collected"): - # Collecting a line is the operator saying the goods are in the - # basket: its quantity must survive the reservation engine even if - # it was never retyped. The demand is left alone, only a quantity - # typed by hand adjusts it. - lines = self.filtered( - lambda line: not line.picked and line.state not in ("done", "cancel") - ) - if lines: - lines.picked = True - lines._freeze_manual_quantity(align_demand=False) - return res + 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, + ) + + @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 diff --git a/stock_picking_batch_collect/models/stock_picking.py b/stock_picking_batch_custom/models/stock_picking.py similarity index 68% rename from stock_picking_batch_collect/models/stock_picking.py rename to stock_picking_batch_custom/models/stock_picking.py index 1cb06ef..2e94ffa 100644 --- a/stock_picking_batch_collect/models/stock_picking.py +++ b/stock_picking_batch_custom/models/stock_picking.py @@ -1,12 +1,28 @@ # Copyright 2026 Criptomart # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import fields from odoo import models class StockPicking(models.Model): _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): """Run collected checks only after Odoo resolves backorders. diff --git a/stock_picking_batch_collect/models/stock_picking_batch.py b/stock_picking_batch_custom/models/stock_picking_batch.py similarity index 99% rename from stock_picking_batch_collect/models/stock_picking_batch.py rename to stock_picking_batch_custom/models/stock_picking_batch.py index 553796a..6c7a409 100644 --- a/stock_picking_batch_collect/models/stock_picking_batch.py +++ b/stock_picking_batch_custom/models/stock_picking_batch.py @@ -231,7 +231,7 @@ class StockPickingBatch(models.Model): "views": [ ( self.env.ref( - "stock_picking_batch_collect.view_move_line_batch_operator" + "stock_picking_batch_custom.view_move_line_batch_operator" ).id, "list", ) diff --git a/stock_picking_batch_custom/readme/CONFIGURE.rst b/stock_picking_batch_custom/readme/CONFIGURE.rst new file mode 100644 index 0000000..2213143 --- /dev/null +++ b/stock_picking_batch_custom/readme/CONFIGURE.rst @@ -0,0 +1,8 @@ +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. diff --git a/stock_picking_batch_collect/readme/CONTRIBUTORS.rst b/stock_picking_batch_custom/readme/CONTRIBUTORS.rst similarity index 100% rename from stock_picking_batch_collect/readme/CONTRIBUTORS.rst rename to stock_picking_batch_custom/readme/CONTRIBUTORS.rst diff --git a/stock_picking_batch_collect/readme/CREDITS.rst b/stock_picking_batch_custom/readme/CREDITS.rst similarity index 100% rename from stock_picking_batch_collect/readme/CREDITS.rst rename to stock_picking_batch_custom/readme/CREDITS.rst diff --git a/stock_picking_batch_custom/readme/DESCRIPTION.rst b/stock_picking_batch_custom/readme/DESCRIPTION.rst new file mode 100644 index 0000000..da6edad --- /dev/null +++ b/stock_picking_batch_custom/readme/DESCRIPTION.rst @@ -0,0 +1,14 @@ +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. diff --git a/stock_picking_batch_collect/readme/INSTALL.rst b/stock_picking_batch_custom/readme/INSTALL.rst similarity index 80% rename from stock_picking_batch_collect/readme/INSTALL.rst rename to stock_picking_batch_custom/readme/INSTALL.rst index 05042a7..b259091 100644 --- a/stock_picking_batch_collect/readme/INSTALL.rst +++ b/stock_picking_batch_custom/readme/INSTALL.rst @@ -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_collect + docker-compose run --rm odoo odoo -d odoo --stop-after-init -u stock_picking_batch_custom diff --git a/stock_picking_batch_custom/readme/USAGE.rst b/stock_picking_batch_custom/readme/USAGE.rst new file mode 100644 index 0000000..89f41e8 --- /dev/null +++ b/stock_picking_batch_custom/readme/USAGE.rst @@ -0,0 +1,14 @@ +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. diff --git a/stock_picking_batch_collect/security/ir.model.access.csv b/stock_picking_batch_custom/security/ir.model.access.csv similarity index 100% rename from stock_picking_batch_collect/security/ir.model.access.csv rename to stock_picking_batch_custom/security/ir.model.access.csv diff --git a/stock_picking_batch_collect/static/description/icon.png b/stock_picking_batch_custom/static/description/icon.png similarity index 100% rename from stock_picking_batch_collect/static/description/icon.png rename to stock_picking_batch_custom/static/description/icon.png diff --git a/stock_picking_batch_collect/static/src/css/stock_picking_batch.css b/stock_picking_batch_custom/static/src/css/stock_picking_batch.css similarity index 82% rename from stock_picking_batch_collect/static/src/css/stock_picking_batch.css rename to stock_picking_batch_custom/static/src/css/stock_picking_batch.css index 549a93a..eada54e 100644 --- a/stock_picking_batch_collect/static/src/css/stock_picking_batch.css +++ b/stock_picking_batch_custom/static/src/css/stock_picking_batch.css @@ -1,3 +1,13 @@ +/* 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 */ /* Note: arch class lands on the root
of the list controller, not */ .o_batch_move_line_list th[data-name="quantity"], diff --git a/stock_picking_batch_custom/tests/__init__.py b/stock_picking_batch_custom/tests/__init__.py new file mode 100644 index 0000000..161ba0b --- /dev/null +++ b/stock_picking_batch_custom/tests/__init__.py @@ -0,0 +1 @@ +from . import test_batch_summary # noqa: F401 diff --git a/stock_picking_batch_collect/tests/test_batch_summary.py b/stock_picking_batch_custom/tests/test_batch_summary.py similarity index 100% rename from stock_picking_batch_collect/tests/test_batch_summary.py rename to stock_picking_batch_custom/tests/test_batch_summary.py diff --git a/stock_picking_batch_collect/views/res_config_settings_views.xml b/stock_picking_batch_custom/views/res_config_settings_views.xml similarity index 100% rename from stock_picking_batch_collect/views/res_config_settings_views.xml rename to stock_picking_batch_custom/views/res_config_settings_views.xml diff --git a/stock_picking_batch_custom/views/stock_move_line_views.xml b/stock_picking_batch_custom/views/stock_move_line_views.xml new file mode 100644 index 0000000..7a294d3 --- /dev/null +++ b/stock_picking_batch_custom/views/stock_move_line_views.xml @@ -0,0 +1,36 @@ + + + + stock.move.line.list.batch.custom + stock.move.line + + + + hide + + + hide + + + hide + + + hide + + + hide + + + + + + + + + + + + + + + diff --git a/stock_picking_batch_collect/views/stock_picking_batch_views.xml b/stock_picking_batch_custom/views/stock_picking_batch_views.xml similarity index 83% rename from stock_picking_batch_collect/views/stock_picking_batch_views.xml rename to stock_picking_batch_custom/views/stock_picking_batch_views.xml index 38c8d70..5379efe 100644 --- a/stock_picking_batch_collect/views/stock_picking_batch_views.xml +++ b/stock_picking_batch_custom/views/stock_picking_batch_views.xml @@ -30,9 +30,9 @@ context="{'display_default_code': False}"/> + + - - @@ -52,12 +52,23 @@ - + + + stock.picking.batch.picking.tree.consumer.group + stock.picking + + + + + + + + stock.move.line.list.batch.custom stock.move.line @@ -76,12 +87,10 @@ + + - - - - hide @@ -100,4 +109,5 @@ + diff --git a/web_list_striped/README.rst b/web_list_striped/README.rst deleted file mode 100644 index d07f1bf..0000000 --- a/web_list_striped/README.rst +++ /dev/null @@ -1,63 +0,0 @@ -================ -Web List Striped -================ - -Visión general -============== - -Aplica un efecto cebra (filas alternas sombreadas) y un resaltado de hover más -suave a **todas** las vistas de lista del backend de Odoo. - -El alcance global es intencionado: es justamente lo que hace este módulo. Sirve -para listas largas de almacén, contabilidad o inventario, donde seguir una fila -con la vista es más fácil si las filas alternan de color. - -Es un módulo de sólo CSS: no define modelos, campos ni vistas. Para volver al -aspecto estándar de Odoo basta con desinstalarlo. - -Nota técnica: el selector usa ``:nth-child(even)``, que cuenta todas las ``tr`` -del ``tbody`` y no sólo las filas de datos. En listas agrupadas o con fila de -*"Añadir línea"* la paridad de las bandas puede desajustarse. -``:nth-child(even of .o_data_row)`` lo resolvería, pero exige Chrome 111+ o -Firefox 113+, lo que no es una suposición segura en tablets de almacén. - -Instalación -=========== - -Instalar el módulo: - -:: - - docker-compose run --rm odoo odoo -d odoo --stop-after-init -i web_list_striped - -No tiene más dependencias que ``web``, así que se puede instalar y desinstalar -en cualquier momento sin afectar a datos. - -Configuración -============= - -No requiere configuración. El efecto se aplica al instalar el módulo y -desaparece al desinstalarlo. - -Para cambiar la intensidad de las bandas, edita los valores ``rgba()`` de -``static/src/css/web_list_striped.css``. - -Uso -=== - -No hay nada que usar: una vez instalado, cualquier vista de lista del backend -(Contactos, Facturas, Albaranes, Operaciones detalladas de un lote...) muestra -las filas alternas sombreadas y un hover más suave. - -Contribuidores -============== - -* Criptomart - -Créditos -======== - -Autor ------ - -* Criptomart diff --git a/web_list_striped/__init__.py b/web_list_striped/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/web_list_striped/__manifest__.py b/web_list_striped/__manifest__.py deleted file mode 100644 index 678c1cf..0000000 --- a/web_list_striped/__manifest__.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2026 Criptomart -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -{ # noqa: B018 - "name": "Web List Striped", - "version": "18.0.1.0.0", - "category": "Technical", - "summary": "Zebra striping and softer hover for all backend list views", - "author": "Odoo Community Association (OCA), Criptomart", - "maintainers": ["Criptomart"], - "website": "https://git.criptomart.net/criptomart/addons-cm", - "license": "AGPL-3", - "depends": ["web"], - "assets": { - "web.assets_backend": [ - "web_list_striped/static/src/css/web_list_striped.css", - ], - }, -} diff --git a/web_list_striped/readme/CONFIGURE.rst b/web_list_striped/readme/CONFIGURE.rst deleted file mode 100644 index 3e6d6d3..0000000 --- a/web_list_striped/readme/CONFIGURE.rst +++ /dev/null @@ -1,8 +0,0 @@ -Configuración -============= - -No requiere configuración. El efecto se aplica al instalar el módulo y -desaparece al desinstalarlo. - -Para cambiar la intensidad de las bandas, edita los valores ``rgba()`` de -``static/src/css/web_list_striped.css``. diff --git a/web_list_striped/readme/CONTRIBUTORS.rst b/web_list_striped/readme/CONTRIBUTORS.rst deleted file mode 100644 index 46076fe..0000000 --- a/web_list_striped/readme/CONTRIBUTORS.rst +++ /dev/null @@ -1,4 +0,0 @@ -Contribuidores -============== - -* Criptomart diff --git a/web_list_striped/readme/CREDITS.rst b/web_list_striped/readme/CREDITS.rst deleted file mode 100644 index 0aef29c..0000000 --- a/web_list_striped/readme/CREDITS.rst +++ /dev/null @@ -1,7 +0,0 @@ -Créditos -======== - -Autor ------ - -* Criptomart diff --git a/web_list_striped/readme/DESCRIPTION.rst b/web_list_striped/readme/DESCRIPTION.rst deleted file mode 100644 index f46dad4..0000000 --- a/web_list_striped/readme/DESCRIPTION.rst +++ /dev/null @@ -1,15 +0,0 @@ -Aplica un efecto cebra (filas alternas sombreadas) y un resaltado de hover más -suave a **todas** las vistas de lista del backend de Odoo. - -El alcance global es intencionado: es justamente lo que hace este módulo. Sirve -para listas largas de almacén, contabilidad o inventario, donde seguir una fila -con la vista es más fácil si las filas alternan de color. - -Es un módulo de sólo CSS: no define modelos, campos ni vistas. Para volver al -aspecto estándar de Odoo basta con desinstalarlo. - -Nota técnica: el selector usa ``:nth-child(even)``, que cuenta todas las ``tr`` -del ``tbody`` y no sólo las filas de datos. En listas agrupadas o con fila de -*"Añadir línea"* la paridad de las bandas puede desajustarse. -``:nth-child(even of .o_data_row)`` lo resolvería, pero exige Chrome 111+ o -Firefox 113+, lo que no es una suposición segura en tablets de almacén. diff --git a/web_list_striped/readme/INSTALL.rst b/web_list_striped/readme/INSTALL.rst deleted file mode 100644 index 3d083d0..0000000 --- a/web_list_striped/readme/INSTALL.rst +++ /dev/null @@ -1,11 +0,0 @@ -Instalación -=========== - -Instalar el módulo: - -:: - - docker-compose run --rm odoo odoo -d odoo --stop-after-init -i web_list_striped - -No tiene más dependencias que ``web``, así que se puede instalar y desinstalar -en cualquier momento sin afectar a datos. diff --git a/web_list_striped/readme/USAGE.rst b/web_list_striped/readme/USAGE.rst deleted file mode 100644 index c169599..0000000 --- a/web_list_striped/readme/USAGE.rst +++ /dev/null @@ -1,6 +0,0 @@ -Uso -=== - -No hay nada que usar: una vez instalado, cualquier vista de lista del backend -(Contactos, Facturas, Albaranes, Operaciones detalladas de un lote...) muestra -las filas alternas sombreadas y un hover más suave. diff --git a/web_list_striped/static/src/css/web_list_striped.css b/web_list_striped/static/src/css/web_list_striped.css deleted file mode 100644 index f0ddb82..0000000 --- a/web_list_striped/static/src/css/web_list_striped.css +++ /dev/null @@ -1,18 +0,0 @@ -/* Zebra striping for every backend list view. - * - * The reach is global on purpose: that is what this addon is for. Uninstall it - * to get the stock Odoo look back. - * - * Note: `:nth-child(even)` counts every `tr` in the `tbody`, not only the data - * rows, so parity can desync in grouped lists or lists carrying an "Add a line" - * row. `:nth-child(even of .o_data_row)` fixes that but needs Chrome 111+ / - * Firefox 113+, which is not a safe assumption for the warehouse tablets. - */ - -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); -} diff --git a/website_sale_aplicoop/README_DEV.md b/website_sale_aplicoop/README_DEV.md index efbb2dc..32c5c62 100644 --- a/website_sale_aplicoop/README_DEV.md +++ b/website_sale_aplicoop/README_DEV.md @@ -135,36 +135,22 @@ La página inicial renderiza la primera página server-side. El botón "Cargar m | Cron | Frecuencia | Acción | | ---- | ---------- | ------ | -| `_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_confirm_group_orders` | Diario (medianoche) | Confirma sale.orders pasado el cutoff; crea lotes de picking agrupados por consumer_group + pickup_date | | `_cron_update_dates` | Diario | Recalcula `delivery_date` y `pickup_date` en órdenes activas | ## Dependencias -Según `__manifest__.py`: - ```text website_sale_aplicoop ├── website_sale (Odoo core) - ├── website_sale_stock (Odoo core) - ├── payment (Odoo core) - ├── product (Odoo core) ├── sale (Odoo core) - ├── stock (Odoo core) - ├── account (Odoo core) - ├── stock_picking_batch (Odoo core) - ├── stock_picking_batch_collect (custom) - │ ├── stock_move_manual_quantity (custom) - │ └── stock_picking_batch (Odoo core) - ├── product_get_price_helper (OCA) - └── l10n_es_partner (OCA) + ├── product_main_seller (OCA) + ├── product_sale_price_from_pricelist (custom) + │ └── product_pricelist_total_margin (custom) + │ └── product_price_category (OCA) + └── stock_picking_batch_custom (custom) ``` -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 ```bash diff --git a/website_sale_aplicoop/__manifest__.py b/website_sale_aplicoop/__manifest__.py index 51ab842..e908de8 100644 --- a/website_sale_aplicoop/__manifest__.py +++ b/website_sale_aplicoop/__manifest__.py @@ -3,7 +3,7 @@ { # noqa: B018 "name": "Website Sale - Aplicoop", - "version": "18.0.1.17.0", + "version": "18.0.1.16.0", "category": "Website/Sale", "summary": "Modern replacement of legacy Aplicoop - Collaborative consumption group orders", "author": "Odoo Community Association (OCA), Criptomart", @@ -18,9 +18,6 @@ "sale", "stock", "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", "product_get_price_helper", "l10n_es_partner", @@ -46,7 +43,6 @@ "views/product_template_views.xml", "views/sale_order_views.xml", "views/stock_picking_views.xml", - "views/stock_picking_batch_views.xml", "views/portal_templates.xml", "views/load_from_history_templates.xml", ], diff --git a/website_sale_aplicoop/controllers/website_sale.py b/website_sale_aplicoop/controllers/website_sale.py index f0a55a6..5254423 100644 --- a/website_sale_aplicoop/controllers/website_sale.py +++ b/website_sale_aplicoop/controllers/website_sale.py @@ -890,6 +890,13 @@ class AplicoopWebsiteSale(WebsiteSale): product_display_info, filtered_products_dict, ) = self._prepare_products_maps(products, pricelist) + # Whether the tags row needs to be reserved on every card: if nothing in + # this batch has a published tag, the row is skipped entirely instead of + # leaving an empty aria-hidden gap on every product (see product-card.css). + any_product_has_tags = any( + v["published_tags"] for v in filtered_products_dict.values() + ) + # Inject draft sale demand context so ribbons/is_out_of_stock use forecasted net qty products, product_max_qty = self._prepare_draft_stock_data(products) @@ -934,6 +941,7 @@ class AplicoopWebsiteSale(WebsiteSale): "placed_order_url": placed_order_url, "products": products, "filtered_product_tags": filtered_products_dict, + "any_product_has_tags": any_product_has_tags, "cart": cart, "available_categories": available_categories, "category_hierarchy": category_hierarchy, @@ -1045,6 +1053,11 @@ class AplicoopWebsiteSale(WebsiteSale): "product": product, "published_tags": published_tags, } + # See eskaera_shop for why this decides whether to reserve the tags row. + any_product_has_tags = any( + v["published_tags"] for v in filtered_products_dict.values() + ) + product_display_info = {} for product in products_page: product_display_info[product.id] = self._prepare_product_display_info( @@ -1062,6 +1075,7 @@ class AplicoopWebsiteSale(WebsiteSale): "group_order": group_order, "products": products_page, "filtered_product_tags": filtered_products_dict, + "any_product_has_tags": any_product_has_tags, "product_supplier_info": product_supplier_info, "product_price_info": product_price_info, "product_display_info": product_display_info, @@ -1171,6 +1185,11 @@ class AplicoopWebsiteSale(WebsiteSale): } for product in products_page } + # See eskaera_shop for why this decides whether to reserve the tags row. + any_product_has_tags = any( + v["published_tags"] for v in filtered_products_dict.values() + ) + # Inject draft demand context for ribbons/stock flags products_page, product_max_qty = self._prepare_draft_stock_data(products_page) @@ -1184,6 +1203,7 @@ class AplicoopWebsiteSale(WebsiteSale): "group_order": group_order, "products": products_page, "filtered_product_tags": filtered_products_dict, + "any_product_has_tags": any_product_has_tags, "product_supplier_info": product_supplier_info, "product_price_info": product_price_info, "product_display_info": product_display_info, diff --git a/website_sale_aplicoop/models/__init__.py b/website_sale_aplicoop/models/__init__.py index 37fdb5c..23d4133 100644 --- a/website_sale_aplicoop/models/__init__.py +++ b/website_sale_aplicoop/models/__init__.py @@ -1,12 +1,11 @@ from . import group_order # noqa: F401 from . import group_order_slot # noqa: F401 -from . import js_translations # noqa: F401 from . import payment_transaction # noqa: F401 from . import product_category_extension # noqa: F401 from . import product_extension # noqa: F401 from . import res_config_settings # noqa: F401 from . import res_partner_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 website # noqa: F401 +from . import js_translations # noqa: F401 diff --git a/website_sale_aplicoop/models/stock_move_line_extension.py b/website_sale_aplicoop/models/stock_move_line_extension.py deleted file mode 100644 index 17ac67a..0000000 --- a/website_sale_aplicoop/models/stock_move_line_extension.py +++ /dev/null @@ -1,28 +0,0 @@ -# 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, - ) diff --git a/website_sale_aplicoop/static/src/css/base/variables.css b/website_sale_aplicoop/static/src/css/base/variables.css index 009f0ce..4073997 100644 --- a/website_sale_aplicoop/static/src/css/base/variables.css +++ b/website_sale_aplicoop/static/src/css/base/variables.css @@ -152,6 +152,7 @@ /* ========== PRODUCT CARD MEDIA ========== */ --ac-card-media-ratio: 4 / 3; + --ac-card-media-height: clamp(5rem, 4rem + 6vw, 8.5rem); /* ========== Z-INDEX ========== */ --ac-z-dropdown: 1000; diff --git a/website_sale_aplicoop/static/src/css/components/product-card.css b/website_sale_aplicoop/static/src/css/components/product-card.css index 6c648aa..852270b 100644 --- a/website_sale_aplicoop/static/src/css/components/product-card.css +++ b/website_sale_aplicoop/static/src/css/components/product-card.css @@ -6,23 +6,13 @@ * Markup (eskaera_shop_products): * .product-card-wrapper.product-card * └ .card - * ├ .product-media - * │ ├ img.product-img-cover | .product-img-placeholder - * │ └ button.product-info-toggle (only when the product has a - * │ tag, a supplier or an origin to show) - * ├ .card-body (title, .product-info-panel, price) + * ├ img.product-img-cover | .product-img-placeholder + * ├ .card-body (title, tags, supplier, origin, price) * └ form.add-to-cart-form → components/quantity-control.css * * The wrapper carries the chrome (border, radius, elevation); the inner * Bootstrap .card is neutralised through its own custom properties so the two * boxes stop drawing a double frame. - * - * Tags/supplier/origin used to sit unconditionally in the card body so every - * card's price row lined up regardless of which fields a product had. The - * compact grid has no room for that: they now live in .product-info-panel, - * collapsed by default and revealed by .product-info-toggle (see - * website_sale.js for the click handler, delegated on #products-grid same as - * the quantity stepper). */ .product-card { @@ -51,23 +41,14 @@ /* ---------- Media ---------- */ -.product-media { - position: relative; - flex-shrink: 0; -} - .product-card .product-image, .product-img-cover, .product-img-fixed, .product-img-placeholder { display: block; + flex-shrink: 0; width: 100%; - /* 4:3, not square: a square photo ate too much vertical space on a - two-up mobile grid. aspect-ratio keeps it fluid across card widths - instead of a fixed height that over- or under-crops depending on how - many columns fit. */ - aspect-ratio: var(--ac-card-media-ratio); - height: auto; + height: var(--ac-card-media-height); border-radius: var(--ac-radius-md) var(--ac-radius-md) 0 0; object-fit: cover; background-color: var(--ac-surface-muted); @@ -80,68 +61,6 @@ color: var(--ac-text-muted); } -/* ---------- Info toggle & panel ---------- */ - -.product-info-toggle { - position: absolute; - top: var(--ac-space-2xs); - right: var(--ac-space-2xs); - display: flex; - align-items: center; - justify-content: center; - width: 1.375rem; - height: 1.375rem; - padding: 0; - border: 1px solid var(--ac-border-strong); - border-radius: var(--ac-radius-pill); - font-size: var(--ac-text-2xs); - color: var(--ac-text-secondary); - background-color: rgb(255 255 255 / 90%); - cursor: pointer; - transition: background-color var(--ac-transition-fast), color var(--ac-transition-fast); -} - -.product-info-toggle[aria-expanded="true"] { - color: var(--ac-text-on-fill); - background-color: var(--ac-color-primary-strong); - border-color: var(--ac-color-primary-strong); -} - -.product-info-panel { - display: flex; - flex-direction: column; - gap: var(--ac-space-3xs); - margin-bottom: var(--ac-space-3xs); - padding: var(--ac-space-2xs); - border: 1px solid var(--ac-border); - border-radius: var(--ac-radius-sm); - background-color: var(--ac-surface-sunken); -} - -.product-info-panel[hidden] { - display: none; -} - -@media (hover: hover) and (pointer: fine) { - .product-info-toggle:hover { - color: var(--ac-text-on-fill); - background-color: var(--ac-color-primary); - border-color: var(--ac-color-primary); - } -} - -.product-info-toggle:focus-visible { - outline: var(--ac-focus-ring-width) solid var(--ac-focus-ring-color); - outline-offset: var(--ac-focus-ring-offset); -} - -@media (pointer: coarse) { - .product-info-toggle { - width: var(--ac-touch-target); - height: var(--ac-touch-target); - } -} - /* ---------- Body ---------- */ .product-card .card-body { @@ -188,6 +107,10 @@ align-content: center; gap: var(--ac-space-3xs); justify-content: center; + /* Reserved even when a product has no tags (rendered empty, aria-hidden — + see eskaera_shop_products), so the supplier/origin/price rows below line + up across every card in the grid row. Matches one row of .badge-km. */ + min-height: calc(var(--ac-text-2xs) * var(--ac-leading-tight) + 2 * var(--ac-space-3xs) + 2px); margin: 0; padding: 0; } @@ -208,12 +131,14 @@ /* ---------- Supplier & origin ---------- */ -/* Only ever rendered inside .product-info-panel now (see - eskaera_shop_products), so there is no longer a cross-card alignment to - protect — no reserved space, no forced line clamp. */ +/* Both rows are reserved even when empty (rendered aria-hidden — see + eskaera_shop_products) and clamped to a fixed line count, so the price row + below lines up across every card in the grid row regardless of which + products actually have a supplier name or an origin. */ .product-card .product-supplier, .product-card .product-origin { margin: 0; + overflow: hidden; font-size: var(--ac-text-xs); font-weight: var(--ac-weight-normal); text-align: center; @@ -221,11 +146,17 @@ } .product-card .product-supplier { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + line-clamp: 2; + min-height: calc(2em * var(--ac-leading-tight)); overflow-wrap: break-word; } .product-card .product-origin { - overflow: hidden; + min-height: calc(1em * var(--ac-leading-tight)); + white-space: nowrap; text-overflow: ellipsis; } diff --git a/website_sale_aplicoop/static/src/css/sections/products-grid.css b/website_sale_aplicoop/static/src/css/sections/products-grid.css index d994649..5151ca3 100644 --- a/website_sale_aplicoop/static/src/css/sections/products-grid.css +++ b/website_sale_aplicoop/static/src/css/sections/products-grid.css @@ -5,18 +5,17 @@ * * The grid used to pin an exact column count at seven breakpoints (1 → 6). It * now derives the count from the space available, which keeps the card width - * stable no matter how wide the sidebar or the container is. + * stable no matter how wide the sidebar or the container is. The single query + * left is the deliberate design decision: one card per row on phones, where a + * two-up grid would shrink names and controls below comfortable size. * - * Two columns from the smallest phones: with the compact "cromo" card (4:3 - * photo, no inline tags/supplier/origin — see product-card.css) a single - * full-width column read as a tall row rather than a browsable grid. 9rem is - * the card's minimum width from 576px up; at the widest container (1320px - * minus the category sidebar) it still resolves to six columns, as before. + * 9rem is the card's minimum width; at the widest container (1320px minus the + * category sidebar) it still resolves to six columns, as before. */ .products-grid { display: grid; - grid-template-columns: repeat(2, 1fr); + grid-template-columns: 1fr; gap: var(--ac-space-md); margin-bottom: var(--ac-space-xl); } diff --git a/website_sale_aplicoop/static/src/js/website_sale.js b/website_sale_aplicoop/static/src/js/website_sale.js index 10eb073..6926f18 100644 --- a/website_sale_aplicoop/static/src/js/website_sale.js +++ b/website_sale_aplicoop/static/src/js/website_sale.js @@ -1246,23 +1246,6 @@ } }); - // Product info toggle: shows/hides the origin/supplier/tags panel - // that the compact card no longer displays inline (via event - // delegation, same reasoning as the stepper above). - productsGrid.addEventListener("click", function (e) { - var infoBtn = e.target.closest(".product-info-toggle"); - if (!infoBtn) return; - - e.preventDefault(); - var panelId = infoBtn.getAttribute("aria-controls"); - var panel = panelId ? document.getElementById(panelId) : null; - if (!panel) return; - - var isOpen = infoBtn.getAttribute("aria-expanded") === "true"; - infoBtn.setAttribute("aria-expanded", isOpen ? "false" : "true"); - panel.hidden = isOpen; - }); - // Add to cart button (via event delegation on grid) productsGrid.addEventListener("click", handleAddToCart); diff --git a/website_sale_aplicoop/tests/test_multi_company.py b/website_sale_aplicoop/tests/test_multi_company.py index bffd074..a1f9d68 100644 --- a/website_sale_aplicoop/tests/test_multi_company.py +++ b/website_sale_aplicoop/tests/test_multi_company.py @@ -14,16 +14,39 @@ class TestMultiCompanyGroupOrder(TransactionCase): def setUp(self): super().setUp() - # Crear dos compañías. `stock_picking_batch_collect` es dependencia del - # módulo, así que los campos de restricción de lote siempre existen. + # Crear dos compañías 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): - return { - "name": name, - "batch_summary_restriction_scope": "processed", - "batch_detailed_restriction_scope": "processed", - } + vals = {"name": name} + if "batch_summary_restriction_scope" in company_model._fields: + vals["batch_summary_restriction_scope"] = "processed" + if "batch_detailed_restriction_scope" in company_model._fields: + vals["batch_detailed_restriction_scope"] = "processed" + return vals self.company1 = company_model.create(_company_vals("Company 1")) self.company2 = company_model.create(_company_vals("Company 2")) diff --git a/website_sale_aplicoop/tests/test_record_rules.py b/website_sale_aplicoop/tests/test_record_rules.py index 55bef5c..99604ee 100644 --- a/website_sale_aplicoop/tests/test_record_rules.py +++ b/website_sale_aplicoop/tests/test_record_rules.py @@ -14,16 +14,39 @@ class TestGroupOrderRecordRules(TransactionCase): def setUp(self): super().setUp() - # Crear dos compañías. `stock_picking_batch_collect` es dependencia del - # módulo, así que los campos de restricción de lote siempre existen. + # Crear dos compañías 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): - return { - "name": name, - "batch_summary_restriction_scope": "processed", - "batch_detailed_restriction_scope": "processed", - } + vals = {"name": name} + if "batch_summary_restriction_scope" in company_model._fields: + vals["batch_summary_restriction_scope"] = "processed" + if "batch_detailed_restriction_scope" in company_model._fields: + vals["batch_detailed_restriction_scope"] = "processed" + return vals self.company1 = company_model.create(_company_vals("Company 1")) self.company2 = company_model.create(_company_vals("Company 2")) diff --git a/website_sale_aplicoop/views/stock_picking_batch_views.xml b/website_sale_aplicoop/views/stock_picking_batch_views.xml deleted file mode 100644 index d5f2a7f..0000000 --- a/website_sale_aplicoop/views/stock_picking_batch_views.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - stock.move.line.batch.operator.consumer.group - stock.move.line - - - - - - - - - - - - stock.move.line.list.batch.consumer.group - stock.move.line - - - - - - - - - - - - stock.picking.batch.picking.tree.consumer.group - stock.picking - - - - - - - - diff --git a/website_sale_aplicoop/views/website_templates.xml b/website_sale_aplicoop/views/website_templates.xml index 0b89f4a..e92e9de 100644 --- a/website_sale_aplicoop/views/website_templates.xml +++ b/website_sale_aplicoop/views/website_templates.xml @@ -274,15 +274,56 @@ - -
-
+
+
+
+
+ + + +
+

+

+
+ +
+
+ +
+
+
+ + + + + + + + + +
+
+
+
+
+
+
My Cart
@@ -321,49 +362,7 @@
- -
-
- - - - - - - - - -
-
-
-
- -
-
-
- - - -
-

-

-
+
@@ -764,31 +763,16 @@