Initial commit: OCA Edi packages (42 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:05 +02:00
commit df976c03db
2184 changed files with 571602 additions and 0 deletions

View file

@ -0,0 +1,47 @@
# Sale Order Import
Odoo addon: sale_order_import
## Installation
```bash
pip install odoo-bringout-oca-edi-framework-sale_order_import
```
## Dependencies
This addon depends on:
- sale_commercial_partner
- base_business_document_import
- onchange_helper
- pdf_helper
## Manifest Information
- **Name**: Sale Order Import
- **Version**: 16.0.1.3.1
- **Category**: Sales Management
- **License**: AGPL-3
- **Installable**: True
## Source
Based on [OCA/edi-framework](https://github.com/OCA/edi-framework) branch 16.0, addon `sale_order_import`.
## License
This package maintains the original AGPL-3 license from the upstream Odoo project.
## Documentation
- Overview: doc/OVERVIEW.md
- Architecture: doc/ARCHITECTURE.md
- Models: doc/MODELS.md
- Controllers: doc/CONTROLLERS.md
- Wizards: doc/WIZARDS.md
- Install: doc/INSTALL.md
- Usage: doc/USAGE.md
- Configuration: doc/CONFIGURATION.md
- Dependencies: doc/DEPENDENCIES.md
- Troubleshooting: doc/TROUBLESHOOTING.md
- FAQ: doc/FAQ.md

View file

@ -0,0 +1,32 @@
# Architecture
```mermaid
flowchart TD
U[Users] -->|HTTP| V[Views and QWeb Templates]
V --> C[Controllers]
V --> W[Wizards Transient Models]
C --> M[Models and ORM]
W --> M
M --> R[Reports]
DX[Data XML] --> M
S[Security ACLs and Groups] -. enforces .-> M
subgraph Sale_order_import Module - sale_order_import
direction LR
M:::layer
W:::layer
C:::layer
V:::layer
R:::layer
S:::layer
DX:::layer
end
classDef layer fill:#eef8ff,stroke:#6ea8fe,stroke-width:1px
```
Notes
- Views include tree/form/kanban templates and report templates.
- Controllers provide website/portal routes when present.
- Wizards are UI flows implemented with `models.TransientModel`.
- Data XML loads data/demo records; Security defines groups and access.

View file

@ -0,0 +1,3 @@
# Configuration
Refer to Odoo settings for sale_order_import. Configure related models, access rights, and options as needed.

View file

@ -0,0 +1,3 @@
# Controllers
This module does not define custom HTTP controllers.

View file

@ -0,0 +1,8 @@
# Dependencies
This addon depends on:
- [sale_commercial_partner](../../odoo-bringout-oca-sale-workflow-sale_commercial_partner)
- [base_business_document_import](../../odoo-bringout-oca-edi-base_business_document_import)
- [onchange_helper](../../odoo-bringout-oca-server-tools-onchange_helper)
- [pdf_helper](../../odoo-bringout-oca-edi-framework-pdf_helper)

View file

@ -0,0 +1,4 @@
# FAQ
- Q: Which Odoo version? A: 16.0 (OCA/OCB packaged).
- Q: How to enable? A: Start server with --addon sale_order_import or install in UI.

View file

@ -0,0 +1,7 @@
# Install
```bash
pip install odoo-bringout-oca-edi-framework-sale_order_import"
# or
uv pip install odoo-bringout-oca-edi-framework-sale_order_import"
```

View file

@ -0,0 +1,12 @@
# Models
Detected core models and extensions in sale_order_import.
```mermaid
classDiagram
class sale_order
```
Notes
- Classes show model technical names; fields omitted for brevity.
- Items listed under _inherit are extensions of existing models.

View file

@ -0,0 +1,6 @@
# Overview
Packaged Odoo addon: sale_order_import. Provides features documented in upstream Odoo 16 under this addon.
- Source: OCA/OCB 16.0, addon sale_order_import
- License: LGPL-3

View file

@ -0,0 +1,3 @@
# Reports
This module does not define custom reports.

View file

@ -0,0 +1,34 @@
# Security
Access control and security definitions in sale_order_import.
## Access Control Lists (ACLs)
Model access permissions defined in:
- **[ir.model.access.csv](../sale_order_import/security/ir.model.access.csv)**
- 1 model access rules
## Record Rules
Row-level security rules defined in:
```mermaid
graph TB
subgraph "Security Layers"
A[Users] --> B[Groups]
B --> C[Access Control Lists]
C --> D[Models]
B --> E[Record Rules]
E --> F[Individual Records]
end
```
Security files overview:
- **[ir.model.access.csv](../sale_order_import/security/ir.model.access.csv)**
- Model access permissions (CRUD rights)
Notes
- Access Control Lists define which groups can access which models
- Record Rules provide row-level security (filter records by user/group)
- Security groups organize users and define permission sets
- All security is enforced at the ORM level by Odoo

View file

@ -0,0 +1,5 @@
# Troubleshooting
- Ensure Python and Odoo environment matches repo guidance.
- Check database connectivity and logs if startup fails.
- Validate that dependent addons listed in DEPENDENCIES.md are installed.

View file

@ -0,0 +1,7 @@
# Usage
Start Odoo including this addon (from repo root):
```bash
python3 scripts/nix_odoo_web_server.py --db-name mydb --addon sale_order_import
```

View file

@ -0,0 +1,8 @@
# Wizards
Transient models exposed as UI wizards in sale_order_import.
```mermaid
classDiagram
class SaleOrderImport
```

View file

@ -0,0 +1,45 @@
[project]
name = "odoo-bringout-oca-edi-framework-sale_order_import"
version = "16.0.0"
description = "Sale Order Import - Import RFQ or sale orders from files"
authors = [
{ name = "Ernad Husremovic", email = "hernad@bring.out.ba" }
]
dependencies = [
"odoo-bringout-oca-edi-framework-sale_commercial_partner>=16.0.0",
"odoo-bringout-oca-edi-framework-base_business_document_import>=16.0.0",
"odoo-bringout-oca-edi-framework-onchange_helper>=16.0.0",
"odoo-bringout-oca-edi-framework-pdf_helper>=16.0.0",
"requests>=2.25.1"
]
readme = "README.md"
requires-python = ">= 3.11"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Office/Business",
]
[project.urls]
homepage = "https://github.com/bringout/0"
repository = "https://github.com/bringout/0"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.metadata]
allow-direct-references = true
[tool.hatch.build.targets.wheel]
packages = ["sale_order_import"]
[tool.rye]
managed = true
dev-dependencies = [
"pytest>=8.4.1",
]

View file

@ -0,0 +1,105 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association
=================
Sale Order Import
=================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:8e01d803e464dc07c4ec36557747613a5f3db4de2c5c712b493c596addb6ce35
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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/license-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%2Fedi-lightgray.png?logo=github
:target: https://github.com/OCA/edi/tree/16.0/sale_order_import
:alt: OCA/edi
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/edi-16-0/edi-16-0-sale_order_import
: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/edi&target_branch=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
This module adds support for the import of electronic RFQ or orders. This module provides the base methods to import electronic orders, and you can also plug additional formats by extending the wizard. It requires additional modules to support specific order formats:
* module *sale_order_import_ubl*: adds support for `Universal Business Language (UBL) <http://ubl.xml.org/>`_ RFQs and orders as:
- XML file,
- PDF file with an embedded XML file.
**Table of contents**
.. contents::
:local:
Usage
=====
This module adds a wizard in the sale menu named *Import RFQ or Order*. This wizard will propose you to select the order or RFQ file. Depending on the format of the file (XML or PDF) and the type of file (RFQ or order), it may propose you additional options.
When you import an order, if there is a quotation in Odoo for the same customer, the wizard will propose you to either update the existing quotation or create a new order (in fact, it will create a new quotation, so that you are free to make some modifications before you click on the *Confirm Sale* button to convert the quotation to a sale order).
Once the RFQ/order is imported, you should read the messages in the chatter of the quotation because it may contain important information about the import.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/edi/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 <https://github.com/OCA/edi/issues/new?body=module:%20sale_order_import%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
~~~~~~~
* Akretion
* Camptocamp
Contributors
~~~~~~~~~~~~
* Alexis de Lattre <alexis.delattre@akretion.com>
* Dennis Sluijk <d.sluijk@onestein.nl>
* Andrea Stirpe <a.stirpe@onestein.nl>
* Simone Orsi <simone.orsi@camptocamp.com>
* Duong (Tran Quoc) <duongtq@trobz.com>
Other credits
~~~~~~~~~~~~~
The migration of this module from 13.0 to 16.0 was 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/edi <https://github.com/OCA/edi/tree/16.0/sale_order_import>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View file

@ -0,0 +1,4 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from . import wizard
from . import models

View file

@ -0,0 +1,25 @@
# © 2016-2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "Sale Order Import",
"version": "16.0.1.3.1",
"category": "Sales Management",
"license": "AGPL-3",
"summary": "Import RFQ or sale orders from files",
"author": "Akretion, Camptocamp, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/edi",
"depends": [
# OCA/sale-workflow
"sale_commercial_partner",
# OCA/edi
"base_business_document_import",
# OCA/server-tools
"onchange_helper",
# TODO: this dependency should be removed
# and support for PDF import should be moved to a glue module
"pdf_helper",
],
"data": ["security/ir.model.access.csv", "wizard/sale_order_import_view.xml"],
"installable": True,
}

View file

