Skip to content

Commit 705517c

Browse files
dmitriypaulovAldeigja
authored andcommitted
[ADD] sale_order_confirm_partial: add module
[ADD] sale_order_confirm_partial: add tests [REF] sale_order_confirm_partial: safer approach to test so lines
1 parent 76d07de commit 705517c

22 files changed

+1232
-0
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
===============================
2+
Sale Order Partial Confirmation
3+
===============================
4+
5+
..
6+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
7+
!! This file is generated by oca-gen-addon-readme !!
8+
!! changes will be overwritten. !!
9+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10+
!! source digest: sha256:5c1808472b6a1de28c62bb966291f6168117f1661076334a1e5b8b8587880f6a
11+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12+
13+
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
14+
:target: https://odoo-community.org/page/development-status
15+
:alt: Beta
16+
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
17+
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
18+
:alt: License: AGPL-3
19+
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsale--workflow-lightgray.png?logo=github
20+
:target: https://github.com/OCA/sale-workflow/tree/16.0/sale_order_confirm_partial
21+
:alt: OCA/sale-workflow
22+
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
23+
:target: https://translation.odoo-community.org/projects/sale-workflow-16-0/sale-workflow-16-0-sale_order_confirm_partial
24+
:alt: Translate me on Weblate
25+
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
26+
:target: https://runboat.odoo-community.org/builds?repo=OCA/sale-workflow&target_branch=16.0
27+
:alt: Try me on Runboat
28+
29+
|badge1| |badge2| |badge3| |badge4| |badge5|
30+
31+
This module allows to select which sale order lines you would like to
32+
confirm. It also can create a new quotation in the "Cancel" state with
33+
all the unconfirmed lines from the original quotation in case you need
34+
to keep that information.
35+
36+
**Table of contents**
37+
38+
.. contents::
39+
:local:
40+
41+
Use Cases / Context
42+
===================
43+
44+
Sometimes you need to confirm only selected lines of a Sales Order. Eg
45+
your customer has asked you a quotation for a desk, five chairs and a
46+
sofa. However in the end he decides to order only a desk and 2 chairs.
47+
48+
Configuration
49+
=============
50+
51+
Go to "Sales -> Configuration -> Settings" and scroll down to the
52+
"Quotation & Orders" section. Enable the "Partial Confirmation"
53+
checkbox. Enable the "Save Unconfirmed Items" checkbox if you want to
54+
create a quotation with all the unconfirmed items. Define a suffix for
55+
the unconfirmed items quotation in the "Unconfirmed Quotation Suffix"
56+
field. If no suffix is defined then a standard "-U" suffix will be used.
57+
Eg "SO00023-U".
58+
59+
Usage
60+
=====
61+
62+
Open a quotation and click the "Confirm" button. A wizard will pop-up
63+
with the following options available:
64+
65+
- "All Items"
66+
- "Selected Items"
67+
68+
Choose "Selected Items", set the lines quantities you want to confirm in
69+
the list below and click "Confirm". If you don't want to confirm
70+
specific lines at all, just set their quantity to 0. Note, that
71+
confirmed quantity cannot be negative or greater than ordered quantity
72+
of related SO line. If you put invalid quantity, you'll be notified via
73+
error message. Quotation will be updated according to your selection and
74+
confirmed.
75+
76+
If you have enabled "Save Unconfirmed Items" in the settings a new
77+
quotation in the "Cancel" state will be created with all the lines that
78+
were not confirmed. Internal note "Created from will be posted in the
79+
chatter of the unconfirmed lines quotation. Internal note "Unconfirmed
80+
lines are saved in will be posted in the chatter of the confirmed sales
81+
order.
82+
83+
Bug Tracker
84+
===========
85+
86+
Bugs are tracked on `GitHub Issues <https://github.com/OCA/sale-workflow/issues>`_.
87+
In case of trouble, please check there if your issue has already been reported.
88+
If you spotted it first, help us to smash it by providing a detailed and welcomed
89+
`feedback <https://github.com/OCA/sale-workflow/issues/new?body=module:%20sale_order_confirm_partial%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
90+
91+
Do not contact contributors directly about support or help with technical issues.
92+
93+
Credits
94+
=======
95+
96+
Authors
97+
-------
98+
99+
* Cetmix
100+
101+
Maintainers
102+
-----------
103+
104+
This module is maintained by the OCA.
105+
106+
.. image:: https://odoo-community.org/logo.png
107+
:alt: Odoo Community Association
108+
:target: https://odoo-community.org
109+
110+
OCA, or the Odoo Community Association, is a nonprofit organization whose
111+
mission is to support the collaborative development of Odoo features and
112+
promote its widespread use.
113+
114+
This module is part of the `OCA/sale-workflow <https://github.com/OCA/sale-workflow/tree/16.0/sale_order_confirm_partial>`_ project on GitHub.
115+
116+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (C) 2024 Cetmix OÜ
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
from . import models
4+
from . import wizard
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Copyright (C) 2024 Cetmix OÜ
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
{
4+
"name": "Sale Order Partial Confirmation",
5+
"summary": "Select sales order lines to be confirmed",
6+
"author": "Cetmix, Odoo Community Association (OCA)",
7+
"website": "https://github.com/OCA/sale-workflow",
8+
"category": "Sales",
9+
"version": "16.0.1.0.0",
10+
"license": "AGPL-3",
11+
"depends": ["sale"],
12+
"data": [
13+
"security/ir.model.access.csv",
14+
"views/res_config_settings_views.xml",
15+
"wizard/sale_order_confirm_partial_views.xml",
16+
],
17+
"installable": True,
18+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (C) 2024 Cetmix OÜ
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
from . import res_config_settings
4+
from . import sale_order
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright (C) 2024 Cetmix OÜ
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
from odoo import fields, models
4+
5+
6+
class ResConfigSettings(models.TransientModel):
7+
_inherit = "res.config.settings"
8+
9+
sale_order_confirm_partial_enabled = fields.Boolean(
10+
string="Partial Confirmation",
11+
config_parameter="sale_order_confirm_partial.enabled",
12+
)
13+
so_confirm_partial_save_unconfirmed = fields.Boolean(
14+
string="Save Unconfirmed Items",
15+
config_parameter="sale_order_confirm_partial.save_unconfirmed",
16+
help=(
17+
"If enabled a new quotation in the 'Cancel' "
18+
"state will be created with all the lines "
19+
"that were not confirmed."
20+
),
21+
)
22+
so_confirm_partial_unconfirmed_suffix = fields.Char(
23+
string="Unconfirmed Quotation Suffix",
24+
config_parameter="sale_order_confirm_partial.unconfirmed_suffix",
25+
default="-U",
26+
)
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# Copyright (C) 2024 Cetmix OÜ
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
from odoo import _, models
4+
5+
6+
class SaleOrder(models.Model):
7+
_inherit = "sale.order"
8+
9+
def action_confirm(self):
10+
"""
11+
If partial confirmation feature is enabled,
12+
instead of standard SO confirmation at first we need
13+
to open the partial confirmation wizard for current SO.
14+
15+
If feature is disabled or 'standard_confirm_proceed' context key
16+
was specified as True, then we proceed with standard confirmation.
17+
"""
18+
19+
force_confirm = self.env.context.get("standard_confirm_proceed", False)
20+
partial_confirm_enabled = self.env["ir.config_parameter"].get_param(
21+
"sale_order_confirm_partial.enabled",
22+
False,
23+
)
24+
if force_confirm or not partial_confirm_enabled:
25+
return super().action_confirm()
26+
action = self.env["ir.actions.act_window"]._for_xml_id(
27+
"sale_order_confirm_partial.sale_order_confirm_partial_action"
28+
)
29+
action.update(
30+
{
31+
"context": {
32+
"default_sale_order_id": self.id,
33+
}
34+
}
35+
)
36+
return action
37+
38+
def _process_unconfirmed_quotation(self, confirmed_lines):
39+
"""
40+
If 'Save Unconfirmed Items' feature is enabled,
41+
then create a new quotation in the 'Cancel' state
42+
and move all unconfirmed lines to it.
43+
44+
Quantities of those lines should be reduced
45+
depending on confirmed quantities.
46+
47+
If after reduction the quantity of any line
48+
is less than or equal to 0, then remove that line.
49+
50+
Args:
51+
confirmed_lines: sale.order.confirm.partial.line recordset.
52+
Lines to be confirmed.
53+
54+
Returns:
55+
sale.order: Created unconfirmed quotation
56+
None: If feature is disabled or no unconfirmed lines
57+
"""
58+
self.ensure_one()
59+
save_unconfirmed = (
60+
self.env["ir.config_parameter"]
61+
.sudo()
62+
.get_param("sale_order_confirm_partial.save_unconfirmed", False)
63+
)
64+
if not save_unconfirmed:
65+
return
66+
# If all lines are confirmed and confirmed quantity
67+
# is equal to ordered quantity, then no need to create
68+
# unconfirmed quotation.
69+
if all(
70+
[
71+
line.confirmed_qty == line.so_line_id.product_uom_qty
72+
for line in confirmed_lines
73+
]
74+
) and len(confirmed_lines) == len(self.order_line):
75+
return
76+
unconfirmed_suffix = (
77+
self.env["ir.config_parameter"]
78+
.sudo()
79+
.get_param("sale_order_confirm_partial.unconfirmed_suffix", "-U")
80+
)
81+
unconfirmed_order = self.copy(
82+
{
83+
"name": self.name + unconfirmed_suffix,
84+
"order_line": False,
85+
}
86+
)
87+
unconfirmed_lines = self.env["sale.order.line"]
88+
for line in self.order_line:
89+
confirmed_line = confirmed_lines.filtered(lambda x: x.so_line_id == line)
90+
if confirmed_line.confirmed_qty == line.product_uom_qty:
91+
continue
92+
unconfirmed_lines |= line.copy(
93+
{
94+
"order_id": unconfirmed_order.id,
95+
"product_uom_qty": line.product_uom_qty
96+
- confirmed_line.confirmed_qty,
97+
}
98+
)
99+
unconfirmed_order.state = "cancel"
100+
unconfirmed_order.message_post(
101+
body=_(
102+
"Created from "
103+
"<a href=# data-oe-model=sale.order data-oe-id=%(id)d>%(name)s</a>"
104+
)
105+
% {"id": self.id, "name": self.name},
106+
partner_id=self.env.ref("base.partner_root").id,
107+
subtype_id=self.env.ref("mail.mt_note").id,
108+
)
109+
return unconfirmed_order
110+
111+
def _update_order_lines_qty(self, confirmed_lines):
112+
"""
113+
Update quantities of order lines depending
114+
on confirmed quantities in selected lines.
115+
116+
Args:
117+
confirmed_lines: sale.order.confirm.partial.line recordset.
118+
"""
119+
self.ensure_one()
120+
for line in confirmed_lines:
121+
line.so_line_id.product_uom_qty = line.confirmed_qty
122+
123+
def action_confirm_partial(self, confirmed_lines):
124+
"""
125+
Confirms only selected lines of the SO.
126+
127+
If 'Save Unconfirmed Items' feature is enabled,
128+
then it creates also a new quotation in the 'Cancel' state
129+
containing all unconfirmed lines and quantities.
130+
131+
Args:
132+
confirmed_lines: sale.order.confirm.partial.line recordset.
133+
Lines to be confirmed.
134+
"""
135+
self.ensure_one()
136+
unconfirmed_quotation = self._process_unconfirmed_quotation(confirmed_lines)
137+
self._update_order_lines_qty(confirmed_lines)
138+
self.with_context(standard_confirm_proceed=True).action_confirm()
139+
if unconfirmed_quotation:
140+
self.message_post(
141+
body=_(
142+
"Unconfirmed lines are saved in "
143+
"<a href=# data-oe-model=sale.order data-oe-id=%(id)d>%(name)s</a>"
144+
)
145+
% {"id": unconfirmed_quotation.id, "name": unconfirmed_quotation.name},
146+
partner_id=self.env.ref("base.partner_root").id,
147+
subtype_id=self.env.ref("mail.mt_note").id,
148+
)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Go to "Sales -> Configuration -> Settings" and scroll down to the "Quotation & Orders" section.
2+
Enable the "Partial Confirmation" checkbox.
3+
Enable the "Save Unconfirmed Items" checkbox if you want to create a quotation with all the unconfirmed items.
4+
Define a suffix for the unconfirmed items quotation in the "Unconfirmed Quotation Suffix" field. If no suffix is defined then a standard "-U" suffix will be used. Eg "SO00023-U".
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Sometimes you need to confirm only selected lines of a Sales Order.
2+
Eg your customer has asked you a quotation for a desk, five chairs and a sofa. However in the end he decides to order only a desk and 2 chairs.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This module allows to select which sale order lines you would like to confirm. It also can create a new quotation in the "Cancel" state with all the unconfirmed lines from the original quotation in case you need to keep that information.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Open a quotation and click the "Confirm" button.
2+
A wizard will pop-up with the following options available:
3+
4+
- "All Items"
5+
- "Selected Items"
6+
7+
Choose "Selected Items", set the lines quantities you want to confirm in the list below and click "Confirm".
8+
If you don't want to confirm specific lines at all, just set their quantity to 0.
9+
Note, that confirmed quantity cannot be negative or greater than ordered quantity of related SO line. If you put invalid quantity, you'll be notified via error message.
10+
Quotation will be updated according to your selection and confirmed.
11+
12+
If you have enabled "Save Unconfirmed Items" in the settings a new quotation in the "Cancel" state will be created with all the lines that were not confirmed.
13+
Internal note "Created from <SalesOrderNumber> will be posted in the chatter of the unconfirmed lines quotation.
14+
Internal note "Unconfirmed lines are saved in <UnconfirmedQuotationNumber> will be posted in the chatter of the confirmed sales order.

0 commit comments

Comments
 (0)