[IMP] attachment_zipped_download: provide ir.attachment.action_download mixin

This helps to download multiple attachments from any models.

[UPD] README.rst

[UPD] Update attachment_zipped_download.pot

[UPD] README.rst

attachment_zipped_download 16.0.2.0.0

[UPD] README.rst

Update translation files

Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Translation: knowledge-16.0/knowledge-16.0-attachment_zipped_download
Translate-URL: https://translation.odoo-community.org/projects/knowledge-16-0/knowledge-16-0-attachment_zipped_download/
This commit is contained in:
Pierre Verkest 2023-04-28 16:13:20 +02:00 committed by Víctor Martínez
parent 25ceed4377
commit e267b0b836
17 changed files with 591 additions and 25 deletions

View File

@ -2,10 +2,13 @@
Attachment Zipped Download
==========================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:ff7e96407afd1498d4d7a92046727ac078de41e9e3789dcbe61c469b4b13ae67
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
@ -19,14 +22,17 @@ Attachment Zipped Download
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/knowledge-16-0/knowledge-16-0-attachment_zipped_download
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/118/16.0
:alt: Try me on Runbot
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/knowledge&target_branch=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
|badge1| |badge2| |badge3| |badge4| |badge5|
This module allows downloading multiple attachments as a zip file.
This also provide a helper class `IrAttachmentActionDownloadMixin`
to be used by developer to add action method on models.
**Table of contents**
.. contents::
@ -38,12 +44,88 @@ Usage
#. Go to *Settings > Technical > Database Structure > Attachments* and select some files.
#. Go to *Actions > Download* and a zip file containing the selected files will be downloaded.
## For developer
You can reuse the `IrAttachmentActionDownloadMixin` on your
favorite models::
from odoo import models
class StockPicking(models.Model):
_name = "stock.picking"
_inherit = ["stock.picking", "ir.attachment.action_download"]
Then you can add an action button on list view line or on the action button
(when multiple lines are selected) to download all files::
<odoo>
<!--
add a button on list view to download all attachement present
on the given transfert
-->
<record id="vpicktree" model="ir.ui.view">
<field name="inherit_id" ref="stock.vpicktree"/>
<field name="name">stock.picking.tree download attachments</field>
<field name="model">stock.picking</field>
<field name="arch" type="xml">
<field name="json_popover" position="after">
<button name="action_download_attachments"
type="object"
icon="fa-download"
string="Download attachment(s)"
aria-label="Download Proof documents"
class="float-right"/>
</field>
</field>
</record>
<!--
Add "Download attachments" item in the Action menu when
multiple records are selected
-->
<record id="action_download_picking_attachements" model="ir.actions.server">
<field name="name">Download attachments</field>
<field name="model_id" ref="stock.model_stock_picking"/>
<field name="binding_model_id" ref="stock.model_stock_picking"/>
<field name="binding_view_types">list</field>
<field name="state">code</field>
<field name="code">
action = records.action_download_attachments()
</field>
</record>
</odoo>
.. note::
Even you will be able to generate a zip file with multiple document with the
same name it's advice to overwrite `_compute_zip_file_name` to improve the
name. When a slash (`/`) is present in the path it will create a directory.
This example will create a directory per stock.picking using its name::
class IrAttachment(models.Model):
_inherit = "ir.attachment"
def _compute_zip_file_name(self):
self.ensure_one()
if self.res_model and self.res_model == "stock.picking":
return (
self.env[self.res_model]
.browse(self.res_id)
.display_name.replace("/", "-")
+ "/"
+ self.name
)
return super()._compute_zip_file_name()
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/knowledge/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/knowledge/issues/new?body=module:%20attachment_zipped_download%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.
@ -66,6 +148,8 @@ Contributors
* Víctor Martínez
* Pedro M. Baeza
* Pierre Verkest <pierreverkest@gmail.com>
Maintainers
~~~~~~~~~~~

View File

@ -2,7 +2,7 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "Attachment Zipped Download",
"version": "16.0.1.0.2",
"version": "16.0.2.0.0",
"category": "Tools",
"website": "https://github.com/OCA/knowledge",
"author": "Tecnativa, Odoo Community Association (OCA)",

View File

