Skip to content
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
2 changes: 2 additions & 0 deletions sale_production_state/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import models
from . import tests
19 changes: 19 additions & 0 deletions sale_production_state/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2021 Akretion (http://www.akretion.com).
# @author Benoît GUILLOT <benoit.guillot@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
"name": "Sale production State",
"summary": "Show the production state on the sale order",
"version": "14.0.1.0.0",
"category": "Product",
"website": "https://github.com/OCA/sale-workflow",
"author": "Akretion, Odoo Community Association (OCA)",
"license": "AGPL-3",
"installable": True,
"depends": ["mrp_sale_info"],
"data": [
"views/sale_order.xml",
],
"demo": [],
}
2 changes: 2 additions & 0 deletions sale_production_state/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import sale_order
from . import sale_order_line
35 changes: 35 additions & 0 deletions sale_production_state/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright 2021 Akretion (http://www.akretion.com).
# @author Benoît GUILLOT <benoit.guillot@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, fields, models


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

production_state = fields.Selection(
selection=[
("no", "No manufacturing"),
("unprocessed", "Unprocessed"),
("partially", "Partially processed"),
("done", "Done"),
],
string="Manufacturing state",
compute="_compute_production_state",
store=True,
Comment thread
sebastienbeau marked this conversation as resolved.
index=True,
)

@api.depends("order_line.production_state")
def _compute_production_state(self):
for order in self:
production_states = [x.production_state for x in order.order_line]
if all(x == "no" for x in production_states):
order.production_state = "no"
elif all(x in ["done", "no"] for x in production_states):
order.production_state = "done"
elif all(x in ["unprocessed", "no"] for x in production_states):
order.production_state = "unprocessed"
else:
order.production_state = "partially"
34 changes: 34 additions & 0 deletions sale_production_state/models/sale_order_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Copyright 2021 Akretion (http://www.akretion.com).
# @author Benoît GUILLOT <benoit.guillot@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, fields, models


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

production_state = fields.Selection(
selection=[
("no", "No manufacturing"),
("unprocessed", "Unprocessed"),
("partially", "Partially processed"),
("done", "Done"),
],
string="Manufacturing state",
compute="_compute_production_state",
store=True,
Comment thread
sebastienbeau marked this conversation as resolved.
index=True,
)

@api.depends("production_ids", "production_ids.state")
def _compute_production_state(self):
for line in self:
if not line.production_ids:
line.production_state = "no"
elif all(x.state in ["done", "cancel"] for x in line.production_ids):
line.production_state = "done"
elif any(x.state == "done" for x in line.production_ids):
line.production_state = "partially"

Check warning on line 32 in sale_production_state/models/sale_order_line.py

View check run for this annotation

Codecov / codecov/patch

sale_production_state/models/sale_order_line.py#L32

Added line #L32 was not covered by tests
else:
line.production_state = "unprocessed"
1 change: 1 addition & 0 deletions sale_production_state/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Benoît Guillot <benoit.guillot@akretion.com>
3 changes: 3 additions & 0 deletions sale_production_state/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This module adds production state on the sale order.

It is computed from the state of the manufactruring orders related to the sale order.
1 change: 1 addition & 0 deletions sale_production_state/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_production_state
116 changes: 116 additions & 0 deletions sale_production_state/tests/test_production_state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Copyright 2018 Akretion (http://www.akretion.com).
# @author Benoît GUILLOT <benoit.guillot@akretion.com>
# Copyright 2018 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo.tests import Form, SavepointCase


class TestSaleProductionState(SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
route_manufacture_1 = cls.env.ref("mrp.route_warehouse0_manufacture")
route_manufacture_2 = cls.env.ref("stock.route_warehouse0_mto")
route_manufacture_2.active = True
cls.product_1 = cls.env["product.product"].create(
{
"name": "Test sale production state product 1",
"type": "product",
"route_ids": [
(4, route_manufacture_1.id),
(4, route_manufacture_2.id),
],
}
)
cls.product = cls.env["product.product"].create(
{
"name": "Test sale production state product",
"type": "product",
}
)
cls.bom_1 = cls.env["mrp.bom"].create(
{
"product_tmpl_id": cls.product_1.product_tmpl_id.id,
}
)
cls.env["mrp.bom.line"].create(
{"bom_id": cls.bom_1.id, "product_id": cls.product.id, "product_qty": 1}
)
cls.product_2 = cls.env["product.product"].create(
{
"name": "Test sale production state product 2",
"type": "product",
"route_ids": [
(4, route_manufacture_1.id),
(4, route_manufacture_2.id),
],
}
)
cls.bom_2 = cls.env["mrp.bom"].create(
{
"product_tmpl_id": cls.product_2.product_tmpl_id.id,
}
)
cls.env["mrp.bom.line"].create(
{"bom_id": cls.bom_2.id, "product_id": cls.product.id, "product_qty": 1}
)
cls.partner = cls.env["res.partner"].create({"name": "Test client"})
cls.order = cls.env["sale.order"].create(
{
"partner_id": cls.partner.id,
"client_order_ref": "SO1",
"order_line": [
(
0,
0,
{
"product_id": cls.product_1.id,
"product_uom_qty": 1,
"price_unit": 1,
},
),
(
0,
0,
{
"product_id": cls.product_2.id,
"product_uom_qty": 1,
"price_unit": 1,
},
),
],
}
)

def test_no_production(self):
self.assertEqual(self.order.order_line[0].production_state, "no")
self.assertEqual(self.order.production_state, "no")

def test_unprocessed_production(self):
self.order.action_confirm()
self.assertEqual(self.order.order_line[0].production_state, "unprocessed")
self.assertEqual(self.order.production_state, "unprocessed")
self.assertTrue(self.order.order_line[0].production_ids)

def test_partially(self):
self.order.action_confirm()
mrp = self.order.order_line[0].production_ids
mrp.action_confirm()
mo_form = Form(mrp)
mo_form.qty_producing = 1
mrp = mo_form.save()
mrp.button_mark_done()
self.assertEqual(self.order.order_line[0].production_state, "done")
self.assertEqual(self.order.production_state, "partially")

def test_production_done(self):
self.order.action_confirm()
for line in self.order.order_line:
mrp = line.production_ids
mrp.action_confirm()
mo_form = Form(mrp)
mo_form.qty_producing = 1
mrp = mo_form.save()
mrp.button_mark_done()
self.assertEqual(self.order.production_state, "done")
24 changes: 24 additions & 0 deletions sale_production_state/views/sale_order.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_order_form_inherit_production_state" model="ir.ui.view">
<field name="name">sale.order.form.sale.stock</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form" />
<field name="arch" type="xml">
<field name='date_order' position="after">
<field name="production_state" readonly="True" />
</field>
</field>
</record>

<record id="view_order_tree_inherit_production_state" model="ir.ui.view">
<field name="name">sale.order.tree</field>
<field name="inherit_id" ref="sale.view_order_tree" />
<field name="model">sale.order</field>
<field name="arch" type="xml">
<field name="invoice_status" position="after">
<field name="production_state" optional="hide" />
</field>
</field>
</record>
</odoo>
6 changes: 6 additions & 0 deletions setup/sale_production_state/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)