Skip to content

Commit

Permalink
[IMP]sale_delivery_state: Skip sale order lines for delivery state
Browse files Browse the repository at this point in the history
  • Loading branch information
manuelregidor authored and henrybackman committed Oct 10, 2024
1 parent 091d352 commit 0eef364
Show file tree
Hide file tree
Showing 12 changed files with 188 additions and 34 deletions.
31 changes: 22 additions & 9 deletions sale_delivery_state/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Sale delivery State
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:0ff06f9e489784baf8b25b5d53c355c7c8ade5638a55431b288c216b3520b689
!! source digest: sha256:df53b074f16b808caf5d41acc70a817089ff3852a2504e53ad9ebb8cf7cbdcdd
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
Expand Down Expand Up @@ -38,8 +38,14 @@ state of the sale order can be forced to fully delivered in case some
quantities were cancelled by the customer and you consider you have
nothing more to deliver.

Sale order lines can have products or services, as long as the field
qty_delivered is set, it will trigger the computation of delivery state.
Sale order lines can have products or services, as long as the field `qty_delivered`
is set, it will trigger the computation of delivery state.

Sale order lines with the Skip Delivery State field set to True will be ignored when
computing the delivery state. This field is automatically set depending on the field
Sales > Configuration > Quotations & Orders > Skip Service products for Sale Delivery
State. If set to True, the field Skip Delivery State in sale order lines containing
service products will be automatically set to True, but it can manually changed.

This module also works with delivery.carrier fees that are added as a
sale order line. Thoses line are special as they will never be
Expand All @@ -56,6 +62,12 @@ from 'sale_stock'.
.. contents::
:local:

Configuration
=============

#. Go to *Sales > Configuration > Quotations & Orders*.
#. Check the Skip Service products for Sale Delivery State checkbox to automatically set the field Skip Delivery State in sale order lines to True when the line contains a service product.

Bug Tracker
===========

Expand All @@ -77,12 +89,13 @@ Authors
Contributors
------------

- Pierrick BRUN <[email protected]>
- Benoît Guillot <[email protected]>
- Yannick Vaucher <[email protected]>
- Daniel Reis <[email protected]>, `Open Source
Integrators <https://opensourceintegrators.com>`__
- Carlos Lopez <[email protected]>
* Pierrick BRUN <[email protected]>
* Benoît Guillot <[email protected]>
* Yannick Vaucher <[email protected]>
* Daniel Reis <[email protected]>,
`Open Source Integrators <https://opensourceintegrators.com>`
* Carlos Lopez <[email protected]>
* Manuel Regidor <[email protected]>

Maintainers
-----------
Expand Down
1 change: 1 addition & 0 deletions sale_delivery_state/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"depends": ["sale"],
"data": [
"views/sale_order_views.xml",
"views/res_config_settings_views.xml",
],
"demo": [
"demo/sale_demo.xml",
Expand Down
3 changes: 3 additions & 0 deletions sale_delivery_state/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
from . import sale_order
from . import sale_order_line
from . import res_company
from . import res_config_settings
12 changes: 12 additions & 0 deletions sale_delivery_state/models/res_company.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright 2023 Manuel Regidor <[email protected]>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import fields, models


class ResCompany(models.Model):
_inherit = "res.company"

skip_service_sale_delivery_state = fields.Boolean(
string="Skip Service products for Sale Delivery State"
)
14 changes: 14 additions & 0 deletions sale_delivery_state/models/res_config_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright 2023 Manuel Regidor <[email protected]>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import fields, models


class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"

skip_service_sale_delivery_state = fields.Boolean(
string="Skip Service products for Sale Delivery State",
related="company_id.skip_service_sale_delivery_state",
readonly=False,
)
19 changes: 15 additions & 4 deletions sale_delivery_state/models/sale_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# @author Pierrick BRUN <[email protected]>
# Copyright 2018 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
# Copyright 2023 Manuel Regidor <[email protected]>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import api, fields, models
from odoo.tools import float_compare, float_is_zero
Expand Down Expand Up @@ -39,7 +41,9 @@ def _all_qty_delivered(self):
"""
self.ensure_one()
# Skip delivery costs lines
sale_lines = self.order_line.filtered(lambda rec: not rec._is_delivery())
sale_lines = self.order_line.filtered(
lambda rec: not rec._is_delivery() and not rec.skip_sale_delivery_state
)
precision = self.env["decimal.precision"].precision_get(
"Product Unit of Measure"
)
Expand All @@ -59,7 +63,9 @@ def _partially_delivered(self):
"""
self.ensure_one()
# Skip delivery costs lines
sale_lines = self.order_line.filtered(lambda rec: not rec._is_delivery())
sale_lines = self.order_line.filtered(
lambda rec: not rec._is_delivery() and not rec.skip_sale_delivery_state
)
precision = self.env["decimal.precision"].precision_get(
"Product Unit of Measure"
)
Expand All @@ -68,8 +74,13 @@ def _partially_delivered(self):
for line in sale_lines
)

