diff --git a/delivery_postlogistics/README.rst b/delivery_postlogistics/README.rst new file mode 100644 index 0000000000..86d6acb63f --- /dev/null +++ b/delivery_postlogistics/README.rst @@ -0,0 +1,148 @@ +============================================== +PostLogistics Shipping - “Barcode” web service +============================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:1845040024de70121aac5dbff03ad3864a211c0a1e621452c12f1c71c4bd11ee + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fdelivery--carrier-lightgray.png?logo=github + :target: https://github.com/OCA/delivery-carrier/tree/17.0/delivery_postlogistics + :alt: OCA/delivery-carrier +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/delivery-carrier-17-0/delivery-carrier-17-0-delivery_postlogistics + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/delivery-carrier&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module uses `PostLogistics BarCodes +WebService `__ +to generate labels for your Delivery Orders. + +It adds a Create label button on Delivery Orders. A generated label will +be an attachement of your Delivery Order. + +To see it, please install documents module. + +You can create multiple delivery method to match your diffent package +types. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +.. important:: + + A "Swiss Post Business customer" account is required to use this + module. + + See `Log in `__ + +To configure: + +- Go to Inventory -> Configuration -> Delivery -> Shipping Methods +- Create new shipping methods for PostLogistics and set your login + informations in the "PostLogistics" tab +- Go to Inventory -> Configuration -> Delivery -> Delivery Packages to + create the PostLogistics delivery packaging with the relevant Package + Code (see section 8.10 of + https://developer.post.ch/en/digital-commerce-api for available + codes) + +Technical references +-------------------- + +`"Barcode" web service +documentation `__ + +Known issues / Roadmap +====================== + +- Integration of price webservice : + https://www.post.ch/en/customer-center/all-online-services/preise-berechnen/info +- Not sure if the recursive patch of suds is still needed as there's no + need to use the integration WS anymore. However we still want to + patch open to get meaningful error messages. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Camptocamp + +Contributors +------------ + +- Yannick Vaucher + +- Guewen Baconnier + +- Akim Juillerat + +- Julien Coux + +- Dung Tran + +- Phuc Tran + +- Jacques-Etienne Baudoux + +- `Trobz `__: + + - Jack Le + +- David Moreno + +Other credits +------------- + +The development of this module in version 14.0 and its migration from +14.0 to 16.0 has been financially supported by: + +- Camptocamp + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/delivery-carrier `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/delivery_postlogistics/__init__.py b/delivery_postlogistics/__init__.py new file mode 100644 index 0000000000..e4a5777ced --- /dev/null +++ b/delivery_postlogistics/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import postlogistics diff --git a/delivery_postlogistics/__manifest__.py b/delivery_postlogistics/__manifest__.py new file mode 100644 index 0000000000..d4c4d7cd48 --- /dev/null +++ b/delivery_postlogistics/__manifest__.py @@ -0,0 +1,29 @@ +# © 2013-2016 Yannick Vaucher (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +{ + "name": "PostLogistics Shipping - “Barcode” web service", + "summary": "Print PostLogistics shipping labels using the Barcode web service", + "version": "17.0.1.0.7", + "author": "Camptocamp,Odoo Community Association (OCA)", + "maintainer": "Camptocamp", + "license": "AGPL-3", + "category": "Delivery", + "complexity": "normal", + "depends": ["mail", "base", "stock_delivery"], + "website": "https://github.com/OCA/delivery-carrier", + "data": [ + "security/ir.model.access.csv", + "data/partner.xml", + "data/product.xml", + "data/delivery.xml", + "views/delivery.xml", + "views/stock_package_type_view.xml", + "views/stock_quant_package_view.xml", + "views/postlogistics_license.xml", + "views/res_partner_view.xml", + "views/stock.xml", + ], + "installable": True, + "auto_install": False, + "application": True, +} diff --git a/delivery_postlogistics/data/barcode handbuch.PDF b/delivery_postlogistics/data/barcode handbuch.PDF new file mode 100644 index 0000000000..0cb568b6aa Binary files /dev/null and b/delivery_postlogistics/data/barcode handbuch.PDF differ diff --git a/delivery_postlogistics/data/delivery.xml b/delivery_postlogistics/data/delivery.xml new file mode 100644 index 0000000000..a3534e06b3 --- /dev/null +++ b/delivery_postlogistics/data/delivery.xml @@ -0,0 +1,132 @@ + + + + + Format A7 + A7 + label_layout + + + + Format A6 + A6 + label_layout + + + + Format A5 + A5 + label_layout + + + + Format FE + FE + label_layout + + + + + EPS + EPS + output_format + + + + GIF + GIF + output_format + + + + JPG + JPG + output_format + + + + PNG + PNG + output_format + + + + PDF + PDF + output_format + + + + sPDF + sPDF + output_format + + + + ZPL2 + ZPL2 + output_format + + + + + 200 ppp + 200 + resolution + + + + 300 ppp + 300 + resolution + + + + 600 ppp + 600 + resolution + + + diff --git a/delivery_postlogistics/data/partner.xml b/delivery_postlogistics/data/partner.xml new file mode 100644 index 0000000000..cb042d0c16 --- /dev/null +++ b/delivery_postlogistics/data/partner.xml @@ -0,0 +1,14 @@ + + + + + PostLogistics + + webservice@post.ch + + diff --git a/delivery_postlogistics/data/product.xml b/delivery_postlogistics/data/product.xml new file mode 100644 index 0000000000..9db56284cd --- /dev/null +++ b/delivery_postlogistics/data/product.xml @@ -0,0 +1,17 @@ + + + + + + PostLogistics Delivery + service + + order + no + + diff --git a/delivery_postlogistics/i18n/delivery_postlogistics.pot b/delivery_postlogistics/i18n/delivery_postlogistics.pot new file mode 100644 index 0000000000..3151b11b50 --- /dev/null +++ b/delivery_postlogistics/i18n/delivery_postlogistics.pot @@ -0,0 +1,873 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * delivery_postlogistics +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_resolution_option_200ppp +msgid "200 ppp" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_resolution_option_300ppp +msgid "300 ppp" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_resolution_option_600ppp +msgid "600 ppp" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__access_token +msgid "Access Token" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__additional +msgid "Additional Service" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__description +msgid "Allow to define a more complete description than in the name field." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_delivery_carrier__postlogistics_tracking_format +msgid "" +"Allows you to define how the ItemNumber (the last 8 digits) of the tracking number will be generated:\n" +"- Default postlogistics numbers: The webservice generates it for you.\n" +"- Picking number with pack counter: Generate it using the digits of picking name and add the pack number. 2 digits forpack number and 6 digits for picking number. (eg. 07000042 for picking 42 and 7th pack" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__attachment_id +msgid "Attachement" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__local_url +msgid "Attachment URL" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "" +"Authorization Required\n" +"\n" +"Please verify postlogistics client id and secret in:\n" +"Delivery Carrier (PostLogistics)." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "" +"Authorization Required\n" +"\n" +"Please verify postlogistics client id and secret in:\n" +"Sale Orders > Configuration -> Sale Orders > Shipping Methods > PostLogistics" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__basic +msgid "Basic Service" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__partner_id +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_package_type__package_carrier_type +msgid "Carrier" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__checksum +msgid "Checksum/SHA1" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_client_id +msgid "Client ID" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_client_secret +msgid "Client Secret" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__code +msgid "Code" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__company_id +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__company_id +msgid "Company" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_logo +msgid "Company Logo on Post labels" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_res_partner +msgid "Contact" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__create_uid +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__create_uid +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__create_uid +msgid "Created by" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__create_date +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__create_date +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__create_date +msgid "Created on" +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "Credentials" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Customer name is required." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__db_datas +msgid "Database Data" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__delivery +msgid "Delivery Instructions" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_picking__delivery_place +msgid "Delivery Place" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_postlogistics_delivery_carrier_template_option +msgid "Delivery carrier template option" +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.view_picking_withcarrier_out_form +msgid "Delivery instructions" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__description +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__description +msgid "Description" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__res_partner__postlogistics_notification__disabled +msgid "Disabled" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__display_name +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__display_name +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__display_name +msgid "Display Name" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_office +msgid "Domicile Post office" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_eps +msgid "EPS" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__res_partner__postlogistics_notification__email +msgid "Email" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Email is required for notification." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_endpoint_url +msgid "Endpoint URL" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Error code: %(code)s, Message: %(message)s" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__datas +msgid "File Content (base64)" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__raw +msgid "File Content (raw)" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__file_size +msgid "File Size" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__file_type +msgid "File type" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_picking__delivery_fixed_date +msgid "Fixed delivery date" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_stock_picking__delivery_place +msgid "For Deposit item service (ZAW3219)" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_stock_picking__delivery_mobile +#: model:ir.model.fields,help:delivery_postlogistics.field_stock_picking__delivery_phone +msgid "For notify delivery by telephone (ZAW3213)" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_layout_option_a5 +msgid "Format A5" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_layout_option_a6 +msgid "Format A6" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_layout_option_a7 +msgid "Format A7" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_layout_option_fe +msgid "Format FE" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_license_id +msgid "Franking License" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_gif +msgid "GIF" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_postlogistics_license__sequence +msgid "" +"Gives the sequence on company to define priority on license when multiple " +"licenses are available for the same group of service." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__id +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__id +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__id +msgid "ID" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_stock_quant_package__postlogistics_manual_cod_amount +msgid "" +"If the cash on delivery amount for this package is different than the total " +"of the sales order, write the amount there." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__image_height +msgid "Image Height" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__image_src +msgid "Image Src" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__image_width +msgid "Image Width" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__index_content +msgid "Indexed Content" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__public +msgid "Is public document" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_jpg +msgid "JPG" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__label_layout +msgid "Label Layout" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_label_layout +msgid "Label layout" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option____last_update +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license____last_update +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label____last_update +msgid "Last Modified on" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__write_uid +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__write_uid +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__write_date +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__write_date +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__write_date +msgid "Last Updated on" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Layout not set" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__mimetype +msgid "Mime Type" +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "Misc." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "" +"Missing Configuration\n" +"\n" +"Please verify postlogistics endpoint url in:\n" +"Delivery Carrier (PostLogistics)." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_picking__delivery_mobile +msgid "Mobile" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__res_partner__postlogistics_notification__sms +msgid "Mobile SMS" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Mobile number is required for sms notification." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__name +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__name +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__name +msgid "Name" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "" +"No PostLogistics packaging services found in packaging {packaging_name}, for" +" picking {pickin_name}." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__number +msgid "Number" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_delivery_carrier__postlogistics_logo +msgid "" +"Optional company logo to show on label.\n" +"If using an image / logo, please note the following:\n" +"– Image width: 47 mm\n" +"– Image height: 25 mm\n" +"– File size: max. 30 kb\n" +"– File format: GIF or PNG\n" +"– Colour table: indexed colours, max. 200 colours\n" +"– The logo will be printed rotated counter-clockwise by 90°\n" +"We recommend using a black and white logo for printing in the ZPL2 format." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__original_id +msgid "Original (unoptimized, unresized) attachment" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__output_format +msgid "Output Format" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__resolution +msgid "Output Resolution" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_output_format +msgid "Output format" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Output format not set" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_pdf +msgid "PDF" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_png +msgid "PNG" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_stock_quant_package +msgid "Packages" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_quant_package__package_carrier_type +msgid "Packaging's Carrier" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_quant_package__parcel_tracking +msgid "Parcel Tracking" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__partner_option +msgid "Partner Option" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Partner city is required." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Partner name is required." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Partner street is required." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Partner zip is required." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_picking__delivery_phone +msgid "Phone" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__res_partner__postlogistics_notification__phone +msgid "Phone Call" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Phone number is required for phone call notification." +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "Post Label Logo" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_delivery_carrier__postlogistics_office +msgid "Post office which will receive the shipped goods" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__delivery_carrier__delivery_type__postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__stock_package_type__package_carrier_type__postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "PostLogistics" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_quant_package__postlogistics_manual_cod_amount +msgid "PostLogistics Cash On Delivery Amount" +msgstr "" + +#. module: delivery_postlogistics +#: model:product.template,name:delivery_postlogistics.product_postlogistics_service_product_template +msgid "PostLogistics Delivery" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_postlogistics_license +msgid "PostLogistics Franking License" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.actions.act_window,name:delivery_postlogistics.action_postlogistics_licenses +#: model:ir.ui.menu,name:delivery_postlogistics.menu_postlogistics_licenses +msgid "PostLogistics Licenses" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_dropoff_site__postlogistics_option_ids +#: model:ir.model.fields,field_description:delivery_postlogistics.field_res_partner__postlogistics_option_ids +#: model:ir.model.fields,field_description:delivery_postlogistics.field_res_users__postlogistics_option_ids +msgid "PostLogistics Options" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__postlogistics_type +msgid "PostLogistics option type" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_default_package_type_id +msgid "Postlogistics Default Package Type" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_dropoff_site__postlogistics_notification +#: model:ir.model.fields,field_description:delivery_postlogistics.field_res_partner__postlogistics_notification +#: model:ir.model.fields,field_description:delivery_postlogistics.field_res_users__postlogistics_notification +msgid "Postlogistics Notification" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_proclima_logo +msgid "Print ProClima logo" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__delivery_type +msgid "Provider" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_resolution +msgid "Resolution" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Resolution not set" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__res_field +msgid "Resource Field" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__res_id +msgid "Resource ID" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__res_model +msgid "Resource Model" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__res_name +msgid "Resource Name" +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.stock_package_type_form_delivery +msgid "See section 8.10 of" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__sequence +msgid "Sequence" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_postlogistics_shipping_label +msgid "Shipping Label for PostLogistics" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_delivery_carrier +msgid "Shipping Methods" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_stock_picking__delivery_fixed_date +msgid "Specific delivery date (ZAW3217)" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_stock_move +msgid "Stock Move" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_stock_package_type +msgid "Stock package type" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__store_fname +msgid "Stored Filename" +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "Template" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/models/stock_picking.py:0 +#: code:addons/delivery_postlogistics/models/stock_quant_package.py:0 +#, python-format +msgid "" +"The cash on delivery amount must be manually specified on the packages when " +"a package contains products from different sales orders." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/models/stock_picking.py:0 +#: code:addons/delivery_postlogistics/models/stock_quant_package.py:0 +#, python-format +msgid "" +"The cash on delivery amount must be manually specified on the packages when " +"a sales order is delivered in several delivery orders." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/models/delivery_carrier.py:0 +#, python-format +msgid "The credential is valid." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "The package %s must have a package type." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_delivery_carrier__postlogistics_proclima_logo +msgid "" +"The “pro clima” logo indicates an item for which the surcharge for carbon-" +"neutral shipping has been paid and a contract to that effect has been " +"signed. For Letters with barcode (BMB) domestic, the ProClima logo is " +"printed automatically (at no additional charge)" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/models/delivery_carrier.py:0 +#, python-format +msgid "This feature is under development" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_tracking_format +msgid "Tracking number format" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_stock_picking +msgid "Transfer" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__type +msgid "Type" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__url +msgid "Url" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__delivery_carrier__postlogistics_tracking_format__postlogistics +msgid "Use default postlogistics tracking numbers" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__delivery_carrier__postlogistics_tracking_format__picking_num +msgid "Use picking number with pack counter" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/models/delivery_carrier.py:0 +#, python-format +msgid "Validated" +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "Verify" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_postlogistics_shipping_label__type +msgid "" +"You can either upload a file from your computer or copy/paste an internet " +"link to your file." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "" +"You need to configure %s. You can set a default value in Inventory / " +"Configuration / Delivery / Shipping Methods. You can also set it on delivery" +" method or on the picking." +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "ZPL Patch" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__zpl_patch_string +msgid "ZPL Patch String" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_zpl2 +msgid "ZPL2" +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.stock_package_type_form_delivery +msgid "for available codes." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "label layout" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "output format" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "resolution" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_spdf +msgid "sPDF" +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.stock_package_type_form_delivery +msgid "the documentation" +msgstr "" diff --git a/delivery_postlogistics/i18n/es.po b/delivery_postlogistics/i18n/es.po new file mode 100644 index 0000000000..22a6858ffa --- /dev/null +++ b/delivery_postlogistics/i18n/es.po @@ -0,0 +1,939 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * delivery_postlogistics +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-10-09 14:36+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_resolution_option_200ppp +msgid "200 ppp" +msgstr "200 ppp" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_resolution_option_300ppp +msgid "300 ppp" +msgstr "300 ppp" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_resolution_option_600ppp +msgid "600 ppp" +msgstr "600 ppp" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__access_token +msgid "Access Token" +msgstr "Ficha de acceso" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__additional +msgid "Additional Service" +msgstr "Servicio adicional" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__description +msgid "Allow to define a more complete description than in the name field." +msgstr "" +"Permite definir un descripción más completa que en el campo del nombre." + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_delivery_carrier__postlogistics_tracking_format +msgid "" +"Allows you to define how the ItemNumber (the last 8 digits) of the tracking " +"number will be generated:\n" +"- Default postlogistics numbers: The webservice generates it for you.\n" +"- Picking number with pack counter: Generate it using the digits of picking " +"name and add the pack number. 2 digits forpack number and 6 digits for " +"picking number. (eg. 07000042 for picking 42 and 7th pack" +msgstr "" +"Permite definir cómo se generará el número de artículo (los últimos 8 " +"dígitos) del número de seguimiento:\n" +"- Números postlogísticos por defecto: El servicio web lo genera por usted.\n" +"- Número de recogida con contador de paquetes: Se genera utilizando los " +"dígitos del nombre de recogida y añadiendo el número de paquete. 2 dígitos " +"para el número de paquete y 6 dígitos para el número de recogida. (ej. " +"07000042 para recogida 42 y 7º paquete)" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__attachment_id +msgid "Attachement" +msgstr "Archivo adjunto" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__local_url +msgid "Attachment URL" +msgstr "URL del archivo adjunto" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "" +"Authorization Required\n" +"\n" +"Please verify postlogistics client id and secret in:\n" +"Delivery Carrier (PostLogistics)." +msgstr "" +"Autorización requerida\n" +"\n" +"Verifique la identificación y el secreto del cliente de postlogística en:\n" +"Transportista de entrega (PostLogistics)." + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "" +"Authorization Required\n" +"\n" +"Please verify postlogistics client id and secret in:\n" +"Sale Orders > Configuration -> Sale Orders > Shipping Methods > PostLogistics" +msgstr "" +"Autorización requerida\n" +"\n" +"Verifique la identificación y el secreto del cliente de postlogística en:\n" +"Órdenes de venta > Configuración -> Órdenes de venta > Métodos de envío > " +"PostLogistics" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__basic +msgid "Basic Service" +msgstr "Servicio básico" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__partner_id +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_package_type__package_carrier_type +msgid "Carrier" +msgstr "Transportista" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__checksum +msgid "Checksum/SHA1" +msgstr "Verificación de suma/SHA1" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_client_id +msgid "Client ID" +msgstr "ID del cliente" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_client_secret +msgid "Client Secret" +msgstr "Secreto del cliente" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__code +msgid "Code" +msgstr "Código" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__company_id +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__company_id +msgid "Company" +msgstr "Companía" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_logo +msgid "Company Logo on Post labels" +msgstr "Logotipo de la compañía en etiquetas de correos" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_res_partner +msgid "Contact" +msgstr "Contacto" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__create_uid +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__create_uid +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__create_date +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__create_date +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__create_date +msgid "Created on" +msgstr "Creado el" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "Credentials" +msgstr "Credenciales" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Customer name is required." +msgstr "El nombre del cliente es obligatorio." + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__db_datas +msgid "Database Data" +msgstr "Fecha de la base de datos" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__delivery +msgid "Delivery Instructions" +msgstr "Instrucciones de entrega" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_picking__delivery_place +msgid "Delivery Place" +msgstr "Lugar de entrega" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_postlogistics_delivery_carrier_template_option +msgid "Delivery carrier template option" +msgstr "Opción de plantilla de transportista de entrega" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.view_picking_withcarrier_out_form +msgid "Delivery instructions" +msgstr "Instrucciones de entrega" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__description +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__description +msgid "Description" +msgstr "Descripción" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__res_partner__postlogistics_notification__disabled +msgid "Disabled" +msgstr "Deshabilitado" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__display_name +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__display_name +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__display_name +msgid "Display Name" +msgstr "Nombre a Mostrar" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_office +msgid "Domicile Post office" +msgstr "Domicilio Oficina de Correos" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_eps +msgid "EPS" +msgstr "EPS" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__res_partner__postlogistics_notification__email +msgid "Email" +msgstr "Correo Electrónico" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Email is required for notification." +msgstr "Se requiere correo electrónico para la notificación." + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_endpoint_url +msgid "Endpoint URL" +msgstr "URL del punto final" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Error code: %(code)s, Message: %(message)s" +msgstr "Código de error: %(code)s, Mensaje: %(message)s" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__datas +msgid "File Content (base64)" +msgstr "Contenido del archivo (base64)" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__raw +msgid "File Content (raw)" +msgstr "Contenido del archivo (sin procesar)" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__file_size +msgid "File Size" +msgstr "Tamaño del archivo" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__file_type +msgid "File type" +msgstr "Tipo de archivo" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_picking__delivery_fixed_date +msgid "Fixed delivery date" +msgstr "Fecha de entrega fijada" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_stock_picking__delivery_place +msgid "For Deposit item service (ZAW3219)" +msgstr "Para el servicio de artículos de depósito (ZAW3219)" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_stock_picking__delivery_mobile +#: model:ir.model.fields,help:delivery_postlogistics.field_stock_picking__delivery_phone +msgid "For notify delivery by telephone (ZAW3213)" +msgstr "Para notificación de entrega por teléfono (ZAW3213)" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_layout_option_a5 +msgid "Format A5" +msgstr "Formato A5" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_layout_option_a6 +msgid "Format A6" +msgstr "Formato A6" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_layout_option_a7 +msgid "Format A7" +msgstr "Formato A7" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_layout_option_fe +msgid "Format FE" +msgstr "Formato FE" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_license_id +msgid "Franking License" +msgstr "Licencia de franquicia" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_gif +msgid "GIF" +msgstr "GIF" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_postlogistics_license__sequence +msgid "" +"Gives the sequence on company to define priority on license when multiple " +"licenses are available for the same group of service." +msgstr "" +"Da la secuencia en la empresa para definir la prioridad en la licencia " +"cuando varias licencias están disponibles para el mismo grupo de servicio." + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__id +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__id +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__id +msgid "ID" +msgstr "ID(identificación)" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_stock_quant_package__postlogistics_manual_cod_amount +msgid "" +"If the cash on delivery amount for this package is different than the total " +"of the sales order, write the amount there." +msgstr "" +"Si el importe del contra reembolso para este paquete es diferente del total " +"del pedido de cliente, escriba el importe allí." + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__image_height +msgid "Image Height" +msgstr "Altura de la imagen" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__image_src +msgid "Image Src" +msgstr "Origen de la imagen" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__image_width +msgid "Image Width" +msgstr "Anchura de la imagen" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__index_content +msgid "Indexed Content" +msgstr "Contenido indexado" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__public +msgid "Is public document" +msgstr "Es un documento público" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_jpg +msgid "JPG" +msgstr "JPG" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__label_layout +msgid "Label Layout" +msgstr "Diseño de etiqueta" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_label_layout +msgid "Label layout" +msgstr "Diseño de etiqueta" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option____last_update +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license____last_update +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label____last_update +msgid "Last Modified on" +msgstr "Modificado por última vez el" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__write_uid +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__write_uid +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__write_uid +msgid "Last Updated by" +msgstr "Actualizado por última vez por" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__write_date +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__write_date +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__write_date +msgid "Last Updated on" +msgstr "Actualizado por última vez el" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Layout not set" +msgstr "Diseño no establecido" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__mimetype +msgid "Mime Type" +msgstr "Tipo Mimo" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "Misc." +msgstr "Varios." + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "" +"Missing Configuration\n" +"\n" +"Please verify postlogistics endpoint url in:\n" +"Delivery Carrier (PostLogistics)." +msgstr "" +"Falta configuración\n" +"\n" +"Por favor verifique la url del punto final de postlogistics en:\n" +"Transportista de entrega (PostLogistics)." + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_picking__delivery_mobile +msgid "Mobile" +msgstr "Móvil" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__res_partner__postlogistics_notification__sms +msgid "Mobile SMS" +msgstr "SMS móvil" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Mobile number is required for sms notification." +msgstr "El número de móvil es necesario para la notificación por SMS." + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__name +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__name +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__name +msgid "Name" +msgstr "Nombre" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "" +"No PostLogistics packaging services found in packaging {packaging_name}, for " +"picking {pickin_name}." +msgstr "" +"No se han encontrado servicios de embalaje PostLogistics en embalaje " +"{packaging_name}, para recogida {pickin_name}." + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__number +msgid "Number" +msgstr "Número" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_delivery_carrier__postlogistics_logo +msgid "" +"Optional company logo to show on label.\n" +"If using an image / logo, please note the following:\n" +"– Image width: 47 mm\n" +"– Image height: 25 mm\n" +"– File size: max. 30 kb\n" +"– File format: GIF or PNG\n" +"– Colour table: indexed colours, max. 200 colours\n" +"– The logo will be printed rotated counter-clockwise by 90°\n" +"We recommend using a black and white logo for printing in the ZPL2 format." +msgstr "" +"Logotipo de la empresa opcional para mostrar en la etiqueta.\n" +"Si utiliza una imagen o un logotipo, tenga en cuenta lo siguiente:\n" +"– Ancho de la imagen: 47 mm\n" +"– Altura de la imagen: 25 mm\n" +"– Tamaño del archivo: máx. 30 KB\n" +"– Formato de archivo: GIF o PNG\n" +"– Tabla de colores: Colores indexados, máx. 200 colores\n" +"– El logotipo se imprimirá girado en sentido contrario a las agujas del " +"reloj 90°\n" +"Recomendamos utilizar un logotipo en blanco y negro para imprimir en formato " +"ZPL2." + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__original_id +msgid "Original (unoptimized, unresized) attachment" +msgstr "Archivo adjunto original (sin optimizar y sin redimensionar)" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__output_format +msgid "Output Format" +msgstr "Formato de Salida" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__resolution +msgid "Output Resolution" +msgstr "Resolución de salida" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_output_format +msgid "Output format" +msgstr "Formato de salida" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Output format not set" +msgstr "Formato de salida no establecido" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_pdf +msgid "PDF" +msgstr "PDF" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_png +msgid "PNG" +msgstr "PNG" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_stock_quant_package +msgid "Packages" +msgstr "Paquetes" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_quant_package__package_carrier_type +msgid "Packaging's Carrier" +msgstr "Transportista de paquetes" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_quant_package__parcel_tracking +msgid "Parcel Tracking" +msgstr "Seguimiento del envío" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__partner_option +msgid "Partner Option" +msgstr "Opción de Socio" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Partner city is required." +msgstr "Se requiere la ciudad del socio." + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Partner name is required." +msgstr "Se requiere el nombre del socio." + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Partner street is required." +msgstr "Se requiere la calle del socio." + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Partner zip is required." +msgstr "Se requiere el código postal del socio." + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_picking__delivery_phone +msgid "Phone" +msgstr "Teléfono" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__res_partner__postlogistics_notification__phone +msgid "Phone Call" +msgstr "Llamada telefónica" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Phone number is required for phone call notification." +msgstr "" +"Se requiere el número de teléfono para la notificación de llamadas " +"telefónicas." + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "Post Label Logo" +msgstr "Logotipo de la etiqueta postal" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_delivery_carrier__postlogistics_office +msgid "Post office which will receive the shipped goods" +msgstr "Oficina de correos que recibirá la mercancía enviada" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__delivery_carrier__delivery_type__postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__stock_package_type__package_carrier_type__postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "PostLogistics" +msgstr "PostLogísticas" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_quant_package__postlogistics_manual_cod_amount +msgid "PostLogistics Cash On Delivery Amount" +msgstr "Importe de pago contra reembolso de PostLogistics" + +#. module: delivery_postlogistics +#: model:product.template,name:delivery_postlogistics.product_postlogistics_service_product_template +msgid "PostLogistics Delivery" +msgstr "Entrega Postlogística" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_postlogistics_license +msgid "PostLogistics Franking License" +msgstr "Licencia de Franqueo Postlogístico" + +#. module: delivery_postlogistics +#: model:ir.actions.act_window,name:delivery_postlogistics.action_postlogistics_licenses +#: model:ir.ui.menu,name:delivery_postlogistics.menu_postlogistics_licenses +msgid "PostLogistics Licenses" +msgstr "Licencias de PostLogística" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_dropoff_site__postlogistics_option_ids +#: model:ir.model.fields,field_description:delivery_postlogistics.field_res_partner__postlogistics_option_ids +#: model:ir.model.fields,field_description:delivery_postlogistics.field_res_users__postlogistics_option_ids +msgid "PostLogistics Options" +msgstr "Opciones de Postlogística" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__postlogistics_type +msgid "PostLogistics option type" +msgstr "Tipo de Opción Postlogística" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_default_package_type_id +msgid "Postlogistics Default Package Type" +msgstr "Tipo de Paquete Predeterminado de Poslogística" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_dropoff_site__postlogistics_notification +#: model:ir.model.fields,field_description:delivery_postlogistics.field_res_partner__postlogistics_notification +#: model:ir.model.fields,field_description:delivery_postlogistics.field_res_users__postlogistics_notification +msgid "Postlogistics Notification" +msgstr "Notificación de Postlogística" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_proclima_logo +msgid "Print ProClima logo" +msgstr "Imprimir logotipo ProClima" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__delivery_type +msgid "Provider" +msgstr "Proveedor" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_resolution +msgid "Resolution" +msgstr "Resolución" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Resolution not set" +msgstr "Resolución no establecida" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__res_field +msgid "Resource Field" +msgstr "Campo de recurso" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__res_id +msgid "Resource ID" +msgstr "ID del Recurso" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__res_model +msgid "Resource Model" +msgstr "Modelo del Recurso" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__res_name +msgid "Resource Name" +msgstr "Nombre del recurso" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.stock_package_type_form_delivery +msgid "See section 8.10 of" +msgstr "Véase la sección 8.10 de" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__sequence +msgid "Sequence" +msgstr "Secuencia" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_postlogistics_shipping_label +msgid "Shipping Label for PostLogistics" +msgstr "Etiqueta de envío para PostLogística" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_delivery_carrier +msgid "Shipping Methods" +msgstr "Métodos de envío" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_stock_picking__delivery_fixed_date +msgid "Specific delivery date (ZAW3217)" +msgstr "Fecha de entrega específica (ZAW3217)" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_stock_move +msgid "Stock Move" +msgstr "Movimiento de existencias" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_stock_package_type +msgid "Stock package type" +msgstr "Tipo de empaquetado de existencias" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__store_fname +msgid "Stored Filename" +msgstr "Nombre del archivo almacenado" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "Template" +msgstr "Plantilla" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/models/stock_picking.py:0 +#: code:addons/delivery_postlogistics/models/stock_quant_package.py:0 +#, python-format +msgid "" +"The cash on delivery amount must be manually specified on the packages when " +"a package contains products from different sales orders." +msgstr "" +"El importe del contra reembolso debe especificarse manualmente en los " +"paquetes cuando un paquete contenga productos de diferentes pedidos de venta." + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/models/stock_picking.py:0 +#: code:addons/delivery_postlogistics/models/stock_quant_package.py:0 +#, python-format +msgid "" +"The cash on delivery amount must be manually specified on the packages when " +"a sales order is delivered in several delivery orders." +msgstr "" +"El importe del contra reembolso debe especificarse manualmente en los " +"paquetes cuando un pedido de cliente se entrega en varias órdenes de entrega." + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/models/delivery_carrier.py:0 +#, python-format +msgid "The credential is valid." +msgstr "La credencial es válida." + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "The package %s must have a package type." +msgstr "El paquete %s debe tener un tipo de paquete." + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_delivery_carrier__postlogistics_proclima_logo +msgid "" +"The “pro clima” logo indicates an item for which the surcharge for carbon-" +"neutral shipping has been paid and a contract to that effect has been " +"signed. For Letters with barcode (BMB) domestic, the ProClima logo is " +"printed automatically (at no additional charge)" +msgstr "" +"El logotipo \"pro clima\" indica un artículo por el que se ha pagado el " +"recargo por envío neutro en carbono y se ha firmado un contrato a tal " +"efecto. Para las Cartas con código de barras (BMB) nacionales, el logotipo " +"ProClima se imprime automáticamente (sin coste adicional)" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/models/delivery_carrier.py:0 +#, python-format +msgid "This feature is under development" +msgstr "Esta función está en desarrollo" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_tracking_format +msgid "Tracking number format" +msgstr "Formato del número de seguimiento" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_stock_picking +msgid "Transfer" +msgstr "Transferencia" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__type +msgid "Type" +msgstr "Tipo" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__url +msgid "Url" +msgstr "URL" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__delivery_carrier__postlogistics_tracking_format__postlogistics +msgid "Use default postlogistics tracking numbers" +msgstr "Utilizar los números de seguimiento predeterminados de Postlogistics" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__delivery_carrier__postlogistics_tracking_format__picking_num +msgid "Use picking number with pack counter" +msgstr "Utilizar número de recogida con contador de paquetes" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/models/delivery_carrier.py:0 +#, python-format +msgid "Validated" +msgstr "Validado" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "Verify" +msgstr "Verificar" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_postlogistics_shipping_label__type +msgid "" +"You can either upload a file from your computer or copy/paste an internet " +"link to your file." +msgstr "" +"Puede cargar un archivo desde su ordenador o copiar/pegar un enlace de " +"Internet a su archivo." + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "" +"You need to configure %s. You can set a default value in Inventory / " +"Configuration / Delivery / Shipping Methods. You can also set it on delivery " +"method or on the picking." +msgstr "" +"Necesita configurar %s. Puede establecer un valor por defecto en " +"Inventario / Configuración / Entrega / Métodos de envío. También puede " +"establecerlo en el método de entrega o en la recogida." + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "ZPL Patch" +msgstr "Parche ZPL" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__zpl_patch_string +msgid "ZPL Patch String" +msgstr "Cadena de parches ZPL" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_zpl2 +msgid "ZPL2" +msgstr "ZPL2" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.stock_package_type_form_delivery +msgid "for available codes." +msgstr "para los códigos disponibles." + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "label layout" +msgstr "Diseño de etiqueta" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "output format" +msgstr "formato de salida" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "resolution" +msgstr "resolución" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_spdf +msgid "sPDF" +msgstr "sPDF" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.stock_package_type_form_delivery +msgid "the documentation" +msgstr "la documentación" + +#, python-format +#~ msgid "" +#~ "No PostLogistics packaging services found in packaging {}, for picking {}." +#~ msgstr "" +#~ "No se encontraron servicios de embalaje de PostLogistics en el embalaje " +#~ "{}, para recoger {}." diff --git a/delivery_postlogistics/i18n/it.po b/delivery_postlogistics/i18n/it.po new file mode 100644 index 0000000000..886b135a73 --- /dev/null +++ b/delivery_postlogistics/i18n/it.po @@ -0,0 +1,877 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * delivery_postlogistics +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_resolution_option_200ppp +msgid "200 ppp" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_resolution_option_300ppp +msgid "300 ppp" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_resolution_option_600ppp +msgid "600 ppp" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__access_token +msgid "Access Token" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__additional +msgid "Additional Service" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__description +msgid "Allow to define a more complete description than in the name field." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_delivery_carrier__postlogistics_tracking_format +msgid "" +"Allows you to define how the ItemNumber (the last 8 digits) of the tracking " +"number will be generated:\n" +"- Default postlogistics numbers: The webservice generates it for you.\n" +"- Picking number with pack counter: Generate it using the digits of picking " +"name and add the pack number. 2 digits forpack number and 6 digits for " +"picking number. (eg. 07000042 for picking 42 and 7th pack" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__attachment_id +msgid "Attachement" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__local_url +msgid "Attachment URL" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "" +"Authorization Required\n" +"\n" +"Please verify postlogistics client id and secret in:\n" +"Delivery Carrier (PostLogistics)." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "" +"Authorization Required\n" +"\n" +"Please verify postlogistics client id and secret in:\n" +"Sale Orders > Configuration -> Sale Orders > Shipping Methods > PostLogistics" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__basic +msgid "Basic Service" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__partner_id +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_package_type__package_carrier_type +msgid "Carrier" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__checksum +msgid "Checksum/SHA1" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_client_id +msgid "Client ID" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_client_secret +msgid "Client Secret" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__code +msgid "Code" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__company_id +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__company_id +msgid "Company" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_logo +msgid "Company Logo on Post labels" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_res_partner +msgid "Contact" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__create_uid +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__create_uid +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__create_uid +msgid "Created by" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__create_date +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__create_date +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__create_date +msgid "Created on" +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "Credentials" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Customer name is required." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__db_datas +msgid "Database Data" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__delivery +msgid "Delivery Instructions" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_picking__delivery_place +msgid "Delivery Place" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_postlogistics_delivery_carrier_template_option +msgid "Delivery carrier template option" +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.view_picking_withcarrier_out_form +msgid "Delivery instructions" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__description +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__description +msgid "Description" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__res_partner__postlogistics_notification__disabled +msgid "Disabled" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__display_name +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__display_name +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__display_name +msgid "Display Name" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_office +msgid "Domicile Post office" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_eps +msgid "EPS" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__res_partner__postlogistics_notification__email +msgid "Email" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Email is required for notification." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_endpoint_url +msgid "Endpoint URL" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Error code: %(code)s, Message: %(message)s" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__datas +msgid "File Content (base64)" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__raw +msgid "File Content (raw)" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__file_size +msgid "File Size" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__file_type +msgid "File type" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_picking__delivery_fixed_date +msgid "Fixed delivery date" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_stock_picking__delivery_place +msgid "For Deposit item service (ZAW3219)" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_stock_picking__delivery_mobile +#: model:ir.model.fields,help:delivery_postlogistics.field_stock_picking__delivery_phone +msgid "For notify delivery by telephone (ZAW3213)" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_layout_option_a5 +msgid "Format A5" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_layout_option_a6 +msgid "Format A6" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_layout_option_a7 +msgid "Format A7" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_layout_option_fe +msgid "Format FE" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_license_id +msgid "Franking License" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_gif +msgid "GIF" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_postlogistics_license__sequence +msgid "" +"Gives the sequence on company to define priority on license when multiple " +"licenses are available for the same group of service." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__id +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__id +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__id +msgid "ID" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_stock_quant_package__postlogistics_manual_cod_amount +msgid "" +"If the cash on delivery amount for this package is different than the total " +"of the sales order, write the amount there." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__image_height +msgid "Image Height" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__image_src +msgid "Image Src" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__image_width +msgid "Image Width" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__index_content +msgid "Indexed Content" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__public +msgid "Is public document" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_jpg +msgid "JPG" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__label_layout +msgid "Label Layout" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_label_layout +msgid "Label layout" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option____last_update +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license____last_update +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label____last_update +msgid "Last Modified on" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__write_uid +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__write_uid +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__write_date +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__write_date +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__write_date +msgid "Last Updated on" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Layout not set" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__mimetype +msgid "Mime Type" +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "Misc." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "" +"Missing Configuration\n" +"\n" +"Please verify postlogistics endpoint url in:\n" +"Delivery Carrier (PostLogistics)." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_picking__delivery_mobile +msgid "Mobile" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__res_partner__postlogistics_notification__sms +msgid "Mobile SMS" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Mobile number is required for sms notification." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__name +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__name +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__name +msgid "Name" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "" +"No PostLogistics packaging services found in packaging {packaging_name}, for " +"picking {pickin_name}." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__number +msgid "Number" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_delivery_carrier__postlogistics_logo +msgid "" +"Optional company logo to show on label.\n" +"If using an image / logo, please note the following:\n" +"– Image width: 47 mm\n" +"– Image height: 25 mm\n" +"– File size: max. 30 kb\n" +"– File format: GIF or PNG\n" +"– Colour table: indexed colours, max. 200 colours\n" +"– The logo will be printed rotated counter-clockwise by 90°\n" +"We recommend using a black and white logo for printing in the ZPL2 format." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__original_id +msgid "Original (unoptimized, unresized) attachment" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__output_format +msgid "Output Format" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__resolution +msgid "Output Resolution" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_output_format +msgid "Output format" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Output format not set" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_pdf +msgid "PDF" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_png +msgid "PNG" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_stock_quant_package +msgid "Packages" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_quant_package__package_carrier_type +msgid "Packaging's Carrier" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_quant_package__parcel_tracking +msgid "Parcel Tracking" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__postlogistics_delivery_carrier_template_option__postlogistics_type__partner_option +msgid "Partner Option" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Partner city is required." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Partner name is required." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Partner street is required." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Partner zip is required." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_picking__delivery_phone +msgid "Phone" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__res_partner__postlogistics_notification__phone +msgid "Phone Call" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Phone number is required for phone call notification." +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "Post Label Logo" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_delivery_carrier__postlogistics_office +msgid "Post office which will receive the shipped goods" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__delivery_carrier__delivery_type__postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__stock_package_type__package_carrier_type__postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "PostLogistics" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_stock_quant_package__postlogistics_manual_cod_amount +msgid "PostLogistics Cash On Delivery Amount" +msgstr "" + +#. module: delivery_postlogistics +#: model:product.template,name:delivery_postlogistics.product_postlogistics_service_product_template +msgid "PostLogistics Delivery" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_postlogistics_license +msgid "PostLogistics Franking License" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.actions.act_window,name:delivery_postlogistics.action_postlogistics_licenses +#: model:ir.ui.menu,name:delivery_postlogistics.menu_postlogistics_licenses +msgid "PostLogistics Licenses" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_dropoff_site__postlogistics_option_ids +#: model:ir.model.fields,field_description:delivery_postlogistics.field_res_partner__postlogistics_option_ids +#: model:ir.model.fields,field_description:delivery_postlogistics.field_res_users__postlogistics_option_ids +msgid "PostLogistics Options" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_delivery_carrier_template_option__postlogistics_type +msgid "PostLogistics option type" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_default_package_type_id +msgid "Postlogistics Default Package Type" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_dropoff_site__postlogistics_notification +#: model:ir.model.fields,field_description:delivery_postlogistics.field_res_partner__postlogistics_notification +#: model:ir.model.fields,field_description:delivery_postlogistics.field_res_users__postlogistics_notification +msgid "Postlogistics Notification" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_proclima_logo +msgid "Print ProClima logo" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__delivery_type +msgid "Provider" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_resolution +msgid "Resolution" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "Resolution not set" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__res_field +msgid "Resource Field" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__res_id +msgid "Resource ID" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__res_model +msgid "Resource Model" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__res_name +msgid "Resource Name" +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.stock_package_type_form_delivery +msgid "See section 8.10 of" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_license__sequence +msgid "Sequence" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_postlogistics_shipping_label +msgid "Shipping Label for PostLogistics" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_delivery_carrier +msgid "Shipping Methods" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_stock_picking__delivery_fixed_date +msgid "Specific delivery date (ZAW3217)" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_stock_move +msgid "Stock Move" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_stock_package_type +msgid "Stock package type" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__store_fname +msgid "Stored Filename" +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "Template" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/models/stock_picking.py:0 +#: code:addons/delivery_postlogistics/models/stock_quant_package.py:0 +#, python-format +msgid "" +"The cash on delivery amount must be manually specified on the packages when " +"a package contains products from different sales orders." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/models/stock_picking.py:0 +#: code:addons/delivery_postlogistics/models/stock_quant_package.py:0 +#, python-format +msgid "" +"The cash on delivery amount must be manually specified on the packages when " +"a sales order is delivered in several delivery orders." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/models/delivery_carrier.py:0 +#, python-format +msgid "The credential is valid." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "The package %s must have a package type." +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_delivery_carrier__postlogistics_proclima_logo +msgid "" +"The “pro clima” logo indicates an item for which the surcharge for carbon-" +"neutral shipping has been paid and a contract to that effect has been " +"signed. For Letters with barcode (BMB) domestic, the ProClima logo is " +"printed automatically (at no additional charge)" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/models/delivery_carrier.py:0 +#, python-format +msgid "This feature is under development" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__postlogistics_tracking_format +msgid "Tracking number format" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model,name:delivery_postlogistics.model_stock_picking +msgid "Transfer" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__type +msgid "Type" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_postlogistics_shipping_label__url +msgid "Url" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__delivery_carrier__postlogistics_tracking_format__postlogistics +msgid "Use default postlogistics tracking numbers" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields.selection,name:delivery_postlogistics.selection__delivery_carrier__postlogistics_tracking_format__picking_num +msgid "Use picking number with pack counter" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/models/delivery_carrier.py:0 +#, python-format +msgid "Validated" +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "Verify" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,help:delivery_postlogistics.field_postlogistics_shipping_label__type +msgid "" +"You can either upload a file from your computer or copy/paste an internet " +"link to your file." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "" +"You need to configure %s. You can set a default value in Inventory / " +"Configuration / Delivery / Shipping Methods. You can also set it on delivery " +"method or on the picking." +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.delivery_carrier_postlogistics_inherit_view +msgid "ZPL Patch" +msgstr "" + +#. module: delivery_postlogistics +#: model:ir.model.fields,field_description:delivery_postlogistics.field_delivery_carrier__zpl_patch_string +msgid "ZPL Patch String" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_zpl2 +msgid "ZPL2" +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.stock_package_type_form_delivery +msgid "for available codes." +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "label layout" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "output format" +msgstr "" + +#. module: delivery_postlogistics +#. odoo-python +#: code:addons/delivery_postlogistics/postlogistics/web_service.py:0 +#, python-format +msgid "resolution" +msgstr "" + +#. module: delivery_postlogistics +#: model:postlogistics.delivery.carrier.template.option,name:delivery_postlogistics.postlogistics_output_format_option_spdf +msgid "sPDF" +msgstr "" + +#. module: delivery_postlogistics +#: model_terms:ir.ui.view,arch_db:delivery_postlogistics.stock_package_type_form_delivery +msgid "the documentation" +msgstr "" diff --git a/delivery_postlogistics/models/__init__.py b/delivery_postlogistics/models/__init__.py new file mode 100644 index 0000000000..7e13a746af --- /dev/null +++ b/delivery_postlogistics/models/__init__.py @@ -0,0 +1,9 @@ +from . import postlogistics_carrier_template_options +from . import delivery_carrier +from . import stock_package_type +from . import postlogistics_license +from . import postlogistics_shipping_label +from . import stock_picking +from . import stock_quant_package +from . import stock_move +from . import res_partner diff --git a/delivery_postlogistics/models/delivery_carrier.py b/delivery_postlogistics/models/delivery_carrier.py new file mode 100644 index 0000000000..d29f7009ef --- /dev/null +++ b/delivery_postlogistics/models/delivery_carrier.py @@ -0,0 +1,169 @@ +# Copyright 2013-2016 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + +from ..postlogistics.web_service import PostlogisticsWebService + + +class DeliveryCarrier(models.Model): + """Add service group""" + + _inherit = "delivery.carrier" + + delivery_type = fields.Selection( + selection_add=[("postlogistics", "PostLogistics")], + ondelete={"postlogistics": "set default"}, + ) + postlogistics_default_package_type_id = fields.Many2one( + "stock.package.type", domain=[("package_carrier_type", "=", "postlogistics")] + ) + postlogistics_token_url = fields.Char( + string="Endpoint Token", + default="https://api-int.post.ch", + required=True, + ) + postlogistics_endpoint_url = fields.Char( + string="Endpoint URL", + default="https://dcapi.apis-int.post.ch", + required=True, + ) + postlogistics_client_id = fields.Char( + string="Client ID", groups="base.group_system" + ) + postlogistics_client_secret = fields.Char( + string="Client Secret", groups="base.group_system" + ) + postlogistics_scope = fields.Char( + string="Scope", + default="DCAPI_BARCODE_READ", + groups="base.group_system", + ) + postlogistics_logo = fields.Binary( + string="Company Logo on Post labels", + help="Optional company logo to show on label.\n" + "If using an image / logo, please note the following:\n" + "– Image width: 47 mm\n" + "– Image height: 25 mm\n" + "– File size: max. 30 kb\n" + "– File format: GIF or PNG\n" + "– Colour table: indexed colours, max. 200 colours\n" + "– The logo will be printed rotated counter-clockwise by 90°" + "\n" + "We recommend using a black and white logo for printing in " + " the ZPL2 format.", + ) + postlogistics_office = fields.Char( + string="Domicile Post office", + help="Post office which will receive the shipped goods", + ) + + postlogistics_label_layout = fields.Many2one( + comodel_name="postlogistics.delivery.carrier.template.option", + string="Label layout", + domain=[("postlogistics_type", "=", "label_layout")], + ) + postlogistics_output_format = fields.Many2one( + comodel_name="postlogistics.delivery.carrier.template.option", + string="Output format", + domain=[("postlogistics_type", "=", "output_format")], + ) + postlogistics_resolution = fields.Many2one( + comodel_name="postlogistics.delivery.carrier.template.option", + string="Resolution", + domain=[("postlogistics_type", "=", "resolution")], + ) + postlogistics_tracking_format = fields.Selection( + [ + ("postlogistics", "Use default postlogistics tracking numbers"), + ("picking_num", "Use picking number with pack counter"), + ], + string="Tracking number format", + default="postlogistics", + help="Allows you to define how the ItemNumber (the last 8 digits) " + "of the tracking number will be generated:\n" + "- Default postlogistics numbers: The webservice generates it" + " for you.\n" + "- Picking number with pack counter: Generate it using the " + "digits of picking name and add the pack number. 2 digits for" + "pack number and 6 digits for picking number. (eg. 07000042 " + "for picking 42 and 7th pack", + ) + postlogistics_proclima_logo = fields.Boolean( + "Print ProClima logo", + help="The “pro clima” logo indicates an item for which the " + "surcharge for carbon-neutral shipping has been paid and a " + "contract to that effect has been signed. For Letters with " + "barcode (BMB) domestic, the ProClima logo is printed " + "automatically (at no additional charge)", + ) + + postlogistics_license_id = fields.Many2one( + comodel_name="postlogistics.license", + string="Franking License", + ) + zpl_patch_string = fields.Char( + string="ZPL Patch String", default="^XA^CW0,E:TT0003M_.TTF^XZ^XA^CI28" + ) + + @api.onchange("prod_environment") + def onchange_prod_environment(self): + """ + Auto change the end point url following the environment + - Test: https://api-int.post.ch/ and https://dcapi.apis.post.ch/ + - Prod: https://api.post.ch/ and https://dcapi.apis-int.post.ch/ + """ + for carrier in self: + if carrier.prod_environment: + carrier.postlogistics_token_url = "https://api.post.ch/" + carrier.postlogistics_endpoint_url = "https://dcapi.apis.post.ch/" + else: + carrier.postlogistics_token_url = "https://api-int.post.ch/" + carrier.postlogistics_endpoint_url = "https://dcapi.apis-int.post.ch/" + + def postlogistics_get_tracking_link(self, picking): + return ( + "https://service.post.ch/EasyTrack/" + "submitParcelData.do?formattedParcelCodes=%s" % picking.carrier_tracking_ref + ) + + def postlogistics_cancel_shipment(self, pickings): + raise UserError(_("This feature is under development")) + + def postlogistics_rate_shipment(self, order): + self.ensure_one() + delivery_product_price = self.product_id and self.product_id.lst_price or 0 + return { + "success": True, + "price": delivery_product_price, + "error_message": False, + "warning_message": False, + } + + def postlogistics_send_shipping(self, pickings): + """ + It will generate the labels for all the packages of the picking. + Packages are mandatory in this case + """ + for pick in pickings: + pick._set_a_default_package() + pick._generate_postlogistics_label() + + return [{"exact_price": False, "tracking_number": False}] + + def verify_credentials(self): + access_token = PostlogisticsWebService.get_access_token(self) + if not access_token: + # Error has already been risen + return + message = { + "type": "ir.actions.client", + "tag": "display_notification", + "params": { + "title": _("Validated"), + "message": _("The credential is valid."), + "sticky": False, + }, + } + return message diff --git a/delivery_postlogistics/models/postlogistics_carrier_template_options.py b/delivery_postlogistics/models/postlogistics_carrier_template_options.py new file mode 100644 index 0000000000..39c8973d9d --- /dev/null +++ b/delivery_postlogistics/models/postlogistics_carrier_template_options.py @@ -0,0 +1,32 @@ +# Copyright 2013-2016 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + +POSTLOGISTICS_TYPES = [ + ("label_layout", "Label Layout"), + ("output_format", "Output Format"), + ("resolution", "Output Resolution"), + ("basic", "Basic Service"), + ("additional", "Additional Service"), + ("delivery", "Delivery Instructions"), + ("partner_option", "Partner Option"), +] + + +class DeliveryCarrierTemplateOption(models.Model): + """Available options for a carrier (partner)""" + + _name = "postlogistics.delivery.carrier.template.option" + _description = "Delivery carrier template option" + + partner_id = fields.Many2one(comodel_name="res.partner", string="Carrier") + name = fields.Char(translate=True) + code = fields.Char() + description = fields.Char( + help="Allow to define a more complete description than in the name field.", + ) + postlogistics_type = fields.Selection( + selection=POSTLOGISTICS_TYPES, + string="PostLogistics option type", + ) diff --git a/delivery_postlogistics/models/postlogistics_license.py b/delivery_postlogistics/models/postlogistics_license.py new file mode 100644 index 0000000000..b0d893d069 --- /dev/null +++ b/delivery_postlogistics/models/postlogistics_license.py @@ -0,0 +1,28 @@ +# Copyright 2013-2016 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +import logging + +from odoo import fields, models + +_logger = logging.getLogger(__name__) + + +class PostlogisticsLicense(models.Model): + _name = "postlogistics.license" + _description = "PostLogistics Franking License" + + _order = "sequence" + + name = fields.Char(translate=True, required=True) + number = fields.Char(required=True) + company_id = fields.Many2one( + comodel_name="res.company", + string="Company", + required=True, + default=lambda self: self.env.user.company_id, + ) + sequence = fields.Integer( + help="Gives the sequence on company to define priority on license " + "when multiple licenses are available for the same group of " + "service.", + ) diff --git a/delivery_postlogistics/models/postlogistics_shipping_label.py b/delivery_postlogistics/models/postlogistics_shipping_label.py new file mode 100644 index 0000000000..d4afeb99b5 --- /dev/null +++ b/delivery_postlogistics/models/postlogistics_shipping_label.py @@ -0,0 +1,20 @@ +# Copyright 2013-2016 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class PostlogisticsShippingLabel(models.Model): + """Child class of ir attachment to identify which are labels""" + + _name = "postlogistics.shipping.label" + _inherits = {"ir.attachment": "attachment_id"} + _description = "Shipping Label for PostLogistics" + + file_type = fields.Char(string="File type", default="pdf") + attachment_id = fields.Many2one( + comodel_name="ir.attachment", + string="Attachement", + required=True, + ondelete="cascade", + ) diff --git a/delivery_postlogistics/models/res_partner.py b/delivery_postlogistics/models/res_partner.py new file mode 100644 index 0000000000..698aadb605 --- /dev/null +++ b/delivery_postlogistics/models/res_partner.py @@ -0,0 +1,26 @@ +# Copyright 2013-2016 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + postlogistics_option_ids = fields.Many2many( + "postlogistics.delivery.carrier.template.option", + relation="postlogistics_options_partner_rel", + column1="partner_id", + column2="option_id", + string="PostLogistics Options", + ) + + postlogistics_notification = fields.Selection( + [ + ("disabled", "Disabled"), + ("email", "Email"), + ("sms", "Mobile SMS"), + ("phone", "Phone Call"), + ], + default="disabled", + ) diff --git a/delivery_postlogistics/models/stock_move.py b/delivery_postlogistics/models/stock_move.py new file mode 100644 index 0000000000..96b0c429af --- /dev/null +++ b/delivery_postlogistics/models/stock_move.py @@ -0,0 +1,22 @@ +# Copyright 2013-2016 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class StockMove(models.Model): + _inherit = "stock.move" + + def _get_new_picking_values(self): + vals = super()._get_new_picking_values() + + order_commitment_date = ( + self.sale_line_id and self.sale_line_id.order_id.commitment_date + ) + + if order_commitment_date: + user_time = fields.Datetime.context_timestamp( + self, order_commitment_date + ).date() + vals["delivery_fixed_date"] = user_time + return vals diff --git a/delivery_postlogistics/models/stock_package_type.py b/delivery_postlogistics/models/stock_package_type.py new file mode 100644 index 0000000000..5339e39257 --- /dev/null +++ b/delivery_postlogistics/models/stock_package_type.py @@ -0,0 +1,21 @@ +# Copyright 2013-2016 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class PackageType(models.Model): + _inherit = "stock.package.type" + + package_carrier_type = fields.Selection( + selection_add=[("postlogistics", "PostLogistics")] + ) + + def _get_packaging_codes(self): + """ + Return the list of packaging codes + """ + self.ensure_one() + if self.shipper_package_code: + return [code.strip() for code in self.shipper_package_code.split(",")] + return [] diff --git a/delivery_postlogistics/models/stock_picking.py b/delivery_postlogistics/models/stock_picking.py new file mode 100644 index 0000000000..f971a6d0c3 --- /dev/null +++ b/delivery_postlogistics/models/stock_picking.py @@ -0,0 +1,238 @@ +# Copyright 2013-2016 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +import base64 +from operator import attrgetter + +from odoo import _, exceptions, fields, models + +from ..postlogistics.web_service import PostlogisticsWebService + + +class StockPicking(models.Model): + _inherit = "stock.picking" + + delivery_fixed_date = fields.Date( + "Fixed delivery date", help="Specific delivery date (ZAW3217)" + ) + + # TODO: consider refactoring these fields using a partner relation instead + delivery_place = fields.Char(help="For Deposit item service (ZAW3219)") + delivery_phone = fields.Char( + "Phone", help="For notify delivery by telephone (ZAW3213)" + ) + delivery_mobile = fields.Char( + "Mobile", help="For notify delivery by telephone (ZAW3213)" + ) + + def _get_packages_from_picking(self): + """Get all the packages from the picking""" + self.ensure_one() + operation_obj = self.env["stock.move.line"] + operations = operation_obj.search( + [ + "|", + ("package_id", "!=", False), + ("result_package_id", "!=", False), + ("picking_id", "=", self.id), + ] + ) + package_ids = set() + for operation in operations: + # Take the destination package. If empty, the package is + # moved so take the source one. + package_ids.add(operation.result_package_id.id or operation.package_id.id) + + packages = self.env["stock.quant.package"].browse(package_ids) + return packages + + def get_shipping_label_values(self, label): + # TODO: consider to depends on base_delivery_carrier_label + self.ensure_one() + return { + "name": label["name"], + "res_id": self.id, + "res_model": "stock.picking", + "datas": label["file"], + "file_type": label["file_type"], + } + + def attach_shipping_label(self, label): + """Attach a label returned by generate_shipping_labels to a picking""" + if self.delivery_type != "postlogistics": + return super().attach_shipping_label(label) + self.ensure_one() + data = self.get_shipping_label_values(label) + context_attachment = self.env.context.copy() + # remove default_type setted for stock_picking + # as it would try to define default value of attachement + if "default_type" in context_attachment: + del context_attachment["default_type"] + return ( + self.env["postlogistics.shipping.label"] + .with_context(**context_attachment) + .create(data) + ) + + def _set_a_default_package(self): + """Pickings using this module must have a package + If not this method put it one silently + """ + # TODO: consider to depends on base_delivery_carrier_label + for picking in self: + move_lines = picking.move_line_ids.filtered( + lambda s: not (s.package_id or s.result_package_id) + ) + if move_lines: + carrier = picking.carrier_id + default_packaging = carrier.postlogistics_default_package_type_id + package = self.env["stock.quant.package"].create( + { + "package_type_id": default_packaging + and default_packaging.id + or False + } + ) + move_lines.write({"result_package_id": package.id}) + + def postlogistics_cod_amount(self): + """Return the PostLogistics Cash on Delivery amount of a picking + + If the picking delivers the whole sales order, we use the total + amount of the sales order. + + Otherwise, we don't know the value of each picking so we raise + an error. The user has to create packages with the cash on + delivery price on each package. + """ + self.ensure_one() + order = self.sale_id + if not order: + return 0.0 + if len(order) > 1: + raise exceptions.UserError( + _( + "The cash on delivery amount must be manually specified " + "on the packages when a package contains products " + "from different sales orders." + ) + ) + # check if the package delivers the whole sales order + if len(order.picking_ids) > 1: + raise exceptions.UserError( + _( + "The cash on delivery amount must be manually specified " + "on the packages when a sales order is delivered " + "in several delivery orders." + ) + ) + return order.amount_total + + def info_from_label(self, label, zpl_patch_string=False): + tracking_number = label["tracking_number"] + data = base64.b64decode(label["binary"]) + + # Apply patch for zpl file + if label["file_type"] == "zpl2" and zpl_patch_string: + data = base64.b64encode( + base64.b64decode(data) + .decode("cp437") + .replace("^XA", zpl_patch_string) + .encode("utf-8") + ) + return { + "file": data, + "file_type": label["file_type"], + "name": tracking_number + "." + label["file_type"], + } + + def write_tracking_number_label(self, label_result, packages): + """ + If there are no pack defined, write tracking_number on picking + otherwise, write it on parcel_tracking field of each pack. + Note we can receive multiple labels for a same package + """ + zpl_patch_string = self.carrier_id.zpl_patch_string + + labels = [] + + # It could happen that no successful label has been returned by the API + if not label_result: + return labels + + if not packages: + label = label_result[0]["value"][0] + self.carrier_tracking_ref = label["tracking_number"] + labels.append(self.info_from_label(label, zpl_patch_string)) + + tracking_refs = [] + for package in packages: + tracking_numbers = [] + for label in label_result: + for label_value in label["value"]: + if package.name in label_value["item_id"].split("+")[-1]: + tracking_numbers.append(label_value["tracking_number"]) + labels.append( + self.info_from_label(label_value, zpl_patch_string) + ) + package.parcel_tracking = "; ".join(tracking_numbers) + tracking_refs += tracking_numbers + + existing_tracking_ref = ( + self.carrier_tracking_ref and self.carrier_tracking_ref.split("; ") or [] + ) + self.carrier_tracking_ref = "; ".join(existing_tracking_ref + tracking_refs) + return labels + + def _generate_postlogistics_label( + self, webservice_class=None, package_ids=None, skip_attach_file=False + ): + """Generate labels and write tracking numbers received""" + self.ensure_one() + user = self.env.user + company = user.company_id + if webservice_class is None: + webservice_class = PostlogisticsWebService + + if package_ids is None: + packages = self._get_packages_from_picking() + packages = packages.sorted(key=attrgetter("name")) + else: + # restrict on the provided packages + package_obj = self.env["stock.quant.package"] + packages = package_obj.browse(package_ids) + + web_service = webservice_class(company) + + # Do not generate label for packages that are already done + packages = packages.filtered(lambda p: not p.parcel_tracking) + + label_results = web_service.generate_label(self, packages) + + # Process the success packages first + success_label_results = [ + label for label in label_results if "errors" not in label + ] + failed_label_results = [label for label in label_results if "errors" in label] + + # Case when there is a failed label, rollback odoo data + if failed_label_results: + self._cr.rollback() + + labels = self.write_tracking_number_label(success_label_results, packages) + + if not skip_attach_file: + for label in labels: + self.attach_shipping_label(label) + + if failed_label_results: + # Commit the change to save the changes, + # This ensures the label pushed recored correctly in Odoo + self._cr.commit() # pylint: disable=invalid-commit + error_message = "\n".join(label["errors"] for label in failed_label_results) + raise exceptions.UserError(error_message) + return labels + + def generate_postlogistics_shipping_labels(self, package_ids=None): + """Add label generation for PostLogistics""" + self.ensure_one() + return self._generate_postlogistics_label(package_ids=package_ids) diff --git a/delivery_postlogistics/models/stock_quant_package.py b/delivery_postlogistics/models/stock_quant_package.py new file mode 100644 index 0000000000..0c8d32752e --- /dev/null +++ b/delivery_postlogistics/models/stock_quant_package.py @@ -0,0 +1,65 @@ +# Copyright 2013-2016 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import _, api, exceptions, fields, models + + +class StockQuantPackage(models.Model): + _inherit = "stock.quant.package" + + postlogistics_manual_cod_amount = fields.Float( + "PostLogistics Cash On Delivery Amount", + help="If the cash on delivery amount for this package is different " + "than the total of the sales order, write the amount there.", + ) + parcel_tracking = fields.Char() + package_carrier_type = fields.Selection( + related="package_type_id.package_carrier_type", + string="Packaging's Carrier", + ) + + @api.returns("stock.picking") + def _get_origin_pickings(self): + self.ensure_one() + move_line_model = self.env["stock.move.line"] + move_line = move_line_model.search([("package_id", "=", self.id)]) + return move_line.mapped("picking_id.sale_id.picking_ids") + + def postlogistics_cod_amount(self): + """Return the PostLogistics Cash on Delivery amount of a package + + If we have only 1 package which delivers the whole sales order + we use the total amount of the sales order. + + Otherwise we don't know the value of each package so we raise an + error and the user has to write the prices on the packages. + + When a price is manually set on a package, it's always used as the + cash on delivery amount. + """ + self.ensure_one() + if self.postlogistics_manual_cod_amount: + return self.postlogistics_manual_cod_amount + + pickings = self._get_origin_pickings() + if len(pickings) > 1: + raise exceptions.UserError( + _( + "The cash on delivery amount must be manually specified " + "on the packages when a sales order is delivered " + "in several delivery orders." + ) + ) + + order = pickings.sale_id + if not order: + return 0.0 + if len(order) > 1: + raise exceptions.UserError( + _( + "The cash on delivery amount must be manually specified " + "on the packages when a package contains products " + "from different sales orders." + ) + ) + + return order.amount_total diff --git a/delivery_postlogistics/postlogistics/__init__.py b/delivery_postlogistics/postlogistics/__init__.py new file mode 100644 index 0000000000..3007a4658a --- /dev/null +++ b/delivery_postlogistics/postlogistics/__init__.py @@ -0,0 +1 @@ +from . import web_service diff --git a/delivery_postlogistics/postlogistics/web_service.py b/delivery_postlogistics/postlogistics/web_service.py new file mode 100644 index 0000000000..92db147576 --- /dev/null +++ b/delivery_postlogistics/postlogistics/web_service.py @@ -0,0 +1,578 @@ +# Copyright 2013-2019 Yannick Vaucher (Camptocamp SA) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import base64 +import json +import logging +import re +import threading +import urllib.parse +from datetime import datetime, timedelta +from io import BytesIO + +import requests +from PIL import Image + +from odoo import _, exceptions + +_logger = logging.getLogger(__name__) + +_compile_itemid = re.compile(r"[^0-9A-Za-z+\-_]") +_compile_itemnum = re.compile(r"[^0-9]") +AUTH_PATH = "/OAuth/token" +GENERATE_LABEL_PATH = "/barcode/v1/generateAddressLabel" + +DISALLOWED_CHARS_MAPPING = { + "|": "", + "\\": "", + "<": "", + ">": "", + "\u2018": "'", + "\u2019": "'", +} + + +class PostlogisticsWebService: + + """Connector with PostLogistics for labels using post.ch API + + Handbook available here: + https://developer.post.ch/en/digital-commerce-api + https://developer.apis.post.ch/ui/apis/5cff6ab7-8325-4a05-bf6a-b783256a0552 + /pages/50fa2b65-2f67-4867-ba2b-652f6738676d + + Allows to generate labels + + """ + + access_token = False + access_token_expiry = False + _lock = threading.Lock() + + def __init__(self, company): + self.default_lang = company.partner_id.lang or "en" + + def _get_language(self, lang): + """Return a language to iso format from odoo format. + + `iso_code` field in res.lang is not mandatory thus not always set. + Use partner language if available, otherwise use english + + :param partner: partner browse record + :return: language code to use. + + """ + if not lang: + lang = self.default_lang + available_languages = ["de", "en", "fr", "it"] # Given by API doc + lang_code = lang.split("_")[0] + if lang_code in available_languages: + return lang_code + return "en" + + def _prepare_recipient(self, picking): + """Create a ns0:Recipient as a dict from a partner + + :param partner: partner browse record + :return a dict containing data for ns0:Recipient + + """ + partner = picking.partner_id + if picking.picking_type_id.code != "outgoing": + location_dest = picking.location_dest_id + partner = ( + location_dest.company_id.partner_id + or self.env.user.company_id.partner_id + ) + + partner_mobile = self._sanitize_string( + picking.delivery_mobile or partner.mobile + ) + partner_phone = self._sanitize_string(picking.delivery_phone or partner.phone) + + if partner.postlogistics_notification == "email" and not partner.email: + raise exceptions.UserError(_("Email is required for notification.")) + elif partner.postlogistics_notification == "sms" and not partner_mobile: + raise exceptions.UserError( + _("Mobile number is required for sms notification.") + ) + elif partner.postlogistics_notification == "phone" and not partner_phone: + raise exceptions.UserError( + _("Phone number is required for phone call notification.") + ) + + if not partner.street: + raise exceptions.UserError(_("Partner street is required.")) + + if not partner.name and not partner.parent_id.name: + raise exceptions.UserError(_("Partner name is required.")) + + if not partner.zip: + raise exceptions.UserError(_("Partner zip is required.")) + + if not partner.city: + raise exceptions.UserError(_("Partner city is required.")) + + partner_name = partner.name or partner.parent_id.name + sanitized_partner_name = self._sanitize_string(partner_name) + partner_street = self._sanitize_string(partner.street) + partner_zip = self._sanitize_string(partner.zip) + partner_city = self._sanitize_string(partner.city) + recipient = { + "name1": sanitized_partner_name[:25], + "street": partner_street[:35], + "zip": partner_zip[:10], + "city": partner_city[:35], + } + + if partner.country_id.code: + country_code = self._sanitize_string(partner.country_id.code.upper()) + recipient["country"] = country_code + + if partner.street2: + # addressSuffix is shown before street on label + recipient["addressSuffix"] = recipient["street"] + recipient["street"] = self._sanitize_string(partner.street2[:35]) + + company_partner_name = partner.commercial_company_name + if company_partner_name and company_partner_name != partner_name: + parent_name = self._sanitize_string(partner.parent_id.name) + recipient["name2"] = parent_name[:35] + recipient["personallyAddressed"] = False + + # Phone and / or mobile should only be displayed if instruction to + # Notify delivery by telephone is set + if partner.postlogistics_notification == "email": + recipient["email"] = self._sanitize_string(partner.email) + elif partner.postlogistics_notification == "phone": + recipient["phone"] = self._sanitize_string(partner_phone) + if partner_mobile: + recipient["mobile"] = partner_mobile + elif partner.postlogistics_notification == "sms": + recipient["mobile"] = partner_mobile + + return recipient + + def _prepare_customer(self, picking): + """Create a ns0:Customer as a dict from picking + + This is the PostLogistics Customer, thus the sender + + :param picking: picking browse record + :return a dict containing data for ns0:Customer + + """ + company = picking.company_id + partner = company.partner_id + if picking.picking_type_id.code != "outgoing": + partner = picking.partner_id + + partner_name = partner.name or partner.parent_id.name + if not partner_name: + raise exceptions.UserError(_("Customer name is required.")) + customer = { + "name1": self._sanitize_string(partner_name)[:25], + "street": self._sanitize_string(partner.street)[:35], + "zip": self._sanitize_string(partner.zip)[:10], + "city": self._sanitize_string(partner.city)[:35], + "country": partner.country_id.code, + "domicilePostOffice": picking.carrier_id.postlogistics_office or None, + } + logo = picking.carrier_id.postlogistics_logo + if logo: + logo_image = Image.open(BytesIO(base64.b64decode(logo))) + logo_format = logo_image.format + customer["logo"] = logo.decode() + customer["logoFormat"] = logo_format + return customer + + def _get_label_layout(self, picking): + """ + Get Label layout define in carrier + """ + return picking.carrier_id.postlogistics_label_layout.code + + def _get_output_format(self, picking): + """ + Get Output format define in carrier + """ + return picking.carrier_id.postlogistics_output_format.code + + def _get_image_resolution(self, picking): + """ + Get Output Resolution Code define in carrier + """ + return picking.carrier_id.postlogistics_resolution.code + + def _get_license(self, picking): + """Get the license + + Take it from carrier and if not defined get the first license. + + :return: license number + """ + franking_license = picking.carrier_id.postlogistics_license_id + return franking_license.number + + def _prepare_attributes( + self, picking, pack=None, pack_num=None, pack_total=None, pack_weight=None + ): + packaging = ( + pack + and pack.package_type_id + or picking.carrier_id.postlogistics_default_package_type_id + ) + services = packaging._get_packaging_codes() + + if pack_weight: + total_weight = pack_weight + else: + total_weight = pack.shipping_weight if pack else picking.shipping_weight + total_weight *= 1000 + + if not services: + raise exceptions.UserError( + _( + "No PostLogistics packaging services found " + "in packaging {packaging_name}, for picking {pickin_name}." + ).format(packaging_name=packaging.name, pickin_name=picking.name) + ) + + # Activate phone notification ZAW3213 + # if phone call notification is set on partner + if picking.partner_id.postlogistics_notification == "phone": + services.append("ZAW3213") + + attributes = { + "weight": int(total_weight), + } + + # Remove the services if the delivery fixed date is not set + if "ZAW3217" in services: + if picking.delivery_fixed_date: + attributes["deliveryDate"] = picking.delivery_fixed_date + else: + services.remove("ZAW3217") + + # parcelNo / parcelTotal cannot be used if service ZAW3218 is not activated + if "ZAW3218" in services: + if pack_total > 1: + attributes.update( + {"parcelTotal": pack_total - 1, "parcelNo": pack_num - 1} + ) + else: + services.remove("ZAW3218") + + if "ZAW3219" in services and picking.delivery_place: + attributes["deliveryPlace"] = picking.delivery_place + if picking.carrier_id.postlogistics_proclima_logo: + attributes["proClima"] = True + else: + attributes["proClima"] = False + + attributes["przl"] = services + + return attributes + + def _get_itemid(self, picking, pack_no): + """Allowed characters are alphanumeric plus `+`, `-` and `_` + Last `+` separates picking name and package number (if any) + + :return string: itemid + + """ + name = _compile_itemid.sub("", picking.name) + if not pack_no: + return name + + pack_no = _compile_itemid.sub("", pack_no) + codes = [name, pack_no] + return "+".join(c for c in codes if c) + + def _cash_on_delivery(self, picking, package=None): + amount = (package or picking).postlogistics_cod_amount() + amount = f"{amount:.2f}" + return [{"Type": "NN_BETRAG", "Value": amount}] + + def _get_item_additional_data(self, picking, package=None): + if package and not package.package_type_id: + raise exceptions.UserError( + _("The package %s must have a package type.") % package.name + ) + + result = [] + packaging_codes = ( + package and package.package_type_id._get_packaging_codes() or [] + ) + + if set(packaging_codes) & {"BLN", "N"}: + cod_attributes = self._cash_on_delivery(picking, package=package) + result += cod_attributes + return result + + def _get_item_number(self, picking, pack_num): + """Generate the tracking reference for the last 8 digits + of tracking number of the label. + + 2 first digits for a pack counter + 6 last digits for the picking name + + e.g. 03000042 for 3rd pack of picking OUT/19000042 + """ + picking_num = _compile_itemnum.sub("", picking.name) + return "%02d%s" % (pack_num, picking_num[-6:].zfill(6)) + + def _prepare_item_list(self, picking, recipient, packages): + """Return a list of item made from the pickings""" + carrier = picking.carrier_id + item_list = [] + pack_counter = 1 + + def add_item(package=None): + assert picking or package + itemid = self._get_itemid(picking, package.name if package else None) + item = { + "itemID": itemid, + "recipient": recipient, + "attributes": attributes, + } + if carrier.postlogistics_tracking_format == "picking_num": + if not package: + # start with 9 to ensure uniqueness and use 7 digits + # of picking number + picking_num = _compile_itemnum.sub("", picking.name) + item_number = "9%s" % picking_num[-7:].zfill(7) + else: + item_number = self._get_item_number(picking, pack_counter) + item["itemNumber"] = item_number + + additional_data = self._get_item_additional_data(picking, package=package) + if additional_data: + item["additionalData"] = additional_data + + item_list.append(item) + + if not packages: + attributes = self._prepare_attributes(picking) + add_item() + return item_list + + pack_total = len(packages) + for pack in packages: + attributes = self._prepare_attributes( + picking, pack, pack_counter, pack_total + ) + add_item(package=pack) + pack_counter += 1 + return item_list + + def _prepare_label_definition(self, picking): + error_missing = _( + "You need to configure %s. You can set a default" + " value in Inventory / Configuration / Delivery / Shipping Methods." + " You can also set it on delivery method or on the picking." + ) + label_layout = self._get_label_layout(picking) + if not label_layout: + raise exceptions.UserError( + _("Layout not set") + "\n" + error_missing % _("label layout") + ) + + output_format = self._get_output_format(picking) + if not output_format: + raise exceptions.UserError( + _("Output format not set") + "\n" + error_missing % _("output format") + ) + + image_resolution = self._get_image_resolution(picking) + if not image_resolution: + raise exceptions.UserError( + _("Resolution not set") + "\n" + error_missing % _("resolution") + ) + + return { + "labelLayout": label_layout, + "printAddresses": "RECIPIENT_AND_CUSTOMER", + "imageFileType": output_format, + "imageResolution": image_resolution, + "printPreview": False, + } + + def _prepare_data( + self, lang, frankingLicense, post_customer, labelDefinition, item + ): + return { + "language": lang.upper(), + "frankingLicense": frankingLicense, + "ppFranking": False, + "customer": post_customer, + "customerSystem": None, + "labelDefinition": labelDefinition, + "sendingID": None, + "item": item, + } + + @classmethod + def _request_access_token(cls, delivery_carrier): + if not delivery_carrier.postlogistics_token_url: + raise exceptions.UserError( + _( + "Missing Configuration\n\n" + "Please verify postlogistics endpoint url in:\n" + "Delivery Carrier (PostLogistics)." + ) + ) + + client_id = delivery_carrier.postlogistics_client_id + client_secret = delivery_carrier.postlogistics_client_secret + scope = delivery_carrier.postlogistics_scope + authentication_url = urllib.parse.urljoin( + delivery_carrier.postlogistics_token_url or "", AUTH_PATH + ) + + if not (client_id and client_secret and scope): + raise exceptions.UserError( + _( + "Authorization Required\n\n" + "Please verify postlogistics client id, secret and scope in:\n" + "Delivery Carrier (PostLogistics)." + ) + ) + + response = requests.post( + url=authentication_url, + headers={"content-type": "application/x-www-form-urlencoded"}, + data={ + "grant_type": "client_credentials", + "client_id": client_id, + "client_secret": client_secret, + "scope": scope, + }, + timeout=60, + ) + return response.json() + + @classmethod + def get_access_token(cls, picking_carrier): + """Threadsafe access to token""" + with cls._lock: + now = datetime.now() + + if cls.access_token: + # keep a safe margin on the expiration + expiry = cls.access_token_expiry - timedelta(seconds=5) + if now < expiry: + return cls.access_token + + response = cls._request_access_token(picking_carrier) + cls.access_token = response.get("access_token", False) + + if not (cls.access_token): + raise exceptions.UserError( + _( + "Authorization Required\n\n" + "Please verify postlogistics client id and secret in:\n" + "Sale Orders > Configuration -> Sale Orders >" + " Shipping Methods > PostLogistics" + ) + ) + + cls.access_token_expiry = now + timedelta(seconds=response["expires_in"]) + return cls.access_token + + def _sanitize_string(self, value): + """Removes disallowed chars ("|", "\", "<", ">", "’", "‘") from strings.""" + if isinstance(value, str): + for char, repl in DISALLOWED_CHARS_MAPPING.items(): + value = value.replace(char, repl) + return value + + def generate_label(self, picking, packages): + """Generate a label for a picking + + :param picking: picking browse record + :param user_lang: OpenERP language code + :param packages: browse records of packages to filter on + :return: { + value: [{item_id: pack id + binary: file returned by API + tracking_number: id number for tracking + file_type: str of file type + } + ] + errors: list of error message if any + warnings: list of warning message if any + } + + """ + results = [] + picking_carrier = picking.carrier_id + access_token = self.get_access_token(picking_carrier) + + # get options + lang = self._get_language(picking.partner_id.lang) + post_customer = self._prepare_customer(picking) + recipient = self._prepare_recipient(picking) + item_list = self._prepare_item_list(picking, recipient, packages) + labelDefinition = self._prepare_label_definition(picking) + frankingLicense = self._get_license(picking) + + for item in item_list: + data = self._prepare_data( + lang, frankingLicense, post_customer, labelDefinition, item + ) + + res = {"value": []} + + generate_label_url = urllib.parse.urljoin( + picking_carrier.postlogistics_endpoint_url, GENERATE_LABEL_PATH + ) + response = requests.post( + url=generate_label_url, + headers={ + "Authorization": "Bearer %s" % access_token, + "accept": "application/json", + "content-type": "application/json", + }, + data=json.dumps(data), + timeout=60, + ) + + if response.status_code != 200: + res["success"] = False + res["errors"] = response.content.decode("utf-8") + _logger.warning( + f"Shipping label could not be generated.\n" + f"Request: {json.dumps(data)}\n" + f"Response: {res['errors']}" + ) + return [res] + + response_dict = json.loads(response.content.decode("utf-8")) + + if response_dict["item"].get("errors"): + # If facing an error, top all operations and return the result + res["success"] = False + res["errors"] = [] + for error in response_dict["item"]["errors"]: + res["errors"] = _("Error code: %(code)s, Message: %(message)s") % { + "code": error["code"], + "message": error["message"], + } + results.append(res) + return results + + output_format = self._get_output_format(picking).lower() + file_type = output_format if output_format != "spdf" else "pdf" + binary = base64.b64encode(bytes(response_dict["item"]["label"][0], "utf-8")) + res["success"] = True + res["value"].append( + { + "item_id": item["itemID"], + "binary": binary, + "tracking_number": response_dict["item"]["identCode"], + "file_type": file_type, + } + ) + results.append(res) + return results diff --git a/delivery_postlogistics/pyproject.toml b/delivery_postlogistics/pyproject.toml new file mode 100644 index 0000000000..4231d0cccb --- /dev/null +++ b/delivery_postlogistics/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/delivery_postlogistics/readme/CONFIGURE.md b/delivery_postlogistics/readme/CONFIGURE.md new file mode 100644 index 0000000000..29f55ba63b --- /dev/null +++ b/delivery_postlogistics/readme/CONFIGURE.md @@ -0,0 +1,21 @@ +> [!IMPORTANT] +> A "Swiss Post Business customer" account is required to use this +> module. +> +> See [Log in](https://account.post.ch/selfadmin/?login&lang=en) + +To configure: + +- Go to Inventory -\> Configuration -\> Delivery -\> Shipping Methods +- Create new shipping methods for PostLogistics and set your login + informations in the "PostLogistics" tab +- Go to Inventory -\> Configuration -\> Delivery -\> Delivery Packages + to create the PostLogistics delivery packaging with the relevant + Package Code (see section 8.10 of + for available + codes) + +## Technical references + +["Barcode" web service +documentation](https://www.post.ch/en/business/a-z-of-subjects/dropping-off-mail-items/business-sending-letters/barcode-support) diff --git a/delivery_postlogistics/readme/CONTRIBUTORS.md b/delivery_postlogistics/readme/CONTRIBUTORS.md new file mode 100644 index 0000000000..8489a05465 --- /dev/null +++ b/delivery_postlogistics/readme/CONTRIBUTORS.md @@ -0,0 +1,18 @@ +- Yannick Vaucher \<\> + +- Guewen Baconnier \<\> + +- Akim Juillerat \<\> + +- Julien Coux \<\> + +- Dung Tran \<\> + +- Phuc Tran \<\> + +- Jacques-Etienne Baudoux \<\> + +- [Trobz](https://trobz.com): + - Jack Le \<\> + +- David Moreno \<\> diff --git a/delivery_postlogistics/readme/CREDITS.md b/delivery_postlogistics/readme/CREDITS.md new file mode 100644 index 0000000000..06c78caaae --- /dev/null +++ b/delivery_postlogistics/readme/CREDITS.md @@ -0,0 +1,4 @@ +The development of this module in version 14.0 and its migration from +14.0 to 16.0 has been financially supported by: + +- Camptocamp diff --git a/delivery_postlogistics/readme/DESCRIPTION.md b/delivery_postlogistics/readme/DESCRIPTION.md new file mode 100644 index 0000000000..bd11941b32 --- /dev/null +++ b/delivery_postlogistics/readme/DESCRIPTION.md @@ -0,0 +1,11 @@ +This module uses [PostLogistics BarCodes +WebService](https://www.post.ch/en/business/a-z-of-subjects/dropping-off-mail-items/business-sending-letters/sending-consignments-web-service-barcode) +to generate labels for your Delivery Orders. + +It adds a Create label button on Delivery Orders. A generated label will +be an attachement of your Delivery Order. + +To see it, please install documents module. + +You can create multiple delivery method to match your diffent package +types. diff --git a/delivery_postlogistics/readme/ROADMAP.md b/delivery_postlogistics/readme/ROADMAP.md new file mode 100644 index 0000000000..430aab3c06 --- /dev/null +++ b/delivery_postlogistics/readme/ROADMAP.md @@ -0,0 +1,5 @@ +- Integration of price webservice : + +- Not sure if the recursive patch of suds is still needed as there's no + need to use the integration WS anymore. However we still want to patch + open to get meaningful error messages. diff --git a/delivery_postlogistics/security/ir.model.access.csv b/delivery_postlogistics/security/ir.model.access.csv new file mode 100644 index 0000000000..c00ec6efde --- /dev/null +++ b/delivery_postlogistics/security/ir.model.access.csv @@ -0,0 +1,13 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_postlogistics_license_salesman,postlogistics.license.salesman,model_postlogistics_license,sales_team.group_sale_salesman,1,0,0,0 +access_postlogistics_license_manager,postlogistics.license.manager,model_postlogistics_license,sales_team.group_sale_manager,1,1,1,1 +access_postlogistics_license_stock_user,postlogistics.license.stock_user,model_postlogistics_license,stock.group_stock_user,1,0,0,0 +access_postlogistics_license_stock_manager,postlogistics.license.stock_manager,model_postlogistics_license,stock.group_stock_manager,1,1,1,1 + +access_delivery_carrier_template_option_salesman,delivery.carrier.relation.option.salesman,model_postlogistics_delivery_carrier_template_option,sales_team.group_sale_salesman,1,0,0,0 +access_delivery_carrier_template_option_sales_manager,delivery.carrier.relation.option.sale.manager,model_postlogistics_delivery_carrier_template_option,sales_team.group_sale_manager,1,1,1,1 +access_delivery_carrier_template_option_stock_user,postlogistics.delivery.carrier.template.option stock_user,model_postlogistics_delivery_carrier_template_option,stock.group_stock_user,1,0,0,0 +access_delivery_carrier_template_option_stock_manager,postlogistics.delivery.carrier.template.option stock_manager,model_postlogistics_delivery_carrier_template_option,stock.group_stock_manager,1,1,1,1 + +access_shipping_label_user,shipping.label user,model_postlogistics_shipping_label,stock.group_stock_user,1,1,1,0 +access_shipping_label_manager,shipping.label manager,model_postlogistics_shipping_label,stock.group_stock_manager,1,1,1,1 diff --git a/delivery_postlogistics/static/description/icon.svg b/delivery_postlogistics/static/description/icon.svg new file mode 100644 index 0000000000..a7a26d0932 --- /dev/null +++ b/delivery_postlogistics/static/description/icon.svg @@ -0,0 +1,79 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/delivery_postlogistics/static/description/index.html b/delivery_postlogistics/static/description/index.html new file mode 100644 index 0000000000..2abc55addb --- /dev/null +++ b/delivery_postlogistics/static/description/index.html @@ -0,0 +1,490 @@ + + + + + +PostLogistics Shipping - “Barcode” web service + + + +
+