@ -0,0 +1,410 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_order_import
#
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: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/models/sale.py:0
#: code:addons/sale_order_import/tests/test_sale_order.py:0
#, python-format
msgid " Amount w/o tax: %(amount)s %(currency)s"
msgstr " Iznos bez poreza: %(amount)s %(currency)s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "%(orders)s new order line(s) created: %(label)s"
msgstr "%(orders)s nova stavka(e) naloga kreirana(e): %(label)s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "%(orders)s order line(s) deleted: %(label)s"
msgstr "%(orders)s stavka(e) naloga obrisana(e): %(label)s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"An order of customer '%(partner)s' with reference '%(ref)s' already exists: "
"%(name)s (state: %(state)s)"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__price_source
msgid "Apply Prices From"
msgstr "Primijeni cijene iz"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Cancel"
msgstr "Otkaži"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__commercial_partner_id
msgid "Commercial Entity"
msgstr "Komercijalni entitet"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__confirm_order
msgid "Confirm Order"
msgstr "Potvrdi nalog"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Create New"
msgstr "Kreiraj novi"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "Created automatically via file import (%s)."
msgstr "Kreiran automatski putem importa datoteke (%s)."
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__create_uid
msgid "Created by"
msgstr "Kreirao"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__create_date
msgid "Created on"
msgstr "Kreirano"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__partner_id
msgid "Customer"
msgstr "Kupac"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__price_source__order
msgid "Customer Order"
msgstr "Nalog kupca"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__display_name
msgid "Display Name"
msgstr "Prikazani naziv"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__doc_type
msgid "Document Type"
msgstr "Tip dokumenta"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__order_filename
msgid "Filename"
msgstr "Naziv datoteke"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__id
msgid "ID"
msgstr "ID"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"If it is a PDF file, Odoo will try to find an XML file in the attachments of"
" the PDF file and then use this XML file to create the quotation."
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"If it is an XML file, Odoo will parse it if the module that adds support for"
" this XML format is installed. For the"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__state__import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Import"
msgstr "Uvoz"
#. module: sale_order_import
#: model:ir.actions.act_window,name:sale_order_import.sale_order_import_action
#: model:ir.ui.menu,name:sale_order_import.sale_order_import_menu
msgid "Import RFQ or Order"
msgstr "Uvoz zahtjeva za ponudu ili naloga"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Import Sale Orders"
msgstr "Uvoz prodajnih naloga"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__import_type
msgid "Import Type"
msgstr "Tip uvoza"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import____last_update
msgid "Last Modified on"
msgstr "Zadnje mijenjano"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__write_uid
msgid "Last Updated by"
msgstr "Zadnji ažurirao"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__write_date
msgid "Last Updated on"
msgstr "Zadnje ažurirano"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "No data provided"
msgstr "Nema podataka"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"No price is defined in the file. Please double check file or select "
"Pricelist as the source for prices."
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__import_type__pdf
msgid "PDF"
msgstr "PDF"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "Please select a valid import type before importing!"
msgstr "Molimo odaberite važeći tip uvoza prije uvoza!"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__price_source__pricelist
msgid "Pricelist"
msgstr "Cjenik"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__sale_id
msgid "Quotation to Update"
msgstr "Ponuda za ažuriranje"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__doc_type__rfq
msgid "Request For Quotation"
msgstr "Zahtjev za ponudu"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__order_file
msgid "Request for Quotation or Order"
msgstr "Zahtjev za ponudu ili nalog"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__doc_type__order
msgid "Sale Order"
msgstr "Prodajni nalog"
#. module: sale_order_import
#: model:ir.model,name:sale_order_import.model_sale_order_import
msgid "Sale Order Import from Files"
msgstr "Uvoz prodajnog naloga iz datoteka"
#. module: sale_order_import
#: model:ir.model,name:sale_order_import.model_sale_order
msgid "Sales Order"
msgstr "Prodajni nalog"
#. module: sale_order_import
#: model:ir.model.fields,help:sale_order_import.field_sale_order_import__import_type
msgid "Select a type which you want to import"
msgstr "Odaberite tip koji želite uvoziti"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__partner_shipping_id
msgid "Shipping Address"
msgstr "Adresa isporuke"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"Some quotations have been found for this customer ; one of them may "
"correspond to the order or RFQ that you are importing. You can either select"
" an existing quotation to update or create a new one."
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__state
msgid "State"
msgstr "Status"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The currency of the imported order (%(old)s) is different from the currency "
"of the existing order (%(new)s)"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The customer '%(name)s' has a pricelist '%(pricelist)s' but the currency of "
"this order is '%(currency)s'."
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The quantity has been updated on the order line with product '%(product)s' "
"from %(qty0)s to %(qty1)s %(uom)s"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The unit price has been updated on the order line with product '%(product)s'"
" from %(old)s to %(new)s %(currency)s"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "There are no embedded XML file in this PDF file."
msgstr "Nema ugrađene XML datoteke u ovoj PDF datoteci."
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This Import Type is not supported. Did you install the module to support "
"this type?"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "This XML file is not XML-compliant"
msgstr "Ova XML datoteka nije XML-kompatibilna"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This file '%(filename)s' is not recognized as a %(type)s file. Please check "
"the file and its extension."
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This file '%s' is not recognised as a XML nor PDF file. Please check the "
"file and it's extension."
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "This order doesn't have any line !"
msgstr "Ovaj nalog nema stavki!"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This quotation has been updated automatically via the import of file %s"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This type of XML RFQ/order is not supported. Did you install the module to "
"support this XML format?"
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Universal Business Language"
msgstr "Universal Business Language"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "Unsupported file format"
msgstr "Nepodržan format datoteke"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__state__update
msgid "Update"
msgstr "Ažuriraj"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Update Existing"
msgstr "Ažuriraj postojeći"
#. module: sale_order_import
#: model:ir.model.fields,help:sale_order_import.field_sale_order_import__order_file
msgid ""
"Upload a Request for Quotation or an Order file. Supported formats: XML and "
"PDF (PDF with an embeded XML file)."
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"Upload below the customer order or request for quotation as XML or PDF file."
" When you click on the Import button:"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__import_type__xml
msgid "XML"
msgstr "XML"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "You must select a quotation to update."
msgstr "Morate odabrati ponudu za ažuriranje."
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"format (UBL), you should install the module <em>sale_order_import_ubl</em>."
msgstr ""

View file

@ -0,0 +1,460 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_order_import
#
# Translators:
# enjolras <yo@miguelrevilla.com>, 2018
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 10.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-03-12 01:43+0000\n"
"PO-Revision-Date: 2023-11-26 20:35+0000\n"
"Last-Translator: Ivorra78 <informatica@totmaterial.es>\n"
"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\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: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/models/sale.py:0
#: code:addons/sale_order_import/tests/test_sale_order.py:0
#, python-format
msgid " Amount w/o tax: %(amount)s %(currency)s"
msgstr " Importe sin impuestos: %(amount)s %(currency)s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "%(orders)s new order line(s) created: %(label)s"
msgstr "%(orders)s nueva(s) línea(s) de pedido creada(s): %(label)s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "%(orders)s order line(s) deleted: %(label)s"
msgstr "%(orders)s línea(s) de pedido suprimida(s): %(label)s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"An order of customer '%(partner)s' with reference '%(ref)s' already exists: "
"%(name)s (state: %(state)s)"
msgstr ""
"Ya existe un pedido del cliente '%(partner)s' con referencia '%(ref)s': "
"%(name)s (state: %(state)s)"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__price_source
msgid "Apply Prices From"
msgstr "Aplicar Precios Desde"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Cancel"
msgstr "Cancelar"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__commercial_partner_id
msgid "Commercial Entity"
msgstr "Entidad Comercial"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__confirm_order
msgid "Confirm Order"
msgstr "Confirmar Pedido"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Create New"
msgstr "Crear nuevo"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "Created automatically via file import (%s)."
msgstr "Creado automáticamente a través de la importación de archivos (%s)."
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__create_uid
msgid "Created by"
msgstr "Creado por"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__create_date
msgid "Created on"
msgstr "Creado el"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__partner_id
msgid "Customer"
msgstr "Cliente"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__price_source__order
msgid "Customer Order"
msgstr "Pedido del cliente"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__display_name
msgid "Display Name"
msgstr "Nombre mostrado"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__doc_type
msgid "Document Type"
msgstr "Tipo de documento"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__order_filename
msgid "Filename"
msgstr "Archivo"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__id
msgid "ID"
msgstr "ID"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"If it is a PDF file, Odoo will try to find an XML file in the attachments of "
"the PDF file and then use this XML file to create the quotation."
msgstr ""
"Si es un archivo PDF, Odoo tratará de encontrar un archivo XML en los "
"adjuntos del archivo PDF y luego usará este archivo XML para crear la "
"cotización."
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"If it is an XML file, Odoo will parse it if the module that adds support for "
"this XML format is installed. For the"
msgstr ""
"Si es un archivo XML, Odoo lo analizará si el módulo que añade soporte para "
"este formato XML está instalado. Para los archivos"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__state__import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Import"
msgstr "Importar"
#. module: sale_order_import
#: model:ir.actions.act_window,name:sale_order_import.sale_order_import_action
#: model:ir.ui.menu,name:sale_order_import.sale_order_import_menu
msgid "Import RFQ or Order"
msgstr "Importar solicitud de presupuesto o pedido"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Import Sale Orders"
msgstr "Importar pedidos de venta"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__import_type
msgid "Import Type"
msgstr "Tipo de Importación"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import____last_update
msgid "Last Modified on"
msgstr "Última modificación el"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__write_uid
msgid "Last Updated by"
msgstr "Última actualización por"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__write_date
msgid "Last Updated on"
msgstr "Última actualización el"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "No data provided"
msgstr "No se han facilitado datos"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"No price is defined in the file. Please double check file or select "
"Pricelist as the source for prices."
msgstr ""
"No se ha definido ningún precio en el archivo. Compruebe el archivo o "
"seleccione Lista de precios como fuente de precios."
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__import_type__pdf
msgid "PDF"
msgstr "PDF"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "Please select a valid import type before importing!"
msgstr ""
"¡Por favor, seleccione un tipo de importación válido antes de importar!"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__price_source__pricelist
msgid "Pricelist"
msgstr "Tarifa"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__sale_id
msgid "Quotation to Update"
msgstr "Presupuesto para actualizar"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__doc_type__rfq
msgid "Request For Quotation"
msgstr "Solicitud de presupuesto"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__order_file
msgid "Request for Quotation or Order"
msgstr "Solicitud de presupuesto o pedido"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__doc_type__order
msgid "Sale Order"
msgstr "Pedido de venta"
#. module: sale_order_import
#: model:ir.model,name:sale_order_import.model_sale_order_import
msgid "Sale Order Import from Files"
msgstr "Importación de Orden de Venta desde Ficheros"
#. module: sale_order_import
#: model:ir.model,name:sale_order_import.model_sale_order
msgid "Sales Order"
msgstr "Pedido de venta"
#. module: sale_order_import
#: model:ir.model.fields,help:sale_order_import.field_sale_order_import__import_type
msgid "Select a type which you want to import"
msgstr "Seleccione el tipo que desea importar"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__partner_shipping_id
msgid "Shipping Address"
msgstr "Dirección de envío"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"Some quotations have been found for this customer ; one of them may "
"correspond to the order or RFQ that you are importing. You can either select "
"an existing quotation to update or create a new one."
msgstr ""
"Se han encontrado algunos presupuestos para este cliente; uno de ellos puede "
"corresponder al pedido o petición de oferta que está importando. Puede "
"seleccionar una oferta existente para actualizarla o crear una nueva."
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__state
msgid "State"
msgstr "Estado"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The currency of the imported order (%(old)s) is different from the currency "
"of the existing order (%(new)s)"
msgstr ""
"La divisa del pedido importado ( %(old)s) es diferente de la divisa del "
"pedido existente (%(new)s)"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The customer '%(name)s' has a pricelist '%(pricelist)s' but the currency of "
"this order is '%(currency)s'."
msgstr ""
"El cliente '%(name)s' tiene una lista de precios '%(pricelist)s' pero la "
"divisa de este pedido es '%(currency)s'."
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The quantity has been updated on the order line with product '%(product)s' "
"from %(qty0)s to %(qty1)s %(uom)s"
msgstr ""
"Se ha actualizado la cantidad en la línea de pedido con el producto "
"'%(product)s' de %(qty0)s a %(qty1)s %(uom)s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The unit price has been updated on the order line with product '%(product)s' "
"from %(old)s to %(new)s %(currency)s"
msgstr ""
"Se ha actualizado el precio unitario en la línea de pedido con el producto "
"'%(product)s' de %(old)s a %(new)s %(currency)s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "There are no embedded XML file in this PDF file."
msgstr "No hay ningún archivo XML incorporado en este archivo PDF."
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This Import Type is not supported. Did you install the module to support "
"this type?"
msgstr ""
"Este Tipo de Importación no está admitido. ¿Has instalado el módulo para "
"admitir este tipo?"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "This XML file is not XML-compliant"
msgstr "Este archivo no es compatible con el formato XML"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This file '%(filename)s' is not recognized as a %(type)s file. Please check "
"the file and its extension."
msgstr ""
"Este archivo '%(filename)s' no se reconoce como un archivo %(type)s. "
"Compruebe el archivo y su extensión."
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This file '%s' is not recognised as a XML nor PDF file. Please check the "
"file and it's extension."
msgstr ""
"Este archivo '%s' no se reconoce como archivo XML ni PDF. Compruebe el "
"archivo y su extensión."
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "This order doesn't have any line !"
msgstr "¡Este pedido no tiene ninguna línea!"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "This quotation has been updated automatically via the import of file %s"
msgstr ""
"Este presupuesto se ha actualizado automáticamente mediante la importación "
"del fichero %s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This type of XML RFQ/order is not supported. Did you install the module to "
"support this XML format?"
msgstr ""
"Este tipo de petición de oferta/pedido XML no es compatible. ¿Ha instalado "
"el módulo para admitir este formato XML?"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Universal Business Language"
msgstr "Lenguaje Comercial Universal"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "Unsupported file format"
msgstr "Formato de archivo no soportado"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__state__update
msgid "Update"
msgstr "Actualizar"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Update Existing"
msgstr "Actualizar existente"
#. module: sale_order_import
#: model:ir.model.fields,help:sale_order_import.field_sale_order_import__order_file
msgid ""
"Upload a Request for Quotation or an Order file. Supported formats: XML and "
"PDF (PDF with an embeded XML file)."
msgstr ""
"Cargue una solicitud de presupuesto o un archivo de pedido. Formatos "
"admitidos: XML y PDF (PDF con un archivo XML incorporado)."
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"Upload below the customer order or request for quotation as XML or PDF file. "
"When you click on the Import button:"
msgstr ""
"Cargue a continuación el pedido del cliente o la solicitud de presupuesto "
"como archivo XML o PDF. Al hacer clic en el botón Importar:"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__import_type__xml
msgid "XML"
msgstr "XML"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "You must select a quotation to update."
msgstr "Debe seleccionar un presupuesto para actualizarlo."
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"format (UBL), you should install the module <em>sale_order_import_ubl</em>."
msgstr "(UBL), debe instalar el módulo <em>sale_order_import_ubl</em>."
#, fuzzy
#~ msgid "Csv Import"
#~ msgstr "Importar CSV"
#~ msgid "Missing customer"
#~ msgstr "Falta cliente"
#, fuzzy
#~ msgid "Quotation"
#~ msgstr "Presupuesto para actualizar"

