Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[16.0][FIX] sale_invoice_policy: compute qty to invoice #3102

Merged
merged 1 commit into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
exclude: |
(?x)
# NOT INSTALLABLE ADDONS
^sale_invoice_policy/|
# END NOT INSTALLABLE ADDONS
# Files and folders generated by bots, to avoid loops
^setup/|/static/description/index\.html$|
Expand Down
4 changes: 3 additions & 1 deletion sale_invoice_policy/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Sale invoice Policy
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:3c1505e28f76dfda1fccdabb3cce63bab46df277823c4236d77da275a16a5a3c
!! source digest: sha256:f7cef4d695f93f0893a61a5db0dc5ea532311d04314a81189214b7a49d43faed
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
Expand Down Expand Up @@ -70,6 +70,8 @@ Contributors
* Denis Roussel <[email protected]>
* Alexei Rivera <[email protected]>
* Luis J. Salvatierra <[email protected]>
* Alejandro Ji Cheung <[email protected]>
* Ioan Galan <[email protected]>

Maintainers
~~~~~~~~~~~
Expand Down
1 change: 0 additions & 1 deletion sale_invoice_policy/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
from . import models
from .post_init_hook import post_init_hook
3 changes: 0 additions & 3 deletions sale_invoice_policy/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@
"license": "AGPL-3",
"depends": ["sale_stock"],
"data": [
"views/product_template_view.xml",
"views/res_config_settings_view.xml",
"views/sale_view.xml",
],
"installable": False,
"post_init_hook": "post_init_hook",
}
1 change: 0 additions & 1 deletion sale_invoice_policy/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from . import product_template
from . import res_config_settings
from . import sale_order
from . import sale_order_line
54 changes: 0 additions & 54 deletions sale_invoice_policy/models/product_template.py

This file was deleted.

10 changes: 0 additions & 10 deletions sale_invoice_policy/models/res_config_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@
class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"

