odoo-addon-delivery-ups-oca 17.0.1.0.0.4__py3-none-any.whl → 18.0.1.0.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- odoo/addons/delivery_ups_oca/README.rst +6 -6
- odoo/addons/delivery_ups_oca/__manifest__.py +1 -1
- odoo/addons/delivery_ups_oca/i18n/delivery_ups_oca.pot +2 -6
- odoo/addons/delivery_ups_oca/models/delivery_carrier.py +2 -4
- odoo/addons/delivery_ups_oca/models/ups_request.py +12 -8
- odoo/addons/delivery_ups_oca/static/description/index.html +4 -4
- odoo/addons/delivery_ups_oca/tests/test_delivery_ups.py +668 -15
- {odoo_addon_delivery_ups_oca-17.0.1.0.0.4.dist-info → odoo_addon_delivery_ups_oca-18.0.1.0.0.2.dist-info}/METADATA +12 -12
- {odoo_addon_delivery_ups_oca-17.0.1.0.0.4.dist-info → odoo_addon_delivery_ups_oca-18.0.1.0.0.2.dist-info}/RECORD +11 -11
- {odoo_addon_delivery_ups_oca-17.0.1.0.0.4.dist-info → odoo_addon_delivery_ups_oca-18.0.1.0.0.2.dist-info}/WHEEL +0 -0
- {odoo_addon_delivery_ups_oca-17.0.1.0.0.4.dist-info → odoo_addon_delivery_ups_oca-18.0.1.0.0.2.dist-info}/top_level.txt +0 -0
|
@@ -11,7 +11,7 @@ Delivery UPS OCA
|
|
|
11
11
|
!! This file is generated by oca-gen-addon-readme !!
|
|
12
12
|
!! changes will be overwritten. !!
|
|
13
13
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
14
|
-
!! source digest: sha256:
|
|
14
|
+
!! source digest: sha256:a822b00c048a67361ef9e4de24e3d5f6ba436b9cd140e4b3ac4c87585d999b73
|
|
15
15
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
16
16
|
|
|
17
17
|
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
|
|
@@ -21,13 +21,13 @@ Delivery UPS OCA
|
|
|
21
21
|
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
|
22
22
|
:alt: License: AGPL-3
|
|
23
23
|
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fdelivery--carrier-lightgray.png?logo=github
|
|
24
|
-
:target: https://github.com/OCA/delivery-carrier/tree/
|
|
24
|
+
:target: https://github.com/OCA/delivery-carrier/tree/18.0/delivery_ups_oca
|
|
25
25
|
:alt: OCA/delivery-carrier
|
|
26
26
|
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
|
|
27
|
-
:target: https://translation.odoo-community.org/projects/delivery-carrier-
|
|
27
|
+
:target: https://translation.odoo-community.org/projects/delivery-carrier-18-0/delivery-carrier-18-0-delivery_ups_oca
|
|
28
28
|
:alt: Translate me on Weblate
|
|
29
29
|
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
|
|
30
|
-
:target: https://runboat.odoo-community.org/builds?repo=OCA/delivery-carrier&target_branch=
|
|
30
|
+
:target: https://runboat.odoo-community.org/builds?repo=OCA/delivery-carrier&target_branch=18.0
|
|
31
31
|
:alt: Try me on Runboat
|
|
32
32
|
|
|
33
33
|
|badge1| |badge2| |badge3| |badge4| |badge5|
|
|
@@ -97,7 +97,7 @@ Bug Tracker
|
|
|
97
97
|
Bugs are tracked on `GitHub Issues <https://github.com/OCA/delivery-carrier/issues>`_.
|
|
98
98
|
In case of trouble, please check there if your issue has already been reported.
|
|
99
99
|
If you spotted it first, help us to smash it by providing a detailed and welcomed
|
|
100
|
-
`feedback <https://github.com/OCA/delivery-carrier/issues/new?body=module:%20delivery_ups_oca%0Aversion:%
|
|
100
|
+
`feedback <https://github.com/OCA/delivery-carrier/issues/new?body=module:%20delivery_ups_oca%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
|
101
101
|
|
|
102
102
|
Do not contact contributors directly about support or help with technical issues.
|
|
103
103
|
|
|
@@ -142,6 +142,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
|
|
|
142
142
|
mission is to support the collaborative development of Odoo features and
|
|
143
143
|
promote its widespread use.
|
|
144
144
|
|
|
145
|
-
This module is part of the `OCA/delivery-carrier <https://github.com/OCA/delivery-carrier/tree/
|
|
145
|
+
This module is part of the `OCA/delivery-carrier <https://github.com/OCA/delivery-carrier/tree/18.0/delivery_ups_oca>`_ project on GitHub.
|
|
146
146
|
|
|
147
147
|
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
#
|
|
5
5
|
msgid ""
|
|
6
6
|
msgstr ""
|
|
7
|
-
"Project-Id-Version: Odoo Server
|
|
7
|
+
"Project-Id-Version: Odoo Server 18.0\n"
|
|
8
8
|
"Report-Msgid-Bugs-To: \n"
|
|
9
9
|
"Last-Translator: \n"
|
|
10
10
|
"Language-Team: \n"
|
|
@@ -31,7 +31,6 @@ msgstr ""
|
|
|
31
31
|
#. module: delivery_ups_oca
|
|
32
32
|
#. odoo-python
|
|
33
33
|
#: code:addons/delivery_ups_oca/models/ups_request.py:0
|
|
34
|
-
#, python-format
|
|
35
34
|
msgid "Both Client ID and Client Secret must be set in UPS delivery carriers."
|
|
36
35
|
msgstr ""
|
|
37
36
|
|
|
@@ -67,7 +66,7 @@ msgstr ""
|
|
|
67
66
|
|
|
68
67
|
#. module: delivery_ups_oca
|
|
69
68
|
#: model:ir.model.fields,field_description:delivery_ups_oca.field_delivery_carrier__ups_default_packaging_id
|
|
70
|
-
msgid "Default Packaging Type"
|
|
69
|
+
msgid "Default Carrier Packaging Type"
|
|
71
70
|
msgstr ""
|
|
72
71
|
|
|
73
72
|
#. module: delivery_ups_oca
|
|
@@ -218,7 +217,6 @@ msgstr ""
|
|
|
218
217
|
#. module: delivery_ups_oca
|
|
219
218
|
#. odoo-python
|
|
220
219
|
#: code:addons/delivery_ups_oca/models/ups_request.py:0
|
|
221
|
-
#, python-format
|
|
222
220
|
msgid "Sending to UPS: {}"
|
|
223
221
|
msgstr ""
|
|
224
222
|
|
|
@@ -387,13 +385,11 @@ msgstr ""
|
|
|
387
385
|
#. module: delivery_ups_oca
|
|
388
386
|
#. odoo-python
|
|
389
387
|
#: code:addons/delivery_ups_oca/models/ups_request.py:0
|
|
390
|
-
#, python-format
|
|
391
388
|
msgid "{date} - Warning: {warn}"
|
|
392
389
|
msgstr ""
|
|
393
390
|
|
|
394
391
|
#. module: delivery_ups_oca
|
|
395
392
|
#. odoo-python
|
|
396
393
|
#: code:addons/delivery_ups_oca/models/ups_request.py:0
|
|
397
|
-
#, python-format
|
|
398
394
|
msgid "{} - Error retrieving the tracking information."
|
|
399
395
|
msgstr ""
|
|
@@ -61,7 +61,7 @@ class DeliveryCarrier(models.Model):
|
|
|
61
61
|
)
|
|
62
62
|
ups_default_packaging_id = fields.Many2one(
|
|
63
63
|
comodel_name="stock.package.type",
|
|
64
|
-
string="Default Packaging Type",
|
|
64
|
+
string="Default Carrier Packaging Type",
|
|
65
65
|
domain=[("package_carrier_type", "=", "ups")],
|
|
66
66
|
)
|
|
67
67
|
ups_package_dimension_code = fields.Selection(
|
|
@@ -185,9 +185,7 @@ class DeliveryCarrier(models.Model):
|
|
|
185
185
|
return self._create_ups_label(picking, response)
|
|
186
186
|
|
|
187
187
|
def ups_get_tracking_link(self, picking):
|
|
188
|
-
return "https://ups.com/WebTracking/track?trackingNumber
|
|
189
|
-
picking.carrier_tracking_ref
|
|
190
|
-
)
|
|
188
|
+
return f"https://ups.com/WebTracking/track?trackingNumber={picking.carrier_tracking_ref}"
|
|
191
189
|
|
|
192
190
|
def ups_cancel_shipment(self, pickings):
|
|
193
191
|
ups_request = UpsRequest(self)
|
|
@@ -24,7 +24,7 @@ class UpsRequest:
|
|
|
24
24
|
self.file_format = self.carrier.ups_file_format
|
|
25
25
|
self.package_dimension_code = self.carrier.ups_package_dimension_code
|
|
26
26
|
self.package_weight_code = self.carrier.ups_package_weight_code
|
|
27
|
-
self.transaction_src = "Odoo (
|
|
27
|
+
self.transaction_src = f"Odoo ({self.carrier.name})"
|
|
28
28
|
self.client_id = self.carrier.ups_client_id
|
|
29
29
|
self.client_secret = self.carrier.ups_client_secret
|
|
30
30
|
self.token = self.carrier.ups_token
|
|
@@ -59,7 +59,7 @@ class UpsRequest:
|
|
|
59
59
|
" must be set in UPS delivery carriers."
|
|
60
60
|
)
|
|
61
61
|
)
|
|
62
|
-
url = "
|
|
62
|
+
url = f"{self.url}/security/v1/oauth/token"
|
|
63
63
|
headers = {"x-merchant-id": self.client_id}
|
|
64
64
|
data = {"grant_type": "client_credentials"}
|
|
65
65
|
status = self._send_request(
|
|
@@ -159,11 +159,15 @@ class UpsRequest:
|
|
|
159
159
|
|
|
160
160
|
def _prepare_create_shipping(self, picking):
|
|
161
161
|
"""Return a dict that can be passed to the shipping endpoint of the UPS API"""
|
|
162
|
-
|
|
162
|
+
packages_ids = (
|
|
163
|
+
picking.move_ids.move_line_ids
|
|
164
|
+
and picking.move_ids.move_line_ids.mapped("result_package_id")
|
|
165
|
+
)
|
|
166
|
+
if self.use_packages_from_picking and packages_ids:
|
|
163
167
|
# modelo: stock.quant.package
|
|
164
168
|
packages = [
|
|
165
169
|
self._quant_package_data_from_picking(package, picking, True)
|
|
166
|
-
for package in
|
|
170
|
+
for package in packages_ids
|
|
167
171
|
]
|
|
168
172
|
else:
|
|
169
173
|
# modelo: stock.package.type
|
|
@@ -227,7 +231,7 @@ class UpsRequest:
|
|
|
227
231
|
|
|
228
232
|
def _send_shipping(self, picking):
|
|
229
233
|
status = self._process_reply(
|
|
230
|
-
url="
|
|
234
|
+
url=f"{self.url}/api/shipments/v1/ship",
|
|
231
235
|
json=self._prepare_create_shipping(picking),
|
|
232
236
|
)
|
|
233
237
|
self._raise_for_status(status, False)
|
|
@@ -300,7 +304,7 @@ class UpsRequest:
|
|
|
300
304
|
|
|
301
305
|
def _rate_shipment(self, order, skip_errors=False):
|
|
302
306
|
status = self._process_reply(
|
|
303
|
-
url="
|
|
307
|
+
url=f"{self.url}/api/rating/v1/Rate",
|
|
304
308
|
json=self._prepare_rate_shipment(order),
|
|
305
309
|
)
|
|
306
310
|
self._raise_for_status(status, skip_errors)
|
|
@@ -320,7 +324,7 @@ class UpsRequest:
|
|
|
320
324
|
|
|
321
325
|
def shipping_label(self, carrier_tracking_ref):
|
|
322
326
|
status = self._process_reply(
|
|
323
|
-
url="
|
|
327
|
+
url=f"{self.url}/api/labels/v1/recovery",
|
|
324
328
|
json=self._prepare_shipping_label(carrier_tracking_ref),
|
|
325
329
|
)
|
|
326
330
|
self._raise_for_status(status, False)
|
|
@@ -349,7 +353,7 @@ class UpsRequest:
|
|
|
349
353
|
return labels
|
|
350
354
|
|
|
351
355
|
def cancel_shipment(self, picking):
|
|
352
|
-
url = "
|
|
356
|
+
url = f"{self.url}/api/shipments/v1/void/cancel"
|
|
353
357
|
url = f"{url}/{picking.carrier_tracking_ref}"
|
|
354
358
|
status = self._process_reply(url=url, method="delete")
|
|
355
359
|
self._raise_for_status(status, False)
|
|
@@ -372,9 +372,9 @@ ul.auto-toc {
|
|
|
372
372
|
!! This file is generated by oca-gen-addon-readme !!
|
|
373
373
|
!! changes will be overwritten. !!
|
|
374
374
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
375
|
-
!! source digest: sha256:
|
|
375
|
+
!! source digest: sha256:a822b00c048a67361ef9e4de24e3d5f6ba436b9cd140e4b3ac4c87585d999b73
|
|
376
376
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
|
377
|
-
<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/license-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/delivery-carrier/tree/
|
|
377
|
+
<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/license-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/delivery-carrier/tree/18.0/delivery_ups_oca"><img alt="OCA/delivery-carrier" src="https://img.shields.io/badge/github-OCA%2Fdelivery--carrier-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/delivery-carrier-18-0/delivery-carrier-18-0-delivery_ups_oca"><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/delivery-carrier&target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
|
|
378
378
|
<p>This module adds <a class="reference external" href="https://ups.com">UPS</a> to the available carriers.</p>
|
|
379
379
|
<p>It allows you to register shippings, generate labels, get rates from
|
|
380
380
|
order, read shipping states and cancel shipments using UPS webservice,
|
|
@@ -446,7 +446,7 @@ method, a periodical state check will be done querying UPS services.</li>
|
|
|
446
446
|
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/delivery-carrier/issues">GitHub Issues</a>.
|
|
447
447
|
In case of trouble, please check there if your issue has already been reported.
|
|
448
448
|
If you spotted it first, help us to smash it by providing a detailed and welcomed
|
|
449
|
-
<a class="reference external" href="https://github.com/OCA/delivery-carrier/issues/new?body=module:%20delivery_ups_oca%0Aversion:%
|
|
449
|
+
<a class="reference external" href="https://github.com/OCA/delivery-carrier/issues/new?body=module:%20delivery_ups_oca%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
|
|
450
450
|
<p>Do not contact contributors directly about support or help with technical issues.</p>
|
|
451
451
|
</div>
|
|
452
452
|
<div class="section" id="credits">
|
|
@@ -488,7 +488,7 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
|
|
|
488
488
|
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
|
|
489
489
|
mission is to support the collaborative development of Odoo features and
|
|
490
490
|
promote its widespread use.</p>
|
|
491
|
-
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/delivery-carrier/tree/
|
|
491
|
+
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/delivery-carrier/tree/18.0/delivery_ups_oca">OCA/delivery-carrier</a> project on GitHub.</p>
|
|
492
492
|
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
|
|
493
493
|
</div>
|
|
494
494
|
</div>
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
# Copyright 2020 Hunki Enterprises BV
|
|
2
|
-
# Copyright 2021-2022 Tecnativa - Víctor Martínez
|
|
3
|
-
# Copyright 2024 Sygel - Manuel Regidor
|
|
4
1
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
|
5
2
|
|
|
6
3
|
import base64
|
|
4
|
+
from datetime import datetime, timedelta
|
|
7
5
|
from unittest import mock
|
|
8
6
|
|
|
7
|
+
from odoo.exceptions import UserError
|
|
9
8
|
from odoo.tests import Form, common
|
|
10
9
|
|
|
10
|
+
from odoo.addons.delivery_ups_oca.models.ups_request import UpsRequest
|
|
11
|
+
|
|
11
12
|
_module_ns = "odoo.addons.delivery_ups_oca"
|
|
12
13
|
_provider_class = _module_ns + ".models.ups_request.UpsRequest"
|
|
13
14
|
|
|
@@ -33,13 +34,22 @@ class TestDeliveryUpsBase(common.TransactionCase):
|
|
|
33
34
|
"ups_default_packaging_id": cls.env.ref(
|
|
34
35
|
"delivery_ups_oca.product_packaging_ups_02"
|
|
35
36
|
).id,
|
|
37
|
+
"ups_shipper_number": "123456",
|
|
38
|
+
"ups_service_code": "11",
|
|
39
|
+
"ups_file_format": "GIF",
|
|
40
|
+
"ups_tracking_state_update_sync": True,
|
|
41
|
+
"ups_client_id": "test_client_id",
|
|
42
|
+
"ups_client_secret": "test_client_secret",
|
|
43
|
+
"ups_package_dimension_code": "IN",
|
|
44
|
+
"ups_package_weight_code": "LBS",
|
|
45
|
+
"ups_cash_on_delivery": False,
|
|
36
46
|
}
|
|
37
47
|
)
|
|
38
48
|
cls.company = cls.env.ref("base.main_company")
|
|
39
49
|
cls.company.partner_id.write(
|
|
40
50
|
{
|
|
41
|
-
"phone": "
|
|
42
|
-
"vat": "
|
|
51
|
+
"phone": f"+{cls.company.country_id.phone_code}976123456",
|
|
52
|
+
"vat": f"{cls.company.country_id.code}09915370R",
|
|
43
53
|
}
|
|
44
54
|
)
|
|
45
55
|
cls.partner = cls.env["res.partner"].create(
|
|
@@ -56,7 +66,12 @@ class TestDeliveryUpsBase(common.TransactionCase):
|
|
|
56
66
|
}
|
|
57
67
|
)
|
|
58
68
|
cls.product = cls.env["product.product"].create(
|
|
59
|
-
{
|
|
69
|
+
{
|
|
70
|
+
"name": "Test product",
|
|
71
|
+
"type": "consu",
|
|
72
|
+
"is_storable": True,
|
|
73
|
+
"weight": 10,
|
|
74
|
+
}
|
|
60
75
|
)
|
|
61
76
|
cls.sale = cls._create_sale_order(cls)
|
|
62
77
|
|
|
@@ -82,22 +97,64 @@ class TestDeliveryUps(TestDeliveryUpsBase):
|
|
|
82
97
|
def setUpClass(cls):
|
|
83
98
|
super().setUpClass()
|
|
84
99
|
cls.picking = cls.sale.picking_ids[0]
|
|
100
|
+
cls.picking.company_id = cls.sale.company_id.id
|
|
85
101
|
cls.picking.move_ids.quantity = 10
|
|
86
102
|
|
|
103
|
+
# Create additional test data
|
|
104
|
+
cls.package_type = cls.env["stock.package.type"].create(
|
|
105
|
+
{
|
|
106
|
+
"name": "Test UPS Package",
|
|
107
|
+
"package_carrier_type": "ups",
|
|
108
|
+
"shipper_package_code": "02",
|
|
109
|
+
"packaging_length": 10,
|
|
110
|
+
"width": 10,
|
|
111
|
+
"height": 10,
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
|
|
87
115
|
def test_order_ups_rate_shipment(self):
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
116
|
+
"""Test rate_shipment method - covers _rate_shipment and _process_reply"""
|
|
117
|
+
# Create UPS request instance
|
|
118
|
+
ups_request = UpsRequest(self.carrier)
|
|
119
|
+
|
|
120
|
+
# Mock _process_reply to return a successful response
|
|
121
|
+
with mock.patch.object(ups_request, "_process_reply") as mock_process_reply:
|
|
122
|
+
# Mock the response structure
|
|
123
|
+
mock_process_reply.return_value = {
|
|
91
124
|
"RateResponse": {
|
|
92
125
|
"RatedShipment": {
|
|
93
|
-
"TotalCharges": {
|
|
126
|
+
"TotalCharges": {
|
|
127
|
+
"MonetaryValue": "150.00",
|
|
128
|
+
"CurrencyCode": "USD",
|
|
129
|
+
}
|
|
94
130
|
}
|
|
95
131
|
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
# Mock _raise_for_status to do nothing
|
|
135
|
+
with mock.patch.object(ups_request, "_raise_for_status"):
|
|
136
|
+
# Call the actual _rate_shipment method
|
|
137
|
+
result = ups_request._rate_shipment(self.sale)
|
|
138
|
+
|
|
139
|
+
# Verify _process_reply was called with correct arguments
|
|
140
|
+
mock_process_reply.assert_called_once()
|
|
141
|
+
call_args = mock_process_reply.call_args
|
|
142
|
+
|
|
143
|
+
# # Check URL
|
|
144
|
+
# self.assertIn("/api/rating/v1/Rate", call_args[0][0])
|
|
145
|
+
|
|
146
|
+
# Check JSON data structure
|
|
147
|
+
json_data = call_args[1]["json"]
|
|
148
|
+
self.assertIn("RateRequest", json_data)
|
|
149
|
+
self.assertIn("Shipment", json_data["RateRequest"])
|
|
150
|
+
|
|
151
|
+
# Verify result
|
|
152
|
+
self.assertEqual(
|
|
153
|
+
result["RateResponse"]["RatedShipment"]["TotalCharges"][
|
|
154
|
+
"MonetaryValue"
|
|
155
|
+
],
|
|
156
|
+
"150.00",
|
|
157
|
+
)
|
|
101
158
|
|
|
102
159
|
def test_order_ups_rate_shipment_currency_extra(self):
|
|
103
160
|
usd = self.env.ref("base.USD")
|
|
@@ -156,6 +213,7 @@ class TestDeliveryUps(TestDeliveryUpsBase):
|
|
|
156
213
|
self.picking.tracking_state_update()
|
|
157
214
|
self.assertEqual(self.picking.delivery_state, "in_transit")
|
|
158
215
|
self.assertTrue(self.picking.tracking_state_history)
|
|
216
|
+
# Cancel UPS Picking
|
|
159
217
|
with mock.patch(
|
|
160
218
|
_provider_class + ".cancel_shipment",
|
|
161
219
|
return_value=True,
|
|
@@ -163,3 +221,598 @@ class TestDeliveryUps(TestDeliveryUpsBase):
|
|
|
163
221
|
self.picking.cancel_shipment()
|
|
164
222
|
self.assertFalse(self.picking.carrier_tracking_ref)
|
|
165
223
|
self.assertEqual(self.picking.delivery_state, "canceled_shipment")
|
|
224
|
+
|
|
225
|
+
def test_ups_create_shipping(self):
|
|
226
|
+
label = b"%PDF-1.4\n%EOF"
|
|
227
|
+
with mock.patch(
|
|
228
|
+
_provider_class + "._send_shipping",
|
|
229
|
+
return_value={
|
|
230
|
+
"price": {"CurrencyCode": "USD", "MonetaryValue": "10.0"},
|
|
231
|
+
"ShipmentIdentificationNumber": "123456",
|
|
232
|
+
"labels": [
|
|
233
|
+
{
|
|
234
|
+
"tracking_ref": "123456",
|
|
235
|
+
"format_code": "GIF",
|
|
236
|
+
"datas": base64.b64encode(label),
|
|
237
|
+
}
|
|
238
|
+
],
|
|
239
|
+
},
|
|
240
|
+
):
|
|
241
|
+
result = self.carrier.ups_create_shipping(self.picking)
|
|
242
|
+
self.assertEqual(result["tracking_number"], "123456")
|
|
243
|
+
self.assertEqual(result["exact_price"], 10.0)
|
|
244
|
+
self.assertEqual(self.picking.carrier_tracking_ref, "123456")
|
|
245
|
+
# Picking status
|
|
246
|
+
ups_request = UpsRequest(self.carrier)
|
|
247
|
+
with mock.patch.object(ups_request, "_process_reply", return_value=result):
|
|
248
|
+
with mock.patch.object(ups_request, "_raise_for_status"):
|
|
249
|
+
# Call _send_shipping
|
|
250
|
+
result = ups_request._send_shipping(self.picking)
|
|
251
|
+
# # Verify result
|
|
252
|
+
self.assertEqual(result["ShipmentIdentificationNumber"], "123456")
|
|
253
|
+
self.assertEqual(result["price"]["CurrencyCode"], "USD")
|
|
254
|
+
self.assertEqual(result["price"]["MonetaryValue"], "10.0")
|
|
255
|
+
self.assertEqual(len(result["labels"]), 1)
|
|
256
|
+
self.assertEqual(result["labels"][0]["tracking_ref"], "123456")
|
|
257
|
+
self.assertEqual(result["labels"][0]["format_code"], "GIF")
|
|
258
|
+
self.assertEqual(
|
|
259
|
+
result["labels"][0]["datas"], b"JVBERi0xLjQKJUVPRg=="
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
def test_ups_send_shipping(self):
|
|
263
|
+
# Mock the dependencies
|
|
264
|
+
mock_response = {
|
|
265
|
+
"ShipmentResponse": {
|
|
266
|
+
"ShipmentResults": {
|
|
267
|
+
"PackageResults": {
|
|
268
|
+
"TrackingNumber": "TRACK123456",
|
|
269
|
+
"ShippingLabel": {
|
|
270
|
+
"ImageFormat": {"Code": "PDF"},
|
|
271
|
+
"GraphicImage": "base64_encoded_pdf_data",
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
"ShipmentCharges": {"TotalCharges": "45.99"},
|
|
275
|
+
"ShipmentIdentificationNumber": "SHIP123456789",
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
self.picking.number_of_packages = 1
|
|
280
|
+
ups_request = UpsRequest(self.carrier)
|
|
281
|
+
with (
|
|
282
|
+
mock.patch.object(
|
|
283
|
+
ups_request, "_process_reply", return_value=mock_response
|
|
284
|
+
),
|
|
285
|
+
mock.patch.object(ups_request, "_raise_for_status"),
|
|
286
|
+
):
|
|
287
|
+
result = ups_request._send_shipping(self.picking)
|
|
288
|
+
self.assertEqual(result["price"], "45.99")
|
|
289
|
+
self.assertEqual(result["ShipmentIdentificationNumber"], "SHIP123456789")
|
|
290
|
+
self.assertEqual(len(result["labels"]), 1)
|
|
291
|
+
self.assertEqual(result["labels"][0]["tracking_ref"], "TRACK123456")
|
|
292
|
+
self.assertEqual(result["labels"][0]["format_code"], "PDF")
|
|
293
|
+
self.assertEqual(result["labels"][0]["datas"], "base64_encoded_pdf_data")
|
|
294
|
+
|
|
295
|
+
def test_ups_send_shipping_multi_pack(self):
|
|
296
|
+
# Mock the dependencies
|
|
297
|
+
mock_response = {
|
|
298
|
+
"ShipmentResponse": {
|
|
299
|
+
"ShipmentResults": {
|
|
300
|
+
"PackageResults": [
|
|
301
|
+
{
|
|
302
|
+
"TrackingNumber": "TRACK123456",
|
|
303
|
+
"ShippingLabel": {
|
|
304
|
+
"ImageFormat": {"Code": "PDF"},
|
|
305
|
+
"GraphicImage": "base64_encoded_pdf_data",
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
"TrackingNumber": "TRACK123457",
|
|
310
|
+
"ShippingLabel": {
|
|
311
|
+
"ImageFormat": {"Code": "PDF"},
|
|
312
|
+
"GraphicImage": "base64_encoded_pdf_data",
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
"ShipmentCharges": {"TotalCharges": "50.99"},
|
|
317
|
+
"ShipmentIdentificationNumber": "SHIP22222",
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
self.picking.number_of_packages = 2
|
|
322
|
+
ups_request = UpsRequest(self.carrier)
|
|
323
|
+
with (
|
|
324
|
+
mock.patch.object(
|
|
325
|
+
ups_request, "_process_reply", return_value=mock_response
|
|
326
|
+
),
|
|
327
|
+
mock.patch.object(ups_request, "_raise_for_status"),
|
|
328
|
+
):
|
|
329
|
+
result = ups_request._send_shipping(self.picking)
|
|
330
|
+
self.assertEqual(result["price"], "50.99")
|
|
331
|
+
self.assertEqual(result["ShipmentIdentificationNumber"], "SHIP22222")
|
|
332
|
+
self.assertEqual(len(result["labels"]), 2)
|
|
333
|
+
self.assertEqual(result["labels"][0]["tracking_ref"], "TRACK123456")
|
|
334
|
+
|
|
335
|
+
def test_ups_send_shipping_multiple_pickings(self):
|
|
336
|
+
# Create a second picking
|
|
337
|
+
picking2 = self.picking.copy()
|
|
338
|
+
picking2.move_ids.quantity = 5
|
|
339
|
+
|
|
340
|
+
label = b"%PDF-1.4\n%EOF"
|
|
341
|
+
with mock.patch(
|
|
342
|
+
_provider_class + "._send_shipping",
|
|
343
|
+
side_effect=[
|
|
344
|
+
{
|
|
345
|
+
"price": {"CurrencyCode": "USD", "MonetaryValue": "10.0"},
|
|
346
|
+
"ShipmentIdentificationNumber": "123456",
|
|
347
|
+
"labels": [
|
|
348
|
+
{
|
|
349
|
+
"tracking_ref": "123456",
|
|
350
|
+
"format_code": "GIF",
|
|
351
|
+
"datas": base64.b64encode(label),
|
|
352
|
+
}
|
|
353
|
+
],
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
"price": {"CurrencyCode": "USD", "MonetaryValue": "15.0"},
|
|
357
|
+
"ShipmentIdentificationNumber": "789012",
|
|
358
|
+
"labels": [
|
|
359
|
+
{
|
|
360
|
+
"tracking_ref": "789012",
|
|
361
|
+
"format_code": "GIF",
|
|
362
|
+
"datas": base64.b64encode(label),
|
|
363
|
+
}
|
|
364
|
+
],
|
|
365
|
+
},
|
|
366
|
+
],
|
|
367
|
+
):
|
|
368
|
+
results = self.carrier.ups_send_shipping(self.picking + picking2)
|
|
369
|
+
self.assertEqual(len(results), 2)
|
|
370
|
+
self.assertEqual(results[0]["tracking_number"], "123456")
|
|
371
|
+
self.assertEqual(results[1]["tracking_number"], "789012")
|
|
372
|
+
|
|
373
|
+
def test_ups_get_label(self):
|
|
374
|
+
ups_request = UpsRequest(self.carrier)
|
|
375
|
+
carrier_tracking_ref = "1Z12345E0291980793"
|
|
376
|
+
mock_label_data = b"%PDF-1.4\nTest PDF Content\n%%EOF"
|
|
377
|
+
mock_response = {
|
|
378
|
+
"LabelRecoveryResponse": {
|
|
379
|
+
"LabelResults": {
|
|
380
|
+
"TrackingNumber": "1Z12345E0291980793",
|
|
381
|
+
"LabelImage": {
|
|
382
|
+
"LabelImageFormat": {"Code": "PDF"},
|
|
383
|
+
"GraphicImage": base64.b64encode(mock_label_data).decode(
|
|
384
|
+
"ascii"
|
|
385
|
+
),
|
|
386
|
+
},
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
with mock.patch.object(
|
|
391
|
+
ups_request, "_process_reply", return_value=mock_response
|
|
392
|
+
):
|
|
393
|
+
with mock.patch.object(
|
|
394
|
+
ups_request,
|
|
395
|
+
"_prepare_shipping_label",
|
|
396
|
+
return_value={"TrackingNumber": carrier_tracking_ref},
|
|
397
|
+
):
|
|
398
|
+
# Call the method
|
|
399
|
+
labels = ups_request.shipping_label(carrier_tracking_ref)
|
|
400
|
+
# Verify the result
|
|
401
|
+
self.assertEqual(len(labels), 1)
|
|
402
|
+
self.assertEqual(labels[0]["tracking_ref"], "1Z12345E0291980793")
|
|
403
|
+
self.assertEqual(labels[0]["format_code"], "PDF")
|
|
404
|
+
self.assertEqual(
|
|
405
|
+
labels[0]["datas"],
|
|
406
|
+
base64.b64encode(mock_label_data).decode("ascii"),
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
def test_shipping_label_multiple_list(self):
|
|
410
|
+
ups_request = UpsRequest(self.carrier)
|
|
411
|
+
carrier_tracking_ref = "1Z12345E0291980793"
|
|
412
|
+
mock_label1_data = b"%PDF-1.4\nTest PDF Content\n%%EOF"
|
|
413
|
+
mock_label2_data = b"%PDF-1.4\nTest PDF Content\n%%EOF"
|
|
414
|
+
mock_response = {
|
|
415
|
+
"LabelRecoveryResponse": {
|
|
416
|
+
"LabelResults": [
|
|
417
|
+
{
|
|
418
|
+
"TrackingNumber": "1Z12345E0291980793",
|
|
419
|
+
"LabelImage": {
|
|
420
|
+
"LabelImageFormat": {"Code": "GIF"},
|
|
421
|
+
"GraphicImage": base64.b64encode(mock_label1_data).decode(
|
|
422
|
+
"ascii"
|
|
423
|
+
),
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
"TrackingNumber": "1Z12345E0291980794",
|
|
428
|
+
"LabelImage": {
|
|
429
|
+
"LabelImageFormat": {"Code": "GIF"},
|
|
430
|
+
"GraphicImage": base64.b64encode(mock_label2_data).decode(
|
|
431
|
+
"ascii"
|
|
432
|
+
),
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
]
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
with mock.patch.object(
|
|
439
|
+
ups_request, "_process_reply", return_value=mock_response
|
|
440
|
+
):
|
|
441
|
+
with mock.patch.object(
|
|
442
|
+
ups_request,
|
|
443
|
+
"_prepare_shipping_label",
|
|
444
|
+
return_value={"TrackingNumber": carrier_tracking_ref},
|
|
445
|
+
):
|
|
446
|
+
# Call the method
|
|
447
|
+
labels = ups_request.shipping_label(carrier_tracking_ref)
|
|
448
|
+
# Verify the result
|
|
449
|
+
self.assertEqual(len(labels), 2)
|
|
450
|
+
# Verify first label
|
|
451
|
+
self.assertEqual(labels[0]["tracking_ref"], "1Z12345E0291980793")
|
|
452
|
+
self.assertEqual(labels[0]["format_code"], "GIF")
|
|
453
|
+
self.assertEqual(
|
|
454
|
+
labels[0]["datas"],
|
|
455
|
+
base64.b64encode(mock_label1_data).decode("ascii"),
|
|
456
|
+
)
|
|
457
|
+
# Verify second label
|
|
458
|
+
self.assertEqual(labels[1]["tracking_ref"], "1Z12345E0291980794")
|
|
459
|
+
self.assertEqual(labels[1]["format_code"], "GIF")
|
|
460
|
+
self.assertEqual(
|
|
461
|
+
labels[1]["datas"],
|
|
462
|
+
base64.b64encode(mock_label2_data).decode("ascii"),
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
def test_ups_get_label_no_tracking_ref(self):
|
|
466
|
+
result = self.carrier.ups_get_label(False)
|
|
467
|
+
self.assertFalse(result)
|
|
468
|
+
|
|
469
|
+
def test_ups_get_tracking_link(self):
|
|
470
|
+
self.picking.carrier_tracking_ref = "123456"
|
|
471
|
+
tracking_link = self.carrier.ups_get_tracking_link(self.picking)
|
|
472
|
+
expected_link = "https://ups.com/WebTracking/track?trackingNumber=123456"
|
|
473
|
+
self.assertEqual(tracking_link, expected_link)
|
|
474
|
+
|
|
475
|
+
def test_ups_cancel_shipment(self):
|
|
476
|
+
"""Test successful shipment cancellation"""
|
|
477
|
+
ups_request = UpsRequest(self.carrier)
|
|
478
|
+
self.picking.carrier_tracking_ref = "123456"
|
|
479
|
+
# Mock successful response
|
|
480
|
+
mock_response = {
|
|
481
|
+
"VoidShipmentResponse": {
|
|
482
|
+
"Response": {"ResponseStatus": {"Code": "1", "Description": "Success"}}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
with mock.patch.object(
|
|
486
|
+
ups_request, "_process_reply", return_value=mock_response
|
|
487
|
+
):
|
|
488
|
+
with mock.patch.object(ups_request, "_raise_for_status", return_value=True):
|
|
489
|
+
result = ups_request.cancel_shipment(self.picking)
|
|
490
|
+
self.assertTrue(result)
|
|
491
|
+
|
|
492
|
+
def test_ups_tracking_state_update(self):
|
|
493
|
+
self.picking.carrier_tracking_ref = "123456"
|
|
494
|
+
with mock.patch(
|
|
495
|
+
_provider_class + ".tracking_state_update",
|
|
496
|
+
return_value={
|
|
497
|
+
"delivery_state": "in_transit",
|
|
498
|
+
"tracking_state_history": "Test history",
|
|
499
|
+
},
|
|
500
|
+
):
|
|
501
|
+
self.carrier.ups_tracking_state_update(self.picking)
|
|
502
|
+
self.assertEqual(self.picking.delivery_state, "in_transit")
|
|
503
|
+
self.assertEqual(self.picking.tracking_state_history, "Test history")
|
|
504
|
+
|
|
505
|
+
def test_ups_tracking_state_update_no_sync(self):
|
|
506
|
+
self.carrier.ups_tracking_state_update_sync = False
|
|
507
|
+
self.picking.carrier_tracking_ref = "123456"
|
|
508
|
+
self.carrier.ups_tracking_state_update(self.picking)
|
|
509
|
+
# Should do nothing when sync is disabled
|
|
510
|
+
|
|
511
|
+
def test_ups_tracking_state_update_no_tracking_ref(self):
|
|
512
|
+
self.picking.carrier_tracking_ref = False
|
|
513
|
+
self.carrier.ups_tracking_state_update(self.picking)
|
|
514
|
+
# Should do nothing when no tracking reference
|
|
515
|
+
|
|
516
|
+
def test_ups_get_new_token_no_credentials(self):
|
|
517
|
+
"""Test _get_new_token raises UserError when no client credentials"""
|
|
518
|
+
# Set no client credentials on carrier
|
|
519
|
+
self.carrier.ups_client_id = False
|
|
520
|
+
self.carrier.ups_client_secret = False
|
|
521
|
+
# Create UpsRequest instance
|
|
522
|
+
ups_request = UpsRequest(self.carrier)
|
|
523
|
+
# Mock the _() translation function in the ups_request module
|
|
524
|
+
# This prevents translation context issues
|
|
525
|
+
with mock.patch(
|
|
526
|
+
"odoo.addons.delivery_ups_oca.models.ups_request._"
|
|
527
|
+
) as mock_translate:
|
|
528
|
+
# Make the translation function return the string unchanged
|
|
529
|
+
mock_translate.side_effect = lambda x: x
|
|
530
|
+
# The _get_new_token method should raise UserError when no credentials
|
|
531
|
+
with self.assertRaises(UserError) as context:
|
|
532
|
+
ups_request._get_new_token()
|
|
533
|
+
# Get the exception message
|
|
534
|
+
error_msg = str(context.exception)
|
|
535
|
+
self.assertIn("Client ID", error_msg)
|
|
536
|
+
self.assertIn("Client Secret", error_msg)
|
|
537
|
+
self.assertIn("must be set", error_msg)
|
|
538
|
+
|
|
539
|
+
def test_ups_update_token(self):
|
|
540
|
+
# Test the actual token update with proper mock
|
|
541
|
+
with mock.patch(
|
|
542
|
+
_provider_class + "._get_new_token",
|
|
543
|
+
return_value=None,
|
|
544
|
+
):
|
|
545
|
+
# Test with client_id and client_secret
|
|
546
|
+
self.carrier.ups_client_id = "test_id"
|
|
547
|
+
self.carrier.ups_client_secret = "test_secret"
|
|
548
|
+
self.carrier.ups_update_token()
|
|
549
|
+
|
|
550
|
+
# Test without client credentials
|
|
551
|
+
self.carrier.ups_client_id = False
|
|
552
|
+
|
|
553
|
+
def test_ups_update_token_expired(self):
|
|
554
|
+
# Test token update when token is expired
|
|
555
|
+
self.carrier.ups_token_expiration_date = datetime.now() - timedelta(days=1)
|
|
556
|
+
self.carrier.ups_client_id = "test_id"
|
|
557
|
+
self.carrier.ups_client_secret = "test_secret"
|
|
558
|
+
|
|
559
|
+
with mock.patch(
|
|
560
|
+
_provider_class + "._get_new_token",
|
|
561
|
+
return_value=None,
|
|
562
|
+
):
|
|
563
|
+
self.carrier.ups_update_token()
|
|
564
|
+
# Should call _get_new_token when token is expired
|
|
565
|
+
|
|
566
|
+
def test_picking_ups_get_label_wrong_carrier(self):
|
|
567
|
+
self.picking.carrier_id.delivery_type = "fixed"
|
|
568
|
+
self.picking.carrier_tracking_ref = "123456"
|
|
569
|
+
result = self.picking.ups_get_label()
|
|
570
|
+
self.assertIsNone(result)
|
|
571
|
+
|
|
572
|
+
def test_picking_ups_get_label_no_tracking(self):
|
|
573
|
+
self.picking.carrier_tracking_ref = False
|
|
574
|
+
result = self.picking.ups_get_label()
|
|
575
|
+
self.assertIsNone(result)
|
|
576
|
+
|
|
577
|
+
def test_ups_rate_shipment_with_packages(self):
|
|
578
|
+
# Test with packages from picking
|
|
579
|
+
self.carrier.ups_use_packages_from_picking = True
|
|
580
|
+
package = self.env["stock.quant.package"].create(
|
|
581
|
+
{
|
|
582
|
+
"name": "Test Package",
|
|
583
|
+
"shipping_weight": 5,
|
|
584
|
+
}
|
|
585
|
+
)
|
|
586
|
+
self.picking.move_ids.move_line_ids.result_package_id = package.id
|
|
587
|
+
|
|
588
|
+
with mock.patch(
|
|
589
|
+
_provider_class + "._rate_shipment",
|
|
590
|
+
return_value={
|
|
591
|
+
"RateResponse": {
|
|
592
|
+
"RatedShipment": {
|
|
593
|
+
"TotalCharges": {"MonetaryValue": 1, "CurrencyCode": "USD"}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
},
|
|
597
|
+
):
|
|
598
|
+
res = self.carrier.ups_rate_shipment(self.sale)
|
|
599
|
+
self.assertGreater(res["price"], 0)
|
|
600
|
+
self.assertTrue(res["success"])
|
|
601
|
+
|
|
602
|
+
def test_ups_label_attachment_preparation(self):
|
|
603
|
+
# Test label attachment preparation
|
|
604
|
+
picking = self.picking
|
|
605
|
+
values = {
|
|
606
|
+
"name": "test_label.GIF",
|
|
607
|
+
"datas": base64.b64encode(b"test"),
|
|
608
|
+
}
|
|
609
|
+
attachment_data = self.carrier._prepare_ups_label_attachment(picking, values)
|
|
610
|
+
self.assertEqual(attachment_data["name"], "test_label.GIF")
|
|
611
|
+
self.assertEqual(attachment_data["res_model"], picking._name)
|
|
612
|
+
self.assertEqual(attachment_data["res_id"], picking.id)
|
|
613
|
+
|
|
614
|
+
def test_ups_create_label_multiple_labels(self):
|
|
615
|
+
# Test creating multiple labels
|
|
616
|
+
label = b"%PDF-1.4\n%EOF"
|
|
617
|
+
labels = [
|
|
618
|
+
{
|
|
619
|
+
"tracking_ref": "123456",
|
|
620
|
+
"format_code": "GIF",
|
|
621
|
+
"datas": base64.b64encode(label),
|
|
622
|
+
},
|
|
623
|
+
{
|
|
624
|
+
"tracking_ref": "789012",
|
|
625
|
+
"format_code": "ZPL",
|
|
626
|
+
"datas": base64.b64encode(label),
|
|
627
|
+
},
|
|
628
|
+
]
|
|
629
|
+
attachments = self.carrier._create_ups_label(self.picking, labels)
|
|
630
|
+
self.assertEqual(len(attachments), 2)
|
|
631
|
+
self.assertEqual(attachments[0].name, "123456-GIF.GIF")
|
|
632
|
+
self.assertEqual(attachments[1].name, "789012-ZPL.ZPL")
|
|
633
|
+
|
|
634
|
+
def _patch_carrier_log_xml(self):
|
|
635
|
+
"""Helper to patch the log_xml method on carrier class"""
|
|
636
|
+
return mock.patch.object(type(self.carrier), "log_xml")
|
|
637
|
+
|
|
638
|
+
def test_ups_process_reply_basic_success_with_helper(self):
|
|
639
|
+
"""Test using helper method for patching"""
|
|
640
|
+
# Set up a valid token
|
|
641
|
+
future_date = datetime.now() + timedelta(hours=1)
|
|
642
|
+
self.carrier.ups_token = "valid_token_123"
|
|
643
|
+
self.carrier.ups_token_expiration_date = future_date
|
|
644
|
+
|
|
645
|
+
ups_request = UpsRequest(self.carrier)
|
|
646
|
+
|
|
647
|
+
# Mock the HTTP response
|
|
648
|
+
mock_response = mock.Mock()
|
|
649
|
+
mock_response.status_code = 200
|
|
650
|
+
mock_response.json.return_value = {"success": True, "data": "test_data"}
|
|
651
|
+
|
|
652
|
+
with mock.patch.object(
|
|
653
|
+
ups_request, "_send_request", return_value=mock_response
|
|
654
|
+
):
|
|
655
|
+
# Use the helper method
|
|
656
|
+
with self._patch_carrier_log_xml() as mock_log:
|
|
657
|
+
result = ups_request._process_reply(
|
|
658
|
+
url="https://api.test.com/endpoint",
|
|
659
|
+
json={"key": "value"},
|
|
660
|
+
method="post",
|
|
661
|
+
headers_extra={"Content-Type": "application/json"},
|
|
662
|
+
)
|
|
663
|
+
# Verify result
|
|
664
|
+
self.assertEqual(result, {"success": True, "data": "test_data"})
|
|
665
|
+
self.assertEqual(mock_log.call_count, 2)
|
|
666
|
+
|
|
667
|
+
def test_ups_prepare_create_shipping_with_packages(self):
|
|
668
|
+
"""Test _prepare_create_shipping with packages from picking"""
|
|
669
|
+
# Enable use packages from picking
|
|
670
|
+
self.carrier.ups_use_packages_from_picking = True
|
|
671
|
+
|
|
672
|
+
ups_request = UpsRequest(self.carrier)
|
|
673
|
+
|
|
674
|
+
# Create test packages
|
|
675
|
+
package1 = self.env["stock.quant.package"].create(
|
|
676
|
+
{
|
|
677
|
+
"name": "Package 1",
|
|
678
|
+
"shipping_weight": 5.0,
|
|
679
|
+
}
|
|
680
|
+
)
|
|
681
|
+
# Create package type
|
|
682
|
+
package_type1 = self.env["stock.package.type"].create(
|
|
683
|
+
{
|
|
684
|
+
"name": "Test Package Type - 001",
|
|
685
|
+
"shipper_package_code": "001",
|
|
686
|
+
"packaging_length": 10.0,
|
|
687
|
+
"width": 8.0,
|
|
688
|
+
"height": 6.0,
|
|
689
|
+
}
|
|
690
|
+
)
|
|
691
|
+
package1.package_type_id = package_type1
|
|
692
|
+
package2 = self.env["stock.quant.package"].create(
|
|
693
|
+
{
|
|
694
|
+
"name": "Package 2",
|
|
695
|
+
"shipping_weight": 3.0,
|
|
696
|
+
}
|
|
697
|
+
)
|
|
698
|
+
# Create package type
|
|
699
|
+
package_type2 = self.env["stock.package.type"].create(
|
|
700
|
+
{
|
|
701
|
+
"name": "Test Package Type - 002",
|
|
702
|
+
"shipper_package_code": "002",
|
|
703
|
+
"packaging_length": 10.0,
|
|
704
|
+
"width": 8.0,
|
|
705
|
+
"height": 6.0,
|
|
706
|
+
}
|
|
707
|
+
)
|
|
708
|
+
package2.package_type_id = package_type2
|
|
709
|
+
|
|
710
|
+
# Set packages on move lines
|
|
711
|
+
self.picking.move_ids.move_line_ids = [
|
|
712
|
+
(
|
|
713
|
+
0,
|
|
714
|
+
0,
|
|
715
|
+
{
|
|
716
|
+
"result_package_id": package1.id,
|
|
717
|
+
"product_id": self.product.id,
|
|
718
|
+
"quantity": 2,
|
|
719
|
+
},
|
|
720
|
+
),
|
|
721
|
+
(
|
|
722
|
+
0,
|
|
723
|
+
0,
|
|
724
|
+
{
|
|
725
|
+
"result_package_id": package2.id,
|
|
726
|
+
"product_id": self.product.id,
|
|
727
|
+
"quantity": 3,
|
|
728
|
+
},
|
|
729
|
+
),
|
|
730
|
+
]
|
|
731
|
+
|
|
732
|
+
# Set picking data
|
|
733
|
+
self.picking.name = "TEST0001"
|
|
734
|
+
self.picking.shipping_weight = 8.0 # 5 + 3
|
|
735
|
+
self.picking.number_of_packages = 2
|
|
736
|
+
|
|
737
|
+
# Prepare shipping data
|
|
738
|
+
result = ups_request._prepare_create_shipping(self.picking)
|
|
739
|
+
packages = result["ShipmentRequest"]["Shipment"]["Package"]
|
|
740
|
+
self.assertEqual(len(packages), 2)
|
|
741
|
+
# Verify package descriptions
|
|
742
|
+
self.assertEqual(packages[0]["Description"], package_type1.name)
|
|
743
|
+
self.assertEqual(packages[1]["Description"], package_type2.name)
|
|
744
|
+
# Verify service code
|
|
745
|
+
self.assertEqual(result["ShipmentRequest"]["Shipment"]["Service"]["Code"], "11")
|
|
746
|
+
# Verify label specification
|
|
747
|
+
self.assertIn("LabelSpecification", result["ShipmentRequest"])
|
|
748
|
+
self.assertEqual(
|
|
749
|
+
result["ShipmentRequest"]["LabelSpecification"]["LabelImageFormat"]["Code"],
|
|
750
|
+
"GIF",
|
|
751
|
+
)
|
|
752
|
+
|
|
753
|
+
def test_ups_prepare_create_shipping_without_packages(self):
|
|
754
|
+
"""Test _prepare_create_shipping without packages (uses default packaging)"""
|
|
755
|
+
self.carrier.ups_use_packages_from_picking = False
|
|
756
|
+
|
|
757
|
+
ups_request = UpsRequest(self.carrier)
|
|
758
|
+
|
|
759
|
+
# Set picking data
|
|
760
|
+
self.picking.name = "TEST0002"
|
|
761
|
+
self.picking.shipping_weight = 30.0
|
|
762
|
+
self.picking.number_of_packages = 3
|
|
763
|
+
|
|
764
|
+
# # Create default packaging
|
|
765
|
+
default_packaging = self.env["stock.package.type"].create(
|
|
766
|
+
{
|
|
767
|
+
"name": "UPS Box",
|
|
768
|
+
"package_carrier_type": "ups",
|
|
769
|
+
"shipper_package_code": "02",
|
|
770
|
+
"packaging_length": 12.0,
|
|
771
|
+
"width": 10.0,
|
|
772
|
+
"height": 8.0,
|
|
773
|
+
}
|
|
774
|
+
)
|
|
775
|
+
self.carrier.ups_default_packaging_id = default_packaging
|
|
776
|
+
|
|
777
|
+
# Prepare shipping data
|
|
778
|
+
result = ups_request._prepare_create_shipping(self.picking)
|
|
779
|
+
|
|
780
|
+
# Verify structure
|
|
781
|
+
packages = result["ShipmentRequest"]["Shipment"]["Package"]
|
|
782
|
+
self.assertEqual(len(packages), 3) # Should create 3 packages
|
|
783
|
+
|
|
784
|
+
# Each package should have weight = 30/3 = 10.0
|
|
785
|
+
for i, package in enumerate(packages):
|
|
786
|
+
self.assertEqual(package["Description"], f"TEST0002 ({i+1})")
|
|
787
|
+
self.assertEqual(package["NumOfPieces"], "1")
|
|
788
|
+
self.assertEqual(package["PackageWeight"]["Weight"], "10.0") # 30/3 = 10
|
|
789
|
+
self.assertEqual(package["Packaging"]["Code"], "02")
|
|
790
|
+
|
|
791
|
+
def test_ups_prepare_create_shipping_with_cash_on_delivery(self):
|
|
792
|
+
"""Test _prepare_create_shipping with cash on delivery"""
|
|
793
|
+
# Enable cash on delivery
|
|
794
|
+
self.carrier.ups_cash_on_delivery = True
|
|
795
|
+
self.carrier.ups_cod_funds_code = "1" # Cash
|
|
796
|
+
ups_request = UpsRequest(self.carrier)
|
|
797
|
+
# Set sale order amount
|
|
798
|
+
self.sale.amount_total = 11.5
|
|
799
|
+
self.sale.currency_id = self.env.ref("base.USD")
|
|
800
|
+
# Ensure picking is linked to sale order
|
|
801
|
+
self.picking.sale_id = self.sale
|
|
802
|
+
# Set picking data
|
|
803
|
+
self.picking.name = "TEST0006"
|
|
804
|
+
self.picking.shipping_weight = 8.0
|
|
805
|
+
self.picking.number_of_packages = 2
|
|
806
|
+
# Prepare shipping data
|
|
807
|
+
result = ups_request._prepare_create_shipping(self.picking)
|
|
808
|
+
# Verify cash on delivery data is included
|
|
809
|
+
shipment = result["ShipmentRequest"]["Shipment"]
|
|
810
|
+
self.assertIn("ShipmentServiceOptions", shipment)
|
|
811
|
+
cod_data = shipment["ShipmentServiceOptions"][0]["COD"]
|
|
812
|
+
self.assertEqual(cod_data["CODFundsCode"], "1")
|
|
813
|
+
self.assertEqual(cod_data["CODAmount"]["CurrencyCode"], "USD")
|
|
814
|
+
self.assertEqual(cod_data["CODAmount"]["MonetaryValue"], "11.5")
|
|
815
|
+
# Verify other shipment details
|
|
816
|
+
self.assertEqual(shipment["Description"], "TEST0006")
|
|
817
|
+
self.assertEqual(shipment["Service"]["Code"], "11")
|
|
818
|
+
self.assertEqual(len(shipment["Package"]), 2)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: odoo-addon-delivery_ups_oca
|
|
3
|
-
Version:
|
|
3
|
+
Version: 18.0.1.0.0.2
|
|
4
4
|
Requires-Python: >=3.10
|
|
5
|
-
Requires-Dist: odoo-addon-delivery_package_number
|
|
6
|
-
Requires-Dist: odoo-addon-delivery_price_method
|
|
7
|
-
Requires-Dist: odoo-addon-delivery_state
|
|
8
|
-
Requires-Dist: odoo
|
|
5
|
+
Requires-Dist: odoo-addon-delivery_package_number==18.0.*
|
|
6
|
+
Requires-Dist: odoo-addon-delivery_price_method==18.0.*
|
|
7
|
+
Requires-Dist: odoo-addon-delivery_state==18.0.*
|
|
8
|
+
Requires-Dist: odoo==18.0.*
|
|
9
9
|
Summary: Integrate UPS webservice
|
|
10
10
|
Home-page: https://github.com/OCA/delivery-carrier
|
|
11
11
|
License: AGPL-3
|
|
@@ -13,7 +13,7 @@ Author: Hunki Enterprises BV, Tecnativa, ForgeFlow, Odoo Community Association (
|
|
|
13
13
|
Author-email: support@odoo-community.org
|
|
14
14
|
Classifier: Programming Language :: Python
|
|
15
15
|
Classifier: Framework :: Odoo
|
|
16
|
-
Classifier: Framework :: Odoo ::
|
|
16
|
+
Classifier: Framework :: Odoo :: 18.0
|
|
17
17
|
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
|
|
18
18
|
Classifier: Development Status :: 4 - Beta
|
|
19
19
|
Description-Content-Type: text/x-rst
|
|
@@ -31,7 +31,7 @@ Delivery UPS OCA
|
|
|
31
31
|
!! This file is generated by oca-gen-addon-readme !!
|
|
32
32
|
!! changes will be overwritten. !!
|
|
33
33
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
34
|
-
!! source digest: sha256:
|
|
34
|
+
!! source digest: sha256:a822b00c048a67361ef9e4de24e3d5f6ba436b9cd140e4b3ac4c87585d999b73
|
|
35
35
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
36
36
|
|
|
37
37
|
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
|
|
@@ -41,13 +41,13 @@ Delivery UPS OCA
|
|
|
41
41
|
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
|
42
42
|
:alt: License: AGPL-3
|
|
43
43
|
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fdelivery--carrier-lightgray.png?logo=github
|
|
44
|
-
:target: https://github.com/OCA/delivery-carrier/tree/
|
|
44
|
+
:target: https://github.com/OCA/delivery-carrier/tree/18.0/delivery_ups_oca
|
|
45
45
|
:alt: OCA/delivery-carrier
|
|
46
46
|
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
|
|
47
|
-
:target: https://translation.odoo-community.org/projects/delivery-carrier-
|
|
47
|
+
:target: https://translation.odoo-community.org/projects/delivery-carrier-18-0/delivery-carrier-18-0-delivery_ups_oca
|
|
48
48
|
:alt: Translate me on Weblate
|
|
49
49
|
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
|
|
50
|
-
:target: https://runboat.odoo-community.org/builds?repo=OCA/delivery-carrier&target_branch=
|
|
50
|
+
:target: https://runboat.odoo-community.org/builds?repo=OCA/delivery-carrier&target_branch=18.0
|
|
51
51
|
:alt: Try me on Runboat
|
|
52
52
|
|
|
53
53
|
|badge1| |badge2| |badge3| |badge4| |badge5|
|
|
@@ -117,7 +117,7 @@ Bug Tracker
|
|
|
117
117
|
Bugs are tracked on `GitHub Issues <https://github.com/OCA/delivery-carrier/issues>`_.
|
|
118
118
|
In case of trouble, please check there if your issue has already been reported.
|
|
119
119
|
If you spotted it first, help us to smash it by providing a detailed and welcomed
|
|
120
|
-
`feedback <https://github.com/OCA/delivery-carrier/issues/new?body=module:%20delivery_ups_oca%0Aversion:%
|
|
120
|
+
`feedback <https://github.com/OCA/delivery-carrier/issues/new?body=module:%20delivery_ups_oca%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
|
121
121
|
|
|
122
122
|
Do not contact contributors directly about support or help with technical issues.
|
|
123
123
|
|
|
@@ -162,6 +162,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose
|
|
|
162
162
|
mission is to support the collaborative development of Odoo features and
|
|
163
163
|
promote its widespread use.
|
|
164
164
|
|
|
165
|
-
This module is part of the `OCA/delivery-carrier <https://github.com/OCA/delivery-carrier/tree/
|
|
165
|
+
This module is part of the `OCA/delivery-carrier <https://github.com/OCA/delivery-carrier/tree/18.0/delivery_ups_oca>`_ project on GitHub.
|
|
166
166
|
|
|
167
167
|
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
odoo/addons/delivery_ups_oca/README.rst,sha256=
|
|
1
|
+
odoo/addons/delivery_ups_oca/README.rst,sha256=aK7qzFNoYeQAi5Q71zd6NkA_Fdv6LUIg3Atmk0VRzyw,5291
|
|
2
2
|
odoo/addons/delivery_ups_oca/__init__.py,sha256=eShEGRadAlxopoLqIQ4-N42FM7MWPSuBe0h_l1cXTPM,87
|
|
3
|
-
odoo/addons/delivery_ups_oca/__manifest__.py,sha256=
|
|
3
|
+
odoo/addons/delivery_ups_oca/__manifest__.py,sha256=Sh0feY3gCZHwYHY7i6nvPfuefS4-OhAlLnqVCckd6WQ,845
|
|
4
4
|
odoo/addons/delivery_ups_oca/data/stock_package_type_data.xml,sha256=PhFMtGKBmbdaokX8F3gasubzAIIOgmxoa0lwkwbetEw,5691
|
|
5
|
-
odoo/addons/delivery_ups_oca/i18n/delivery_ups_oca.pot,sha256=
|
|
5
|
+
odoo/addons/delivery_ups_oca/i18n/delivery_ups_oca.pot,sha256=JIEdykm7RiigIDQj6asWKJH--ncCdyBFBApphENfRDw,12966
|
|
6
6
|
odoo/addons/delivery_ups_oca/i18n/it.po,sha256=NQfcUHYFGyC08-sBbSlP-N1Fn4f4zn0sSWPVEGF1aqw,19817
|
|
7
7
|
odoo/addons/delivery_ups_oca/models/__init__.py,sha256=yuukCOHXALZomJz8kz97Y1mbp_uXm6h8wNc3UqbOcVU,183
|
|
8
|
-
odoo/addons/delivery_ups_oca/models/delivery_carrier.py,sha256
|
|
8
|
+
odoo/addons/delivery_ups_oca/models/delivery_carrier.py,sha256=l4tcha_lwhXHqR54emqalKWxZbDtsdWzcEV08kBBQmI,8072
|
|
9
9
|
odoo/addons/delivery_ups_oca/models/stock_package_type.py,sha256=nraw8nT02RRIRbP1ulh_6vqYnorPaWOzcSemzqdmEDs,283
|
|
10
10
|
odoo/addons/delivery_ups_oca/models/stock_picking.py,sha256=TNroETJZ0JJAP5Nttvv0qZWeetHZ7ZuUzxXGgmZsGm8,446
|
|
11
|
-
odoo/addons/delivery_ups_oca/models/ups_request.py,sha256=
|
|
11
|
+
odoo/addons/delivery_ups_oca/models/ups_request.py,sha256=5vTYEicw54980mbiY74VDj_9U4ELOAB0L3VqWwxXmlM,16847
|
|
12
12
|
odoo/addons/delivery_ups_oca/readme/CONFIGURE.md,sha256=mDViGpGJ8BtEC-Gm60D47C5tmaUUvG_lZZRPfUqkmlI,878
|
|
13
13
|
odoo/addons/delivery_ups_oca/readme/CONTRIBUTORS.md,sha256=5rRwa8H463CvvXeLURAeGnmMrb0eWAHTyutPGXbr-0A,279
|
|
14
14
|
odoo/addons/delivery_ups_oca/readme/DESCRIPTION.md,sha256=i8wS58sFjqj3r0AkEFUAeg3_q54AQQaO3LvMMTnxNf4,475
|
|
15
15
|
odoo/addons/delivery_ups_oca/readme/ROADMAP.md,sha256=lx0aOESEhWHxzdOlvp4giX3Py3izFcSxk3XIY_eUD00,64
|
|
16
16
|
odoo/addons/delivery_ups_oca/readme/USAGE.md,sha256=aqWOcJ4GIbsoxkXOpJJAIOWwbvAfSEnsqDG-NGjfTbE,547
|
|
17
17
|
odoo/addons/delivery_ups_oca/static/description/icon.png,sha256=KYPV9VXO6IFBW-uC3sbMyoLtQGvPtl3b7O8W1VgikwA,38594
|
|
18
|
-
odoo/addons/delivery_ups_oca/static/description/index.html,sha256=
|
|
18
|
+
odoo/addons/delivery_ups_oca/static/description/index.html,sha256=J0Kt_lvFd38rX7wiJcK7M4U3pV8YYNRbsVfjQBWTCNg,15910
|
|
19
19
|
odoo/addons/delivery_ups_oca/tests/__init__.py,sha256=RRkl0Vake-JsHRO2NhaW2M3itoAWIp2MnZeQ2Uq4vs0,98
|
|
20
|
-
odoo/addons/delivery_ups_oca/tests/test_delivery_ups.py,sha256=
|
|
20
|
+
odoo/addons/delivery_ups_oca/tests/test_delivery_ups.py,sha256=oJgMpQfZfBi1p9mO3VlQ-XeUu1NS1BPapI-BIioHyEA,33197
|
|
21
21
|
odoo/addons/delivery_ups_oca/views/delivery_carrier_view.xml,sha256=YIG7BbpZFr7Jc3uAz3lYu-U37n_EYWGmBdz1NxHF1sI,3734
|
|
22
22
|
odoo/addons/delivery_ups_oca/views/stock_picking_view.xml,sha256=OeasGlIKNxTUNLAzNXXM7TPSeUdCm5Sxt2ZQrzmxy90,851
|
|
23
|
-
odoo_addon_delivery_ups_oca-
|
|
24
|
-
odoo_addon_delivery_ups_oca-
|
|
25
|
-
odoo_addon_delivery_ups_oca-
|
|
26
|
-
odoo_addon_delivery_ups_oca-
|
|
23
|
+
odoo_addon_delivery_ups_oca-18.0.1.0.0.2.dist-info/METADATA,sha256=G7JRbM7s-ekDqdzQUFPrcEkZ5ucogGfpqfrEh0TTbEk,6079
|
|
24
|
+
odoo_addon_delivery_ups_oca-18.0.1.0.0.2.dist-info/WHEEL,sha256=ZhOvUsYhy81Dx67gN3TV0RchQWBIIzutDZaJODDg2Vo,81
|
|
25
|
+
odoo_addon_delivery_ups_oca-18.0.1.0.0.2.dist-info/top_level.txt,sha256=QE6RBQ0QX5f4eFuUcGgU5Kbq1A_qJcDs-e_vpr6pmfU,4
|
|
26
|
+
odoo_addon_delivery_ups_oca-18.0.1.0.0.2.dist-info/RECORD,,
|
|
File without changes
|