View file

@ -0,0 +1,426 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_order_import
#
# Translators:
# OCA Transbot <transbot@odoo-community.org>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-12 13:36+0000\n"
"PO-Revision-Date: 2024-11-06 16:06+0000\n"
"Last-Translator: samibc2c <sami.bouzidi@camptocamp.com>\n"
"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n"
"Language: fr\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 5.6.2\n"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/models/sale.py:0
#: code:addons/sale_order_import/tests/test_sale_order.py:0
#, python-format
msgid " Amount w/o tax: %(amount)s %(currency)s"
msgstr " Montant hors taxe: %(amount)s %(currency)s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "%(orders)s new order line(s) created: %(label)s"
msgstr "%(orders)s nouvelle(s) ligne(s) de commande créée(s): %(label)s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "%(orders)s order line(s) deleted: %(label)s"
msgstr "%(orders)s ligne(s) de commande supprimée(s): %(label)s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"An order of customer '%(partner)s' with reference '%(ref)s' already exists: "
"%(name)s (state: %(state)s)"
msgstr ""
"Une commande avec la référence '%(ref)s' existe déjà pour le client "
"'%(partner)s': %(name)s (état: %(state)s)"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__price_source
msgid "Apply Prices From"
msgstr "Appliquer les prix à partir de"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Cancel"
msgstr "Annuler"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__commercial_partner_id
msgid "Commercial Entity"
msgstr "Entité commerciale"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__confirm_order
msgid "Confirm Order"
msgstr "Confirmer la commande"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Create New"
msgstr "Créer une nouvelle"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "Created automatically via file import (%s)."
msgstr "Créé automatiquement par importation de fichier (%s)."
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__create_uid
msgid "Created by"
msgstr "Créé par"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__create_date
msgid "Created on"
msgstr "Créé le"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__partner_id
msgid "Customer"
msgstr "Client"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__price_source__order
msgid "Customer Order"
msgstr "Commande client"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__display_name
msgid "Display Name"
msgstr "Nom affiché"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__doc_type
msgid "Document Type"
msgstr "Type de document"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__order_filename
msgid "Filename"
msgstr "Nom du fichier"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__id
msgid "ID"
msgstr "ID"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"If it is a PDF file, Odoo will try to find an XML file in the attachments of "
"the PDF file and then use this XML file to create the quotation."
msgstr ""
"S'il s'agit d'un document PDF, Odoo tentera de trouver un fichier XML en "
"pièce-jointe et utilisera ensuite ce document XML pour créer le devis."
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"If it is an XML file, Odoo will parse it if the module that adds support for "
"this XML format is installed. For the"
msgstr ""
"S'il s'agit d'un document XML, Odoo l'analysera si le module adéquat est "
"installé. Pour le"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__state__import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Import"
msgstr "Importer"
#. module: sale_order_import
#: model:ir.actions.act_window,name:sale_order_import.sale_order_import_action
#: model:ir.ui.menu,name:sale_order_import.sale_order_import_menu
msgid "Import RFQ or Order"
msgstr "Importer la demande ou la commande d'achat"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Import Sale Orders"
msgstr "Importer le bon de commande"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__import_type
msgid "Import Type"
msgstr "Type d'import"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import____last_update
msgid "Last Modified on"
msgstr "Dernière modification le"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__write_uid
msgid "Last Updated by"
msgstr "Dernière mise-à-jour par"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__write_date
msgid "Last Updated on"
msgstr "Dernière mise-à-jour le"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "No data provided"
msgstr "Aucune donnée fournie"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"No price is defined in the file. Please double check file or select "
"Pricelist as the source for prices."
msgstr ""
"Aucun prix définit dans le fichier. Veuillez vérifier le fichier ou "
"sélectionner une liste de prix source."
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__import_type__pdf
msgid "PDF"
msgstr "PDF"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "Please select a valid import type before importing!"
msgstr "Veuillez sélectionner un type d'importation valide avant d'importer!"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__price_source__pricelist
msgid "Pricelist"
msgstr "Liste de prix"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__sale_id
msgid "Quotation to Update"
msgstr "Devis à mettre à jour"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__doc_type__rfq
msgid "Request For Quotation"
msgstr "Demande de prix"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__order_file
msgid "Request for Quotation or Order"
msgstr "Demande de prix ou Bon de conmande"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__doc_type__order
msgid "Sale Order"
msgstr "Bon de commande"
#. module: sale_order_import
#: model:ir.model,name:sale_order_import.model_sale_order_import
msgid "Sale Order Import from Files"
msgstr ""
#. module: sale_order_import
#: model:ir.model,name:sale_order_import.model_sale_order
msgid "Sales Order"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,help:sale_order_import.field_sale_order_import__import_type
msgid "Select a type which you want to import"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__partner_shipping_id
msgid "Shipping Address"
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"Some quotations have been found for this customer ; one of them may "
"correspond to the order or RFQ that you are importing. You can either select "
"an existing quotation to update or create a new one."
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__state
msgid "State"
msgstr "Etat"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The currency of the imported order (%(old)s) is different from the currency "
"of the existing order (%(new)s)"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The customer '%(name)s' has a pricelist '%(pricelist)s' but the currency of "
"this order is '%(currency)s'."
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The quantity has been updated on the order line with product '%(product)s' "
"from %(qty0)s to %(qty1)s %(uom)s"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The unit price has been updated on the order line with product '%(product)s' "
"from %(old)s to %(new)s %(currency)s"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "There are no embedded XML file in this PDF file."
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This Import Type is not supported. Did you install the module to support "
"this type?"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "This XML file is not XML-compliant"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This file '%(filename)s' is not recognized as a %(type)s file. Please check "
"the file and its extension."
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This file '%s' is not recognised as a XML nor PDF file. Please check the "
"file and it's extension."
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "This order doesn't have any line !"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "This quotation has been updated automatically via the import of file %s"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This type of XML RFQ/order is not supported. Did you install the module to "
"support this XML format?"
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Universal Business Language"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "Unsupported file format"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__state__update
msgid "Update"
msgstr "Mettre à jour"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Update Existing"
msgstr "Mettre à jour une existante"
#. module: sale_order_import
#: model:ir.model.fields,help:sale_order_import.field_sale_order_import__order_file
msgid ""
"Upload a Request for Quotation or an Order file. Supported formats: XML and "
"PDF (PDF with an embeded XML file)."
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"Upload below the customer order or request for quotation as XML or PDF file. "
"When you click on the Import button:"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__import_type__xml
msgid "XML"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "You must select a quotation to update."
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"format (UBL), you should install the module <em>sale_order_import_ubl</em>."
msgstr ""
#, fuzzy
#~ msgid "Csv Import"
#~ msgstr "Importer"

View file