@api.depends("order_line.qty_delivered", "state", "force_delivery_state")
def _compute_oca_delivery_status(self):
@api.depends(
"order_line.qty_delivered",
"order_line.skip_sale_delivery_state",
"state",
"force_delivery_state",
)
def _compute_sale_delivery_state(self):
for order in self:
if order.state in ("draft", "cancel"):
order.delivery_status = None
Expand Down
27 changes: 27 additions & 0 deletions sale_delivery_state/models/sale_order_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 2023 Manuel Regidor <[email protected]>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import api, fields, models


class SaleOrderLine(models.Model):
_inherit = "sale.order.line"

skip_sale_delivery_state = fields.Boolean(
string="Skip Delivery State",
compute="_compute_skip_sale_delivery_state",
store=True,
readonly=False,
)

@api.depends("company_id", "product_id")
def _compute_skip_sale_delivery_state(self):
for line in self:
skip_sale_delivery_state = False
if (
line.product_id
and line.product_id.type == "service"
and line.company_id.skip_service_sale_delivery_state
):
skip_sale_delivery_state = True
line.skip_sale_delivery_state = skip_sale_delivery_state
2 changes: 2 additions & 0 deletions sale_delivery_state/readme/CONFIGURE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#. Go to *Sales > Configuration > Quotations & Orders*.
#. Check the Skip Service products for Sale Delivery State checkbox to automatically set the field Skip Delivery State in sale order lines to True when the line contains a service product.
45 changes: 29 additions & 16 deletions sale_delivery_state/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ <h1 class="title">Sale delivery State</h1>
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:0ff06f9e489784baf8b25b5d53c355c7c8ade5638a55431b288c216b3520b689
!! source digest: sha256:df53b074f16b808caf5d41acc70a817089ff3852a2504e53ad9ebb8cf7cbdcdd
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<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/17.0/sale_delivery_state"><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-17-0/sale-workflow-17-0-sale_delivery_state"><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=17.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This odoo module add delivery state on the sale order.</p>
Expand All @@ -376,8 +376,13 @@ <h1 class="title">Sale delivery State</h1>
state of the sale order can be forced to fully delivered in case some
quantities were cancelled by the customer and you consider you have
nothing more to deliver.</p>
<p>Sale order lines can have products or services, as long as the field
qty_delivered is set, it will trigger the computation of delivery state.</p>
<p>Sale order lines can have products or services, as long as the field <cite>qty_delivered</cite>
is set, it will trigger the computation of delivery state.</p>
<p>Sale order lines with the Skip Delivery State field set to True will be ignored when
computing the delivery state. This field is automatically set depending on the field
Sales &gt; Configuration &gt; Quotations &amp; Orders &gt; Skip Service products for Sale Delivery
State. If set to True, the field Skip Delivery State in sale order lines containing
service products will be automatically set to True, but it can manually changed.</p>
<p>This module also works with delivery.carrier fees that are added as a
sale order line. Thoses line are special as they will never be
considered delivered. Delivery fees lines are ignored in the computation
Expand All @@ -389,44 +394,52 @@ <h1 class="title">Sale delivery State</h1>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-1">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-2">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-3">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-4">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-5">Maintainers</a></li>
<li><a class="reference internal" href="#configuration" id="toc-entry-1">Configuration</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
<ol class="arabic simple">
<li>Go to <em>Sales &gt; Configuration &gt; Quotations &amp; Orders</em>.</li>
<li>Check the Skip Service products for Sale Delivery State checkbox to automatically set the field Skip Delivery State in sale order lines to True when the line contains a service product.</li>
</ol>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-1">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/OCA/sale-workflow/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/sale-workflow/issues/new?body=module:%20sale_delivery_state%0Aversion:%2017.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>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-2">Credits</a></h1>
<h1><a class="toc-backref" href="#toc-entry-3">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-3">Authors</a></h2>
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<ul class="simple">
<li>Akretion</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-4">Contributors</a></h2>
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<ul class="simple">
<li>Pierrick BRUN &lt;<a class="reference external" href="mailto:pierrick.brun&#64;akretion.com">pierrick.brun&#64;akretion.com</a>&gt;</li>
<li>Benoît Guillot &lt;<a class="reference external" href="mailto:benoit.guillot&#64;akretion.com">benoit.guillot&#64;akretion.com</a>&gt;</li>
<li>Yannick Vaucher &lt;<a class="reference external" href="mailto:yannick.vaucher&#64;camptocamp.com">yannick.vaucher&#64;camptocamp.com</a>&gt;</li>
<li>Daniel Reis &lt;<a class="reference external" href="mailto:dreis&#64;opensourceintegrators.com">dreis&#64;opensourceintegrators.com</a>&gt;, <a class="reference external" href="https://opensourceintegrators.com">Open Source
Integrators</a></li>
<li>Carlos Lopez &lt;<a class="reference external" href="mailto:celm1990&#64;gmail.com">celm1990&#64;gmail.com</a>&gt;</li>
<li>Daniel Reis &lt;<a class="reference external" href="mailto:dreis&#64;opensourceintegrators.com">dreis&#64;opensourceintegrators.com</a>&gt;,
<a class="reference external" href="https://opensourceintegrators.com">Open Source Integrators</a></li>
<li>Manuel Regidor &lt;<a class="reference external" href="mailto:manuel.regidor&#64;sygel.es">manuel.regidor&#64;sygel.es</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-5">Maintainers</a></h2>
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
Expand Down
31 changes: 30 additions & 1 deletion sale_delivery_state/tests/test_delivery_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ def setUpClass(cls):
cls.delivery_cost = cls.env["product.product"].create(
{"name": "delivery", "type": "service"}
)
cls.service_product = cls.env["product.product"].create(
{"name": "service", "type": "service"}
)