@ -13,6 +13,14 @@ msgstr ""
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: attachment_zipped_download
#: model:ir.model,name:attachment_zipped_download.model_ir_attachment_action_download
msgid ""
"\n"
" Mixin to help download attachments linked to record(s).\n"
" "
msgstr ""
#. module: attachment_zipped_download
#: model:ir.model,name:attachment_zipped_download.model_ir_attachment
msgid "Attachment"
@ -23,6 +31,13 @@ msgstr ""
msgid "Download"
msgstr ""
#. module: attachment_zipped_download
#. odoo-python
#: code:addons/attachment_zipped_download/models/ir_attachment_action_download.py:0
#, python-format
msgid "No attachment!"
msgstr ""
#. module: attachment_zipped_download
#. odoo-python
#: code:addons/attachment_zipped_download/models/ir_attachment.py:0
@ -30,6 +45,13 @@ msgstr ""
msgid "None attachment selected. Only binary attachments allowed."
msgstr ""
#. module: attachment_zipped_download
#. odoo-python
#: code:addons/attachment_zipped_download/models/ir_attachment_action_download.py:0
#, python-format
msgid "There is no document found to download."
msgstr ""
#. module: attachment_zipped_download
#. odoo-python
#: code:addons/attachment_zipped_download/controllers/main.py:0

View File

@ -17,6 +17,14 @@ msgstr ""
"Plural-Forms: \n"
"X-Generator: Poedit 2.3\n"
#. module: attachment_zipped_download
#: model:ir.model,name:attachment_zipped_download.model_ir_attachment_action_download
msgid ""
"\n"
" Mixin to help download attachments linked to record(s).\n"
" "
msgstr ""
#. module: attachment_zipped_download
#: model:ir.model,name:attachment_zipped_download.model_ir_attachment
msgid "Attachment"
@ -27,6 +35,13 @@ msgstr "Adjunto"
msgid "Download"
msgstr "Descargar"
#. module: attachment_zipped_download
#. odoo-python
#: code:addons/attachment_zipped_download/models/ir_attachment_action_download.py:0
#, python-format
msgid "No attachment!"
msgstr ""
#. module: attachment_zipped_download
#. odoo-python
#: code:addons/attachment_zipped_download/models/ir_attachment.py:0
@ -36,6 +51,13 @@ msgstr ""
"No se seleccionó ningún archivo adjunto. Solo se permiten archivos adjuntos "
"binarios."
#. module: attachment_zipped_download
#. odoo-python
#: code:addons/attachment_zipped_download/models/ir_attachment_action_download.py:0
#, python-format
msgid "There is no document found to download."
msgstr ""
#. module: attachment_zipped_download
#. odoo-python
#: code:addons/attachment_zipped_download/controllers/main.py:0

View File

@ -0,0 +1,78 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * attachment_zipped_download
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.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: attachment_zipped_download
#: model:ir.model,name:attachment_zipped_download.model_ir_attachment_action_download
msgid ""
"\n"
" Mixin to help download attachments linked to record(s).\n"
" "
msgstr "Mixin pour faciliter le téléchargements des pièces jointes lié aux enregistrements."
#. module: attachment_zipped_download
#: model:ir.model,name:attachment_zipped_download.model_ir_attachment
msgid "Attachment"
msgstr "Pièce jointe"
#. module: attachment_zipped_download
#: model:ir.model.fields,field_description:attachment_zipped_download.field_ir_attachment__display_name
#: model:ir.model.fields,field_description:attachment_zipped_download.field_ir_attachment_action_download__display_name
msgid "Display Name"
msgstr "Nom affiché"
#. module: attachment_zipped_download
#: model:ir.actions.server,name:attachment_zipped_download.action_attachments_download
msgid "Download"
msgstr "Télécharger"
#. module: attachment_zipped_download
#: model:ir.model.fields,field_description:attachment_zipped_download.field_ir_attachment__id
#: model:ir.model.fields,field_description:attachment_zipped_download.field_ir_attachment_action_download__id
msgid "ID"
msgstr ""
#. module: attachment_zipped_download
#: model:ir.model.fields,field_description:attachment_zipped_download.field_ir_attachment____last_update
#: model:ir.model.fields,field_description:attachment_zipped_download.field_ir_attachment_action_download____last_update
msgid "Last Modified on"
msgstr "Dernière modification le"
#. module: attachment_zipped_download
#: code:addons/attachment_zipped_download/models/ir_attachment_action_download.py:0
#: code:addons/src/knowledge/attachment_zipped_download/models/ir_attachment_action_download.py:0
#, python-format
msgid "No attachment!"
msgstr "Aucune pièce jointe !"
#. module: attachment_zipped_download
#: code:addons/attachment_zipped_download/models/ir_attachment.py:0
#: code:addons/src/knowledge/attachment_zipped_download/models/ir_attachment.py:0
#, python-format
msgid "None attachment selected. Only binary attachments allowed."
msgstr "Aucune pièce jointe sélectionnée. Seul les picèces jointes de type Binaire sont permises."
#. module: attachment_zipped_download
#: code:addons/attachment_zipped_download/models/ir_attachment_action_download.py:0
#: code:addons/src/knowledge/attachment_zipped_download/models/ir_attachment_action_download.py:0
#, python-format
msgid "There is no document found to download."
msgstr "Aucune pièce jointe téléchargeable trouvé."
#. module: attachment_zipped_download
#: code:addons/attachment_zipped_download/controllers/main.py:0
#: code:addons/src/knowledge/attachment_zipped_download/controllers/main.py:0
#, python-format
msgid "attachments.zip"
msgstr "pieces-jointes.zip"