@ -0,0 +1,447 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_order_import
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2025-07-24 16:25+0000\n"
"Last-Translator: mymage <stefano.consolaro@mymage.it>\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"
"X-Generator: Weblate 5.10.4\n"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/models/sale.py:0
#: code:addons/sale_order_import/tests/test_sale_order.py:0
#, python-format
msgid " Amount w/o tax: %(amount)s %(currency)s"
msgstr " Valore senza imposte: %(amount)s %(currency)s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "%(orders)s new order line(s) created: %(label)s"
msgstr "%(orders)s nuova riga(e) ordine creata: %(label)s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "%(orders)s order line(s) deleted: %(label)s"
msgstr "%(orders)s riga(e) ordine cancellata: %(label)s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"An order of customer '%(partner)s' with reference '%(ref)s' already exists: "
"%(name)s (state: %(state)s)"
msgstr ""
"Un ordine del cliente '%(partner)s' con riferimento '%(ref)s' esiste già: "
"%(name)s (stato: %(state)s)"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__price_source
msgid "Apply Prices From"
msgstr "Maschera applicazione prezzi"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Cancel"
msgstr "Annulla"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__commercial_partner_id
msgid "Commercial Entity"
msgstr "Entità commerciale"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__confirm_order
msgid "Confirm Order"
msgstr "Conferma ordine"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Create New"
msgstr "Crea nuovo"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "Created automatically via file import (%s)."
msgstr "Creati automaticamente con importazione file (%s)."
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__create_uid
msgid "Created by"
msgstr "Creato da"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__create_date
msgid "Created on"
msgstr "Creato il"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__partner_id
msgid "Customer"
msgstr "Cliente"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__price_source__order
msgid "Customer Order"
msgstr "Ordine cliente"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__display_name
msgid "Display Name"
msgstr "Nome visualizzato"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__doc_type
msgid "Document Type"
msgstr "Tipo documento"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__order_filename
msgid "Filename"
msgstr "Nome file"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__id
msgid "ID"
msgstr "ID"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"If it is a PDF file, Odoo will try to find an XML file in the attachments of"
" the PDF file and then use this XML file to create the quotation."
msgstr ""
"Se è un file PDF, Odoo cercherà di trovare un file XML allegato al file PDF "
"e usarlo per creare il preventivo."
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"If it is an XML file, Odoo will parse it if the module that adds support for"
" this XML format is installed. For the"
msgstr ""
"Se è un file XML, Odoo lo analizzerà se è installato il modulo che aggiunge "
"il supporto per questo formato XML. Per il"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__state__import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Import"
msgstr "Importa"
#. module: sale_order_import
#: model:ir.actions.act_window,name:sale_order_import.sale_order_import_action
#: model:ir.ui.menu,name:sale_order_import.sale_order_import_menu
msgid "Import RFQ or Order"
msgstr "Importa RdP o ordine"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Import Sale Orders"
msgstr "Importa gli ordini di vendita"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__import_type
msgid "Import Type"
msgstr "Tipo importazione"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import____last_update
msgid "Last Modified on"
msgstr "Ultima modifica il"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__write_uid
msgid "Last Updated by"
msgstr "Ultimo aggiornamento di"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__write_date
msgid "Last Updated on"
msgstr "Ultimo aggiornamento il"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "No data provided"
msgstr "Nessun dato fornito"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"No price is defined in the file. Please double check file or select "
"Pricelist as the source for prices."
msgstr ""
"Nessun prezzo definito nel file. Ricontrollare il file o selezionare un "
"listino per i prezzi."
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__import_type__pdf
msgid "PDF"
msgstr "PDF"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "Please select a valid import type before importing!"
msgstr "Selezionare un tipo importazione valido prima di importare!"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__price_source__pricelist
msgid "Pricelist"
msgstr "Listino prezzi"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__sale_id
msgid "Quotation to Update"
msgstr "Preventivo da aggiornare"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__doc_type__rfq
msgid "Request For Quotation"
msgstr "Richiesta di preventivo"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__order_file
msgid "Request for Quotation or Order"
msgstr "Richiesta di preventivo o ordine"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__doc_type__order
msgid "Sale Order"
msgstr "Ordine di vendita"
#. module: sale_order_import
#: model:ir.model,name:sale_order_import.model_sale_order_import
msgid "Sale Order Import from Files"
msgstr "Importazione ordine di vendita da file"
#. module: sale_order_import
#: model:ir.model,name:sale_order_import.model_sale_order
msgid "Sales Order"
msgstr "Ordine di vendita"
#. module: sale_order_import
#: model:ir.model.fields,help:sale_order_import.field_sale_order_import__import_type
msgid "Select a type which you want to import"
msgstr "Selezionare un tipo che si vuole importare"
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__partner_shipping_id
msgid "Shipping Address"
msgstr "Indirizzo di spedizione"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"Some quotations have been found for this customer ; one of them may "
"correspond to the order or RFQ that you are importing. You can either select"
" an existing quotation to update or create a new one."
msgstr ""
"Sono stati trovati alcuni preventivi per questo cliente; uno di essi può "
"corrispondere all'ordine o alla RdP che si sta importando. Si può "
"selezionare un preventivo esistente o crearne uno nuovo."
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__state
msgid "State"
msgstr "Stato"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The currency of the imported order (%(old)s) is different from the currency "
"of the existing order (%(new)s)"
msgstr ""
"La valuta dell'ordine importato (%(old)s) è diversa dalla valuta dell'ordine "
"esistente (%(new)s)"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The customer '%(name)s' has a pricelist '%(pricelist)s' but the currency of "
"this order is '%(currency)s'."
msgstr ""
"Il cliente '%(name)s' ha un listino '%(pricelist)s' ma la valuta dell'ordine "
"è '%(currency)s'."
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The quantity has been updated on the order line with product '%(product)s' "
"from %(qty0)s to %(qty1)s %(uom)s"
msgstr ""
"La quantità è stata aggiornata nella riga ordine con prodotto '%(product)s' "
"da %(qty0)s a %(qty1)s %(uom)s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The unit price has been updated on the order line with product '%(product)s'"
" from %(old)s to %(new)s %(currency)s"
msgstr ""
"Il prezzo unitario è stato aggiornato nella riga ordine con prodotto "
"'%(product)s' da %(old)s a %(new)s %(currency)s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "There are no embedded XML file in this PDF file."
msgstr "In questo PDF non c'è un file XML integrato."
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This Import Type is not supported. Did you install the module to support "
"this type?"
msgstr ""
"Questo tipo di importazione non è supportato. Il modulo per supportarlo è "
"stato installato?"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "This XML file is not XML-compliant"
msgstr "Il file XML non è compatibile al formato XML"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This file '%(filename)s' is not recognized as a %(type)s file. Please check "
"the file and its extension."
msgstr ""
"Questo file '%(filename)s' non è riconosciuto come file %(type)s. "
"Controllare il file e la sua estensione."
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This file '%s' is not recognised as a XML nor PDF file. Please check the "
"file and it's extension."
msgstr ""
"Il file '%s' non è riconosciuto come file XML o PDF. Controllare il file e "
"la sua estensione."
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "This order doesn't have any line !"
msgstr "Questo ordine non ha righe!"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This quotation has been updated automatically via the import of file %s"
msgstr ""
"Il preventivo è stato aggiornato automaticamente con l'importazione del file "
"%s"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This type of XML RFQ/order is not supported. Did you install the module to "
"support this XML format?"
msgstr ""
"Questo tipo RdP/ordine XML non è supportato. Il modulo per supportare questo "
"formato è stato installato?"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Universal Business Language"
msgstr "Linguaggio commerciale universale"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "Unsupported file format"
msgstr "Formato file non supportato"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__state__update
msgid "Update"
msgstr "Aggiorna"
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Update Existing"
msgstr "Aggiorna esistente"
#. module: sale_order_import
#: model:ir.model.fields,help:sale_order_import.field_sale_order_import__order_file
msgid ""
"Upload a Request for Quotation or an Order file. Supported formats: XML and "
"PDF (PDF with an embeded XML file)."
msgstr ""
"Caricare un file richiesta di preventivo o un ordine. Formati supportati: "
"XML e PDF (PDF con file XML integrato)."
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"Upload below the customer order or request for quotation as XML or PDF file."
" When you click on the Import button:"
msgstr ""
"Caricare in calce l'ordine cliente o la richiesta di preventivo come file "
"XML o PDF. Quando si fa clic sul pulsante importazione:"
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__import_type__xml
msgid "XML"
msgstr "XML"
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "You must select a quotation to update."
msgstr "Bisogna selezionare un preventivo da aggiornare."
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"format (UBL), you should install the module <em>sale_order_import_ubl</em>."
msgstr ""
"formato (UBL), bisogna installare il modulo <em>sale_order_import_ubl</em>."

View file

@ -0,0 +1,410 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_order_import
#
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: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/models/sale.py:0
#: code:addons/sale_order_import/tests/test_sale_order.py:0
#, python-format
msgid " Amount w/o tax: %(amount)s %(currency)s"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "%(orders)s new order line(s) created: %(label)s"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "%(orders)s order line(s) deleted: %(label)s"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"An order of customer '%(partner)s' with reference '%(ref)s' already exists: "
"%(name)s (state: %(state)s)"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__price_source
msgid "Apply Prices From"
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Cancel"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__commercial_partner_id
msgid "Commercial Entity"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__confirm_order
msgid "Confirm Order"
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Create New"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "Created automatically via file import (%s)."
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__create_uid
msgid "Created by"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__create_date
msgid "Created on"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__partner_id
msgid "Customer"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__price_source__order
msgid "Customer Order"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__display_name
msgid "Display Name"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__doc_type
msgid "Document Type"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__order_filename
msgid "Filename"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__id
msgid "ID"
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"If it is a PDF file, Odoo will try to find an XML file in the attachments of"
" the PDF file and then use this XML file to create the quotation."
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"If it is an XML file, Odoo will parse it if the module that adds support for"
" this XML format is installed. For the"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__state__import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Import"
msgstr ""
#. module: sale_order_import
#: model:ir.actions.act_window,name:sale_order_import.sale_order_import_action
#: model:ir.ui.menu,name:sale_order_import.sale_order_import_menu
msgid "Import RFQ or Order"
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Import Sale Orders"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__import_type
msgid "Import Type"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import____last_update
msgid "Last Modified on"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__write_uid
msgid "Last Updated by"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__write_date
msgid "Last Updated on"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "No data provided"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"No price is defined in the file. Please double check file or select "
"Pricelist as the source for prices."
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__import_type__pdf
msgid "PDF"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "Please select a valid import type before importing!"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__price_source__pricelist
msgid "Pricelist"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__sale_id
msgid "Quotation to Update"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__doc_type__rfq
msgid "Request For Quotation"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__order_file
msgid "Request for Quotation or Order"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__doc_type__order
msgid "Sale Order"
msgstr ""
#. module: sale_order_import
#: model:ir.model,name:sale_order_import.model_sale_order_import
msgid "Sale Order Import from Files"
msgstr ""
#. module: sale_order_import
#: model:ir.model,name:sale_order_import.model_sale_order
msgid "Sales Order"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,help:sale_order_import.field_sale_order_import__import_type
msgid "Select a type which you want to import"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__partner_shipping_id
msgid "Shipping Address"
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"Some quotations have been found for this customer ; one of them may "
"correspond to the order or RFQ that you are importing. You can either select"
" an existing quotation to update or create a new one."
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,field_description:sale_order_import.field_sale_order_import__state
msgid "State"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The currency of the imported order (%(old)s) is different from the currency "
"of the existing order (%(new)s)"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The customer '%(name)s' has a pricelist '%(pricelist)s' but the currency of "
"this order is '%(currency)s'."
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The quantity has been updated on the order line with product '%(product)s' "
"from %(qty0)s to %(qty1)s %(uom)s"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"The unit price has been updated on the order line with product '%(product)s'"
" from %(old)s to %(new)s %(currency)s"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "There are no embedded XML file in this PDF file."
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This Import Type is not supported. Did you install the module to support "
"this type?"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "This XML file is not XML-compliant"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This file '%(filename)s' is not recognized as a %(type)s file. Please check "
"the file and its extension."
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This file '%s' is not recognised as a XML nor PDF file. Please check the "
"file and it's extension."
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "This order doesn't have any line !"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This quotation has been updated automatically via the import of file %s"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid ""
"This type of XML RFQ/order is not supported. Did you install the module to "
"support this XML format?"
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Universal Business Language"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "Unsupported file format"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__state__update
msgid "Update"
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid "Update Existing"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields,help:sale_order_import.field_sale_order_import__order_file
msgid ""
"Upload a Request for Quotation or an Order file. Supported formats: XML and "
"PDF (PDF with an embeded XML file)."
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"Upload below the customer order or request for quotation as XML or PDF file."
" When you click on the Import button:"
msgstr ""
#. module: sale_order_import
#: model:ir.model.fields.selection,name:sale_order_import.selection__sale_order_import__import_type__xml
msgid "XML"
msgstr ""
#. module: sale_order_import
#. odoo-python
#: code:addons/sale_order_import/wizard/sale_order_import.py:0
#, python-format
msgid "You must select a quotation to update."
msgstr ""
#. module: sale_order_import
#: model_terms:ir.ui.view,arch_db:sale_order_import.sale_order_import_form
msgid ""
"format (UBL), you should install the module <em>sale_order_import_ubl</em>."
msgstr ""

