Skip to content

Commit 8c8a3e2

Browse files
committed
[FIX] sale_stock_ux: update delivery status logic and remove 'no' state from sale orders
1 parent c19aa24 commit 8c8a3e2

File tree

6 files changed

+132
-27
lines changed

6 files changed

+132
-27
lines changed

sale_stock_ux/__manifest__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
##############################################################################
2020
{
2121
"name": "Sale Stock UX",
22-
"version": "18.0.1.2.0",
22+
"version": "18.0.1.3.0",
2323
"category": "Sales",
2424
"sequence": 14,
2525
"summary": "",
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
##############################################################################
2+
# For copyright and license notices, see __manifest__.py file in module root
3+
# directory
4+
##############################################################################
5+
from odoo import SUPERUSER_ID, api
6+
7+
8+
def migrate(cr, version):
9+
"""
10+
Migration script to handle removal of 'no' state from delivery_status field.
11+
12+
This migration recalculates delivery_status for sale orders and sale order lines
13+
that previously had delivery_status = 'no' and cleans up force_delivery_status.
14+
"""
15+
env = api.Environment(cr, SUPERUSER_ID, {})
16+
cr.execute("""
17+
SELECT id
18+
FROM sale_order
19+
WHERE delivery_status = 'no'
20+
""")
21+
order_ids = [row[0] for row in cr.fetchall()]
22+
if order_ids:
23+
orders = env["sale.order"].browse(order_ids)
24+
orders._compute_delivery_status()
25+
26+
cr.execute("""
27+
SELECT id
28+
FROM sale_order_line
29+
WHERE delivery_status = 'no'
30+
""")
31+
line_ids = [row[0] for row in cr.fetchall()]
32+
if line_ids:
33+
lines = env["sale.order.line"].browse(line_ids)
34+
lines._compute_delivery_status()
35+
36+
cr.execute("""
37+
SELECT COUNT(*)
38+
FROM sale_order
39+
WHERE force_delivery_status = 'no'
40+
""")
41+
force_count = cr.fetchone()[0]
42+
if force_count > 0:
43+
cr.execute("""
44+
UPDATE sale_order
45+
SET force_delivery_status = NULL
46+
WHERE force_delivery_status = 'no'
47+
""")

sale_stock_ux/models/sale_order.py

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,14 @@
44
##############################################################################
55
from odoo import _, api, fields, models
66
from odoo.exceptions import UserError
7+
from odoo.tools.float_utils import float_compare
78

89

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

12-
delivery_status = fields.Selection(
13-
selection_add=[
14-
("no", "Nothing to Deliver"),
15-
],
16-
readonly=True,
17-
default="no",
18-
)
1913
force_delivery_status = fields.Selection(
2014
[
21-
("no", "Nothing to Deliver"),
2215
("full", "Fully Delivered"),
2316
],
2417
tracking=True,
@@ -43,17 +36,66 @@ def action_cancel(self):
4336
)
4437
return super().action_cancel()
4538

46-
@api.depends("picking_ids", "picking_ids.state", "force_delivery_status")
39+
@api.depends(
40+
"picking_ids",
41+
"picking_ids.state",
42+
"force_delivery_status",
43+
"order_line.qty_delivered",
44+
"order_line.product_uom_qty",
45+
)
4746
def _compute_delivery_status(self):
47+
"""
48+
Compute delivery status considering both storable products and services.
49+
"""
4850
super()._compute_delivery_status()
51+
precision = self.env["decimal.precision"].precision_get("Product Unit of Measure")
4952
for order in self:
50-
if not order.picking_ids or all(p.state == "cancel" for p in order.picking_ids):
51-
order.delivery_status = "no"
52-
continue
5353
if order.force_delivery_status:
5454
order.delivery_status = order.force_delivery_status
5555
continue
5656

57+
storable_lines = order.order_line.filtered(
58+
lambda l: l.product_id.type == "consu" and l.product_id.is_storable
59+
)
60+
service_lines = order.order_line.filtered(lambda l: l.product_id.type == "service")
61+
62+
if not storable_lines and not service_lines:
63+
order.delivery_status = False
64+
continue
65+
66+
if not service_lines:
67+
continue
68+
69+
service_fully_delivered = service_partially_delivered = True
70+
for line in service_lines:
71+
delivered, ordered = line.qty_delivered, line.product_uom_qty
72+
if float_compare(delivered, ordered, precision_digits=precision) < 0:
73+
service_fully_delivered = False
74+
if float_compare(delivered, 0.0, precision_digits=precision) == 0:
75+
service_partially_delivered = False
76+
break
77+
78+
service_status = (
79+
"full" if service_fully_delivered else ("partial" if service_partially_delivered else "pending")
80+
)
81+
82+
if not storable_lines:
83+
order.delivery_status = service_status
84+
continue
85+
86+
storable_status = order.delivery_status
87+
if storable_status == "full" and service_status == "full":
88+
order.delivery_status = "full"
89+
elif (
90+
storable_status == "partial"
91+
or storable_status == "full"
92+
or service_status == "partial"
93+
or service_status == "full"
94+
):
95+
order.delivery_status = "partial"
96+
else:
97+
order.delivery_status = "pending"
98+
5799
def write(self, vals):
58100
self.check_force_delivery_status(vals)
59101
return super().write(vals)

sale_stock_ux/models/sale_order_line.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,14 @@ class SaleOrderLine(models.Model):
2525

2626
delivery_status = fields.Selection(
2727
[
28-
("no", "Nothing to deliver"),
2928
("to deliver", "To Deliver"),
29+
("partial", "Partially Delivered"),
3030
("full", "Fully Delivered"),
3131
],
3232
compute="_compute_delivery_status",
3333
store=True,
3434
readonly=True,
3535
copy=False,
36-
default="no",
3736
)
3837

3938
total_reserved_quantity = fields.Float(compute="_compute_total_reserved_quantity")
@@ -56,23 +55,34 @@ def _compute_all_qty_delivered(self):
5655

5756
@api.depends("order_id.state", "qty_delivered", "product_uom_qty", "order_id.force_delivery_status")
5857
def _compute_delivery_status(self):
58+
"""
59+
Compute delivery status for order lines considering both storable products and services.
60+
Services are considered delivered based on qty_delivered field.
61+
"""
5962
precision = self.env["decimal.precision"].precision_get("Product Unit of Measure")
6063
for line in self:
6164
if line.state not in ("sale", "done"):
62-
line.delivery_status = "no"
65+
line.delivery_status = False
6366
continue
6467

6568
if line.order_id.force_delivery_status:
6669
line.delivery_status = line.order_id.force_delivery_status
6770
continue
6871

69-
if float_compare(line.all_qty_delivered, line.product_uom_qty, precision_digits=precision) == -1:
70-
delivery_status = "to deliver"
71-
elif float_compare(line.all_qty_delivered, line.product_uom_qty, precision_digits=precision) >= 0:
72-
delivery_status = "full"
72+
if line.product_id.type == "service":
73+
if float_compare(line.qty_delivered, line.product_uom_qty, precision_digits=precision) >= 0:
74+
line.delivery_status = "full"
75+
elif float_compare(line.qty_delivered, 0.0, precision_digits=precision) > 0:
76+
line.delivery_status = "partial"
77+
else:
78+
line.delivery_status = "to deliver"
7379
else:
74-
delivery_status = "no"
75-
line.delivery_status = delivery_status
80+
if float_compare(line.all_qty_delivered, line.product_uom_qty, precision_digits=precision) >= 0:
81+
line.delivery_status = "full"
82+
elif float_compare(line.all_qty_delivered, 0.0, precision_digits=precision) > 0:
83+
line.delivery_status = "partial"
84+
else:
85+
line.delivery_status = "to deliver"
7686

7787
def button_cancel_remaining(self):
7888
# la cancelación de kits no está bien resuelta ya que odoo solo computa

sale_ux/migrations/18.0.1.6.0/post-migration.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,27 @@ def migrate(cr, version):
2929
old_group_id = old_group[0]
3030
new_group_id = new_group[0]
3131

32-
cr.execute("""
32+
cr.execute(
33+
"""
3334
SELECT COUNT(*)
3435
FROM res_groups_users_rel
3536
WHERE gid = %s
36-
""", (old_group_id,))
37+
""",
38+
(old_group_id,),
39+
)
3740

3841
users_count = cr.fetchone()[0]
3942

4043
if users_count == 0:
4144
return
4245

43-
cr.execute("""
46+
cr.execute(
47+
"""
4448
INSERT INTO res_groups_users_rel (gid, uid)
4549
SELECT %s, uid
4650
FROM res_groups_users_rel
4751
WHERE gid = %s
4852
ON CONFLICT (gid, uid) DO NOTHING
49-
""", (new_group_id, old_group_id))
53+
""",
54+
(new_group_id, old_group_id),
55+
)

sale_ux/models/res_config_settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class ResConfigSettings(models.TransientModel):
5151
)
5252
group_delivery_date = fields.Boolean(
5353
"Show Delivery Date in Quotations report and online budget",
54-
implied_group='sale_ux.group_delivery_date_on_report_online'
54+
implied_group="sale_ux.group_delivery_date_on_report_online",
5555
)
5656

5757
def get_values(self):

0 commit comments

Comments
 (0)