View File

@ -17,6 +17,14 @@ msgstr ""
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 4.14.1\n"
#. module: attachment_zipped_download
#: model:ir.model,name:attachment_zipped_download.model_ir_attachment_action_download
msgid ""
"\n"
" Mixin to help download attachments linked to record(s).\n"
" "
msgstr ""
#. module: attachment_zipped_download
#: model:ir.model,name:attachment_zipped_download.model_ir_attachment
msgid "Attachment"
@ -27,6 +35,13 @@ msgstr "Prilog"
msgid "Download"
msgstr "Preuzimanje"
#. module: attachment_zipped_download
#. odoo-python
#: code:addons/attachment_zipped_download/models/ir_attachment_action_download.py:0
#, python-format
msgid "No attachment!"
msgstr ""
#. module: attachment_zipped_download
#. odoo-python
#: code:addons/attachment_zipped_download/models/ir_attachment.py:0
@ -34,6 +49,13 @@ msgstr "Preuzimanje"
msgid "None attachment selected. Only binary attachments allowed."
msgstr "Nema odabranih priloga. Samo binarni prilozi su dozvoljeni."
#. module: attachment_zipped_download
#. odoo-python
#: code:addons/attachment_zipped_download/models/ir_attachment_action_download.py:0
#, python-format
msgid "There is no document found to download."
msgstr ""
#. module: attachment_zipped_download
#. odoo-python
#: code:addons/attachment_zipped_download/controllers/main.py:0

View File

@ -16,6 +16,14 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.14.1\n"
#. module: attachment_zipped_download
#: model:ir.model,name:attachment_zipped_download.model_ir_attachment_action_download
msgid ""
"\n"
" Mixin to help download attachments linked to record(s).\n"
" "
msgstr ""
#. module: attachment_zipped_download
#: model:ir.model,name:attachment_zipped_download.model_ir_attachment
msgid "Attachment"
@ -26,6 +34,13 @@ msgstr "Allegato"
msgid "Download"
msgstr "Scarica"
#. module: attachment_zipped_download
#. odoo-python
#: code:addons/attachment_zipped_download/models/ir_attachment_action_download.py:0
#, python-format
msgid "No attachment!"
msgstr ""
#. module: attachment_zipped_download
#. odoo-python
#: code:addons/attachment_zipped_download/models/ir_attachment.py:0
@ -33,9 +48,25 @@ msgstr "Scarica"
msgid "None attachment selected. Only binary attachments allowed."
msgstr "Nessun allegato selezionato. Consentiti solo allegati binari."
#. module: attachment_zipped_download
#. odoo-python
#: code:addons/attachment_zipped_download/models/ir_attachment_action_download.py:0
#, python-format
msgid "There is no document found to download."
msgstr ""
#. module: attachment_zipped_download
#. odoo-python
#: code:addons/attachment_zipped_download/controllers/main.py:0
#, python-format
msgid "attachments.zip"
msgstr "attachments.zip"
#~ msgid "Display Name"
#~ msgstr "Nome visualizzato"
#~ msgid "ID"
#~ msgstr "ID"
#~ msgid "Last Modified on"
#~ msgstr "Ultima modifica il"

View File

@ -1 +1,2 @@
from . import ir_attachment
from . import ir_attachment_action_download

View File