PostLogistics Shipping - “Barcode” web service

+ + +

Beta License: AGPL-3 OCA/delivery-carrier Translate me on Weblate Try me on Runboat

+

This module uses PostLogistics BarCodes +WebService +to generate labels for your Delivery Orders.

+

It adds a Create label button on Delivery Orders. A generated label will +be an attachement of your Delivery Order.

+

To see it, please install documents module.

+

You can create multiple delivery method to match your diffent package +types.

+

Table of contents

+ +
+

Configuration

+
+

Important

+

A “Swiss Post Business customer” account is required to use this +module.

+

See Log in

+
+

To configure:

+
    +
  • Go to Inventory -> Configuration -> Delivery -> Shipping Methods
  • +
  • Create new shipping methods for PostLogistics and set your login +informations in the “PostLogistics” tab
  • +
  • Go to Inventory -> Configuration -> Delivery -> Delivery Packages to +create the PostLogistics delivery packaging with the relevant Package +Code (see section 8.10 of +https://developer.post.ch/en/digital-commerce-api for available +codes)
  • +
+ +
+
+

Known issues / Roadmap

+ +
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Camptocamp
  • +
+
+
+

Contributors

+ +
+
+

Other credits

+

The development of this module in version 14.0 and its migration from +14.0 to 16.0 has been financially supported by:

+
    +
  • Camptocamp
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/delivery-carrier project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/delivery_postlogistics/static/img/postlogistics-logo.jpg b/delivery_postlogistics/static/img/postlogistics-logo.jpg new file mode 100644 index 0000000000..3e508b97d0 Binary files /dev/null and b/delivery_postlogistics/static/img/postlogistics-logo.jpg differ diff --git a/delivery_postlogistics/tests/__init__.py b/delivery_postlogistics/tests/__init__.py new file mode 100644 index 0000000000..d097ba5c66 --- /dev/null +++ b/delivery_postlogistics/tests/__init__.py @@ -0,0 +1,3 @@ +from . import test_postlogistics +from . import test_sanitize_values +from . import test_packaging_code diff --git a/delivery_postlogistics/tests/common.py b/delivery_postlogistics/tests/common.py new file mode 100644 index 0000000000..e846d391d2 --- /dev/null +++ b/delivery_postlogistics/tests/common.py @@ -0,0 +1,134 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +import requests + +from odoo.tests.common import TransactionCase + +from ..postlogistics.web_service import PostlogisticsWebService + +ENDPOINT_URL = "https://api-int.post.ch/" +CLIENT_ID = "XXX" +CLIENT_SECRET = "XXX" +LICENSE = "XXX" + + +class TestPostlogisticsCommon(TransactionCase): + @classmethod + def setUpClassLicense(cls): + cls.license = cls.env["postlogistics.license"].create( + {"name": "TEST", "number": LICENSE} + ) + + @classmethod + def setUpClassCarrier(cls): + shipping_product = cls.env["product.product"].create({"name": "Shipping"}) + option_model = cls.env["postlogistics.delivery.carrier.template.option"] + partner_id = cls.env.ref("delivery_postlogistics.partner_postlogistics").id + label_layout = option_model.create({"code": "A6", "partner_id": partner_id}) + output_format = option_model.create({"code": "PDF", "partner_id": partner_id}) + image_resolution = option_model.create( + {"code": "600", "partner_id": partner_id} + ) + cls.carrier = cls.env["delivery.carrier"].create( + { + "name": "Postlogistics", + "delivery_type": "postlogistics", + "product_id": shipping_product.id, + "postlogistics_endpoint_url": ENDPOINT_URL, + "postlogistics_client_id": CLIENT_ID, + "postlogistics_client_secret": CLIENT_SECRET, + "postlogistics_license_id": cls.license.id, + "postlogistics_label_layout": label_layout.id, + "postlogistics_output_format": output_format.id, + "postlogistics_resolution": image_resolution.id, + } + ) + + @classmethod + def setUpClassPackaging(cls): + cls.postlogistics_pd_package_type = cls.env["stock.package.type"].create( + { + "name": "PRI-TEST", + "package_carrier_type": "postlogistics", + "shipper_package_code": "PRI, BLN", + } + ) + + @classmethod + def setUpClassUserCompany(cls): + cls.env.user.company_id.write( + {"street": "Rue de Lausanne 1", "zip": "1030", "city": "Bussigny"} + ) + cls.env.user.company_id.partner_id.country_id = cls.env.ref("base.ch") + cls.env.user.lang = "en_US" + + @classmethod + def setUpClassLocation(cls): + cls.stock_location = cls.env.ref("stock.stock_location_stock") + cls.customer_location = cls.env.ref("stock.stock_location_customers") + + @classmethod + def create_picking(cls, partner=None, product_matrix=None): + package_type = cls.postlogistics_pd_package_type + if not partner: + partner = cls.env["res.partner"].create( + { + "name": "Camptocamp SA", + "street": "EPFL Innovation Park, Bât A", + "zip": "1015", + "city": "Lausanne", + } + ) + picking = cls.env["stock.picking"].create( + { + "partner_id": partner.id, + "carrier_id": cls.carrier.id, + "picking_type_id": cls.env.ref("stock.picking_type_out").id, + "location_id": cls.stock_location.id, + "location_dest_id": cls.customer_location.id, + } + ) + if not product_matrix: + product_matrix = [ + (cls.env["product.product"].create({"name": "Product A"}), 3), + ] + for product, qty in product_matrix: + cls.env["stock.move"].create( + { + "name": product.name, + "product_id": product.id, + "product_uom_qty": qty, + "product_uom": product.uom_id.id, + "picking_id": picking.id, + "location_id": cls.stock_location.id, + "location_dest_id": cls.customer_location.id, + } + ) + choose_delivery_package_wizard = cls.env["choose.delivery.package"].create( + {"picking_id": picking.id, "delivery_package_type_id": package_type.id} + ) + picking.action_assign() + choose_delivery_package_wizard.action_put_in_pack() + return picking + + @classmethod + def setUpClassWebservice(cls): + cls.service_class = PostlogisticsWebService(cls.env.user.company_id) + + @classmethod + def _request_handler(cls, s, r, /, **kw): + """Don't block external requests.""" + return cls._super_send(s, r, **kw) + + @classmethod + def setUpClass(cls): + cls._super_send = requests.Session.send + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.setUpClassLicense() + cls.setUpClassCarrier() + cls.setUpClassPackaging() + cls.setUpClassUserCompany() + cls.setUpClassLocation() + cls.setUpClassWebservice() diff --git a/delivery_postlogistics/tests/fixtures/cassettes/test_missing_language.yaml b/delivery_postlogistics/tests/fixtures/cassettes/test_missing_language.yaml new file mode 100644 index 0000000000..3eb2c75807 --- /dev/null +++ b/delivery_postlogistics/tests/fixtures/cassettes/test_missing_language.yaml @@ -0,0 +1,116 @@ +interactions: + - request: + body: scope=DCAPI_BARCODE_READ&client_secret=c70e3696ae5146e7fe317434e50a90cd&grant_type=client_credentials&client_id=865783331e39e91e633c3916fe892d92 + headers: + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - "144" + User-Agent: + - python-requests/2.20.0 + content-type: + - application/x-www-form-urlencoded + method: POST + uri: https://api-int.post.ch/OAuth/token + response: + body: + string: '{"access_token":"XXX","token_type":"Bearer","expires_in":60}' + headers: + Cache-Control: + - no-store + Connection: + - Keep-Alive + Content-Length: + - "1279" + Content-Type: + - application/json; charset=UTF-8 + Date: + - Tue, 13 Oct 2020 10:52:22 GMT + Keep-Alive: + - timeout=5, max=100 + Pragma: + - no-cache + Server: + - Apache + Set-Cookie: + - NavajoIWedec=; Max-Age=0; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT; + Secure; HttpOnly + status: + code: 200 + message: OK + - request: + body: + '{"customerSystem": null, "labelDefinition": {"imageFileType": "PDF", + "printAddresses": "RECIPIENT_AND_CUSTOMER", "labelLayout": "A6", + "imageResolution": "600", "printPreview": false}, "sendingID": null, "item": + {"attributes": {"przl": ["PRI"], "weight": 0.0}, "recipient": {"city": + "Lausanne", "street": "EPFL Innovation Park, B\u00e2t A", "zip": "1015", + "name1": "Camptocamp SA", "email": null}, "itemID": "WHOUT00042+WHOUT00042"}, + "customer": {"street": "Rue de Lausanne 1", "domicilePostOffice": false, "city": + "Bussigny", "country": "CH", "zip": "1030", "name1": "YourCompany"}, + "frankingLicense": "60013217", "ppFranking": false, "language": "EN"}' + headers: + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - "652" + User-Agent: + - python-requests/2.20.0 + accept: + - application/json + content-type: + - application/json + method: POST + uri: https://dcapi.apis-int.post.ch/barcode/v1/generateAddressLabel + response: + body: + string: "{\n \"labelDefinition\" : {\n \"labelLayout\" : \"A6\",\n \"\ + printAddresses\" : \"RECIPIENT_AND_CUSTOMER\",\n \"imageFileType\" : \"\ + pdf\",\n \"imageResolution\" : 600,\n \"printPreview\" : false,\n \ + \ \"colorPrintRequired\" : true\n },\n \"item\" : {\n \"itemID\" : \"\ + WHOUT00042+WHOUT00042\",\n \"identCode\" : \"996001321700005958\",\n \ + \ \"label\" : [ \"JVBERi0xLjQKJeLjz9MKMiAwIG9iago8PC9Db2xvclNwY...\"\ + \ ]\n }\n}" + headers: + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - Keep-Alive + Content-Type: + - application/json;charset=UTF-8 + Date: + - Tue, 13 Oct 2020 10:52:25 GMT + Expires: + - "0" + Keep-Alive: + - timeout=5, max=100 + Pragma: + - no-cache + Server: + - Apache + Strict-Transport-Security: + - max-age=15552000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-XSS-Protection: + - 1; mode=block + content-length: + - "78215" + isiwebauthstate: + - valid + status: + code: 200 + message: OK +version: 1 diff --git a/delivery_postlogistics/tests/fixtures/cassettes/test_store_label.yaml b/delivery_postlogistics/tests/fixtures/cassettes/test_store_label.yaml new file mode 100644 index 0000000000..684c442c83 --- /dev/null +++ b/delivery_postlogistics/tests/fixtures/cassettes/test_store_label.yaml @@ -0,0 +1,116 @@ +interactions: + - request: + body: scope=DCAPI_BARCODE_READ&client_secret=c70e3696ae5146e7fe317434e50a90cd&grant_type=client_credentials&client_id=865783331e39e91e633c3916fe892d92 + headers: + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - "144" + User-Agent: + - python-requests/2.20.0 + content-type: + - application/x-www-form-urlencoded + method: POST + uri: https://api-int.post.ch/OAuth/token + response: + body: + string: '{"access_token":"XXX","token_type":"Bearer","expires_in":60}' + headers: + Cache-Control: + - no-store + Connection: + - Keep-Alive + Content-Length: + - "1279" + Content-Type: + - application/json; charset=UTF-8 + Date: + - Tue, 13 Oct 2020 10:52:26 GMT + Keep-Alive: + - timeout=5, max=100 + Pragma: + - no-cache + Server: + - Apache + Set-Cookie: + - NavajoIWedec=; Max-Age=0; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT; + Secure; HttpOnly + status: + code: 200 + message: OK + - request: + body: + '{"customerSystem": null, "labelDefinition": {"imageFileType": "PDF", + "printAddresses": "RECIPIENT_AND_CUSTOMER", "labelLayout": "A6", + "imageResolution": "600", "printPreview": false}, "sendingID": null, "item": + {"attributes": {"przl": ["PRI"], "weight": 0.0}, "recipient": {"city": + "Lausanne", "street": "EPFL Innovation Park, B\u00e2t A", "zip": "1015", + "name1": "Camptocamp SA", "email": null}, "itemID": "WHOUT00042+WHOUT00042"}, + "customer": {"street": "Rue de Lausanne 1", "domicilePostOffice": false, "city": + "Bussigny", "country": "CH", "zip": "1030", "name1": "YourCompany"}, + "frankingLicense": "60013217", "ppFranking": false, "language": "EN"}' + headers: + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - "652" + User-Agent: + - python-requests/2.20.0 + accept: + - application/json + content-type: + - application/json + method: POST + uri: https://dcapi.apis-int.post.ch/barcode/v1/generateAddressLabel + response: + body: + string: "{\n \"labelDefinition\" : {\n \"labelLayout\" : \"A6\",\n \"\ + printAddresses\" : \"RECIPIENT_AND_CUSTOMER\",\n \"imageFileType\" : \"\ + pdf\",\n \"imageResolution\" : 600,\n \"printPreview\" : false,\n \ + \ \"colorPrintRequired\" : true\n },\n \"item\" : {\n \"itemID\" : \"\ + WHOUT00042+WHOUT00042\",\n \"identCode\" : \"996001321700005959\",\n \ + \ \"label\" : [ \"JVBERi0xLjQKJeLjz9MKMiAwIG9iago8PC9Db2xvclNw\"\ + \ ]\n }\n}" + headers: + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Connection: + - Keep-Alive + Content-Type: + - application/json;charset=UTF-8 + Date: + - Tue, 13 Oct 2020 10:52:27 GMT + Expires: + - "0" + Keep-Alive: + - timeout=5, max=100 + Pragma: + - no-cache + Server: + - Apache + Strict-Transport-Security: + - max-age=15552000; includeSubDomains + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-XSS-Protection: + - 1; mode=block + content-length: + - "77759" + isiwebauthstate: + - valid + status: + code: 200 + message: OK +version: 1 diff --git a/delivery_postlogistics/tests/test_packaging_code.py b/delivery_postlogistics/tests/test_packaging_code.py new file mode 100644 index 0000000000..9ef2162547 --- /dev/null +++ b/delivery_postlogistics/tests/test_packaging_code.py @@ -0,0 +1,44 @@ +# Copyright 2022 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + +from odoo.tests.common import Form, TransactionCase + +PACKAGE_CODE = "blah-biddy, bloo-blah, blah-blah-biddy, bloo-blah" +EXPECTED_CODES = ["blah-biddy", "bloo-blah", "blah-blah-biddy", "bloo-blah"] + + +class TestPackagingCode(TransactionCase): + at_install = False + post_install = True + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.carrier = cls.env.ref("delivery.delivery_carrier") + cls.carrier.delivery_type = "postlogistics" + cls.package_type = cls.env["stock.package.type"].create( + { + "name": "Packaging Test", + "package_carrier_type": "postlogistics", + "shipper_package_code": "PRI, BLN", + } + ) + + def test_shipper_package_code_get_packaging_code(self): + # If no shipper_package_code is set on the package_type then + # _get_packaging_codes should return [] + with Form(self.package_type) as package_type: + package_type.package_carrier_type = False + self.assertEqual(self.package_type._get_packaging_codes(), []) + # case 2: type is set, but no matching carrier is found + # _get_packaging_codes returns [] + with Form(self.package_type) as package_type: + package_type.package_carrier_type = "none" + self.assertEqual(self.package_type._get_packaging_codes(), []) + # case 3: When package_carrier_type is set, shipper_package_code is + # computed, and _get_packaging_codes should return the expected codes + with Form(self.package_type) as package_type: + package_type.package_carrier_type = self.carrier.delivery_type + package_type.shipper_package_code = PACKAGE_CODE + self.assertEqual(self.package_type._get_packaging_codes(), EXPECTED_CODES) diff --git a/delivery_postlogistics/tests/test_postlogistics.py b/delivery_postlogistics/tests/test_postlogistics.py new file mode 100644 index 0000000000..d594a29d30 --- /dev/null +++ b/delivery_postlogistics/tests/test_postlogistics.py @@ -0,0 +1,110 @@ +# Copyright 2015-2019 Camptocamp +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from os.path import dirname, join + +from vcr import VCR + +from .common import TestPostlogisticsCommon + +recorder = VCR( + record_mode="once", + cassette_library_dir=join(dirname(__file__), "fixtures/cassettes"), + path_transformer=VCR.ensure_suffix(".yaml"), + filter_headers=["Authorization"], + filter_post_data_parameters=["client_id", "client_secret"], + # ignore scheme, host, port + match_on=("method", "path", "query"), + # allow to read and edit content in cassettes + decode_compressed_response=True, +) + + +class TestPostlogistics(TestPostlogisticsCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.picking = cls.create_picking() + + def test_misc(self): + self.assertFalse(self.carrier.prod_environment) + self.carrier.toggle_prod_environment() + self.carrier.onchange_prod_environment() + self.assertTrue(self.carrier.prod_environment) + self.carrier.toggle_prod_environment() + self.carrier.onchange_prod_environment() + self.assertFalse(self.carrier.prod_environment) + self.assertEqual( + self.carrier.get_tracking_link(self.picking), + "https://service.post.ch/EasyTrack/" + "submitParcelData.do?formattedParcelCodes=False", + ) + + def test_store_label(self): + with recorder.use_cassette("test_store_label") as cassette: + res = self.picking._generate_postlogistics_label(skip_attach_file=True) + self.assertEqual(len(cassette.requests), 2) + ref = "996001321700005959" + self.assertEqual(res[0]["file_type"], "pdf") + self.assertEqual(res[0]["name"], f"{ref}.pdf") + self.assertEqual(res[0]["file"][:30], b"JVBERi0xLjQKJeLjz9MKMiAwIG9iag") + self.assertEqual(self.picking.carrier_tracking_ref, ref) + + def test_missing_language(self): + self.env.user.lang = False + with recorder.use_cassette("test_missing_language") as cassette: + self.picking._generate_postlogistics_label(skip_attach_file=True) + self.assertEqual(len(cassette.requests), 2) + + def test_store_label_postlogistics_tracking_format_picking_num(self): + self.carrier.postlogistics_tracking_format = "picking_num" + with recorder.use_cassette("test_store_label") as cassette: + res = self.picking._generate_postlogistics_label(skip_attach_file=True) + self.assertEqual(len(cassette.requests), 2) + ref = "996001321700005959" + self.assertEqual(res[0]["file_type"], "pdf") + self.assertEqual(res[0]["name"], f"{ref}.pdf") + self.assertEqual(res[0]["file"][:30], b"JVBERi0xLjQKJeLjz9MKMiAwIG9iag") + self.assertEqual(self.picking.carrier_tracking_ref, ref) + + def test_prepare_recipient(self): + partner_id = self.picking.partner_id + partner_id.is_company = True + partner_id.country_id = self.env.ref("base.fr").id + recipient = self.env["res.partner"].create( + { + "name": "Recipient", + "street": "EPFL Innovation Park, Bât A", + "zip": "1015", + "city": "Lausanne", + "street2": "Street 2", + "parent_id": partner_id.id, + "company_name": "Camptocamp", + } + ) + self.picking.partner_id = recipient + customer = self.service_class._prepare_recipient(self.picking) + self.assertEqual(customer["country"], "FR") + self.assertEqual(customer["name2"], "Camptocamp SA") + + def test_send_to_shipper(self): + with recorder.use_cassette("test_store_label") as cassette: + self.picking.send_to_shipper() + self.assertEqual(len(cassette.requests), 2) + + def test_send_to_shipper_default_package(self): + pl_package_type = self.postlogistics_pd_package_type + self.carrier.postlogistics_default_package_type_id = pl_package_type + self.picking.move_line_ids.write( + { + "result_package_id": False, + } + ) + with recorder.use_cassette("test_store_label") as cassette: + self.picking.send_to_shipper() + self.assertEqual(len(cassette.requests), 2) + + def test_postlogistics_rate_shipment(self): + with recorder.use_cassette("test_store_label") as cassette: + res = self.carrier.postlogistics_rate_shipment(None) + self.assertEqual(len(cassette.requests), 2) + self.assertEqual(res["price"], 1.0) diff --git a/delivery_postlogistics/tests/test_sanitize_values.py b/delivery_postlogistics/tests/test_sanitize_values.py new file mode 100644 index 0000000000..5bd2338eb3 --- /dev/null +++ b/delivery_postlogistics/tests/test_sanitize_values.py @@ -0,0 +1,60 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) + + +from ..postlogistics.web_service import DISALLOWED_CHARS_MAPPING +from .common import TestPostlogisticsCommon + + +class TestSanitizeValues(TestPostlogisticsCommon): + """Just create records full of disallowed chars, an test that everyone of them + is correctly removed, as none of those chars should be sent on postlogistics api. + """ + + @classmethod + def setUpPartner(cls): + cls.partner = cls.env["res.partner"].create( + { + "name": "‘Po’", + "mobile": "+33123456789>", + "phone": ">+33123456789<", + "email": "w<>|\\hatever@whatever.too", + "street": "42\\|<>whateverstraße", + "street2": "42\\|<>whateverstraße", + "zip": "43123\\", + "city": "Mouais\\<>|", + } + ) + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.setUpPartner() + cls.picking = cls.create_picking(cls.partner) + + def check_strings_in_dict(self, values): + # Do not check other types than strings. + # Dict values are individually tested, no recursion here. + values_to_check = [value for value in values.values() if isinstance(value, str)] + self.check_strings_in_list(values_to_check) + + def check_strings_in_list(self, values): + for value in values: + self.assertFalse( + any(char in value for char in DISALLOWED_CHARS_MAPPING.keys()) + ) + + def test_sanitize(self): + customer = self.service_class._prepare_customer(self.picking) + self.check_strings_in_dict(customer) + recipient = self.service_class._prepare_recipient(self.picking) + self.check_strings_in_dict(recipient) + packages = self.picking._get_packages_from_picking() + item_list = self.service_class._prepare_item_list( + self.picking, recipient, packages + ) + self.check_strings_in_list(item_list) + attributes = self.service_class._prepare_attributes( + self.picking, packages, 1, 1 + ) + self.check_strings_in_dict(attributes) diff --git a/delivery_postlogistics/views/delivery.xml b/delivery_postlogistics/views/delivery.xml new file mode 100644 index 0000000000..169c5601a8 --- /dev/null +++ b/delivery_postlogistics/views/delivery.xml @@ -0,0 +1,93 @@ + + + + + delivery.carrier.postlogistics.inherit.view + delivery.carrier + + + + + + + + + + + +