sale_default_invoice_policy = fields.Selection(
pedrobaeza marked this conversation as resolved.
Show resolved Hide resolved
related="default_invoice_policy",
string="Default Sale Invoice Policy",
readonly=True,
)
sale_invoice_policy_required = fields.Boolean(
help="This makes Invoice Policy required on Sale Orders"
)
Expand All @@ -36,9 +31,4 @@ def set_values(self):
"sale_invoice_policy_required",
self.sale_invoice_policy_required,
)
ir_default_obj.set(
"res.config.settings",
"sale_default_invoice_policy",
self.sale_default_invoice_policy,
)
return True
16 changes: 11 additions & 5 deletions sale_invoice_policy/models/sale_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,23 @@ class SaleOrder(models.Model):
@api.model
def default_get(self, fields_list):
res = super().default_get(fields_list)
default_sale_invoice_policy = self.env["ir.default"].get(
"res.config.settings", "sale_default_invoice_policy"
default_invoice_policy = (
self.env["res.config.settings"]
.sudo()
.default_get(["default_invoice_policy"])
.get("default_invoice_policy", False)
)
if "invoice_policy" not in res:
res.update({"invoice_policy": default_sale_invoice_policy})
res.update({"invoice_policy": default_invoice_policy})
return res

@api.depends("partner_id")
def _compute_invoice_policy_required(self):
invoice_policy_required = self.env["ir.default"].get(
"res.config.settings", "sale_invoice_policy_required"
invoice_policy_required = (
self.env["res.config.settings"]
.sudo()
.default_get(["sale_invoice_policy_required"])
.get("sale_invoice_policy_required", False)
)
for sale in self:
sale.invoice_policy_required = invoice_policy_required
122 changes: 78 additions & 44 deletions sale_invoice_policy/models/sale_order_line.py
Original file line number Diff line number Diff line change
@@ -1,68 +1,102 @@
# Copyright 2017 ACSONE SA/NV (<http://acsone.eu>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import api, models
from odoo import api, fields, models


class SaleOrderLine(models.Model):

_inherit = "sale.order.line"

@api.depends(
"qty_invoiced",
"qty_delivered",
"product_uom_qty",
"order_id.state",
"state",
"order_id.invoice_policy",
)
def _compute_qty_to_invoice(self):
invoice_policies = set(self.mapped("order_id.invoice_policy"))
line_by_id = {line.id: line for line in self}
done_lines = self.env["sale.order.line"].browse()
for invoice_policy in invoice_policies:
so_lines = (
self.with_context(invoice_policy=invoice_policy)
.filtered(lambda x, p=invoice_policy: x.order_id.invoice_policy == p)
.with_prefetch()
)
if so_lines:
done_lines |= so_lines
super(SaleOrderLine, so_lines)._compute_qty_to_invoice()
for line in so_lines:
# due to the change of context in compute methods,
# assign the value in the modified context to self
line_by_id[line.id].qty_to_invoice = line.qty_to_invoice
# Not to break function if (it could not happen) some records
# were not in so_lines
super(SaleOrderLine, self - done_lines)._compute_qty_to_invoice()
other_lines = self.filtered(
lambda l: l.product_id.type == "service"
or not l.order_id.invoice_policy
or not l.order_id.invoice_policy_required
)
super(SaleOrderLine, other_lines)._compute_qty_to_invoice()
for line in self - other_lines:
invoice_policy = line.order_id.invoice_policy
if invoice_policy == "order":
line.qty_to_invoice = line.product_uom_qty - line.qty_invoiced
else:
line.qty_to_invoice = line.qty_delivered - line.qty_invoiced
return True

@api.depends(
"state",
"product_uom_qty",
"price_reduce",
"product_id",
"untaxed_amount_invoiced",
"qty_delivered",
"qty_to_invoice",
"qty_invoiced",
"product_uom_qty",
"order_id.invoice_policy",
)
def _compute_invoice_status(self):
invoice_policies = set(self.mapped("order_id.invoice_policy"))
line_by_id = {line.id: line for line in self}
done_lines = self.env["sale.order.line"].browse()
for invoice_policy in invoice_policies:
so_lines = (
self.with_context(invoice_policy=invoice_policy)
.filtered(lambda x, p=invoice_policy: x.order_id.invoice_policy == p)
.with_prefetch()
def _compute_untaxed_amount_to_invoice(self):
other_lines = self.filtered(
lambda line: line.product_id.type == "service"
or not line.order_id.invoice_policy
or line.order_id.invoice_policy == line.product_id.invoice_policy
or line.state not in ["sale", "done"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, I think you need to also check if l.order_id.invoice_policy_required is set on False, because if it is, you don't need to modify the line, since it is not required.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

or not line.order_id.invoice_policy_required
)
super(SaleOrderLine, other_lines)._compute_untaxed_amount_to_invoice()
for line in self - other_lines:
invoice_policy = line.order_id.invoice_policy
amount_to_invoice = 0.0
price_subtotal = 0.0
uom_qty_to_consider = (

Check warning on line 54 in sale_invoice_policy/models/sale_order_line.py

View check run for this annotation

Codecov / codecov/patch

sale_invoice_policy/models/sale_order_line.py#L51-L54

Added lines #L51 - L54 were not covered by tests
line.qty_delivered
if invoice_policy == "delivery"
else line.product_uom_qty
)
done_lines |= so_lines
if so_lines:
super(SaleOrderLine, so_lines)._compute_invoice_status()
for line in so_lines:
# due to the change of context in compute methods,
# assign the value in the modified context to self
line_by_id[line.id].invoice_status = line.invoice_status
# Not to break function if (it could not happen) some records
# were not in so_lines
super(SaleOrderLine, self - done_lines)._compute_invoice_status()
price_reduce = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
price_subtotal = price_reduce * uom_qty_to_consider

Check warning on line 60 in sale_invoice_policy/models/sale_order_line.py

View check run for this annotation

Codecov / codecov/patch

sale_invoice_policy/models/sale_order_line.py#L59-L60

Added lines #L59 - L60 were not covered by tests
if len(line.tax_id.filtered(lambda tax: tax.price_include)) > 0:
price_subtotal = line.tax_id.compute_all(

Check warning on line 62 in sale_invoice_policy/models/sale_order_line.py

View check run for this annotation

Codecov / codecov/patch

sale_invoice_policy/models/sale_order_line.py#L62

Added line #L62 was not covered by tests
price_reduce,
currency=line.currency_id,
quantity=uom_qty_to_consider,
product=line.product_id,
partner=line.order_id.partner_shipping_id,
)["total_excluded"]
inv_lines = line._get_invoice_lines()

Check warning on line 69 in sale_invoice_policy/models/sale_order_line.py

View check run for this annotation

Codecov / codecov/patch

sale_invoice_policy/models/sale_order_line.py#L69

Added line #L69 was not covered by tests
if any(inv_lines.mapped(lambda l: l.discount != line.discount)):
amount = 0

Check warning on line 71 in sale_invoice_policy/models/sale_order_line.py

View check run for this annotation

Codecov / codecov/patch

sale_invoice_policy/models/sale_order_line.py#L71

Added line #L71 was not covered by tests
for inv_line in inv_lines:
if (
len(inv_line.tax_ids.filtered(lambda tax: tax.price_include))
> 0
):
amount += inv_line.tax_ids.compute_all(

Check warning on line 77 in sale_invoice_policy/models/sale_order_line.py

View check run for this annotation

Codecov / codecov/patch

sale_invoice_policy/models/sale_order_line.py#L77

Added line #L77 was not covered by tests
inv_line.currency_id._convert(
inv_line.price_unit,
line.currency_id,
line.company_id,
inv_line.date or fields.Date.today(),
round=False,
)
* inv_line.quantity
)["total_excluded"]
else:
amount += (

Check warning on line 88 in sale_invoice_policy/models/sale_order_line.py

View check run for this annotation

Codecov / codecov/patch

sale_invoice_policy/models/sale_order_line.py#L88

Added line #L88 was not covered by tests
inv_line.currency_id._convert(
inv_line.price_unit,
line.currency_id,
line.company_id,
inv_line.date or fields.Date.today(),
round=False,
)
* inv_line.quantity
)
amount_to_invoice = max(price_subtotal - amount, 0)

Check warning on line 98 in sale_invoice_policy/models/sale_order_line.py

View check run for this annotation

Codecov / codecov/patch

sale_invoice_policy/models/sale_order_line.py#L98

Added line #L98 was not covered by tests
else:
amount_to_invoice = price_subtotal - line.untaxed_amount_invoiced
line.untaxed_amount_to_invoice = amount_to_invoice

Check warning on line 101 in sale_invoice_policy/models/sale_order_line.py

View check run for this annotation

Codecov / codecov/patch

sale_invoice_policy/models/sale_order_line.py#L100-L101

Added lines #L100 - L101 were not covered by tests
return True
15 changes: 0 additions & 15 deletions sale_invoice_policy/post_init_hook.py

This file was deleted.

2 changes: 2 additions & 0 deletions sale_invoice_policy/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
* Denis Roussel <[email protected]>
* Alexei Rivera <[email protected]>
* Luis J. Salvatierra <[email protected]>
* Alejandro Ji Cheung <[email protected]>
* Ioan Galan <[email protected]>
5 changes: 3 additions & 2 deletions sale_invoice_policy/static/description/index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
Expand Down Expand Up @@ -367,7 +366,7 @@ <h1 class="title">Sale invoice Policy</h1>
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:3c1505e28f76dfda1fccdabb3cce63bab46df277823c4236d77da275a16a5a3c
!! source digest: sha256:f7cef4d695f93f0893a61a5db0dc5ea532311d04314a81189214b7a49d43faed
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<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/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/sale-workflow/tree/16.0/sale_invoice_policy"><img alt="OCA/sale-workflow" src="https://img.shields.io/badge/github-OCA%2Fsale--workflow-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/sale-workflow-16-0/sale-workflow-16-0-sale_invoice_policy"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/sale-workflow&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This modules helps to get Invoicing Policy on Sale Order Level without
Expand Down Expand Up @@ -418,6 +417,8 @@ <h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<li>Denis Roussel &lt;<a class="reference external" href="mailto:denis.roussel&#64;acsone.eu">denis.roussel&#64;acsone.eu</a>&gt;</li>
<li>Alexei Rivera &lt;<a class="reference external" href="mailto:arivera&#64;archeti.com">arivera&#64;archeti.com</a>&gt;</li>
<li>Luis J. Salvatierra &lt;<a class="reference external" href="mailto:luis.salvatierra&#64;factorlibre.com">luis.salvatierra&#64;factorlibre.com</a>&gt;</li>
<li>Alejandro Ji Cheung &lt;<a class="reference external" href="mailto:alejandro.jicheung&#64;factorlibre.com">alejandro.jicheung&#64;factorlibre.com</a>&gt;</li>
<li>Ioan Galan &lt;<a class="reference external" href="mailto:ioan&#64;studio73.es">ioan&#64;studio73.es</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
Expand Down
Loading
Loading