diff --git a/__init__.py b/__init__.py index 31660d6a9650857f10c9dbdcd139145e0897ef6e..907658493b2b2108e37a890254bba9d0b9da9951 100644 --- a/__init__.py +++ b/__init__.py @@ -1,3 +1,6 @@ -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +# © 2019 Le Filament (<http://www.le-filament.com>) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from . import controllers from . import models +from . import wizard diff --git a/__manifest__.py b/__manifest__.py index fac1c29fb308607a237e62b6e5408d67669e69c3..bcd26ec73c4e3a03f1647c17281a51a4884a6259 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -9,10 +9,18 @@ "depends": [ 'base', 'web', + 'cgscop_partner' ], "data": [ # "security/ir.model.access.csv", "datas/ir_config_parameter.xml", + "views/assets.xml", + "views/alfresco_partner_files.xml", + "views/res_partner.xml", + "wizard/add_file_wizard.xml", + ], + 'qweb': [ + 'static/src/xml/*.xml', ], 'installable': True, 'auto_install': False, diff --git a/controllers/__init__.py b/controllers/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..4a51cde9123b17a6c4dd5311c7f5a8e0f51ad296 --- /dev/null +++ b/controllers/__init__.py @@ -0,0 +1,4 @@ +# © 2019 Le Filament (<http://www.le-filament.com>) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import main \ No newline at end of file diff --git a/controllers/main.py b/controllers/main.py new file mode 100644 index 0000000000000000000000000000000000000000..ea71fc1dc95b74c272252d177959fd05e46978c6 --- /dev/null +++ b/controllers/main.py @@ -0,0 +1,29 @@ +# © 2019 Le Filament (<http://www.le-filament.com>) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import base64 + +from odoo import http +from odoo.http import request +from odoo.addons.web.controllers.main import serialize_exception, content_disposition + + +class AlfrescoBinary(http.Controller): + @http.route('/web/binary/download_alfresco', type='http', auth="user") + @serialize_exception + def download_alfresco_document(self, id_alfresco, **kwargs): + """ Téléchargement des fichiers depuis alfresco. + + :param str id_alfresco: id de la ressource + @return: :class:`werkzeug.wrappers.Response` + """ + doc = request.env['alfresco.partner.files'].search( + [['file_id', '=', id_alfresco]]).alfresco_get_doc(id_alfresco) + filecontent = base64.b64decode( + doc['base64NodeContent']) + if not filecontent: + return request.not_found() + else: + return request.make_response(filecontent, [ + ('Content-Type', 'application/octet-stream'), + ('Content-Disposition', content_disposition(doc['name']))]) diff --git a/models/__init__.py b/models/__init__.py index a594022b97f66125d548d2f3a1d06437c19e22e2..ceb46c486344944e35411adc7ffbf19d0a8ccb21 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -2,3 +2,5 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from . import api_alfresco +from . import alfresco_partner_files +from . import res_partner diff --git a/models/alfresco_partner_files.py b/models/alfresco_partner_files.py new file mode 100644 index 0000000000000000000000000000000000000000..abb2ea29697092fcd235308c61035fdb93639c4f --- /dev/null +++ b/models/alfresco_partner_files.py @@ -0,0 +1,35 @@ +# © 2019 Le Filament (<http://www.le-filament.com>) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import models, fields, api + + +class AlfrescoPartnerFiles(models.TransientModel): + _name = 'alfresco.partner.files' + _inherit = 'connector.alfresco' + _description = "Requete fichiers par organisme" + + name = fields.Char('Nom du Fichier') + type = fields.Char('Type') + periode = fields.Char('Période') + validite = fields.Char('Validité') + file_id = fields.Char('ID Fichier') + last_modification = fields.Datetime('Dernière Modification') + user_id = fields.Many2one( + comodel_name='res.users', + string='User') + partner_id = fields.Many2one( + comodel_name='res.partner', + string='Organisme') + + @api.multi + def download_file(self): + for doc in self: + return { + 'type': 'ir.actions.act_url', + 'url': '/web/binary/download_alfresco?id_alfresco=%s' % ( + doc.file_id, ), + 'target': 'self', + } + + diff --git a/models/api_alfresco.py b/models/api_alfresco.py index 590d8e3d056adfff3d503e523f9b274d10f249d1..1c3e208851a919a4b6101cc73ef21bb717d77950 100644 --- a/models/api_alfresco.py +++ b/models/api_alfresco.py @@ -57,13 +57,16 @@ class ConnectorAlfresco(models.AbstractModel): err.__str__(), ) if response.status_code not in [200, 201]: - raise exceptions.Warning( - "L'appel url '%s' a échoué\n" - "- Code erreur : %d\n" - "- Message : %s" % ( - response.url, - response.status_code, - response.json().get('message'))) + if 'Le dossier organisme est inexistant' in response.json().get('message'): + print(response.json().get('message')) + else: + raise exceptions.Warning( + "L'appel url '%s' a échoué\n" + "- Code erreur : %d\n" + "- Message : %s" % ( + response.url, + response.status_code, + response.json().get('message'))) return response.json() # Get Methods @@ -118,7 +121,7 @@ class ConnectorAlfresco(models.AbstractModel): return self.get_nodeRef( self.alfresco_get_by_url(url=url, call_type='post', json=json)) - def alfresco_upload(self, doc): + def alfresco_upload(self, raisonSociale, type, periode, validite, filename, doc): """ Upload d'un document sur Alfresco :param doc: document encodé en base64 @@ -127,12 +130,12 @@ class ConnectorAlfresco(models.AbstractModel): """ url = '/alfresco/s/erp/depotdocument' json = { - 'raisonSociale': "LeFilament", - 'periode': u"Liste ministère 2020", - 'type': u"Autre", - 'nomOrigine': "NomFichier.pdf", - 'mimeType': "application/pdf", - 'validite': "2020", + 'raisonSociale': raisonSociale, + 'periode': periode, + 'type': type, + 'nomOrigine': filename, + 'mimeType': "application/octet-stream", + 'validite': validite, 'contentBase64': doc, } return self.get_nodeRef( diff --git a/models/res_partner.py b/models/res_partner.py new file mode 100644 index 0000000000000000000000000000000000000000..2a0b88bcf4a2f2ab75e6ef421946ee01ef3b4131 --- /dev/null +++ b/models/res_partner.py @@ -0,0 +1,49 @@ +# © 2019 Le Filament (<http://www.le-filament.com>) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import dateutil.parser +import pytz + +from odoo import models, fields + + +class AlfrescoPartner(models.Model): + _name = 'res.partner' + _inherit = ['res.partner', 'connector.alfresco'] + + id_alfresco = fields.Char('ID Dossier Alfresco') + + def get_partner_files(self): + """ Liste l'ensemble des fichiers pour un organisme + + La fonction fait appel à l'API Alfresco et enregistre le résultat + dans un modèle Transient. + L'ID user est ajouté à la table pour définir les requêtes propres à + chaque user + + @return: ir.act.window + """ + files = self.alfresco_list_docs(self.name).get('docs', '') + uid = self.env.user.id + alfresco_obj = self.env["alfresco.partner.files"] + alfresco_obj.search([['user_id', '=', uid]]).unlink() + for doc in files: + alfresco_obj.create({ + 'name': doc['name'], + 'type': doc['type'], + 'file_id': doc['nodeRef'].replace('workspace://SpacesStore/', ''), + 'user_id': uid, + 'periode': doc['periode'], + 'validite': doc['validite'], + 'last_modification': dateutil.parser.parse( + doc['modifiedOn']).astimezone(pytz.utc), + 'partner_id': self.id, + }) + return { + "type": "ir.actions.act_window", + "name": "Fichiers liés", + "res_model": "alfresco.partner.files", + "views": [[False, "tree"]], + "search_view_id": self.env.ref( + "connector_alfresco.alfresco_partner_files_search").id, + } diff --git a/static/src/js/alfresco_add_file.js b/static/src/js/alfresco_add_file.js new file mode 100644 index 0000000000000000000000000000000000000000..65d36723542daf5365db2ad74b7cc34dcd019993 --- /dev/null +++ b/static/src/js/alfresco_add_file.js @@ -0,0 +1,31 @@ +odoo.define('connector_alfresco.alfresco_add_file', function (require){ +"use strict"; + +var core = require('web.core'); +var ListController = require('web.ListController'); +var QWeb = core.qweb; +var session = require('web.session'); + +ListController.include({ + + renderButtons: function() { + this._super.apply(this, arguments); + var self = this; + this.$buttons.on('click', '.add_file', function() { + var active_id = self.getParent().getParent()._current_state.active_id; + self.do_action({ + type: "ir.actions.act_window", + name: "Ajouter un fichier", + res_model: "add.file.wizard", + views: [[false,'form']], + target: 'new', + view_type : 'form', + view_mode : 'form', + context: { 'active_id': Number(active_id) } + }); + }); + }, + +}); + +}); \ No newline at end of file diff --git a/static/src/xml/widget_listview.xml b/static/src/xml/widget_listview.xml new file mode 100644 index 0000000000000000000000000000000000000000..8067f943d6b1ff65574948c867f1344a93357159 --- /dev/null +++ b/static/src/xml/widget_listview.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright 2017 Le Filament (<https://www.le-filament.com>) + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> + +<templates xml:space="preserve"> + <t t-extend="ListView.buttons"> + <t t-jquery="div.o_list_buttons" t-operation="append"> + <t t-if="widget.modelName == 'alfresco.partner.files'" > + <button class="btn btn-secondary add_file" type="button" >Ajouter un fichier</button> + </t> + </t> + </t> +</templates> \ No newline at end of file diff --git a/views/alfresco_partner_files.xml b/views/alfresco_partner_files.xml new file mode 100644 index 0000000000000000000000000000000000000000..2f7ba0631e2089e8630ef46639c9b330892a18ac --- /dev/null +++ b/views/alfresco_partner_files.xml @@ -0,0 +1,44 @@ +<?xml version="1.0"?> +<!-- Copyright 2019 Le Filament + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> + +<odoo> + <data> + + <record id="alfresco_partner_files_search" model="ir.ui.view"> + <field name="name">alfresco.partner.files.search</field> + <field name="model">alfresco.partner.files</field> + <field name="arch" type="xml"> + <search> + <!-- Champs de recherche --> + <field name="name" /> + <field name="type"/> + <!-- Groupes --> + <group expand="0" name="group_by" string="Group By"> + <filter string="Types" name="file_type" context="{'group_by': 'type'}"/> + <filter string="Période" name="file_periode" context="{'group_by': 'periode'}"/> + <filter string="Validité" name="file_validite" context="{'group_by': 'validite'}"/> + </group> + + </search> + </field> + </record> + + <record id="alfresco_partner_files_tree" model="ir.ui.view"> + <field name="name">alfresco.partner.files.tree</field> + <field name="model">alfresco.partner.files</field> + <field eval="8" name="priority"/> + <field name="arch" type="xml"> + <tree string="Fichiers" create="false" edit="false" delete="false"> + <field name="name" /> + <field name="type"/> + <field name="periode"/> + <field name="validite"/> + <field name="last_modification"/> + <button name="download_file" string="Télécharger" type="object" /> + </tree> + </field> + </record> + + </data> +</odoo> diff --git a/views/assets.xml b/views/assets.xml new file mode 100644 index 0000000000000000000000000000000000000000..80fb9b27a537cbe396b182539f0ca0b1e03a0e04 --- /dev/null +++ b/views/assets.xml @@ -0,0 +1,13 @@ +<?xml version="1.0"?> +<!-- Copyright 2019 Le Filament + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> + +<odoo> + + <template id="alfresco_assets_backend" name="account assets" inherit_id="web.assets_backend"> + <xpath expr="." position="inside"> + <script type="text/javascript" src="/connector_alfresco/static/src/js/alfresco_add_file.js"></script> + </xpath> + </template> + +</odoo> \ No newline at end of file diff --git a/views/res_partner.xml b/views/res_partner.xml new file mode 100644 index 0000000000000000000000000000000000000000..ba1d761ecb1313257644106b3f12084655f99e2a --- /dev/null +++ b/views/res_partner.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<!-- Copyright 2019 Le Filament + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> + +<odoo> + <data> + + <record id="view_partner_cooperative_form_inherited" model="ir.ui.view"> + <field name="name">cooperative.alfresco.form</field> + <field name="model">res.partner</field> + <field name="inherit_id" ref="cgscop_partner.view_partner_cooperative_form"/> + <field name="arch" type="xml"> + <header position="inside"> + <button string="Fichiers" type="object" name="get_partner_files" /> + </header> + </field> + </record> + + </data> +</odoo> diff --git a/wizard/__init__.py b/wizard/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..0f342bee3af4bc001f4d7f4615711ed9ad3c87e9 --- /dev/null +++ b/wizard/__init__.py @@ -0,0 +1,4 @@ +# © 2019 Le Filament (<http://www.le-filament.com>) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import add_file_wizard \ No newline at end of file diff --git a/wizard/add_file_wizard.py b/wizard/add_file_wizard.py new file mode 100644 index 0000000000000000000000000000000000000000..45e7217fbeaa5aa1ad60c550611477ddacc79395 --- /dev/null +++ b/wizard/add_file_wizard.py @@ -0,0 +1,67 @@ +# © 2019 Le Filament (<http://www.le-filament.com>) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, fields, models + + +class AddFileWizard(models.TransientModel): + _name = 'add.file.wizard' + _inherit = 'connector.alfresco' + _description = "Ajout de fichier dans Alfresco" + + # Default functions + def _get_selection(self, value): + file_type = self.alfresco_list_type()[value] + select_type = [] + for type in file_type: + select_type.append( + (type, type)) + return select_type + + @api.model + def _get_type(self): + return self._get_selection('type') + + @api.model + def _get_periode(self): + return self._get_selection('periode') + + @api.model + def _get_validite(self): + return self._get_selection('validite') + + @api.model + def _default_partner_id(self): + return self.env.context.get('active_id') + + type = fields.Selection(selection=_get_type, string='Type') + periode = fields.Selection(selection=_get_periode, string='Période') + validite = fields.Selection(selection=_get_validite, string='Validité') + file = fields.Binary('Fichier') + filename = fields.Char('Nom') + content_type = fields.Char('MimeType') + partner_id = fields.Many2one( + comodel_name='res.partner', + string='Organisme', + default=_default_partner_id,) + + @api.multi + def add_file(self): + self.alfresco_upload( + raisonSociale=self.partner_id.name, + type=self.type, + periode=self.periode, + validite=self.validite, + filename=self.filename, + doc=self.file.decode('utf-8')) + + return { + "type": "ir.actions.act_window", + "name": "Fichiers liés", + "res_model": "alfresco.partner.files", + "views": [[False, "tree"]], + "target": "main", + "search_view_id": self.env.ref( + "connector_alfresco.alfresco_partner_files_search").id, + } + diff --git a/wizard/add_file_wizard.xml b/wizard/add_file_wizard.xml new file mode 100644 index 0000000000000000000000000000000000000000..b50f7e962b3bee67f0c2f94fe5cfd7ae12ec061a --- /dev/null +++ b/wizard/add_file_wizard.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<odoo> + <!-- WIZARD FORM --> + <record id="add_file_wizard_view_form" model="ir.ui.view"> + <field name="name">add.file.wizard.form</field> + <field name="model">add.file.wizard</field> + <field name="arch" type="xml"> + <form string="Ajouter un Fichier"> + <group name="infos" string="Informations"> + <field name="partner_id" readonly="1" /> + <field name="type" required="1" /> + <field name="periode" required="1" /> + <field name="validite" required="1" /> + </group> + <group> + <field name="filename" invisible="1"/> + <field name="content_type" invisible="1"/> + <field name="file" filename="filename" content_type="content_type" required="1"/> + </group> + <footer> + <button class="btn btn-sm btn-primary" name="add_file" string="Ajouter" type="object" confirm="Êtes-vous sûr de vouloir ajouter ce fichier ?"/> + <button class="btn btn-sm btn-default" special="cancel" string="Fermer"/> + </footer> + </form> + </field> + </record> + + <record id="add_file_wizard_create_action" model="ir.actions.act_window"> + <field name="name">Ajouter un fichier</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">add.file.wizard</field> + <field name="view_mode">form</field> + <field name="view_id" ref="add_file_wizard_view_form"/> + <field name="target">new</field> + </record> + +</odoo>