@ -0,0 +1,55 @@
# Copyright 2023 Foodles (https://www.foodles.com/)
# @author Pierre Verkest <pierreverkest84@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import _, models
class IrAttachmentActionDownloadMixin(models.AbstractModel):
_name = "ir.attachment.action_download"
_description = """
Mixin to help download attachments linked to record(s).
"""
def _get_downloadable_attachments(self):
"""Give a chance to easily overwrite this method
on sub modules to limit restict attachement able to downlaods
In some case we probably want the user download some specific
document that are probably related to the current model
By default return all attachment link the the record.
"""
return self.env["ir.attachment"].search(
[("res_model", "=", self._name), ("res_id", "in", self.ids)]
)
def action_download_attachments(self):
"""Return action to:
* emit a warning message if no attachment found
* download a file if only 1 file found
* zip and download the list of attachment returns by `_get_downloadable_attachments`
"""
attachments = self._get_downloadable_attachments()
if not attachments:
title = _("No attachment!")
message = _("There is no document found to download.")
return {
"type": "ir.actions.client",
"tag": "display_notification",
"params": {
"type": "warning",
"title": title,
"message": message,
"sticky": True,
},
}
if len(attachments) == 1:
return {
"target": "self",
"type": "ir.actions.act_url",
"url": "/web/content/%s?download=1" % attachments.id,
}
else:
return attachments.action_attachments_download()

View File

@ -4,3 +4,5 @@
* Víctor Martínez
* Pedro M. Baeza
* Pierre Verkest <pierreverkest@gmail.com>

View File

@ -1 +1,4 @@
This module allows downloading multiple attachments as a zip file.
This also provide a helper class `IrAttachmentActionDownloadMixin`
to be used by developer to add action method on models.

View File

@ -1,2 +1,78 @@
#. Go to *Settings > Technical > Database Structure > Attachments* and select some files.
#. Go to *Actions > Download* and a zip file containing the selected files will be downloaded.
## For developer
You can reuse the `IrAttachmentActionDownloadMixin` on your
favorite models::
from odoo import models
class StockPicking(models.Model):
_name = "stock.picking"
_inherit = ["stock.picking", "ir.attachment.action_download"]
Then you can add an action button on list view line or on the action button
(when multiple lines are selected) to download all files::
<odoo>
<!--
add a button on list view to download all attachement present
on the given transfert
-->
<record id="vpicktree" model="ir.ui.view">
<field name="inherit_id" ref="stock.vpicktree"/>
<field name="name">stock.picking.tree download attachments</field>
<field name="model">stock.picking</field>
<field name="arch" type="xml">
<field name="json_popover" position="after">
<button name="action_download_attachments"
type="object"
icon="fa-download"
string="Download attachment(s)"
aria-label="Download Proof documents"
class="float-right"/>
</field>
</field>
</record>
<!--
Add "Download attachments" item in the Action menu when
multiple records are selected
-->
<record id="action_download_picking_attachements" model="ir.actions.server">
<field name="name">Download attachments</field>
<field name="model_id" ref="stock.model_stock_picking"/>
<field name="binding_model_id" ref="stock.model_stock_picking"/>
<field name="binding_view_types">list</field>
<field name="state">code</field>
<field name="code">
action = records.action_download_attachments()
</field>
</record>
</odoo>
.. note::
Even you will be able to generate a zip file with multiple document with the
same name it's advice to overwrite `_compute_zip_file_name` to improve the
name. When a slash (`/`) is present in the path it will create a directory.
This example will create a directory per stock.picking using its name::
class IrAttachment(models.Model):
_inherit = "ir.attachment"
def _compute_zip_file_name(self):
self.ensure_one()
if self.res_model and self.res_model == "stock.picking":
return (
self.env[self.res_model]
.browse(self.res_id)
.display_name.replace("/", "-")
+ "/"
+ self.name
)
return super()._compute_zip_file_name()

View File

