[chore] update pre-commits

This commit is contained in:
Niels Göttsch 2025-07-24 08:06:28 +02:00 committed by Niels Göttsch
parent 73e11724f9
commit c1e229ef72
6 changed files with 108 additions and 38 deletions

View file

@ -16,9 +16,9 @@ Sale Order Batch
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png .. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3 :alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-bruecksen%2Fife_nfu-lightgray.png?logo=github .. |badge3| image:: https://img.shields.io/badge/github-bruecksen%2Fnfu-lightgray.png?logo=github
:target: https://github.com/bruecksen/ife_nfu/tree/16.0/sale_order_batch :target: https://github.com/bruecksen/nfu/tree/16.0/sale_order_batch
:alt: bruecksen/ife_nfu :alt: bruecksen/nfu
|badge1| |badge2| |badge3| |badge1| |badge2| |badge3|
@ -48,10 +48,10 @@ Changelog
Bug Tracker Bug Tracker
=========== ===========
Bugs are tracked on `GitHub Issues <https://github.com/bruecksen/ife_nfu/issues>`_. Bugs are tracked on `GitHub Issues <https://github.com/bruecksen/nfu/issues>`_.
In case of trouble, please check there if your issue has already been reported. In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/bruecksen/ife_nfu/issues/new?body=module:%20sale_order_batch%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. `feedback <https://github.com/bruecksen/nfu/issues/new?body=module:%20sale_order_batch%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues. Do not contact contributors directly about support or help with technical issues.
@ -71,6 +71,6 @@ Contributors
Maintainers Maintainers
~~~~~~~~~~~ ~~~~~~~~~~~
This module is part of the `bruecksen/ife_nfu <https://github.com/bruecksen/ife_nfu/tree/16.0/sale_order_batch>`_ project on GitHub. This module is part of the `bruecksen/nfu <https://github.com/bruecksen/nfu/tree/16.0/sale_order_batch>`_ project on GitHub.
You are welcome to contribute. You are welcome to contribute.

View file

@ -5,7 +5,12 @@ from odoo.exceptions import UserError
class SaleOrder(models.Model): class SaleOrder(models.Model):
_inherit = "sale.order" _inherit = "sale.order"
batch_id = fields.Many2one("sale.order.batch", copy=False, check_company=True, domain="[('state','!=','closed')]") batch_id = fields.Many2one(
"sale.order.batch",
copy=False,
check_company=True,
domain="[('state','!=','closed')]",
)
def _get_current_batch(self): def _get_current_batch(self):
""" """
@ -47,7 +52,9 @@ class SaleOrder(models.Model):
if order.batch_id: if order.batch_id:
invalid_orders.append(order.name) invalid_orders.append(order.name)
if invalid_orders: if invalid_orders:
raise UserError(_(f"Sale Order belongs to a Batch: {', '.join(invalid_orders)}")) raise UserError(
_(f"Sale Order belongs to a Batch: {', '.join(invalid_orders)}")
)
return super().action_confirm() return super().action_confirm()
def write(self, vals): def write(self, vals):

View file