def _mock_delivery(self, delivery_prod=None):
delivery_prod = delivery_prod or self.delivery_cost
Expand All @@ -38,6 +41,19 @@ def _add_delivery_cost_line(self):
}
)

def _add_service_line(self, skip_sale_delivery_state=False):
self.env["sale.order.line"].create(
{
"order_id": self.order.id,
"name": "Service",
"product_id": self.service_product.id,
"product_uom_qty": 1,
"product_uom": self.env.ref("uom.product_uom_unit").id,
"price_unit": 10.0,
"skip_sale_delivery_state": skip_sale_delivery_state,
}
)

def test_no_delivery(self):
self.assertFalse(self.order.delivery_status)

Expand Down Expand Up @@ -90,4 +106,17 @@ def test_delivery_done_delivery_cost(self):
if line._is_delivery():
continue
line.qty_delivered = line.product_uom_qty
self.assertEqual(self.order.delivery_status, "full")
self.assertEqual(self.order.delivery_state, "done")

def test_skip_service_line(self):
self._add_service_line()
self.order.action_confirm()
for line in self.order.order_line:
if line.product_id == self.service_product:
continue
line.qty_delivered = line.product_uom_qty
self.assertEqual(self.order.delivery_state, "partially")
self.order.order_line.filtered(
lambda a: a.product_id and a.product_id == self.service_product
).write({"skip_sale_delivery_state": True})
self.assertEqual(self.order.delivery_state, "done")
26 changes: 26 additions & 0 deletions sale_delivery_state/views/res_config_settings_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="sale_delivery_state_res_config_settings_view_form" model="ir.ui.view">
<field name="name">sale.delivery.state.res.config.settings.view.form</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="sale.res_config_settings_view_form" />
<field name="arch" type="xml">
<xpath expr="//div[@id='proforma_configuration']" position="after">
<div
class="col-12 col-lg-6 o_setting_box"
id="skip_service_sale_delivery_state_configuration"
>
<div class="o_setting_left_pane">
<field name="skip_service_sale_delivery_state" />
</div>
<div class="o_setting_right_pane">
<label for="skip_service_sale_delivery_state" />
<div class="text-muted">
If active, sale order lines containing Service products will not be evaluated by default when determining the Delivery State.
</div>
</div>
</div>
</xpath>
</field>
</record>
</odoo>
11 changes: 7 additions & 4 deletions sale_delivery_state/views/sale_order_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@
invisible="not force_delivery_state or state != 'sale' or not locked"
/>
</field>
<group name="sale_shipping" position="inside">
<field name="delivery_status" invisible="state != 'sale'" />
<field name="force_delivery_state" invisible="1" />
</group>
<field name='date_order' position="after">
<field name="delivery_state" readonly="True" />
<field name="force_delivery_state" invisible="True" />
</field>
<xpath expr="//field[@name='order_line']//tree" position="inside">
<field name="skip_sale_delivery_state" optional="hide" />
</xpath>
</field>
</record>

Expand Down

0 comments on commit 0eef364

Please sign in to comment.