@ -1,20 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<?xml version="1.0" encoding="utf-8"?>
<!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 0.15.1: http://docutils.sourceforge.net/" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>Attachment Zipped Download</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
@ -366,47 +366,125 @@ ul.auto-toc {
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:ff7e96407afd1498d4d7a92046727ac078de41e9e3789dcbe61c469b4b13ae67
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" 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" 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" href="https://github.com/OCA/knowledge/tree/16.0/attachment_zipped_download"><img alt="OCA/knowledge" src="https://img.shields.io/badge/github-OCA%2Fknowledge-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/knowledge-16-0/knowledge-16-0-attachment_zipped_download"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/118/16.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<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/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/knowledge/tree/16.0/attachment_zipped_download"><img alt="OCA/knowledge" src="https://img.shields.io/badge/github-OCA%2Fknowledge-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/knowledge-16-0/knowledge-16-0-attachment_zipped_download"><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/knowledge&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 allows downloading multiple attachments as a zip file.</p>
<p>This also provide a helper class <cite>IrAttachmentActionDownloadMixin</cite>
to be used by developer to add action method on models.</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="id1">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id6">Maintainers</a></li>
<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="#maintainers" id="toc-entry-6">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id1">Usage</a></h1>
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<ol class="arabic simple">
<li>Go to <em>Settings &gt; Technical &gt; Database Structure &gt; Attachments</em> and select some files.</li>
<li>Go to <em>Actions &gt; Download</em> and a zip file containing the selected files will be downloaded.</li>
</ol>
<p>## For developer</p>
<p>You can reuse the <cite>IrAttachmentActionDownloadMixin</cite> on your
favorite models:</p>
<pre class="literal-block">
from odoo import models
class StockPicking(models.Model):
_name = &quot;stock.picking&quot;
_inherit = [&quot;stock.picking&quot;, &quot;ir.attachment.action_download&quot;]
</pre>
<p>Then you can add an action button on list view line or on the action button
(when multiple lines are selected) to download all files:</p>
<pre class="literal-block">
&lt;odoo&gt;
&lt;!--
add a button on list view to download all attachement present
on the given transfert
--&gt;
&lt;record id=&quot;vpicktree&quot; model=&quot;ir.ui.view&quot;&gt;
&lt;field name=&quot;inherit_id&quot; ref=&quot;stock.vpicktree&quot;/&gt;
&lt;field name=&quot;name&quot;&gt;stock.picking.tree download attachments&lt;/field&gt;
&lt;field name=&quot;model&quot;&gt;stock.picking&lt;/field&gt;
&lt;field name=&quot;arch&quot; type=&quot;xml&quot;&gt;
&lt;field name=&quot;json_popover&quot; position=&quot;after&quot;&gt;
&lt;button name=&quot;action_download_attachments&quot;
type=&quot;object&quot;
icon=&quot;fa-download&quot;
string=&quot;Download attachment(s)&quot;
aria-label=&quot;Download Proof documents&quot;
class=&quot;float-right&quot;/&gt;
&lt;/field&gt;
&lt;/field&gt;
&lt;/record&gt;
&lt;!--
Add &quot;Download attachments&quot; item in the Action menu when
multiple records are selected
--&gt;
&lt;record id=&quot;action_download_picking_attachements&quot; model=&quot;ir.actions.server&quot;&gt;
&lt;field name=&quot;name&quot;&gt;Download attachments&lt;/field&gt;
&lt;field name=&quot;model_id&quot; ref=&quot;stock.model_stock_picking&quot;/&gt;
&lt;field name=&quot;binding_model_id&quot; ref=&quot;stock.model_stock_picking&quot;/&gt;
&lt;field name=&quot;binding_view_types&quot;&gt;list&lt;/field&gt;
&lt;field name=&quot;state&quot;&gt;code&lt;/field&gt;
&lt;field name=&quot;code&quot;&gt;
action = records.action_download_attachments()
&lt;/field&gt;
&lt;/record&gt;
&lt;/odoo&gt;
</pre>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p>Even you will be able to generate a zip file with multiple document with the
same name its advice to overwrite <cite>_compute_zip_file_name</cite> to improve the
name. When a slash (<cite>/</cite>) is present in the path it will create a directory.
This example will create a directory per stock.picking using its name:</p>
<pre class="last literal-block">
class IrAttachment(models.Model):
_inherit = &quot;ir.attachment&quot;
def _compute_zip_file_name(self):
self.ensure_one()
if self.res_model and self.res_model == &quot;stock.picking&quot;:
return (
self.env[self.res_model]
.browse(self.res_id)
.display_name.replace(&quot;/&quot;, &quot;-&quot;)
+ &quot;/&quot;
+ self.name
)
return super()._compute_zip_file_name()
</pre>
</div>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id2">Bug Tracker</a></h1>
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/knowledge/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 smashing it by providing a detailed and welcomed
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/knowledge/issues/new?body=module:%20attachment_zipped_download%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="#id3">Credits</a></h1>
<h1><a class="toc-backref" href="#toc-entry-3">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id4">Authors</a></h2>
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<ul class="simple">
<li>Tecnativa</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id5">Contributors</a></h2>
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<ul class="simple">
<li>César Fernández Domínguez &lt;<a class="reference external" href="mailto:cesfernandez&#64;outlook.com">cesfernandez&#64;outlook.com</a>&gt;</li>
<li><a class="reference external" href="https://www.tecnativa.com">Tecnativa</a>:<ul>
@ -414,10 +492,11 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<li>Pedro M. Baeza</li>
</ul>
</li>
<li>Pierre Verkest &lt;<a class="reference external" href="mailto:pierreverkest&#64;gmail.com">pierreverkest&#64;gmail.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id6">Maintainers</a></h2>
<h2><a class="toc-backref" href="#toc-entry-6">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

View File

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

View File

@ -0,0 +1,9 @@
# Copyright 2023 Foodles (https://www.foodles.com/)
# @author Pierre Verkest <pierreverkest84@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import models
class ResPartner(models.Model):
_name = "res.partner"
_inherit = ["res.partner", "ir.attachment.action_download"]

View File

@ -0,0 +1,81 @@
# Copyright 2023 Foodles (https://www.foodles.com/)
# @author Pierre Verkest <pierreverkest84@gmail.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo_test_helper import FakeModelLoader
from odoo.tests import SavepointCase
from .test_attachment_zipped_download import TestAttachmentZippedDownloadBase
class TestMixin(SavepointCase, TestAttachmentZippedDownloadBase):
@classmethod
def setUpClass(cls):
super(TestMixin, cls).setUpClass()
cls.loader = FakeModelLoader(cls.env, cls.__module__)
cls.addClassCleanup(cls.loader.restore_registry)
cls.loader.backup_registry()
# Imported Test model must be done after the backup_registry
from .models.res_partner import ResPartner
cls.loader.update_registry((ResPartner,))
cls.partner_1 = cls.env.ref("base.res_partner_1")
cls.partner_2 = cls.env.ref("base.res_partner_2")
cls.partner_3 = cls.env.ref("base.res_partner_3")
cls.partner_1_f1 = cls._create_attachment(
cls.env,
cls.env.uid,
"partner_1-f1.txt",
model="res.partner",
res_id=cls.partner_1.id,
)
cls.partner_1_f2 = cls._create_attachment(
cls.env,
cls.env.uid,
"partner_1-f2.txt",
model="res.partner",
res_id=cls.partner_1.id,
)
cls.partner_2_f1 = cls._create_attachment(
cls.env,
cls.env.uid,
"partner_2-f1.txt",
model="res.partner",
res_id=cls.partner_2.id,
)
def test_action_download_attachments_no_attachment(self):
action = self.partner_3.action_download_attachments()
self.assertEqual(action["type"], "ir.actions.client")
self.assertEqual(action["tag"], "display_notification")
def test_action_download_attachments_one_attachment(self):
action = (self.partner_2 | self.partner_3).action_download_attachments()
self.assertEqual(action["type"], "ir.actions.act_url")
self.assertEqual(action["target"], "self")
self.assertEqual(
action["url"], "/web/content/%s?download=1" % self.partner_2_f1.id
)
def test_action_download_attachments_two_attachment_one_record(self):
action = (self.partner_1).action_download_attachments()
self.assertEqual(action["type"], "ir.actions.act_url")
self.assertEqual(action["target"], "self")
self.assertTrue(action["url"].startswith("/web/attachment/download_zip?ids="))
ids = sorted(map(int, action["url"].split("=")[1].split(",")))
self.assertEqual(ids, (self.partner_1_f1 | self.partner_1_f2).ids)
def test_action_download_attachments_three_attachment_n_records(self):
action = (
self.partner_1 | self.partner_2 | self.partner_3
).action_download_attachments()
self.assertEqual(action["type"], "ir.actions.act_url")
self.assertEqual(action["target"], "self")
self.assertTrue(action["url"].startswith("/web/attachment/download_zip?ids="))
ids = sorted(map(int, action["url"].split("=")[1].split(",")))
self.assertEqual(
ids, (self.partner_1_f1 + self.partner_1_f2 + self.partner_2_f1).ids
)