diff --git a/delivery_carrier_label_paazl/README.rst b/delivery_carrier_label_paazl/README.rst index 73bb78ff6e..a19c9ce9f3 100644 --- a/delivery_carrier_label_paazl/README.rst +++ b/delivery_carrier_label_paazl/README.rst @@ -23,7 +23,7 @@ Carrier labels for paazl :target: https://runbot.odoo-community.org/runbot/99/12.0 :alt: Try me on Runbot -|badge1| |badge2| |badge3| |badge4| |badge5| +|badge1| |badge2| |badge3| |badge4| |badge5| This module adds `paazl `_ to the available carriers. @@ -38,6 +38,7 @@ Configuration To configure this module, you need to: #. Add options to your paazl carrier +#. Select wanted paazl label format (PDF or ZPL) on delivery carrier options, if nothing is set default label format will be PDF. #. Add a carrier account with delivery type ``paazl``, fill in your webshop id as account number, and the integration password as password. You find those values in Integrations/SOAP API on paazl's website #. If you want to receive status updates (including the carrier's tracking url), you need to enable the push API in your paazl account, and fill in ``https://$yourdomain/_paazl/push_api/v1`` as notification URL. You should enable client authentication and fill in the token generated there in the `Bearer token` field of the carrier account in Odoo @@ -50,6 +51,7 @@ To use this module, you need to: #. Set exactly one delivery option #. As a label needs to be generated for the tracking code, there's no need to manually generate labels via the button #. Note that the addon passes the package's dimensions if a packaging is set on the package, and on the product's dimensions otherwise +#. Depending on the label format settings attached to the carrier option, get .zpl or .pdf format labels. Bug Tracker =========== diff --git a/delivery_carrier_label_paazl/__manifest__.py b/delivery_carrier_label_paazl/__manifest__.py index 6fe4e03c50..797eb54075 100644 --- a/delivery_carrier_label_paazl/__manifest__.py +++ b/delivery_carrier_label_paazl/__manifest__.py @@ -15,6 +15,7 @@ "data/delivery_carrier.xml", "data/delivery_carrier_template_option.xml", "views/carrier_account.xml", + "views/delivery_carrier_option.xml", ], "demo": [], "external_dependencies": {"python": ["zeep"]}, diff --git a/delivery_carrier_label_paazl/models/__init__.py b/delivery_carrier_label_paazl/models/__init__.py index 281a0a6d9a..97d163c65e 100644 --- a/delivery_carrier_label_paazl/models/__init__.py +++ b/delivery_carrier_label_paazl/models/__init__.py @@ -3,3 +3,4 @@ from . import carrier_account from . import delivery_carrier from . import stock_picking +from . import delivery_carrier_option diff --git a/delivery_carrier_label_paazl/models/delivery_carrier_option.py b/delivery_carrier_label_paazl/models/delivery_carrier_option.py new file mode 100644 index 0000000000..b1cf33e0b5 --- /dev/null +++ b/delivery_carrier_label_paazl/models/delivery_carrier_option.py @@ -0,0 +1,12 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class DeliveryCarrierOption(models.Model): + _inherit = 'delivery.carrier.option' + + file_format = fields.Selection([("PDF", "PDF"), ("ZPL", "ZPL")]) + delivery_type = fields.Selection(related="carrier_id.delivery_type") + shipping_method_type = fields.Selection([('delivery', 'Delivery'), ('servicepoint', 'Service point')], + default="delivery") diff --git a/delivery_carrier_label_paazl/models/stock_picking.py b/delivery_carrier_label_paazl/models/stock_picking.py index e257de463f..3529b97216 100644 --- a/delivery_carrier_label_paazl/models/stock_picking.py +++ b/delivery_carrier_label_paazl/models/stock_picking.py @@ -73,6 +73,11 @@ def _paazl_generate_labels(self): # as we have the labels anyways, attach them account = self._get_carrier_account() file_type = (account.file_format or "").lower() or "pdf" + options_paazl_label_format = self.option_ids.filtered( + lambda x: x.file_format + ) + if options_paazl_label_format: + file_type = options_paazl_label_format[0].file_format.lower() label = { "name": self._paazl_reference(), "file": base64.b64encode(status.labels), @@ -201,15 +206,22 @@ def _paazl_commit_order_data(self): shipping_address["customerName"] = shipping_address.pop("addresseeLine") if self.partner_id.parent_id: shipping_address["companyName"] = self.partner_id.parent_id.name + if self.option_ids[:1].shipping_method_type == "servicepoint": + identifier = self._paazl_get_servicepoints().shippingOption[0]["servicePoint"][0]["code"] + servicepointNotificationEmail = self.partner_id.email + else: + identifier = 0 + servicepointNotificationEmail = False return dict( **self._paazl_auth_order_id(), pendingOrderReference=self._paazl_reference(), customerEmail=self.partner_id.email, customerPhoneNumber=self.partner_id.phone, shippingMethod=dict( - type="delivery", - identifier=0, + type=self.option_ids[:1].shipping_method_type, + identifier=identifier, option=self.option_ids[:1].code, + servicepointNotificationEmail=servicepointNotificationEmail, orderWeight=sum( product["quantity"] * product["weight"] for product in self._paazl_order_data()["products"]["product"] @@ -261,9 +273,15 @@ def _paazl_generate_labels_data(self): self.ensure_one() auth_order_id = self._paazl_auth_order_id() account = self._get_carrier_account() + file_format = account.file_format or "PDF" + options_paazl_label_format = self.option_ids.filtered( + lambda x: x.file_format + ) + if options_paazl_label_format: + file_format = options_paazl_label_format[0].file_format return { "webshop": auth_order_id.pop("webshop"), - "labelFormat": account.file_format or "PDF", + "labelFormat": file_format, "order": auth_order_id, "includeMetaData": True, } @@ -287,3 +305,19 @@ def _paazl_reference(self): """Return a reference for a picking to be used for paazl""" self.ensure_one() return self.name + + def _paazl_get_servicepoints(self): + """Return servicepoints response for the order's partner hardcoded to only return the nearest DHL servicepoint + """ + api = self._paazl_api() + account = self._get_carrier_account() + country = self.partner_id.country_id.code + postcode = self.partner_id.zip + hash_data = hashlib.sha1((account.account + account.password + country + postcode).encode()).hexdigest() + webshop = account.account + response = api.service.servicePoints( + hash=hash_data, webshop=webshop, country=country, postcode=postcode, + shippingOption="DHL_PARCEL_CONNECT_SHOP", + limit=1, + ) + return response diff --git a/delivery_carrier_label_paazl/tests/test_delivery_carrier_label_paazl.py b/delivery_carrier_label_paazl/tests/test_delivery_carrier_label_paazl.py index b7a0596027..491e3aff4d 100644 --- a/delivery_carrier_label_paazl/tests/test_delivery_carrier_label_paazl.py +++ b/delivery_carrier_label_paazl/tests/test_delivery_carrier_label_paazl.py @@ -56,6 +56,9 @@ def _setup_mock_client(self): mock_client.service.generateLabels.return_value = Mock( error=False, labels=b"hello world", metaData=[{"trackingNumber": "number"}], ) + mock_client.service.servicePoints.return_value = Mock( + error=False, shippingOption=[{"servicePoint": [{"code": "1234-NL-123456"}]}], + ) with patch.object(zeep, "Client") as mock_client_class: mock_client_class.return_value = mock_client yield mock_client @@ -114,6 +117,7 @@ def _request(self, path, method="POST", data=None, headers=None): class TestDeliveryCarrierLabelPaazl( DeliveryCarrierLabelPaazlCase, carrier_label_case.TestCarrierLabel): + def test_cancel_shipment(self): self.assertTrue(self.picking.carrier_tracking_ref) with self._setup_mock_client() as mock_client: @@ -176,6 +180,23 @@ def test_push_api(self): ) self.assertTrue(self.picking.message_ids - messages_before) + def test_label_type_format_from_paazl(self): + """ + Test if getting .zpl format label after using delivery option with zpl format + """ + picking = self.picking.copy() + picking.option_ids.file_format = "ZPL" + self.assertEqual(picking.option_ids.file_format, "ZPL") + picking.move_lines.quantity_done = 1 + with self._setup_mock_client(): + payload = picking._paazl_generate_labels() + + labels = payload["labels"][0] + self.assertTrue(labels) + self.assertTrue(labels["file"]) + self.assertEqual(labels["file_type"], "zpl") + self.assertEqual(labels["filename"].split('.')[1], "zpl") + def test_change_order(self): """Test change order in paazl""" self.assertTrue(self.picking.carrier_tracking_ref) @@ -186,6 +207,18 @@ def test_change_order(self): self.picking._paazl_send_update_order(change_order=True) self.assertTrue(self.picking.carrier_tracking_ref) + def test_servicepoint_order(self): + """Test committing an order with type servicepoint""" + picking = self.picking.copy() + picking.option_ids.shipping_method_type = "servicepoint" + picking.partner_id.country_id = self.env.ref("base.nl") + picking.partner_id.zip = "1092AD" + with self._setup_mock_client() as mock_client: + mock_client.service.servicePoints.return_value = Mock( + error=False, shippingOption=[{"servicePoint": [{"code": "1234-NL-123456"}]}], + ) + picking._paazl_send_update_order() + class TestDeliveryCarrierLabelPaazlPackaging(TestDeliveryCarrierLabelPaazl): def _picking_data(self): diff --git a/delivery_carrier_label_paazl/views/delivery_carrier_option.xml b/delivery_carrier_label_paazl/views/delivery_carrier_option.xml new file mode 100644 index 0000000000..6b68dbd8c1 --- /dev/null +++ b/delivery_carrier_label_paazl/views/delivery_carrier_option.xml @@ -0,0 +1,15 @@ + + + + delivery_base.delivery_carrier_option.view_form + delivery.carrier.option + + + + + + + + + +