[IMP] stock_picking_batch_custom: configuraciones de bloqueo por pestaña

This commit is contained in:
snt 2026-04-08 18:48:18 +02:00
parent 05a8908007
commit 18fd73ed1b
7 changed files with 211 additions and 25 deletions

View file

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

View file

@ -0,0 +1,37 @@
# Copyright 2026 Criptomart
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields
from odoo import models
class ResCompany(models.Model):
_inherit = "res.company"
batch_summary_restriction_enabled = fields.Boolean(
string="Enforce Product Summary Restriction",
default=False,
)
batch_summary_restriction_scope = fields.Selection(
selection=[
("processed", "Only processed products"),
("all", "All summary products"),
],
string="Product Summary Restriction Scope",
default="processed",
required=True,
)
batch_detailed_restriction_enabled = fields.Boolean(
string="Enforce Detailed Operations Restriction",
default=True,
)
batch_detailed_restriction_scope = fields.Selection(
selection=[
("processed", "Only processed lines"),
("all", "All detailed lines"),
],
string="Detailed Operations Restriction Scope",
default="processed",
required=True,
)

View file

@ -0,0 +1,27 @@
# Copyright 2026 Criptomart
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields
from odoo import models
class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"
batch_summary_restriction_enabled = fields.Boolean(
related="company_id.batch_summary_restriction_enabled",
readonly=False,
)
batch_summary_restriction_scope = fields.Selection(
related="company_id.batch_summary_restriction_scope",
readonly=False,
)
batch_detailed_restriction_enabled = fields.Boolean(
related="company_id.batch_detailed_restriction_enabled",
readonly=False,
)
batch_detailed_restriction_scope = fields.Selection(
related="company_id.batch_detailed_restriction_scope",
readonly=False,
)

View file

@ -140,15 +140,47 @@ class StockPickingBatch(models.Model):
else:
batch.summary_line_ids = [fields.Command.clear()]
def _check_all_products_collected(self, pickings=None):
"""Validate only Detailed Operations collected flags.
def _raise_collected_restriction(self, base_message, product_names):
message = self.env._(base_message)
if product_names:
message += "\n" + self.env._(
"Pending products: %(products)s", products=product_names
)
raise UserError(message)
Product Summary checkboxes are informative and must not block the flow.
The blocking validation applies to stock.move.line.is_collected in the
detailed operations tab for lines with processed quantity.
"""
def _get_not_collected_summary_lines(self, batch_pickings, scope):
summary_lines = self.summary_line_ids
if scope == "processed":
processed_product_ids = set(
batch_pickings.move_line_ids.filtered(
lambda line: (
line.move_id.state not in ("cancel", "done")
and line.product_id
and line.move_id.quantity > 0
)
).mapped("product_id.id")
)
summary_lines = summary_lines.filtered(
lambda line: line.product_id.id in processed_product_ids
)
return summary_lines.filtered(lambda line: not line.is_collected)
def _get_not_collected_detailed_lines(self, batch_pickings, scope):
detailed_lines = batch_pickings.move_line_ids.filtered(
lambda line: line.move_id.state not in ("cancel", "done")
and line.product_id
)
if scope == "processed":
detailed_lines = detailed_lines.filtered(
lambda line: line.move_id.quantity > 0
)
return detailed_lines.filtered(lambda line: not line.is_collected)
def _check_all_products_collected(self, pickings=None):
"""Validate collected restrictions based on tab configuration."""
for batch in self:
company = batch.company_id or self.env.company
batch_pickings = (
pickings.filtered(lambda p, batch=batch: p.batch_id == batch)
if pickings
@ -157,28 +189,37 @@ class StockPickingBatch(models.Model):
if not batch_pickings:
continue
not_collected_move_lines = batch_pickings.move_line_ids.filtered(
lambda line: (
line.move_id.state not in ("cancel", "done")
and line.product_id
and line.move_id.quantity > 0
and not line.is_collected
if company.batch_detailed_restriction_enabled:
not_collected_detailed = batch._get_not_collected_detailed_lines(
batch_pickings, company.batch_detailed_restriction_scope
)
)
if not not_collected_move_lines:
continue
if not_collected_detailed:
product_names = ", ".join(
sorted(
set(
not_collected_detailed.mapped("product_id.display_name")
)
)
)
batch._raise_collected_restriction(
"You must mark detailed operation lines as collected before validating the batch.",
product_names,
)
product_names = ", ".join(
sorted(set(not_collected_move_lines.mapped("product_id.display_name")))
)
message = batch.env._(
"You must mark detailed operation lines as collected before validating the batch."
)
if product_names:
message += "\n" + batch.env._(
"Pending products: %(products)s", products=product_names
if company.batch_summary_restriction_enabled:
not_collected_summary = batch._get_not_collected_summary_lines(
batch_pickings, company.batch_summary_restriction_scope
)
raise UserError(message)
if not_collected_summary:
product_names = ", ".join(
sorted(
set(not_collected_summary.mapped("product_id.display_name"))
)
)
batch._raise_collected_restriction(
"You must mark product summary lines as collected before validating the batch.",
product_names,
)
class StockPickingBatchSummaryLine(models.Model):