View file

@ -0,0 +1,3 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from . import sale

View file

@ -0,0 +1,27 @@
# © 2016-2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import _, models
class SaleOrder(models.Model):
_inherit = "sale.order"
def name_get(self):
"""Add amount_untaxed in name_get of sale orders"""
res = super().name_get()
if self._context.get("sale_order_show_amount"):
new_res = []
for (sale_id, name) in res:
sale = self.browse(sale_id)
# TODO: find a python method to easily display a float + currency
# symbol (before or after) depending on lang of context and currency
name += _(
" Amount w/o tax: %(amount)s %(currency)s",
amount=sale.amount_untaxed,
currency=sale.currency_id.name,
)
new_res.append((sale_id, name))
return new_res
else:
return res

View file

@ -0,0 +1,5 @@
* Alexis de Lattre <alexis.delattre@akretion.com>
* Dennis Sluijk <d.sluijk@onestein.nl>
* Andrea Stirpe <a.stirpe@onestein.nl>
* Simone Orsi <simone.orsi@camptocamp.com>
* Duong (Tran Quoc) <duongtq@trobz.com>

View file

@ -0,0 +1 @@
The migration of this module from 13.0 to 16.0 was financially supported by Camptocamp

View file

@ -0,0 +1,7 @@
This module adds support for the import of electronic RFQ or orders. This module provides the base methods to import electronic orders, and you can also plug additional formats by extending the wizard. It requires additional modules to support specific order formats:
* module *sale_order_import_ubl*: adds support for `Universal Business Language (UBL) <http://ubl.xml.org/>`_ RFQs and orders as:
- XML file,
- PDF file with an embedded XML file.

View file

@ -0,0 +1,5 @@
This module adds a wizard in the sale menu named *Import RFQ or Order*. This wizard will propose you to select the order or RFQ file. Depending on the format of the file (XML or PDF) and the type of file (RFQ or order), it may propose you additional options.
When you import an order, if there is a quotation in Odoo for the same customer, the wizard will propose you to either update the existing quotation or create a new order (in fact, it will create a new quotation, so that you are free to make some modifications before you click on the *Confirm Sale* button to convert the quotation to a sale order).
Once the RFQ/order is imported, you should read the messages in the chatter of the quotation because it may contain important information about the import.

View file

@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sale_order_import,access_sale_order_import,model_sale_order_import,sales_team.group_sale_salesman,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_sale_order_import access_sale_order_import model_sale_order_import sales_team.group_sale_salesman 1 1 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View file

@ -0,0 +1,453 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>README.rst</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document">
<a class="reference external image-reference" href="https://odoo-community.org/get-involved?utm_source=readme">
<img alt="Odoo Community Association" src="https://odoo-community.org/readme-banner-image" />
</a>
<div class="section" id="sale-order-import">
<h1>Sale Order Import</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:8e01d803e464dc07c4ec36557747613a5f3db4de2c5c712b493c596addb6ce35
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/license-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/edi/tree/16.0/sale_order_import"><img alt="OCA/edi" src="https://img.shields.io/badge/github-OCA%2Fedi-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/edi-16-0/edi-16-0-sale_order_import"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/edi&amp;target_branch=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module adds support for the import of electronic RFQ or orders. This module provides the base methods to import electronic orders, and you can also plug additional formats by extending the wizard. It requires additional modules to support specific order formats:</p>
<ul class="simple">
<li>module <em>sale_order_import_ubl</em>: adds support for <a class="reference external" href="http://ubl.xml.org/">Universal Business Language (UBL)</a> RFQs and orders as:<ul>
<li>XML file,</li>
<li>PDF file with an embedded XML file.</li>
</ul>
</li>
</ul>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="toc-entry-1">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li>
<li><a class="reference internal" href="#other-credits" id="toc-entry-6">Other credits</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-7">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h2><a class="toc-backref" href="#toc-entry-1">Usage</a></h2>
<p>This module adds a wizard in the sale menu named <em>Import RFQ or Order</em>. This wizard will propose you to select the order or RFQ file. Depending on the format of the file (XML or PDF) and the type of file (RFQ or order), it may propose you additional options.</p>
<p>When you import an order, if there is a quotation in Odoo for the same customer, the wizard will propose you to either update the existing quotation or create a new order (in fact, it will create a new quotation, so that you are free to make some modifications before you click on the <em>Confirm Sale</em> button to convert the quotation to a sale order).</p>
<p>Once the RFQ/order is imported, you should read the messages in the chatter of the quotation because it may contain important information about the import.</p>
</div>
<div class="section" id="bug-tracker">
<h2><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h2>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/edi/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/edi/issues/new?body=module:%20sale_order_import%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h2><a class="toc-backref" href="#toc-entry-3">Credits</a></h2>
<div class="section" id="authors">
<h3><a class="toc-backref" href="#toc-entry-4">Authors</a></h3>
<ul class="simple">
<li>Akretion</li>
<li>Camptocamp</li>
</ul>
</div>
<div class="section" id="contributors">
<h3><a class="toc-backref" href="#toc-entry-5">Contributors</a></h3>
<ul class="simple">
<li>Alexis de Lattre &lt;<a class="reference external" href="mailto:alexis.delattre&#64;akretion.com">alexis.delattre&#64;akretion.com</a>&gt;</li>
<li>Dennis Sluijk &lt;<a class="reference external" href="mailto:d.sluijk&#64;onestein.nl">d.sluijk&#64;onestein.nl</a>&gt;</li>
<li>Andrea Stirpe &lt;<a class="reference external" href="mailto:a.stirpe&#64;onestein.nl">a.stirpe&#64;onestein.nl</a>&gt;</li>
<li>Simone Orsi &lt;<a class="reference external" href="mailto:simone.orsi&#64;camptocamp.com">simone.orsi&#64;camptocamp.com</a>&gt;</li>
<li>Duong (Tran Quoc) &lt;<a class="reference external" href="mailto:duongtq&#64;trobz.com">duongtq&#64;trobz.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="other-credits">
<h3><a class="toc-backref" href="#toc-entry-6">Other credits</a></h3>
<p>The migration of this module from 13.0 to 16.0 was financially supported by Camptocamp</p>
</div>
<div class="section" id="maintainers">
<h3><a class="toc-backref" href="#toc-entry-7">Maintainers</a></h3>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>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.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/edi/tree/16.0/sale_order_import">OCA/edi</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,5 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from . import test_sale_order
from . import test_order_import
from . import test_parse_validate

View file