@ -3,7 +3,12 @@ from odoo import _, api, fields, models
from odoo.addons.sale.models.sale_order import INVOICE_STATUS from odoo.addons.sale.models.sale_order import INVOICE_STATUS
STATES = [("open", "Open"), ("in_progress", "In Progress"), ("closed", "Closed"), ("cancel", "Cancelled")] STATES = [
("open", "Open"),
("in_progress", "In Progress"),
("closed", "Closed"),
("cancel", "Cancelled"),
]
READONLY_FIELD_STATES = {state: [("readonly", True)] for state in {"closed"}} READONLY_FIELD_STATES = {state: [("readonly", True)] for state in {"closed"}}
@ -25,10 +30,19 @@ class SaleOrderBatch(models.Model):
default=lambda self: _("New"), default=lambda self: _("New"),
) )
company_id = fields.Many2one( company_id = fields.Many2one(
comodel_name="res.company", required=True, index=True, default=lambda self: self.env.company comodel_name="res.company",
required=True,
index=True,
default=lambda self: self.env.company,
) )
state = fields.Selection( state = fields.Selection(
selection=STATES, string="Status", readonly=True, copy=False, index=True, tracking=1, default="open" selection=STATES,
string="Status",
readonly=True,
copy=False,
index=True,
tracking=1,
default="open",
) )
date_order = fields.Datetime( date_order = fields.Datetime(
string="Order Date", string="Order Date",
@ -41,10 +55,14 @@ class SaleOrderBatch(models.Model):
) )
sale_order_ids = fields.One2many("sale.order", "batch_id") sale_order_ids = fields.One2many("sale.order", "batch_id")
sale_order_count = fields.Integer(compute="_compute_sale_order_count") sale_order_count = fields.Integer(compute="_compute_sale_order_count")
sale_order_line_ids = fields.One2many("sale.order.line", "batch_id", states=READONLY_FIELD_STATES) sale_order_line_ids = fields.One2many(
"sale.order.line", "batch_id", states=READONLY_FIELD_STATES
)
invoice_ids = fields.Many2many("account.move", compute="_compute_invoice_ids") invoice_ids = fields.Many2many("account.move", compute="_compute_invoice_ids")
invoice_count = fields.Integer(compute="_compute_invoice_ids") invoice_count = fields.Integer(compute="_compute_invoice_ids")
invoice_status = fields.Selection(selection=INVOICE_STATUS, compute="_compute_invoice_status", store=True) invoice_status = fields.Selection(
selection=INVOICE_STATUS, compute="_compute_invoice_status", store=True
)
amount_total = fields.Float(compute="_compute_amount_total", string="Total") amount_total = fields.Float(compute="_compute_amount_total", string="Total")
product_ids = fields.One2many("sale.order.batch.product", "batch_id") product_ids = fields.One2many("sale.order.batch.product", "batch_id")
product_count = fields.Integer(compute="_compute_product_count") product_count = fields.Integer(compute="_compute_product_count")
@ -66,11 +84,13 @@ class SaleOrderBatch(models.Model):
def _compute_invoice_status(self): def _compute_invoice_status(self):
for batch in self: for batch in self:
if batch.sale_order_ids and any( if batch.sale_order_ids and any(
invoice_status == "to invoice" for invoice_status in batch.sale_order_ids.mapped("invoice_status") invoice_status == "to invoice"
for invoice_status in batch.sale_order_ids.mapped("invoice_status")
): ):
batch.invoice_status = "to invoice" batch.invoice_status = "to invoice"
elif batch.sale_order_ids and all( elif batch.sale_order_ids and all(
invoice_status == "invoiced" for invoice_status in batch.sale_order_ids.mapped("invoice_status") invoice_status == "invoiced"
for invoice_status in batch.sale_order_ids.mapped("invoice_status")
): ):
batch.invoice_status = "invoiced" batch.invoice_status = "invoiced"
elif batch.sale_order_ids and all( elif batch.sale_order_ids and all(
@ -113,11 +133,15 @@ class SaleOrderBatch(models.Model):
def action_view_products(self): def action_view_products(self):
self.ensure_one() self.ensure_one()
result = self.env["ir.actions.act_window"]._for_xml_id("product.product_normal_action_sell") result = self.env["ir.actions.act_window"]._for_xml_id(
"product.product_normal_action_sell"
)
if len(self.product_ids) > 1: if len(self.product_ids) > 1:
result["domain"] = [("id", "in", self.product_ids.ids)] result["domain"] = [("id", "in", self.product_ids.ids)]
elif len(self.product_ids) == 1: elif len(self.product_ids) == 1:
result["views"] = [(self.env.ref("product.product_product_tree_view", False).id, "form")] result["views"] = [
(self.env.ref("product.product_product_tree_view", False).id, "form")
]
result["res_id"] = self.product_ids.id result["res_id"] = self.product_ids.id
else: else:
result = {"type": "ir.actions.act_window_close"} result = {"type": "ir.actions.act_window_close"}
@ -125,13 +149,17 @@ class SaleOrderBatch(models.Model):
def action_view_invoice(self): def action_view_invoice(self):
invoices = self.mapped("invoice_ids") invoices = self.mapped("invoice_ids")
action = self.env["ir.actions.actions"]._for_xml_id("account.action_move_out_invoice_type") action = self.env["ir.actions.actions"]._for_xml_id(
"account.action_move_out_invoice_type"
)
if len(invoices) > 1: if len(invoices) > 1:
action["domain"] = [("id", "in", invoices.ids)] action["domain"] = [("id", "in", invoices.ids)]
elif len(invoices) == 1: elif len(invoices) == 1:
form_view = [(self.env.ref("account.view_move_form").id, "form")] form_view = [(self.env.ref("account.view_move_form").id, "form")]
if "views" in action: if "views" in action:
action["views"] = form_view + [(state, view) for state, view in action["views"] if view != "form"] action["views"] = form_view + [
(state, view) for state, view in action["views"] if view != "form"
]
else: else:
action["views"] = form_view action["views"] = form_view
action["res_id"] = invoices.id action["res_id"] = invoices.id
@ -169,5 +197,7 @@ class SaleOrderBatch(models.Model):
if "company_id" in vals: if "company_id" in vals:
self = self.with_company(vals["company_id"]) self = self.with_company(vals["company_id"])
if vals.get("name", _("New")) == _("New"): if vals.get("name", _("New")) == _("New"):
vals["name"] = self.env["ir.sequence"].next_by_code("sale.order.batch") or _("New") vals["name"] = self.env["ir.sequence"].next_by_code(
"sale.order.batch"
) or _("New")
return super().create(vals_list) return super().create(vals_list)

View file

@ -19,14 +19,26 @@ class SaleOrderBatchProduct(models.Model):
readonly=True, readonly=True,
) )
state = fields.Selection(related="batch_id.state") state = fields.Selection(related="batch_id.state")
product_id = fields.Many2one(comodel_name="product.product", required=True, readonly=True) product_id = fields.Many2one(
product_template_id = fields.Many2one( comodel_name="product.product", required=True, readonly=True
"product.template", related="product_id.product_tmpl_id", string="Product Template" )
product_template_id = fields.Many2one(
"product.template",
related="product_id.product_tmpl_id",
string="Product Template",
)
sale_order_line_ids = fields.One2many(
"sale.order.line", "batch_product_id", states=READONLY_FIELD_STATES
)
product_uom_category_id = fields.Many2one(
related="product_id.uom_id.category_id", depends=["product_id"]
) )
sale_order_line_ids = fields.One2many("sale.order.line", "batch_product_id", states=READONLY_FIELD_STATES)
product_uom_category_id = fields.Many2one(related="product_id.uom_id.category_id", depends=["product_id"])
product_uom_qty = fields.Float( product_uom_qty = fields.Float(
string="Quantity", compute="_compute_uom_qty", precompute=True, store=True, digits=[12, 3] string="Quantity",
compute="_compute_uom_qty",
precompute=True,
store=True,
digits=[12, 3],
) )
product_uom = fields.Many2one(related="product_id.uom_id") product_uom = fields.Many2one(related="product_id.uom_id")
lst_price = fields.Float( lst_price = fields.Float(
@ -50,26 +62,42 @@ class SaleOrderBatchProduct(models.Model):
@api.constrains("product_id", "sale_order_line_ids") @api.constrains("product_id", "sale_order_line_ids")
def _check_sale_order_line_products(self): def _check_sale_order_line_products(self):
for product in self: for product in self:
if any(line.product_id != product.product_id for line in product.sale_order_line_ids): if any(
line.product_id != product.product_id
for line in product.sale_order_line_ids
):
raise ValueError("Product must be the same for all Sale Order Lines") raise ValueError("Product must be the same for all Sale Order Lines")
@api.depends("sale_order_line_ids.product_uom_qty") @api.depends("sale_order_line_ids.product_uom_qty")
def _compute_uom_qty(self): def _compute_uom_qty(self):
for product in self: for product in self:
product.product_uom_qty = sum(product.sale_order_line_ids.mapped("product_uom_qty")) product.product_uom_qty = sum(
product.sale_order_line_ids.mapped("product_uom_qty")
)
@api.depends("product_id", "product_uom_qty", "product_uom") @api.depends("product_id", "product_uom_qty", "product_uom")
def _compute_product_packaging_id(self): def _compute_product_packaging_id(self):
for line in self: for line in self:
# remove packaging if not match the product # remove packaging if not match the product
if line.product_packaging_id and line.product_packaging_id.product_id != line.product_id: if (
line.product_packaging_id
and line.product_packaging_id.product_id != line.product_id
):
line.product_packaging_id = False line.product_packaging_id = False
# suggest always the first packaging # suggest always the first packaging
if line.product_id and line.product_uom_qty and line.product_uom: if line.product_id and line.product_uom_qty and line.product_uom:
suggested_packaging = line.product_id.packaging_ids[0] if line.product_id.packaging_ids else False suggested_packaging = (
line.product_packaging_id = suggested_packaging or line.product_packaging_id line.product_id.packaging_ids[0]
if line.product_id.packaging_ids
else False
)
line.product_packaging_id = (
suggested_packaging or line.product_packaging_id
)
@api.depends("product_packaging_id") @api.depends("product_packaging_id")
def _compute_product_packaging_qty(self): def _compute_product_packaging_qty(self):
for product in self: for product in self:
product.product_packaging_qty = product.product_packaging_id.qty if product.product_packaging_id else 1 product.product_packaging_qty = (
product.product_packaging_id.qty if product.product_packaging_id else 1
)

View file

@ -12,7 +12,11 @@ class SaleOrderLine(models.Model):
for line in lines_with_batch: for line in lines_with_batch:
batch_id = line.batch_id batch_id = line.batch_id
batch_product = self.env["sale.order.batch.product"].search( batch_product = self.env["sale.order.batch.product"].search(
[("product_id", "=", line.product_id.id), ("batch_id", "=", batch_id.id)], limit=1 [
("product_id", "=", line.product_id.id),
("batch_id", "=", batch_id.id),
],
limit=1,
) )
if not batch_product: if not batch_product:
batch_product = self.env["sale.order.batch.product"].create( batch_product = self.env["sale.order.batch.product"].create(
@ -30,7 +34,8 @@ class SaleOrderLine(models.Model):
lines_with_batch = self.filtered(lambda l: l.batch_id) lines_with_batch = self.filtered(lambda l: l.batch_id)
lines_without_batch = self - lines_with_batch lines_without_batch = self - lines_with_batch
lines_with_batch.filtered( lines_with_batch.filtered(
lambda l: l.batch_product_id and l.batch_product_id.product_id != l.product_id lambda l: l.batch_product_id
and l.batch_product_id.product_id != l.product_id
)._unlink_batch_product() )._unlink_batch_product()
lines_with_batch._link_batch_product() lines_with_batch._link_batch_product()
lines_without_batch._unlink_batch_product() lines_without_batch._unlink_batch_product()

View file

@ -369,7 +369,7 @@ ul.auto-toc {
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:6686f0672ede8093b17d5d7b165f72f8e49341c7849f9e0d5a162e350fc36d71 !! source digest: sha256:6686f0672ede8093b17d5d7b165f72f8e49341c7849f9e0d5a162e350fc36d71
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/bruecksen/ife_nfu/tree/16.0/sale_order_batch"><img alt="bruecksen/ife_nfu" src="https://img.shields.io/badge/github-bruecksen%2Fife_nfu-lightgray.png?logo=github" /></a></p> <p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/bruecksen/nfu/tree/16.0/sale_order_batch"><img alt="bruecksen/nfu" src="https://img.shields.io/badge/github-bruecksen%2Fnfu-lightgray.png?logo=github" /></a></p>
<p>This module adds the possibility to group Sale orders into batches. Attributes of a Sale Order Batch will be written to all <p>This module adds the possibility to group Sale orders into batches. Attributes of a Sale Order Batch will be written to all
Sale Order. Wenn attached to a batch they can be processed together. On the other hand they cannot be proccesed individual Sale Order. Wenn attached to a batch they can be processed together. On the other hand they cannot be proccesed individual
anymore as log as they are part of a batch. Only Sale Orders in state Qutotation or Quotation Send can be attached to a batch.</p> anymore as log as they are part of a batch. Only Sale Orders in state Qutotation or Quotation Send can be attached to a batch.</p>
@ -417,10 +417,10 @@ anymore as log as they are part of a batch. Only Sale Orders in state Qutotation
</div> </div>
<div class="section" id="bug-tracker"> <div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1> <h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/bruecksen/ife_nfu/issues">GitHub Issues</a>. <p>Bugs are tracked on <a class="reference external" href="https://github.com/bruecksen/nfu/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported. In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/bruecksen/ife_nfu/issues/new?body=module:%20sale_order_batch%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p> <a class="reference external" href="https://github.com/bruecksen/nfu/issues/new?body=module:%20sale_order_batch%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p> <p>Do not contact contributors directly about support or help with technical issues.</p>
</div> </div>
<div class="section" id="credits"> <div class="section" id="credits">
@ -439,7 +439,7 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
</div> </div>
<div class="section" id="maintainers"> <div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2> <h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
<p>This module is part of the <a class="reference external" href="https://github.com/bruecksen/ife_nfu/tree/16.0/sale_order_batch">bruecksen/ife_nfu</a> project on GitHub.</p> <p>This module is part of the <a class="reference external" href="https://github.com/bruecksen/nfu/tree/16.0/sale_order_batch">bruecksen/nfu</a> project on GitHub.</p>
<p>You are welcome to contribute.</p> <p>You are welcome to contribute.</p>
</div> </div>
</div> </div>