Initial commit: OCA Technical packages (595 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:03 +02:00
commit 2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions

View file

@ -0,0 +1,47 @@
# Asynchronous Import
Odoo addon: base_import_async
## Installation
```bash
pip install odoo-bringout-oca-queue-base_import_async
```
## Dependencies
This addon depends on:
- base_import
- queue_job
## Manifest Information
- **Name**: Asynchronous Import
- **Version**: 16.0.1.2.0
- **Category**: Generic Modules
- **License**: AGPL-3
- **Installable**: True
## Source
Based on [OCA/queue](https://github.com/OCA/queue) branch 16.0, addon `base_import_async`.
## 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
- Reports: doc/REPORTS.md
- Security: doc/SECURITY.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,149 @@
===================
Asynchronous Import
===================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:07386b2c38bebbafa1ae11daf67ccfa3682f8fc15f7ae91080ed341ec3269ec8
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png
:target: https://odoo-community.org/page/development-status
:alt: Production/Stable
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fqueue-lightgray.png?logo=github
:target: https://github.com/OCA/queue/tree/16.0/base_import_async
:alt: OCA/queue
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/queue-16-0/queue-16-0-base_import_async
: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/queue&target_branch=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
This module extends the standard CSV import functionality
to import files in the background using the OCA/queue
framework.
**Table of contents**
.. contents::
:local:
Usage
=====
The user is presented with a new checkbox in the import
screen. When selected, the import is delayed in a background
job.
This job in turn splits the CSV file in chunks of minimum
100 lines (or more to align with record boundaries). Each
chunk is then imported in a separate background job.
When an import fails, the job is marked as such and the
user can read the error in the job status. The CSV chunk
being imported is stored as an attachment to the job, making
it easy to download it, fix it and run a new import, possibly
in synchronous mode since the chunks are small.
Any file that can be imported by the standard import mechanism
can also be imported in the background.
This module's scope is limited to making standard imports
asynchronous. It does not attempt to transform the data nor
automate ETL flows.
Other modules may benefit from this infrastructure in the following way
(as illustrated in the test suite):
1. create an instance of `base_import.import` and populate its fields
(`res_model`, `file`, `file_name`),
2. invoke the `do` method with appropriate options
(`header`, `encoding`, `separator`, `quoting`,
`use_queue`, `chunk_size`).
Known issues / Roadmap
======================
* There is currently no user interface to control the chunk size,
which is currently 100 by default. Should this proves to be an issue,
it is easy to add an option to extend the import screen.
* Validation cannot be run in the background.
Changelog
=========
13.0.1.0.0 (2019-12-20)
~~~~~~~~~~~~~~~~~~~~~~~
* [MIGRATION] from 12.0 branched at rev. a7f8031
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/queue/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/queue/issues/new?body=module:%20base_import_async%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
* ACSONE SA/NV
Contributors
~~~~~~~~~~~~
Sébastien Beau (Akretion) authored the initial prototype.
Stéphane Bidoul (ACSONE) extended it to version 1.0 to support
multi-line records, store data to import as attachments
and let the user control the asynchronous behaviour.
Other contributors include:
* Anthony Muschang (ACSONE)
* David Béal (Akretion)
* Jonathan Nemry (ACSONE)
* Laurent Mignon (ACSONE)
* Dennis Sluijk (Onestein)
* Guewen Baconnier (Camptocamp)
* `Trobz <https://trobz.com>`_:
* Dzung Tran <dungtd@trobz.com>
* Daniel Duque (FactorLibre)
Other credits
~~~~~~~~~~~~~
The migration of this module from 15.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/queue <https://github.com/OCA/queue/tree/16.0/base_import_async>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View file

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

View file

@ -0,0 +1,25 @@
# @author Stéphane Bidoul <stephane.bidoul@acsone.eu>
# @author Sébastien BEAU <sebastien.beau@akretion.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "Asynchronous Import",
"summary": "Import CSV files in the background",
"version": "16.0.1.2.0",
"author": "Akretion, ACSONE SA/NV, Odoo Community Association (OCA)",
"license": "AGPL-3",
"website": "https://github.com/OCA/queue",
"category": "Generic Modules",
"depends": ["base_import", "queue_job"],
"data": [
"data/queue_job_function_data.xml",
],
"assets": {
"web.assets_backend": [
"base_import_async/static/src/js/import.js",
"base_import_async/static/src/xml/import.xml",
],
},
"installable": True,
"development_status": "Production/Stable",
}

View file

@ -0,0 +1,28 @@
<odoo noupdate="1">
<record model="queue.job.channel" id="channel_base_import">
<field name="name">base_import</field>
<field name="parent_id" ref="queue_job.channel_root" />
</record>
<record id="job_function_base_import_import_split_file" model="queue.job.function">
<field name="model_id" ref="base_import.model_base_import_import" />
<field name="method">_split_file</field>
<field name="channel_id" ref="channel_base_import" />
<field
name="related_action"
eval='{"func_name": "_related_action_attachment"}'
/>
</record>
<record
id="job_function_base_import_import_import_one_chunk"
model="queue.job.function"
>
<field name="model_id" ref="base_import.model_base_import_import" />
<field name="method">_import_one_chunk</field>
<field name="channel_id" ref="channel_base_import" />
<field
name="related_action"
eval='{"func_name": "_related_action_attachment"}'
/>
</record>
</odoo>

View file

@ -0,0 +1,78 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_import_async
#
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: base_import_async
#. odoo-python
#: code:addons/base_import_async/models/queue_job.py:0
#, python-format
msgid "Attachment"
msgstr ""
#. module: base_import_async
#: model:ir.model,name:base_import_async.model_base_import_import
msgid "Base Import"
msgstr ""
#. module: base_import_async
#. odoo-python
#: code:addons/base_import_async/models/base_import_import.py:0
#, python-format
msgid ""
"Import %(model)s from file %(file_name)s - #%(chunk)s - lines %(from)s to "
"%(to)s"
msgstr ""
#. module: base_import_async
#. odoo-python
#: code:addons/base_import_async/models/base_import_import.py:0
#, python-format
msgid "Import %(model)s from file %(from_file)s"
msgstr ""
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/xml/import.xml:0
#, python-format
msgid "Import in the background"
msgstr ""
#. module: base_import_async
#: model:ir.model,name:base_import_async.model_queue_job
msgid "Queue Job"
msgstr ""
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/xml/import.xml:0
#, python-format
msgid ""
"When checked, the import will be executed as a background job, after "
"splitting your file in small chunks that will be processed independently. "
"Use this to import very large files."
msgstr ""
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/js/import.js:0
#, python-format
msgid "You can check the status of this job in menu 'Queue / Jobs'."
msgstr ""
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/js/import.js:0
#, python-format
msgid "Your request is being processed"
msgstr ""

View file

@ -0,0 +1,78 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_import_async
#
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: base_import_async
#. odoo-python
#: code:addons/base_import_async/models/queue_job.py:0
#, python-format
msgid "Attachment"
msgstr "Prilog"
#. module: base_import_async
#: model:ir.model,name:base_import_async.model_base_import_import
msgid "Base Import"
msgstr "Bazni uvoz"
#. module: base_import_async
#. odoo-python
#: code:addons/base_import_async/models/base_import_import.py:0
#, python-format
msgid ""
"Import %(model)s from file %(file_name)s - #%(chunk)s - lines %(from)s to "
"%(to)s"
msgstr ""
#. module: base_import_async
#. odoo-python
#: code:addons/base_import_async/models/base_import_import.py:0
#, python-format
msgid "Import %(model)s from file %(from_file)s"
msgstr "Uvoz %(model)s iz datoteke %(from_file)s"
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/xml/import.xml:0
#, python-format
msgid "Import in the background"
msgstr "Uvoz u pozadini"
#. module: base_import_async
#: model:ir.model,name:base_import_async.model_queue_job
msgid "Queue Job"
msgstr "Posao u redu"
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/xml/import.xml:0
#, python-format
msgid ""
"When checked, the import will be executed as a background job, after "
"splitting your file in small chunks that will be processed independently. "
"Use this to import very large files."
msgstr ""
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/js/import.js:0
#, python-format
msgid "You can check the status of this job in menu 'Queue / Jobs'."
msgstr "Možete provjeriti status ovog posla u meniju 'Red čekanja / Poslovi'."
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/js/import.js:0
#, python-format
msgid "Your request is being processed"
msgstr "Vaš zahtjev se obrađuje"

View file

@ -0,0 +1,88 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_import_async
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-09-25 09:34+0000\n"
"Last-Translator: Asier Neira <asier_neira@hotmail.com>\n"
"Language-Team: none\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: base_import_async
#. odoo-python
#: code:addons/base_import_async/models/queue_job.py:0
#, python-format
msgid "Attachment"
msgstr "Archivo adjunto"
#. module: base_import_async
#: model:ir.model,name:base_import_async.model_base_import_import
msgid "Base Import"
msgstr "Importación Base"
#. module: base_import_async
#. odoo-python
#: code:addons/base_import_async/models/base_import_import.py:0
#, python-format
msgid ""
"Import %(model)s from file %(file_name)s - #%(chunk)s - lines %(from)s to "
"%(to)s"
msgstr ""
"Importar %(model)s del archivo %(file_name)s - #%(chunk)s - líneas %(from)s "
"a %(to)s"
#. module: base_import_async
#. odoo-python
#: code:addons/base_import_async/models/base_import_import.py:0
#, python-format
msgid "Import %(model)s from file %(from_file)s"
msgstr "Importar %(model)s del fichero %(from_file)s"
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/xml/import.xml:0
#, python-format
msgid "Import in the background"
msgstr "Importación en segundo plano"
#. module: base_import_async
#: model:ir.model,name:base_import_async.model_queue_job
msgid "Queue Job"
msgstr "Cola de trabajo"
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/xml/import.xml:0
#, python-format
msgid ""
"When checked, the import will be executed as a background job, after "
"splitting your file in small chunks that will be processed independently. "
"Use this to import very large files."
msgstr ""
"Si esta opción está seleccionada, la importación se ejecutará como un "
"trabajo en segundo plano, tras dividir el archivo en pequeños trozos que se "
"procesarán de forma independiente. Utilícelo para importar archivos muy "
"grandes."
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/js/import.js:0
#, python-format
msgid "You can check the status of this job in menu 'Queue / Jobs'."
msgstr ""
"Puede comprobar el estado de este trabajo en el menú 'Cola / Trabajos'."
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/js/import.js:0
#, python-format
msgid "Your request is being processed"
msgstr "Su solicitud está siendo procesada"

View file

@ -0,0 +1,87 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_import_async
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-01-11 09:34+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 4.17\n"
#. module: base_import_async
#. odoo-python
#: code:addons/base_import_async/models/queue_job.py:0
#, python-format
msgid "Attachment"
msgstr "Allegato"
#. module: base_import_async
#: model:ir.model,name:base_import_async.model_base_import_import
msgid "Base Import"
msgstr "Importazione base"
#. module: base_import_async
#. odoo-python
#: code:addons/base_import_async/models/base_import_import.py:0
#, python-format
msgid ""
"Import %(model)s from file %(file_name)s - #%(chunk)s - lines %(from)s to "
"%(to)s"
msgstr ""
"Importa %(model)s dal file %(file_name)s - #%(chunk)s - linee %(from)s a "
"%(to)s"
#. module: base_import_async
#. odoo-python
#: code:addons/base_import_async/models/base_import_import.py:0
#, python-format
msgid "Import %(model)s from file %(from_file)s"
msgstr "Importa %(model)s dal file %(from_file)s"
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/xml/import.xml:0
#, python-format
msgid "Import in the background"
msgstr "Importa in background"
#. module: base_import_async
#: model:ir.model,name:base_import_async.model_queue_job
msgid "Queue Job"
msgstr "Lavoro in coda"
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/xml/import.xml:0
#, python-format
msgid ""
"When checked, the import will be executed as a background job, after "
"splitting your file in small chunks that will be processed independently. "
"Use this to import very large files."
msgstr ""
"Quando selezionata, l'importazione verrà eseguita com un lavoro in "
"backgroud, dopo la divisine del file in piccole parti che verranno "
"processate indipendentemente. Utilizzare questa opzione per importare file "
"di grandi dimensioni."
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/js/import.js:0
#, python-format
msgid "You can check the status of this job in menu 'Queue / Jobs'."
msgstr "Si può controllare lo stato di questo lavoro nel menu 'Coda / Lavori'."
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/js/import.js:0
#, python-format
msgid "Your request is being processed"
msgstr "La richiesta è in lavorazione"

View file

@ -0,0 +1,95 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_import_async
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.0-20221029\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-24 07:21+0000\n"
"PO-Revision-Date: 2025-02-18 16:06+0000\n"
"Last-Translator: İsmail Çağan Yılmaz <ismail.cagan.yilmaz@gmail.com>\n"
"Language-Team: \n"
"Language: tr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.6.2\n"
#. module: base_import_async
#. odoo-python
#: code:addons/base_import_async/models/queue_job.py:0
#, python-format
msgid "Attachment"
msgstr "Ek"
#. module: base_import_async
#: model:ir.model,name:base_import_async.model_base_import_import
msgid "Base Import"
msgstr "İçe aktarım"
#. module: base_import_async
#. odoo-python
#: code:addons/base_import_async/models/base_import_import.py:0
#, python-format
msgid ""
"Import %(model)s from file %(file_name)s - #%(chunk)s - lines %(from)s to "
"%(to)s"
msgstr ""
"%(model)s dosyasını %(file_name)s dosyasından içe aktarın - #%(chunk)s - "
"%(from)s ile %(to)s arasındaki satırları"
#. module: base_import_async
#. odoo-python
#: code:addons/base_import_async/models/base_import_import.py:0
#, python-format
msgid "Import %(model)s from file %(from_file)s"
msgstr "%(model)s dosyasını %(from_file)s dosyasından içe aktar"
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/xml/import.xml:0
#, python-format
msgid "Import in the background"
msgstr "Arka planda içe aktarım"
#. module: base_import_async
#: model:ir.model,name:base_import_async.model_queue_job
msgid "Queue Job"
msgstr "İş Kuyruğu"
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/xml/import.xml:0
#, python-format
msgid ""
"When checked, the import will be executed as a background job, after "
"splitting your file in small chunks that will be processed independently. "
"Use this to import very large files."
msgstr ""
"İşaretlendiğinde, içe aktarım işlemi, dosyanızı bağımsız olarak işlenecek "
"küçük parçalara ayırdıktan sonra bir arka plan işi olarak yürütülür. Çok "
"büyük dosyaları içe aktarmak için bunu kullanın."
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/js/import.js:0
#, python-format
msgid "You can check the status of this job in menu 'Queue / Jobs'."
msgstr "Bu işin durumunu 'Kuyruk / İşler' menüsünden kontrol edebilirsiniz."
#. module: base_import_async
#. odoo-javascript
#: code:addons/base_import_async/static/src/js/import.js:0
#, python-format
msgid "Your request is being processed"
msgstr "İsteğiniz işleniyor"
#, python-format
#~ msgid "Import %s from file %s"
#~ msgstr "%s dosyasından %s içe aktar"
#, python-format
#~ msgid "Import %s from file %s - #%s - lines %s to %s"
#~ msgstr "%s dosyasından %s - #%s - %s - %s satırlarını içe aktar"

View file

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

View file

@ -0,0 +1,194 @@
# Copyright 2014 ACSONE SA/NV (http://acsone.eu).
# Copyright 2013 Akretion (http://www.akretion.com).
# @author Stéphane Bidoul <stephane.bidoul@acsone.eu>
# @author Sébastien BEAU <sebastien.beau@akretion.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import base64
import csv
from io import BytesIO, StringIO, TextIOWrapper
from os.path import splitext
from odoo import _, api, models
from odoo.models import fix_import_export_id_paths
from odoo.addons.queue_job.exception import FailedJobError
# options defined in base_import/import.js
OPT_HAS_HEADER = "has_headers"
OPT_SEPARATOR = "separator"
OPT_QUOTING = "quoting"
OPT_ENCODING = "encoding"
# options defined in base_import_async/import.js
OPT_USE_QUEUE = "use_queue"
OPT_CHUNK_SIZE = "chunk_size"
# option not available in UI, but usable from scripts
OPT_PRIORITY = "priority"
INIT_PRIORITY = 100
DEFAULT_CHUNK_SIZE = 100
class BaseImportImport(models.TransientModel):
_inherit = "base_import.import"
def execute_import(self, fields, columns, options, dryrun=False):
if dryrun or not options.get(OPT_USE_QUEUE):
# normal import
return super().execute_import(fields, columns, options, dryrun=dryrun)
# asynchronous import
try:
data, import_fields = self._convert_import_data(fields, options)
# Parse date and float field
data = self._parse_import_data(data, import_fields, options)
except ValueError as e:
return {"messages": [{"type": "error", "message": str(e), "record": False}]}
# get the translated model name to build
# a meaningful job description
search_result = (
self.env["ir.model"].sudo().name_search(self.res_model, operator="=")
)
if search_result:
translated_model_name = search_result[0][1]
else:
translated_model_name = self._description
description = _("Import %(model)s from file %(from_file)s") % {
"model": translated_model_name,
"from_file": self.file_name,
}
attachment = self._create_csv_attachment(
import_fields, data, options, self.file_name
)
delayed_job = self.with_delay(description=description)._split_file(
model_name=self.res_model,
translated_model_name=translated_model_name,
attachment=attachment,
options=options,
file_name=self.file_name,
)
self._link_attachment_to_job(delayed_job, attachment)
return []
def _link_attachment_to_job(self, delayed_job, attachment):
queue_job = self.env["queue.job"].search(
[("uuid", "=", delayed_job.uuid)], limit=1
)
attachment.write({"res_model": "queue.job", "res_id": queue_job.id})
@api.returns("ir.attachment")
def _create_csv_attachment(self, fields, data, options, file_name):
# write csv
f = StringIO()
writer = csv.writer(
f,
delimiter=str(options.get(OPT_SEPARATOR)) or ",",
quotechar=str(options.get(OPT_QUOTING)),
)
encoding = options.get(OPT_ENCODING) or "utf-8"
writer.writerow(fields)
for row in data:
writer.writerow(row)
# create attachment. Remove default values from context
context = self.env.context
context_copy = {}
for key in context.keys():
if not key.startswith("default_"):
context_copy[key] = context[key]
datas = base64.encodebytes(f.getvalue().encode(encoding))
attachment = (
self.env["ir.attachment"]
.with_context(**context_copy)
.create({"name": file_name, "datas": datas})
)
return attachment
def _read_csv_attachment(self, attachment, options):
decoded_datas = base64.decodebytes(attachment.datas)
encoding = options.get(OPT_ENCODING) or "utf-8"
f = TextIOWrapper(BytesIO(decoded_datas), encoding=encoding)
reader = csv.reader(
f,
delimiter=str(options.get(OPT_SEPARATOR)) or ",",
quotechar=str(options.get(OPT_QUOTING)),
)
fields = next(reader)
data = [row for row in reader]
return fields, data
@staticmethod
def _extract_chunks(model_obj, fields, data, chunk_size):
"""Split the data on record boundaries, in chunks of minimum chunk_size"""
fields = list(map(fix_import_export_id_paths, fields))
row_from = 0
for rows in model_obj._extract_records(fields, data):
rows = rows[1]["rows"]
if rows["to"] - row_from + 1 >= chunk_size:
yield row_from, rows["to"]
row_from = rows["to"] + 1
if row_from < len(data):
yield row_from, len(data) - 1
def _split_file(
self,
model_name,
translated_model_name,
attachment,
options,
file_name="file.csv",
):
"""Split a CSV attachment in smaller import jobs"""
model_obj = self.env[model_name]
fields, data = self._read_csv_attachment(attachment, options)
padding = len(str(len(data)))
priority = options.get(OPT_PRIORITY, INIT_PRIORITY)
if options.get(OPT_HAS_HEADER):
header_offset = 1
else:
header_offset = 0
chunk_size = options.get(OPT_CHUNK_SIZE) or DEFAULT_CHUNK_SIZE
for row_from, row_to in self._extract_chunks(
model_obj, fields, data, chunk_size
):
chunk = str(priority - INIT_PRIORITY).zfill(padding)
description = _(
"Import %(model)s from file %(file_name)s - "
"#%(chunk)s - lines %(from)s to %(to)s"
)
description = description % {
"model": translated_model_name,
"file_name": file_name,
"chunk": chunk,
"from": row_from + 1 + header_offset,
"to": row_to + 1 + header_offset,
}
# create a CSV attachment and enqueue the job
root, ext = splitext(file_name)
attachment = self._create_csv_attachment(
fields,
data[row_from : row_to + 1],
options,
file_name=root + "-" + chunk + ext,
)
delayed_job = self.with_delay(
description=description, priority=priority
)._import_one_chunk(
model_name=model_name, attachment=attachment, options=options
)
self._link_attachment_to_job(delayed_job, attachment)
priority += 1
def _import_one_chunk(self, model_name, attachment, options):
model_obj = self.env[model_name]
fields, data = self._read_csv_attachment(attachment, options)
result = model_obj.load(fields, data)
error_message = [
message["message"]
for message in result["messages"]
if message["type"] == "error"
]
if error_message:
raise FailedJobError("\n".join(error_message))
return result

View file

@ -0,0 +1,21 @@
# Copyright 2017 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import _, models
class QueueJob(models.Model):
"""Job status and result"""
_inherit = "queue.job"
def _related_action_attachment(self):
res_id = self.kwargs.get("att_id")
action = {
"name": _("Attachment"),
"type": "ir.actions.act_window",
"res_model": "ir.attachment",
"view_mode": "form",
"res_id": res_id,
}
return action

View file

@ -0,0 +1,17 @@
Sébastien Beau (Akretion) authored the initial prototype.
Stéphane Bidoul (ACSONE) extended it to version 1.0 to support
multi-line records, store data to import as attachments
and let the user control the asynchronous behaviour.
Other contributors include:
* Anthony Muschang (ACSONE)
* David Béal (Akretion)
* Jonathan Nemry (ACSONE)
* Laurent Mignon (ACSONE)
* Dennis Sluijk (Onestein)
* Guewen Baconnier (Camptocamp)
* `Trobz <https://trobz.com>`_:
* Dzung Tran <dungtd@trobz.com>
* Daniel Duque (FactorLibre)

View file

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

View file

@ -0,0 +1,3 @@
This module extends the standard CSV import functionality
to import files in the background using the OCA/queue
framework.

View file

@ -0,0 +1,4 @@
13.0.1.0.0 (2019-12-20)
~~~~~~~~~~~~~~~~~~~~~~~
* [MIGRATION] from 12.0 branched at rev. a7f8031

View file

@ -0,0 +1,4 @@
* There is currently no user interface to control the chunk size,
which is currently 100 by default. Should this proves to be an issue,
it is easy to add an option to extend the import screen.
* Validation cannot be run in the background.

View file

@ -0,0 +1,29 @@
The user is presented with a new checkbox in the import
screen. When selected, the import is delayed in a background
job.
This job in turn splits the CSV file in chunks of minimum
100 lines (or more to align with record boundaries). Each
chunk is then imported in a separate background job.
When an import fails, the job is marked as such and the
user can read the error in the job status. The CSV chunk
being imported is stored as an attachment to the job, making
it easy to download it, fix it and run a new import, possibly
in synchronous mode since the chunks are small.
Any file that can be imported by the standard import mechanism
can also be imported in the background.
This module's scope is limited to making standard imports
asynchronous. It does not attempt to transform the data nor
automate ETL flows.
Other modules may benefit from this infrastructure in the following way
(as illustrated in the test suite):
1. create an instance of `base_import.import` and populate its fields
(`res_model`, `file`, `file_name`),
2. invoke the `do` method with appropriate options
(`header`, `encoding`, `separator`, `quoting`,
`use_queue`, `chunk_size`).

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View file

@ -0,0 +1,502 @@
<!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>Asynchronous Import</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" id="asynchronous-import">
<h1 class="title">Asynchronous Import</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:07386b2c38bebbafa1ae11daf67ccfa3682f8fc15f7ae91080ed341ec3269ec8
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Production/Stable" src="https://img.shields.io/badge/maturity-Production%2FStable-green.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/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/queue/tree/16.0/base_import_async"><img alt="OCA/queue" src="https://img.shields.io/badge/github-OCA%2Fqueue-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/queue-16-0/queue-16-0-base_import_async"><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/queue&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 extends the standard CSV import functionality
to import files in the background using the OCA/queue
framework.</p>
<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="#known-issues-roadmap" id="toc-entry-2">Known issues / Roadmap</a></li>
<li><a class="reference internal" href="#changelog" id="toc-entry-3">Changelog</a><ul>
<li><a class="reference internal" href="#section-1" id="toc-entry-4">13.0.1.0.0 (2019-12-20)</a></li>
</ul>
</li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-5">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-6">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-7">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-8">Contributors</a></li>
<li><a class="reference internal" href="#other-credits" id="toc-entry-9">Other credits</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-10">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<p>The user is presented with a new checkbox in the import
screen. When selected, the import is delayed in a background
job.</p>
<p>This job in turn splits the CSV file in chunks of minimum
100 lines (or more to align with record boundaries). Each
chunk is then imported in a separate background job.</p>
<p>When an import fails, the job is marked as such and the
user can read the error in the job status. The CSV chunk
being imported is stored as an attachment to the job, making
it easy to download it, fix it and run a new import, possibly
in synchronous mode since the chunks are small.</p>
<p>Any file that can be imported by the standard import mechanism
can also be imported in the background.</p>
<p>This modules scope is limited to making standard imports
asynchronous. It does not attempt to transform the data nor
automate ETL flows.</p>
<p>Other modules may benefit from this infrastructure in the following way
(as illustrated in the test suite):</p>
<ol class="arabic simple">
<li>create an instance of <cite>base_import.import</cite> and populate its fields
(<cite>res_model</cite>, <cite>file</cite>, <cite>file_name</cite>),</li>
<li>invoke the <cite>do</cite> method with appropriate options
(<cite>header</cite>, <cite>encoding</cite>, <cite>separator</cite>, <cite>quoting</cite>,
<cite>use_queue</cite>, <cite>chunk_size</cite>).</li>
</ol>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#toc-entry-2">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>There is currently no user interface to control the chunk size,
which is currently 100 by default. Should this proves to be an issue,
it is easy to add an option to extend the import screen.</li>
<li>Validation cannot be run in the background.</li>
</ul>
</div>
<div class="section" id="changelog">
<h1><a class="toc-backref" href="#toc-entry-3">Changelog</a></h1>
<div class="section" id="section-1">
<h2><a class="toc-backref" href="#toc-entry-4">13.0.1.0.0 (2019-12-20)</a></h2>
<ul class="simple">
<li>[MIGRATION] from 12.0 branched at rev. a7f8031</li>
</ul>
</div>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-5">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/queue/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/queue/issues/new?body=module:%20base_import_async%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">
<h1><a class="toc-backref" href="#toc-entry-6">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-7">Authors</a></h2>
<ul class="simple">
<li>Akretion</li>
<li>ACSONE SA/NV</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-8">Contributors</a></h2>
<p>Sébastien Beau (Akretion) authored the initial prototype.</p>
<p>Stéphane Bidoul (ACSONE) extended it to version 1.0 to support
multi-line records, store data to import as attachments
and let the user control the asynchronous behaviour.</p>
<p>Other contributors include:</p>
<ul class="simple">
<li>Anthony Muschang (ACSONE)</li>
<li>David Béal (Akretion)</li>
<li>Jonathan Nemry (ACSONE)</li>
<li>Laurent Mignon (ACSONE)</li>
<li>Dennis Sluijk (Onestein)</li>
<li>Guewen Baconnier (Camptocamp)</li>
<li><dl class="first docutils">
<dt><a class="reference external" href="https://trobz.com">Trobz</a>:</dt>
<dd><ul class="first last">
<li>Dzung Tran &lt;<a class="reference external" href="mailto:dungtd&#64;trobz.com">dungtd&#64;trobz.com</a>&gt;</li>
</ul>
</dd>
</dl>
</li>
<li>Daniel Duque (FactorLibre)</li>
</ul>
</div>
<div class="section" id="other-credits">
<h2><a class="toc-backref" href="#toc-entry-9">Other credits</a></h2>
<p>The migration of this module from 15.0 to 16.0 was financially supported by Camptocamp</p>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-10">Maintainers</a></h2>
<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/queue/tree/16.0/base_import_async">OCA/queue</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>
</body>
</html>

View file

@ -0,0 +1,30 @@
odoo.define("base_import_async.import", function (require) {
"use strict";
var core = require("web.core");
var _t = core._t;
var DataImport = require("base_import.import").DataImport;
DataImport.include({
import_options: function () {
var options = this._super.apply(this, arguments);
options.use_queue = this.$("input.oe_import_queue").prop("checked");
return options;
},
onimported: function () {
if (this.$("input.oe_import_queue").prop("checked")) {
this.displayNotification({
type: "warning",
title: _t("Your request is being processed"),
message: _t(
"You can check the status of this job in menu 'Queue / Jobs'."
),
});
this.exit();
} else {
this._super.apply(this, arguments);
}
},
});
});

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" ?>
<templates>
<t t-extend="ImportView.side_panel">
<t t-jquery="#oe_import_has_header" t-operation="before">
<div
title="When checked, the import will be executed as a background job,
after splitting your file in small chunks that will be processed independently.
Use this to import very large files."
>
<input
type="checkbox"
class="oe_import_queue form-check-input"
id="oe_import_queue"
/>
<label for="oe_import_queue">Import in the background</label>
</div>
</t>
</t>
</templates>

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 Base_import_async Module - base_import_async
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 base_import_async. 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,6 @@
# Dependencies
This addon depends on:
- [base_import](../../odoo-bringout-oca-ocb-base_import)
- [queue_job](../../odoo-bringout-oca-queue-queue_job)

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 base_import_async or install in UI.

View file

@ -0,0 +1,7 @@
# Install
```bash
pip install odoo-bringout-oca-queue-base_import_async"
# or
uv pip install odoo-bringout-oca-queue-base_import_async"
```

View file

@ -0,0 +1,13 @@
# Models
Detected core models and extensions in base_import_async.
```mermaid
classDiagram
class base_import_import
class queue_job
```
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: base_import_async. Provides features documented in upstream Odoo 16 under this addon.
- Source: OCA/OCB 16.0, addon base_import_async
- License: LGPL-3

View file

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

View file

@ -0,0 +1,8 @@
# Security
This module does not define custom security rules or access controls beyond Odoo defaults.
Default Odoo security applies:
- Base user access through standard groups
- Model access inherited from dependencies
- No custom row-level security rules

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 base_import_async
```

View file

@ -0,0 +1,3 @@
# Wizards
This module does not include UI wizards.

View file

@ -0,0 +1,43 @@
[project]
name = "odoo-bringout-oca-queue-base_import_async"
version = "16.0.0"
description = "Asynchronous Import - Import CSV files in the background"
authors = [
{ name = "Ernad Husremovic", email = "hernad@bring.out.ba" }
]
dependencies = [
"odoo-bringout-oca-queue-base_import>=16.0.0",
"odoo-bringout-oca-queue-queue_job>=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 = ["base_import_async"]
[tool.rye]
managed = true
dev-dependencies = [
"pytest>=8.4.1",
]