@ -0,0 +1,22 @@
# Copyright 2022 Camptocamp SA
# @author: Simone Orsi <simahawk@gmail.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import base64
import os
from odoo.tests.common import TransactionCase
class TestCommon(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
cls.wiz_model = cls.env["sale.order.import"]
cls.partner = cls.env["res.partner"].create({"name": "SO Test"})
def read_test_file(self, filename, mode="r", as_b64=False):
path = os.path.join(os.path.dirname(__file__), "fixtures", filename)
with open(path, mode) as thefile:
content = thefile.read()
return content if not as_b64 else base64.b64encode(content)

View file

@ -0,0 +1,182 @@
# Copyright 2018 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# Copyright 2022 Camptocamp SA
# @author: Simone Orsi <simahawk@gmail.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import base64
from unittest import mock
from odoo import exceptions
from odoo.tests.common import Form
from .common import TestCommon
class TestOrderImport(TestCommon):
"""Test order create/update."""
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.parsed_order = {
"partner": {"email": "deco.addict82@example.com"},
"date": "2018-08-14",
"order_ref": "TEST1242",
"lines": [
{
"product": {"code": "FURN_8888"},
"qty": 2,
"uom": {"unece_code": "C62"},
"price_unit": 12.42,
}
],
"chatter_msg": [],
"doc_type": "rfq",
}
def test_order_import(self):
order = self.wiz_model.create_order(self.parsed_order, "pricelist")
self.assertEqual(order.client_order_ref, self.parsed_order["order_ref"])
self.assertEqual(
order.order_line[0].product_id.default_code,
self.parsed_order["lines"][0]["product"]["code"],
)
self.assertEqual(int(order.order_line[0].product_uom_qty), 2)
# Now update the order
parsed_order_up = dict(
self.parsed_order,
partner={"email": "agrolait@yourcompany.example.com"},
lines=[
{
"product": {"code": "FURN_8888"},
"qty": 3,
"uom": {"unece_code": "C62"},
"price_unit": 12.42,
},
{
"product": {"code": "FURN_9999"},
"qty": 1,
"uom": {"unece_code": "C62"},
"price_unit": 1.42,
},
],
)
self.wiz_model.update_order_lines(parsed_order_up, order, "pricelist")
self.assertEqual(len(order.order_line), 2)
self.assertEqual(int(order.order_line[0].product_uom_qty), 3)
# test raise UserError if not price_unit
parsed_order_up_no_price_unit = dict(
self.parsed_order,
partner={"email": "agrolait@yourcompany.example.com"},
lines=[
{
"product": {"code": "FURN_7777"},
"qty": 4,
"uom": {"unece_code": "C62"},
},
],
)
parsed_order_up_no_price_unit["doc_type"] = "order"
parsed_order_up_no_price_unit["price_source"] = "order"
expected_msg = (
"No price is defined in the file. Please double check "
"file or select Pricelist as the source for prices."
)
with self.assertRaisesRegex(exceptions.UserError, expected_msg):
self.wiz_model.update_order_lines(
parsed_order_up_no_price_unit, order, "order"
)
def test_order_import_action(self):
wiz = self.wiz_model.create({"import_type": "xml"})
action = wiz.create_order_return_action(self.parsed_order, "order.ref")
order = self.env["sale.order"].browse(action["res_id"])
self.assertEqual(order.state, "draft")
def test_order_import_confirm(self):
wiz = self.wiz_model.create({"import_type": "xml", "confirm_order": True})
action = wiz.create_order_return_action(self.parsed_order, "order.ref")
order = self.env["sale.order"].browse(action["res_id"])
self.assertEqual(order.state, "sale")
def test_order_import_default_so_vals(self):
default = {"client_order_ref": "OVERRIDE"}
order = self.wiz_model.with_context(
sale_order_import__default_vals=dict(order=default)
).create_order(self.parsed_order, "pricelist")
self.assertEqual(order.client_order_ref, "OVERRIDE")
def test_with_order_buttons(self):
# Prepare test data
order_file_data = base64.b64encode(
b"<?xml version='1.0' encoding='utf-8'?><root><foo>baz</foo></root>"
)
order_filename = "test_order.xml"
mock_parse_order = mock.patch.object(type(self.wiz_model), "parse_xml_order")
# Create a new form
with Form(
self.wiz_model.with_context(
default_order_filename=order_filename,
)
) as form:
with mock_parse_order as mocked:
# Return 'rfq' for doc_type
mocked.return_value = "rfq"
# Set values for the required fields
form.import_type = "xml"
form.order_file = order_file_data
mocked.assert_called()
# Test the button with the simulated values
mocked.return_value = self.parsed_order
action = form.save().import_order_button()
self.assertEqual(action["xml_id"], "sale.action_quotations")
self.assertEqual(action["view_mode"], "form,tree,calendar,graph")
self.assertEqual(action["view_id"], False)
mocked.assert_called()
so = self.env["sale.order"].browse(action["res_id"])
self.assertEqual(so.partner_id.email, "deco.addict82@example.com")
self.assertEqual(so.client_order_ref, "TEST1242")
self.assertEqual(so.order_line.product_id.code, "FURN_8888")
self.assertEqual(so.state, "draft")
# Create another form to update the above sale order
with Form(
self.wiz_model.with_context(
default_order_filename=order_filename,
)
) as form:
with mock_parse_order as mocked:
# Return 'rfq' for doc_type
mocked.return_value = "rfq"
# Set the required fields
form.import_type = "xml"
form.order_file = order_file_data
parsed_order_up = dict(
self.parsed_order,
lines=[
{
"product": {"code": "FURN_8888"},
"qty": 3,
"uom": {"unece_code": "C62"},
"price_unit": 12.42,
},
{
"product": {"code": "FURN_9999"},
"qty": 1,
"uom": {"unece_code": "C62"},
"price_unit": 1.42,
},
],
)
mocked.return_value = parsed_order_up
action = form.save().import_order_button()
form = form.save()
self.assertEqual(
action["xml_id"], "sale_order_import.sale_order_import_action"
)
self.assertEqual(form.state, "update")
self.assertEqual(form.sale_id, so)
form.update_order_button()
self.assertEqual(len(so.order_line), 2)
self.assertEqual(so.order_line[0].product_uom_qty, 3)

View file

@ -0,0 +1,170 @@
# Copyright 2022 Camptocamp SA
# @author: Simone Orsi <simahawk@gmail.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import base64
from unittest import mock
from lxml import etree
from odoo import exceptions
from odoo.tests.common import Form
from .common import TestCommon
class TestParsingValidation(TestCommon):
"""Mostly unit tests on wizard parsing methods."""
def test_wrong_import_type(self):
order_file_data = base64.b64encode(
b"<?xml version='1.0' encoding='utf-8'?><root><foo>baz</foo></root>"
)
order_filename = "test_order.xml"
expected_error_message = (
"This file 'test_order.xml' is not recognized as"
" a PDF file. Please check the file and its extension."
)
with self.assertRaisesRegex(exceptions.UserError, expected_error_message):
with Form(
self.wiz_model.with_context(default_order_filename=order_filename)
) as form:
form.import_type = "pdf"
form.order_file = order_file_data
def test_onchange_validation_xml(self):
xml_data = base64.b64encode(
b"<?xml version='1.0' encoding='utf-8'?><root><foo>baz</foo></root>"
)
# Simulate bad file handling
mock_parse_xml = mock.patch.object(type(self.wiz_model), "_parse_xml")
with Form(
self.wiz_model.with_context(default_order_filename="test.xml")
) as form:
with mock_parse_xml as mocked:
mocked.return_value = ("", "I don't like this file")
with self.assertRaisesRegex(
exceptions.UserError, "I don't like this file"
):
form.import_type = "xml"
form.order_file = xml_data
mocked.assert_called()
mock_parse_order = mock.patch.object(type(self.wiz_model), "parse_xml_order")
with Form(
self.wiz_model.with_context(default_order_filename="test.xml")
) as form:
with mock_parse_order as mocked:
mocked.return_value = "rfq"
form.import_type = "xml"
form.order_file = xml_data
mocked.assert_called()
self.assertEqual(form.doc_type, "rfq")
def test_onchange_validation_pdf(self):
pdf_data = self.read_test_file("test.pdf", mode="rb", as_b64=True)
mock_parse_order = mock.patch.object(type(self.wiz_model), "parse_pdf_order")
with Form(
self.wiz_model.with_context(default_order_filename="test.pdf")
) as form:
with mock_parse_order as mocked:
mocked.return_value = "rfq"
form.import_type = "pdf"
form.order_file = pdf_data
mocked.assert_called()
self.assertEqual(form.doc_type, "rfq")
def test_parse_xml_bad(self):
xml_root, error_msg = self.wiz_model._parse_xml("")
self.assertEqual(xml_root, None)
self.assertEqual(error_msg, "No data provided")
xml_root, error_msg = self.wiz_model._parse_xml("something_wrong")
self.assertEqual(xml_root, None)
self.assertEqual(error_msg, "This XML file is not XML-compliant")
def test_parse_xml_unsupported(self):
xml_data = b"<?xml version='1.0' encoding='utf-8'?><root><foo>baz</foo></root>"
xml_root, error_msg = self.wiz_model._parse_xml(xml_data)
self.assertTrue(isinstance(xml_root, etree._Element))
# Due to parse_xml_order NotImplementedError
mock_parse_order = mock.patch.object(type(self.wiz_model), "parse_xml_order")
with mock_parse_order as mocked:
mocked.side_effect = exceptions.UserError("I don't like this file")
self.assertTrue(isinstance(xml_root, etree._Element))
def test_parse_xml_good(self):
xml_data = b"<?xml version='1.0' encoding='utf-8'?><root><foo>baz</foo></root>"
mock_parse_order = mock.patch.object(type(self.wiz_model), "parse_xml_order")
with mock_parse_order as mocked:
mocked.return_value = "rfq"
xml_root, error_msg = self.wiz_model._parse_xml(xml_data)
self.assertTrue(isinstance(xml_root, etree._Element))
self.assertTrue(error_msg is None)
def test_parse_pdf_bad(self):
pdf_data = self.read_test_file("test.pdf", mode="rb", as_b64=True)
mock_pdf_get_xml_files = mock.patch.object(
type(self.env["pdf.helper"]), "pdf_get_xml_files"
)
with mock_pdf_get_xml_files as mocked:
mocked.return_value = {}
with self.assertRaisesRegex(
exceptions.UserError, "There are no embedded XML file in this PDF file."
):
self.wiz_model.parse_pdf_order(pdf_data)
mocked.assert_called()
def test_parse_pdf_good(self):
pdf_data = self.read_test_file("test.pdf", mode="rb", as_b64=True)
mock_pdf_get_xml_files = mock.patch.object(
type(self.env["pdf.helper"]), "pdf_get_xml_files"
)
mock_parse_xml_order = mock.patch.object(
type(self.wiz_model), "parse_xml_order"
)
with mock_pdf_get_xml_files as m1, mock_parse_xml_order as m2:
m1.return_value = {
"test.pdf": etree.fromstring(
b"<?xml version='1.0' encoding='utf-8'?><root><foo>baz</foo></root>"
)
}
fake_parsed_order = {"got": "a wonderful order"}
m2.return_value = fake_parsed_order
res = self.wiz_model.parse_pdf_order(pdf_data)
m1.assert_called()
m2.assert_called()
self.assertEqual(res, fake_parsed_order)
def test_parse_pdf_good_but_no_file(self):
pdf_data = self.read_test_file("test.pdf", mode="rb", as_b64=True)
mock_pdf_get_xml_files = mock.patch.object(
type(self.env["pdf.helper"]), "pdf_get_xml_files"
)
mock_parse_xml_order = mock.patch.object(
type(self.wiz_model), "parse_xml_order"
)
with mock_pdf_get_xml_files as m1, mock_parse_xml_order as m2:
m1.return_value = {
"test.pdf": etree.fromstring(
b"<?xml version='1.0' encoding='utf-8'?><root><foo>baz</foo></root>"
)
}
m2.side_effect = etree.LxmlError("Bad XML sir!")
expected_msg = (
"This type of XML RFQ/order is not supported. Did you install "
"the module to support this XML format?"
)
with self.assertRaisesRegex(exceptions.UserError, expected_msg):
self.wiz_model.parse_pdf_order(pdf_data)
m1.assert_called()
m2.assert_called()
# same w/ UserError catched somewhere else
m2.side_effect = exceptions.UserError("Something is wrong w/ this file")
with self.assertRaisesRegex(exceptions.UserError, expected_msg):
self.wiz_model.parse_pdf_order(pdf_data)
m1.assert_called()
m2.assert_called()

View file

@ -0,0 +1,25 @@
# Copyright 2018 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# Copyright 2022 Camptocamp SA
# @author: Simone Orsi <simahawk@gmail.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import _
from odoo.tests.common import TransactionCase
class TestOrderImport(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
def test_name_get(self):
sale_order = self.env.ref("sale.sale_order_1")
name = sale_order.name + _(
" Amount w/o tax: %(amount)s %(currency)s",
amount=sale_order.amount_untaxed,
currency=sale_order.currency_id.name,
)
so = self.env["sale.order"].with_context(sale_order_show_amount=True)
name_get_res = so.search([("id", "=", sale_order.id)]).name_get()
self.assertEqual(name, name_get_res[0][1])

View file

@ -0,0 +1,3 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from . import sale_order_import

View file

@ -0,0 +1,690 @@
# Copyright 2016-2017 Akretion
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# Copyright 2022 Camptocamp
# @author: Simone Orsi <simahawk@gmail.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import logging
import mimetypes
from base64 import b64decode, b64encode
from lxml import etree
from odoo import _, api, fields, models
from odoo.exceptions import UserError
from odoo.osv.expression import AND
from odoo.tools import config, float_compare, float_is_zero
logger = logging.getLogger(__name__)
class SaleOrderImport(models.TransientModel):
_name = "sale.order.import"
_description = "Sale Order Import from Files"
state = fields.Selection(
[("import", "Import"), ("update", "Update")], default="import"
)
partner_id = fields.Many2one("res.partner", string="Customer")
import_type = fields.Selection(
[("xml", "XML"), ("pdf", "PDF")],
required=True,
default=None,
help="Select a type which you want to import",
)
order_file = fields.Binary(
string="Request for Quotation or Order",
required=True,
help="Upload a Request for Quotation or an Order file. Supported "
"formats: XML and PDF (PDF with an embeded XML file).",
)
order_filename = fields.Char(string="Filename")
doc_type = fields.Selection(
[("rfq", "Request For Quotation"), ("order", "Sale Order")],
string="Document Type",
readonly=True,
)
price_source = fields.Selection(
[("pricelist", "Pricelist"), ("order", "Customer Order")],
string="Apply Prices From",
)
# for state = update
commercial_partner_id = fields.Many2one(
"res.partner", string="Commercial Entity", readonly=True
)
partner_shipping_id = fields.Many2one(
"res.partner", string="Shipping Address", readonly=True
)
sale_id = fields.Many2one("sale.order", string="Quotation to Update")
confirm_order = fields.Boolean(default=False)
@api.onchange("order_file")
def order_file_change(self):
if not self.order_filename or not self.order_file:
self.doc_type = False
return
doc_type = self._parse_file(
self.order_filename, b64decode(self.order_file), detect_doc_type=True
)
if doc_type is None:
return {"warning": self._unsupported_file_msg(self.order_filename)}
self.doc_type = doc_type
def _get_supported_types(self):
# Define the supported types dictionary
supported_types = {
"xml": ("application/xml", "text/xml"),
"pdf": ("application/pdf"),
}
return supported_types
def _parse_file(self, filename, filecontent, detect_doc_type=False):
assert filename, "Missing filename"
assert filecontent, "Missing file content"
filetype = mimetypes.guess_type(filename)
logger.debug("Order file mimetype: %s", filetype)
mimetype = filetype[0]
supported_types = self._get_supported_types()
# Check if the selected import type is supported
if self.import_type not in supported_types:
raise UserError(_("Please select a valid import type before importing!"))
# Check if the detected MIME type is supported for the selected import type
if mimetype not in supported_types[self.import_type]:
raise UserError(
_(
"This file '%(filename)s' is not recognized as a %(type)s file. "
"Please check the file and its extension.",
filename=filename,
type=self.import_type.upper(),
)
)
if parser_method := getattr(self, f"parse_{self.import_type}_order", None):
return parser_method(filecontent, detect_doc_type=detect_doc_type)
else:
logger.error(
"%(meth)s not found %(itype)s not supported",
meth=f"parse_{self.import_type}_order",
itype=self.import_type,
)
raise UserError(
_(
"This Import Type is not supported. Did you install "
"the module to support this type?"
)
)
def _unsupported_file_msg(self, filename):
return {
"title": _("Unsupported file format"),
"message": _(
"This file '%s' is not recognised as a XML nor "
"PDF file. Please check the file and it's "
"extension."
)
% filename,
}
@api.model
def _parse_xml(self, data):
if not data:
return None, _("No data provided")
xml_root = None
try:
xml_root = etree.fromstring(data)
error_msg = None
except etree.XMLSyntaxError:
error_msg = _("This XML file is not XML-compliant")
return xml_root, error_msg
return xml_root, error_msg
@api.model
def parse_xml_order(self, data, detect_doc_type=False):
if not self.env.context.get("xml_root", False):
xml_root, error_msg = self._parse_xml(data)
else:
xml_root = data
error_msg = None
if (xml_root is None or not len(xml_root)) and error_msg:
raise UserError(error_msg)
raise NotImplementedError(
_(
"This type of XML RFQ/order is not supported. Did you install "
"the module to support this XML format?"
)
)
@api.model
def parse_pdf_order(self, order_file, detect_doc_type=False):
"""
Get PDF attachments, filter on XML files and call import_order_xml
"""
xml_files_dict = self.env["pdf.helper"].pdf_get_xml_files(order_file)
if not xml_files_dict:
raise UserError(_("There are no embedded XML file in this PDF file."))
for xml_filename, xml_root in xml_files_dict.items():
logger.info("Trying to parse XML file %s", xml_filename)
try:
parsed_order = self.with_context(xml_root=True).parse_xml_order(
xml_root, detect_doc_type=detect_doc_type
)
return parsed_order
except (etree.LxmlError, UserError):
continue
raise UserError(
_(
"This type of XML RFQ/order is not supported. Did you install "
"the module to support this XML format?"
)
)
# Format of parsed_order
# {
# 'partner': {
# 'vat': 'FR25499247138',
# 'name': 'Camptocamp',
# 'email': 'luc@camptocamp.com',
# },
# 'ship_to': {
# 'partner': partner_dict,
# 'address': {
# 'country_code': 'FR',
# 'state_code': False,
# 'zip': False,
# },
# 'company': {'vat': 'FR12123456789'}, # Only used to check we are not
# # importing the order in the
# # wrong company by mistake
# 'date': '2016-08-16', # order date
# 'order_ref': 'PO1242', # Customer PO number
# 'currency': {'iso': 'EUR', 'symbol': u'€'},
# 'incoterm': 'EXW',
# 'note': 'order notes of the customer',
# 'chatter_msg': ['msg1', 'msg2']
# 'lines': [{
# 'product': {
# 'code': 'EA7821',
# 'ean13': '2100002000003',
# },
# 'qty': 2.5,
# 'uom': {'unece_code': 'C62'},
# 'price_unit': 12.42, # without taxes
# 'doc_type': 'rfq' or 'order',
# }]
@api.model
def _search_existing_order_domain(
self, parsed_order, commercial_partner, state_domain
):
return AND(
[
state_domain,
[
("client_order_ref", "=", parsed_order["order_ref"]),
("commercial_partner_id", "=", commercial_partner.id),
],
]
)
@api.model
def _prepare_order(self, parsed_order, price_source):
soo = self.env["sale.order"]
bdio = self.env["business.document.import"]
partner = bdio._match_partner(
parsed_order["partner"],
parsed_order["chatter_msg"],
partner_type="customer",
)
currency = bdio._match_currency(
parsed_order.get("currency"), parsed_order["chatter_msg"]
)
# FIXME: this should work but it's not as it breaks core price compute
# so_vals = soo.default_get(soo._fields.keys())
so_vals = {
"partner_id": partner.id,
"client_order_ref": parsed_order.get("order_ref"),
}
self._validate_currency(partner, currency)
self._validate_existing_orders(partner, parsed_order)
so_vals = soo.play_onchanges(so_vals, ["partner_id"])
so_vals["order_line"] = []
if parsed_order.get("ship_to"):
shipping_partner = bdio._match_shipping_partner(
parsed_order["ship_to"], partner, parsed_order["chatter_msg"]
)
so_vals["partner_shipping_id"] = shipping_partner.id
if parsed_order.get("delivery_detail"):
so_vals.update(parsed_order.get("delivery_detail"))
if parsed_order.get("invoice_to"):
invoicing_partner = bdio._match_partner(
parsed_order["invoice_to"], parsed_order["chatter_msg"], partner_type=""
)
so_vals["partner_invoice_id"] = invoicing_partner.id
if parsed_order.get("date"):
so_vals["date_order"] = parsed_order["date"]
for line in parsed_order["lines"]:
# partner=False because we don't want to use product.supplierinfo
product = bdio._match_product(
line["product"], parsed_order["chatter_msg"], seller=False
)
uom = bdio._match_uom(line.get("uom"), parsed_order["chatter_msg"], product)
line_vals = self._prepare_create_order_line(
product, uom, so_vals, line, price_source
)
so_vals["order_line"].append((0, 0, line_vals))
defaults = self.env.context.get("sale_order_import__default_vals", {}).get(
"order", {}
)
so_vals.update(defaults)
return so_vals
def _validate_currency(self, partner, currency):
if partner.property_product_pricelist.currency_id != currency:
raise UserError(
_(
"The customer '%(name)s' has a pricelist '%(pricelist)s' but the "
"currency of this order is '%(currency)s'.",
name=partner.display_name,
pricelist=partner.property_product_pricelist.display_name,
currency=currency.name,
)
)
def _validate_existing_orders(self, partner, parsed_order):
if not parsed_order.get("order_ref"):
return
commercial_partner = partner.commercial_partner_id
existing_orders = self.env["sale.order"].search(
self._search_existing_order_domain(
parsed_order, commercial_partner, [("state", "!=", "cancel")]
),
limit=1,
)
if existing_orders:
raise UserError(
_(
"An order of customer '%(partner)s' with reference '%(ref)s' "
"already exists: %(name)s (state: %(state)s)",
partner=partner.display_name,
ref=parsed_order["order_ref"],
name=existing_orders[0].name,
state=existing_orders[0].state,
)
)
# TODO: I wonder why these methods are model methods
@api.model
def create_order(
self, parsed_order, price_source, order_filename=None, confirm_order=False
):
soo = self.env["sale.order"].with_context(mail_create_nosubscribe=True)
bdio = self.env["business.document.import"]
so_vals = self._prepare_order(parsed_order, price_source)
order = soo.create(so_vals)
if confirm_order:
order.action_confirm()
bdio.post_create_or_update(parsed_order, order, doc_filename=order_filename)
logger.info("Sale Order ID %d created", order.id)
return order
@api.model
def create_order_ws(
self, parsed_order, price_source, order_filename=None, confirm_order=False
):
"""Same method as create_order() but callable via JSON-RPC
webservice. Returns an ID to avoid this error:
TypeError: sale.order(15,) is not JSON serializable"""
order = self.create_order(
parsed_order,
price_source,
order_filename=order_filename,
confirm_order=confirm_order,
)
return order.id
@api.model
def parse_order(self, order_file, order_filename, partner=False):
parsed_order = self._parse_file(order_filename, order_file)
logger.debug("Result of order parsing: %s", parsed_order)
defaults = (
("attachments", {}),
("chatter_msg", []),
)
for key, val in defaults:
parsed_order.setdefault(key, val)
parsed_order["attachments"][order_filename] = b64encode(order_file)
if (
parsed_order.get("company")
and not config["test_enable"]
and not self._context.get("edi_skip_company_check")
):
self.env["business.document.import"]._check_company(
parsed_order["company"], parsed_order["chatter_msg"]
)
return parsed_order
def import_order_button(self):
self.ensure_one()
bdio = self.env["business.document.import"]
order_file_decoded = b64decode(self.order_file)
parsed_order = self.parse_order(
order_file_decoded, self.order_filename, self.partner_id
)
if not parsed_order.get("lines"):
raise UserError(_("This order doesn't have any line !"))
partner = bdio._match_partner(
parsed_order["partner"], [], partner_type="customer"
)
commercial_partner = partner.commercial_partner_id
partner_shipping_id = False
if parsed_order.get("ship_to"):
partner_shipping_id = bdio._match_shipping_partner(
parsed_order["ship_to"], partner, []
).id
existing_quotations = self.env["sale.order"].search(
self._search_existing_order_domain(
parsed_order, commercial_partner, [("state", "in", ("draft", "sent"))]
)
)
if existing_quotations:
default_sale_id = False
if len(existing_quotations) == 1:
default_sale_id = existing_quotations[0].id
self.write(
{
"commercial_partner_id": commercial_partner.id,
"partner_shipping_id": partner_shipping_id,
"state": "update",
"sale_id": default_sale_id,
"doc_type": parsed_order.get("doc_type"),
}
)
action = self.env["ir.actions.act_window"]._for_xml_id(
"sale_order_import.sale_order_import_action"
)
action["res_id"] = self.id
return action
else:
return self.create_order_return_action(parsed_order, self.order_filename)
def create_order_button(self):
self.ensure_one()
parsed_order = self.parse_order(
b64decode(self.order_file), self.order_filename, self.partner_id
)
return self.create_order_return_action(parsed_order, self.order_filename)
def create_order_return_action(self, parsed_order, order_filename):
self.ensure_one()
order = self.create_order(
parsed_order,
self.price_source,
order_filename,
confirm_order=self._order_should_be_confirmed(),
)
order.message_post(
body=_("Created automatically via file import (%s).") % self.order_filename
)
action = self.env["ir.actions.actions"]._for_xml_id("sale.action_quotations")
action.update(
{
"view_mode": "form,tree,calendar,graph",
"views": False,
"view_id": False,
"res_id": order.id,
}
)
return action
def _order_should_be_confirmed(self):
# Hook to override behavior
return self.confirm_order
# TODO: add tests
@api.model
def _prepare_update_order_vals(self, parsed_order, order, partner):
bdio = self.env["business.document.import"]
partner = bdio._match_partner(
parsed_order["partner"],
parsed_order["chatter_msg"],
partner_type="customer",
)
vals = {"partner_id": partner.id}
if parsed_order.get("ship_to"):
shipping_partner = bdio._match_shipping_partner(
parsed_order["ship_to"], partner, parsed_order["chatter_msg"]
)
vals["partner_shipping_id"] = shipping_partner.id
if parsed_order.get("order_ref"):
vals["client_order_ref"] = parsed_order["order_ref"]
return vals
@api.model
def _prepare_create_order_line(
self, product, uom, order, import_line, price_source
):
"""the 'order' arg can be a recordset (in case of an update of a sale order)
or a dict (in case of the creation of a new sale order)"""
solo = self.env["sale.order.line"]
vals = {}
# Ensure the company is loaded before we play onchanges.
# Yes, `company_id` is related to `order_id.company_id`
# but when we call `play_onchanges` it will be empty
# w/out this precaution.
company_id = self._prepare_order_line_get_company_id(order)
vals.update(
{
"product_id": product.id,
"product_uom_qty": import_line["qty"],
"product_uom": uom.id,
"company_id": company_id,
}
)
if price_source == "order":
if "price_unit" not in import_line:
raise UserError(
_(
"No price is defined in the file. Please double check "
"file or select Pricelist as the source for prices."
)
)
vals["price_unit"] = import_line["price_unit"]
elif price_source == "pricelist":
# product_id_change is played in the inherit of create()
# of sale.order.line cf odoo/addons/sale/models/sale.py
# but it is not enough: we also need to play _onchange_discount()
# to have the right discount for pricelist
vals["order_id"] = order
vals.pop("order_id")
# Handle additional fields dynamically if available.
# If a field is added to a record and its value is injected by a parser
# you won't have to override `_prepare_create_order_line`
# to let it propagate.
for k, v in import_line.items():
if k not in vals and k in solo._fields:
vals[k] = v
defaults = self.env.context.get("sale_order_import__default_vals", {}).get(
"lines", {}
)
vals.update(defaults)
return vals
def _prepare_order_line_get_company_id(self, order):
company_id = self.env.company.id
if isinstance(order, models.Model):
company_id = order.company_id.id
elif isinstance(order, dict):
company_id = order.get("company_id") or company_id
return company_id
# TODO: add tests
@api.model
def update_order_lines(self, parsed_order, order, price_source):
chatter = parsed_order["chatter_msg"]
solo = self.env["sale.order.line"]
dpo = self.env["decimal.precision"]
bdio = self.env["business.document.import"]
qty_prec = dpo.precision_get("Product UoS")
price_prec = dpo.precision_get("Product Price")
existing_lines = []
for oline in order.order_line:
# compute price unit without tax
price_unit = 0.0
if not float_is_zero(oline.product_uom_qty, precision_digits=qty_prec):
qty = float(oline.product_uom_qty)
price_unit = oline.price_subtotal / qty
existing_lines.append(
{
"product": oline.product_id or False,
"name": oline.name,
"qty": oline.product_uom_qty,
"uom": oline.product_uom,
"line": oline,
"price_unit": price_unit,
}
)
compare_res = bdio.compare_lines(
existing_lines,
parsed_order["lines"],
chatter,
qty_precision=qty_prec,
seller=False,
)
# NOW, we start to write/delete/create the order lines
for oline, cdict in compare_res["to_update"].items():
write_vals = {}
# TODO: add support for price_source == order
if cdict.get("qty"):
chatter.append(
_(
"The quantity has been updated on the order line "
"with product '%(product)s' from %(qty0)s to %(qty1)s %(uom)s",
product=oline.product_id.display_name,
qty0=cdict["qty"][0],
qty1=cdict["qty"][1],
uom=oline.product_uom.name,
)
)
write_vals["product_uom_qty"] = cdict["qty"][1]
if price_source != "order":
new_price_unit = order.pricelist_id.with_context(
date=order.date_order, uom=oline.product_uom.id
)._price_get(oline.product_id, write_vals["product_uom_qty"],)[
order.pricelist_id.id
]
if float_compare(
new_price_unit, oline.price_unit, precision_digits=price_prec
):
chatter.append(
_(
"The unit price has been updated on the order "
"line with product '%(product)s' from %(old)s to "
"%(new)s %(currency)s",
product=oline.product_id.display_name,
old=oline.price_unit,
new=new_price_unit,
currency=order.currency_id.name,
)
)
write_vals["price_unit"] = new_price_unit
write_vals.update(self._prepare_update_order_line_vals(cdict))
if write_vals:
oline.write(write_vals)
if compare_res["to_remove"]:
to_remove_label = [
f"{line.product_uom_qty} {line.product_uom.name} "
f"x {line.product_id.name}"
for line in compare_res["to_remove"]
]
chatter.append(
_(
"%(orders)s order line(s) deleted: %(label)s",
orders=len(compare_res["to_remove"]),
label=", ".join(to_remove_label),
)
)
compare_res["to_remove"].unlink()
if compare_res["to_add"]:
to_create_label = []
for add in compare_res["to_add"]:
line_vals = self._prepare_create_order_line(
add["product"], add["uom"], order, add["import_line"], price_source
)
line_vals["order_id"] = order.id
new_line = solo.create(line_vals)
to_create_label.append(
f"{new_line.product_uom_qty} {new_line.product_uom.name} "
f"x {new_line.name}"
)
chatter.append(
_(
"%(orders)s new order line(s) created: %(label)s",
orders=len(compare_res["to_add"]),
label=", ".join(to_create_label),
)
)
return True
def _prepare_update_order_line_vals(self, change_dict):
# Allows other module to update some fields on the line
return {}
def update_order_button(self):
self.ensure_one()
bdio = self.env["business.document.import"]
order = self.sale_id
if not order:
raise UserError(_("You must select a quotation to update."))
parsed_order = self.parse_order(
b64decode(self.order_file), self.order_filename, self.partner_id
)
currency = bdio._match_currency(
parsed_order.get("currency"), parsed_order["chatter_msg"]
)
if currency != order.currency_id:
raise UserError(
_(
"The currency of the imported order (%(old)s) is different from "
"the currency of the existing order (%(new)s)",
old=currency.name,
new=order.currency_id.name,
)
)
vals = self._prepare_update_order_vals(
parsed_order, order, self.commercial_partner_id
)
if vals:
order.write(vals)
self.update_order_lines(parsed_order, order, self.price_source)
bdio.post_create_or_update(parsed_order, order)
logger.info(
"Quotation ID %d updated via import of file %s",
order.id,
self.order_filename,
)
order.message_post(
body=_(
"This quotation has been updated automatically via the import of "
"file %s"
)
% self.order_filename
)
action = self.env["ir.actions.act_window"]._for_xml_id("sale.action_quotations")
action.update(
{
"view_mode": "form,tree,calendar,graph",
"views": False,
"view_id": False,
"res_id": order.id,
}
)
return action

View file

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
© 2016-2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="sale_order_import_form" model="ir.ui.view">
<field name="name">sale.order.import.form</field>
<field name="model">sale.order.import</field>
<field name="arch" type="xml">
<form string="Import Sale Orders">
<group name="technical" invisible="1">
<field name="state" />
</group>
<group colspan="4" name="help-import" states="import">
<div colspan="2">
<p
>Upload below the customer order or request for quotation as XML or PDF file. When you click on the Import button:</p>
<ol>
<li
>If it is an XML file, Odoo will parse it if the module that adds support for this XML format is installed. For the <a
href="http://ubl.xml.org/"
target="_blank"
>Universal Business Language</a> format (UBL), you should install the module <em
>sale_order_import_ubl</em>.</li>
<li
>If it is a PDF file, Odoo will try to find an XML file in the attachments of the PDF file and then use this XML file to create the quotation.</li>
</ol>
</div>
</group>
<group colspan="4" name="help-update" states="update">
<div colspan="2">
<p
>Some quotations have been found for this customer ; one of them may correspond to the order or RFQ that you are importing. You can either select an existing quotation to update or create a new one.</p>
</div>
</group>
<group name="import" states="import">
<field name="import_type" />
<field
name="order_file"
filename="order_filename"
attrs="{'readonly': [('import_type', '=', False)]}"
/>
<field name="order_filename" invisible="1" />
</group>
<group name="update" states="update">
<field name="commercial_partner_id" />
<field
name="partner_shipping_id"
context="{'show_address': 1}"
options="{'always_reload': 1}"
/>
<field
name="sale_id"
domain="[('state', 'in', ('draft', 'sent')), ('commercial_partner_id', '=', commercial_partner_id)]"
/>
</group>
<group name="common">
<field name="doc_type" />
<field
name="price_source"
attrs="{'invisible': [('doc_type', '!=', 'order')], 'required': [('doc_type', '=', 'order')]}"
/>
<field name="confirm_order" />
</group>
<footer>
<button
name="import_order_button"
type="object"
states="import"
class="oe_highlight"
string="Import"
/>
<button
name="update_order_button"
type="object"
states="update"
class="oe_highlight"
string="Update Existing"
/>
<button
name="create_order_button"
type="object"
states="update"
class="oe_highlight"
string="Create New"
/>
<button special="cancel" string="Cancel" class="oe_link" />
</footer>
</form>
</field>
</record>
<record id="sale_order_import_action" model="ir.actions.act_window">
<field name="name">Import RFQ or Order</field>
<field name="res_model">sale.order.import</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="context">{'sale_order_show_amount': True}</field>
</record>
<menuitem
id="sale_order_import_menu"
parent="sale.sale_order_menu"
action="sale_order_import_action"
sequence="12"
/>
</odoo>