Skip to content

Commit 0fbb970

Browse files
committed
[IMP] shopinvader_api_delivery_carrier: Add deliveries lines and state
1 parent 9236941 commit 0fbb970

File tree

7 files changed

+169
-7
lines changed

7 files changed

+169
-7
lines changed

shopinvader_api_delivery_carrier/__manifest__.py

+2
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,7 @@
5656
"security/acl_product_product.xml",
5757
"security/acl_stock_picking.xml",
5858
"security/acl_stock_picking_type.xml",
59+
"security/acl_stock_move.xml",
60+
"security/acl_stock_move_line.xml",
5961
],
6062
}

shopinvader_api_delivery_carrier/routers/delivery.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,11 @@ class ShopinvaderApiDeliveryRouterHelper(models.AbstractModel):
4646

4747
partner = fields.Many2one("res.partner")
4848

49+
def _get_picking_sale_domain(self):
50+
return [("typology", "=", "sale"), ("partner_id", "=", self.partner.id)]
51+
4952
def _get_domain_adapter(self):
50-
sales = self.env["sale.order"].search(
51-
[("typology", "=", "sale"), ("partner_id", "=", self.partner.id)]
52-
)
53+
sales = self.env["sale.order"].search(self._get_picking_sale_domain())
5354
return [
5455
("sale_id", "in", sales.ids),
5556
("picking_type_id.code", "=", "outgoing"),

shopinvader_api_delivery_carrier/schemas/picking.py

+42
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
from pydantic import Field
1010

1111
from odoo import api
12+
from odoo.tools.float_utils import json_float_round
1213

1314
from ..schemas import DeliveryCarrier
1415

16+
1517
class PickingState(str, Enum):
1618
"""Enum for picking states."""
1719

@@ -24,6 +26,12 @@ class PickingState(str, Enum):
2426

2527

2628
class PickingSearch(StrictExtendableBaseModel):
29+
name: Annotated[
30+
str | None,
31+
Field(
32+
description="Name of the picking. If not provided, all names are returned.",
33+
),
34+
] = None
2735
state: Annotated[
2836
PickingState | None,
2937
Field(
@@ -53,6 +61,8 @@ class PickingSearch(StrictExtendableBaseModel):
5361
def to_odoo_domain(self, env: api.Environment):
5462
domain = []
5563

64+
if self.name:
65+
domain.append(("name", "=", self.name))
5666
if self.state:
5767
domain.append(("state", "=", self.state.value))
5868
if self.tracking_reference:
@@ -63,16 +73,45 @@ def to_odoo_domain(self, env: api.Environment):
6373
domain.append(("sale_id", "=", self.sale_id))
6474
return domain
6575

76+
77+
class PickingLine(StrictExtendableBaseModel):
78+
product_id: int
79+
product_name: str
80+
state: str
81+
qty: float
82+
qty_done: float
83+
84+
@classmethod
85+
def from_picking_line(cls, odoo_rec):
86+
return cls.model_construct(
87+
product_id=odoo_rec.product_id.id,
88+
product_name=odoo_rec.product_id.name,
89+
state=odoo_rec.state,
90+
qty=json_float_round(
91+
odoo_rec.product_uom_qty,
92+
precision_digits=len(str(odoo_rec.product_uom.rounding).split(".")[1]),
93+
),
94+
qty_done=json_float_round(
95+
odoo_rec.quantity_done,
96+
precision_digits=len(str(odoo_rec.product_uom.rounding).split(".")[1]),
97+
),
98+
)
99+
100+
66101
class Picking(StrictExtendableBaseModel):
67102
delivery_id: int
68103
name: str
104+
state: PickingState
69105
tracking_reference: str | None = None
106+
tracking_url: str | None = None
70107
delivery_date: datetime | None = Field(
71108
None, description="Date done or Scheduled Date"
72109
)
73110
carrier: DeliveryCarrier | None = None
74111
sale_id: int | None = None
75112

113+
lines: list[PickingLine]
114+
76115
@classmethod
77116
def from_picking(cls, odoo_rec):
78117
delivery_date = None
@@ -83,10 +122,13 @@ def from_picking(cls, odoo_rec):
83122
return cls.model_construct(
84123
delivery_id=odoo_rec.id,
85124
name=odoo_rec.name,
125+
state=odoo_rec.state,
86126
tracking_reference=odoo_rec.carrier_tracking_ref or None,
127+
tracking_url=odoo_rec.carrier_tracking_url or None,
87128
delivery_date=delivery_date,
88129
carrier=DeliveryCarrier.from_delivery_carrier(odoo_rec.carrier_id)
89130
if odoo_rec.carrier_id
90131
else None,
91132
sale_id=odoo_rec.sale_id.id or None,
133+
lines=[PickingLine.from_picking_line(line) for line in odoo_rec.move_ids],
92134
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Copyright 2025 Akretion (http://www.akretion.com).
4+
@author Florian Mounier <[email protected]>
5+
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
6+
-->
7+
<odoo>
8+
9+
<record model="ir.model.access" id="shopinvader_stock_move_access_view">
10+
<field name="name">stock.move shopinvader delivery user read access</field>
11+
<field name="model_id" ref="stock.model_stock_move" />
12+
<field
13+
name="group_id"
14+
ref="shopinvader_api_delivery_carrier.shopinvader_delivery_carrier_user_group"
15+
/>
16+
<field name="perm_read" eval="1" />
17+
<field name="perm_create" eval="0" />
18+
<field name="perm_unlink" eval="0" />
19+
<field name="perm_write" eval="0" />
20+
</record>
21+
22+
</odoo>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Copyright 2025 Akretion (http://www.akretion.com).
4+
@author Florian Mounier <[email protected]>
5+
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
6+
-->
7+
<odoo>
8+
9+
<record model="ir.model.access" id="shopinvader_stock_move_line_access_view">
10+
<field name="name">stock.move.line shopinvader delivery user read access</field>
11+
<field name="model_id" ref="stock.model_stock_move_line" />
12+
<field
13+
name="group_id"
14+
ref="shopinvader_api_delivery_carrier.shopinvader_delivery_carrier_user_group"
15+
/>
16+
<field name="perm_read" eval="1" />
17+
<field name="perm_create" eval="0" />
18+
<field name="perm_unlink" eval="0" />
19+
<field name="perm_write" eval="0" />
20+
</record>
21+
22+
</odoo>

shopinvader_api_delivery_carrier/static/description/index.html

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
<?xml version="1.0" encoding="utf-8"?>
21
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
32
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
43
<head>
@@ -9,10 +8,11 @@
98

109
/*
1110
:Author: David Goodger ([email protected])
12-
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
11+
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
1312
:Copyright: This stylesheet has been placed in the public domain.
1413
1514
Default cascading style sheet for the HTML output of Docutils.
15+
Despite the name, some widely supported CSS2 features are used.
1616
1717
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
1818
customize this style sheet.
@@ -275,7 +275,7 @@
275275
margin-left: 2em ;
276276
margin-right: 2em }
277277

278-
pre.code .ln { color: grey; } /* line numbers */
278+
pre.code .ln { color: gray; } /* line numbers */
279279
pre.code, code { background-color: #eeeeee }
280280
pre.code .comment, code .comment { color: #5C6576 }
281281
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
@@ -301,7 +301,7 @@
301301
span.pre {
302302
white-space: pre }
303303

304-
span.problematic {
304+
span.problematic, pre.problematic {
305305
color: red }
306306

307307
span.section-subtitle {

shopinvader_api_delivery_carrier/tests/test_search_deliveries.py

+73
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,14 @@ def _check_data_content(self, data, pickings):
117117
)
118118
else:
119119
self.assertFalse(current_data.get("delivery_date"))
120+
121+
self.assertEqual(len(current_data.get("lines")), len(picking.move_ids))
122+
for line_data, line in zip(current_data.get("lines"), picking.move_ids):
123+
self.assertEqual(line_data.get("product_id"), line.product_id.id)
124+
self.assertEqual(line_data.get("product_name"), line.product_id.name)
125+
self.assertEqual(line_data.get("state"), line.state)
126+
self.assertEqual(line_data.get("qty"), line.product_uom_qty)
127+
self.assertEqual(line_data.get("qty_done"), line.quantity_done)
120128
return True
121129

122130
def test_get_picking_logged_without_sale(self):
@@ -172,3 +180,68 @@ def test_get_multi_picking(self):
172180
self.assertEqual(response.status_code, 200)
173181
info = response.json()
174182
self._check_data_content(info["items"], pickings)
183+
184+
def test_get_picking_search_name(self):
185+
picking1 = self._create_picking(self.partner, sale=True)
186+
self._create_picking(self.partner, sale=True)
187+
188+
with self._create_test_client(router=delivery_router) as test_client:
189+
response: Response = test_client.get(
190+
"/deliveries", params={"name": picking1.name}
191+
)
192+
self.assertEqual(response.status_code, 200)
193+
info = response.json()
194+
self._check_data_content(info["items"], picking1)
195+
196+
def test_get_picking_search_tracking_ref(self):
197+
picking1 = self._create_picking(self.partner, sale=True)
198+
self._create_picking(self.partner, sale=True)
199+
self._fill_picking_optional_values(picking1)
200+
201+
with self._create_test_client(router=delivery_router) as test_client:
202+
response: Response = test_client.get(
203+
"/deliveries",
204+
params={"tracking_reference": picking1.carrier_tracking_ref},
205+
)
206+
self.assertEqual(response.status_code, 200)
207+
info = response.json()
208+
self._check_data_content(info["items"], picking1)
209+
210+
def test_get_picking_search_sale_id(self):
211+
picking1 = self._create_picking(self.partner, sale=True)
212+
self._create_picking(self.partner, sale=True)
213+
self._fill_picking_optional_values(picking1)
214+
215+
with self._create_test_client(router=delivery_router) as test_client:
216+
response: Response = test_client.get(
217+
"/deliveries", params={"sale_id": picking1.sale_id.id}
218+
)
219+
self.assertEqual(response.status_code, 200)
220+
info = response.json()
221+
self._check_data_content(info["items"], picking1)
222+
223+
def test_get_picking_search_carrier_id(self):
224+
picking1 = self._create_picking(self.partner, sale=True)
225+
self._create_picking(self.partner, sale=True)
226+
self._fill_picking_optional_values(picking1)
227+
228+
with self._create_test_client(router=delivery_router) as test_client:
229+
response: Response = test_client.get(
230+
"/deliveries", params={"carrier_id": picking1.carrier_id.id}
231+
)
232+
self.assertEqual(response.status_code, 200)
233+
info = response.json()
234+
self._check_data_content(info["items"], picking1)
235+
236+
def test_get_picking_search_state(self):
237+
picking1 = self._create_picking(self.partner, sale=True)
238+
self._create_picking(self.partner, sale=True)
239+
picking1.action_cancel()
240+
241+
with self._create_test_client(router=delivery_router) as test_client:
242+
response: Response = test_client.get(
243+
"/deliveries", params={"state": "cancel"}
244+
)
245+
self.assertEqual(response.status_code, 200)
246+
info = response.json()
247+
self._check_data_content(info["items"], picking1)

0 commit comments

Comments
 (0)