From eda071a029e530617db8d8a5cac1ec20df061b81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Tue, 13 Oct 2015 16:58:43 +0200 Subject: [PATCH] [MOV] move addons out of __unported__ (they remain not installable) --- pingen/__init__.py | 25 ++ pingen/__openerp__.py | 119 ++++++++ pingen/i18n/fr.po | 396 ++++++++++++++++++++++++++ pingen/i18n/pingen.pot | 388 +++++++++++++++++++++++++ pingen/ir_attachment.py | 123 ++++++++ pingen/ir_attachment_view.xml | 31 ++ pingen/pingen.py | 227 +++++++++++++++ pingen/pingen_data.xml | 32 +++ pingen/pingen_document.py | 425 ++++++++++++++++++++++++++++ pingen/pingen_document_view.xml | 161 +++++++++++ pingen/res_company.py | 42 +++ pingen/res_company_view.xml | 20 ++ pingen/security/ir.model.access.csv | 3 + 13 files changed, 1992 insertions(+) create mode 100644 pingen/__init__.py create mode 100644 pingen/__openerp__.py create mode 100644 pingen/i18n/fr.po create mode 100644 pingen/i18n/pingen.pot create mode 100644 pingen/ir_attachment.py create mode 100644 pingen/ir_attachment_view.xml create mode 100644 pingen/pingen.py create mode 100644 pingen/pingen_data.xml create mode 100644 pingen/pingen_document.py create mode 100644 pingen/pingen_document_view.xml create mode 100644 pingen/res_company.py create mode 100644 pingen/res_company_view.xml create mode 100644 pingen/security/ir.model.access.csv diff --git a/pingen/__init__.py b/pingen/__init__.py new file mode 100644 index 0000000..4ff2fea --- /dev/null +++ b/pingen/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Guewen Baconnier +# Copyright 2012 Camptocamp SA +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import ir_attachment +import pingen +import pingen_document +import res_company diff --git a/pingen/__openerp__.py b/pingen/__openerp__.py new file mode 100644 index 0000000..4ae5dc8 --- /dev/null +++ b/pingen/__openerp__.py @@ -0,0 +1,119 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Guewen Baconnier +# Copyright 2012 Camptocamp SA +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +{ + 'name': 'pingen.com integration', + 'version': '1.0', + 'author': "Camptocamp,Odoo Community Association (OCA)", + 'maintainer': 'Camptocamp', + 'license': 'AGPL-3', + 'category': 'Reporting', + 'complexity': 'easy', + 'depends': [], + 'external_dependencies': { + 'python': ['requests'], + }, + 'description': """ +Integration with pingen.com +=========================== + +What is pingen.com +------------------ + +Pingen.com is a paid online service. +It sends uploaded documents by letter post. + +Scope of the integration +------------------------ + +One can decide, per document / attachment, if it should be pushed +to pingen.com. The documents are pushed asynchronously. + +A second cron updates the informations of the documents from pingen.com, so we +know which of them have been sent. + +Configuration +------------- + +The authentication token is configured on the company's view. You can also +tick a checkbox if the staging environment (https://stage-api.pingen.com) +should be used. + +The setup of the 2 crons can be changed as well: + + * Run Pingen Document Push + * Run Pingen Document Update + +Usage +----- + +On the attachment view, a new pingen.com tab has been added. +You can tick a box to push the document to pingen.com. + +There is 3 additional options: + + * Send: the document will not be only uploaded, but will be also be sent + * Speed: priority or economy + * Type of print: color or black and white + +Once the configuration is done and the attachment saved, a Pingen Document +is created. You can directly access to the latter on the Link on the right on +the attachment view. + +You can find them in `Settings > Customization > Low Level Objets > Pingen +Documents` or in the more convenient `Documents` menu if you have installed the +`document` module. + +Errors +------ + +Sometimes, pingen.com will refuse to send a document because it does not meet +its requirements. In such case, the document's state becomes "Pingen Error" and +you will need to manually handle the case, either from the pingen.com backend, +or by changing the document on OpenERP and resolving the error on the Pingen +Document. + +When a connection error occurs, the action will be retried on the next scheduler +run. + +Dependencies +------------ + + * Require the Python library `requests `_ + * The PDF files sent to pingen.com have to respect some `formatting rules + `_. + * The address must be in a format accepted by pingen.com: the last line + is the country in English or German. + +""", + 'website': 'http://www.camptocamp.com', + 'data': [ + 'ir_attachment_view.xml', + 'pingen_document_view.xml', + 'pingen_data.xml', + 'res_company_view.xml', + 'security/ir.model.access.csv', + ], + 'tests': [], + 'installable': False, + 'auto_install': False, + 'application': True, +} diff --git a/pingen/i18n/fr.po b/pingen/i18n/fr.po new file mode 100644 index 0000000..8132281 --- /dev/null +++ b/pingen/i18n/fr.po @@ -0,0 +1,396 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * pingen +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 6.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-11-26 10:55+0000\n" +"PO-Revision-Date: 2014-02-25 15:09+0000\n" +"Last-Translator: Yannick Vaucher @ Camptocamp \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2014-05-06 07:28+0000\n" +"X-Generator: Launchpad (build 16996)\n" + +#. module: pingen +#: code:addons/pingen/pingen_document.py:177 +#: code:addons/pingen/pingen_document.py:307 +#: code:addons/pingen/pingen_document.py:414 +#, python-format +msgid "Unexcepted Error when updating the status of Document %s" +msgstr "Erreur inattendue lors de la mise à jour du document %s" + +#. module: pingen +#: field:pingen.document,push_date:0 +msgid "Push Date" +msgstr "Date d'ajout" + +#. module: pingen +#: view:pingen.document:0 +msgid "Errors" +msgstr "Erreurs" + +#. module: pingen +#: field:pingen.document,pingen_id:0 +msgid "Pingen ID" +msgstr "ID Pingen" + +#. module: pingen +#: constraint:res.company:0 +msgid "Error! You can not create recursive companies." +msgstr "Error! You can not create recursive companies." + +#. module: pingen +#: field:ir.attachment,pingen_send:0 +msgid "Send" +msgstr "Envoyer" + +#. module: pingen +#: code:addons/pingen/pingen_document.py:399 +#, python-format +msgid "Connection Error when updating the status of Document %s from Pingen" +msgstr "" +"Erreur de connexion lors de la mise à jour de l'état du document %s depuis " +"Pingen" + +#. module: pingen +#: field:pingen.document,state:0 +msgid "State" +msgstr "État" + +#. module: pingen +#: field:ir.attachment,pingen_color:0 +msgid "Type of print" +msgstr "Type d'impression" + +#. module: pingen +#: view:pingen.document:0 +msgid "Attachment" +msgstr "Attachement" + +#. module: pingen +#: code:addons/pingen/pingen_document.py:405 +#, python-format +msgid "" +"Error when updating the status of Document %s from Pingen: \n" +"%s" +msgstr "" +"Erreur lors de la mise à jour de l'état du document %s depuis Pingen: \n" +"%s" + +#. module: pingen +#: model:ir.actions.act_window,name:pingen.act_attachment_to_pingen_document +#: field:ir.attachment,pingen_document_ids:0 +#: view:pingen.document:0 +msgid "Pingen Document" +msgstr "Document Pingen" + +#. module: pingen +#: field:pingen.document,attachment_id:0 +msgid "Document" +msgstr "Document" + +#. module: pingen +#: help:ir.attachment,pingen_send:0 +msgid "Defines if a document is merely uploaded or also sent" +msgstr "Définit si un fichier est juste ajouté ou également envoyé" + +#. module: pingen +#: view:pingen.document:0 +#: selection:pingen.document,state:0 +msgid "Pending" +msgstr "En attente" + +#. module: pingen +#: selection:ir.attachment,pingen_speed:0 +msgid "Economy" +msgstr "Économique" + +#. module: pingen +#: view:pingen.document:0 +msgid "Errors resolved" +msgstr "Erreurs résolues" + +#. module: pingen +#: sql_constraint:pingen.document:0 +msgid "Only one Pingen document is allowed per attachment." +msgstr "Uniquement un document Pingen est autorisé par attachement." + +#. module: pingen +#: code:addons/pingen/pingen_document.py:168 +#: code:addons/pingen/pingen_document.py:298 +#, python-format +msgid "" +"Error when asking Pingen to send the document %s: \n" +"%s" +msgstr "" +"Erreurs lors de l'envoi du document par Pingen %s: \n" +"%s" + +#. module: pingen +#: view:pingen.document:0 +msgid "Update the letter's informations" +msgstr "Mettre à jour les informations de la lettre" + +#. module: pingen +#: view:pingen.document:0 +#: selection:pingen.document,state:0 +msgid "Canceled" +msgstr "Annulé" + +#. module: pingen +#: selection:pingen.document,state:0 +msgid "Connection Error" +msgstr "Erreur de connexion" + +#. module: pingen +#: model:ir.actions.act_window,name:pingen.action_pingen_document +#: model:ir.ui.menu,name:pingen.menu_pingen_document +msgid "Pingen Documents" +msgstr "Documents Pingen" + +#. module: pingen +#: field:pingen.document,last_error_message:0 +msgid "Error Message" +msgstr "Message d'erreur" + +#. module: pingen +#: selection:ir.attachment,pingen_color:0 +msgid "B/W" +msgstr "N/B" + +#. module: pingen +#: field:res.company,pingen_staging:0 +msgid "Pingen Staging" +msgstr "Staging Pingen" + +#. module: pingen +#: model:ir.model,name:pingen.model_ir_attachment +msgid "ir.attachment" +msgstr "ir.attachment" + +#. module: pingen +#: view:pingen.document:0 +#: selection:pingen.document,state:0 +msgid "In Sendcenter" +msgstr "Dans le Sendcenter" + +#. module: pingen +#: view:pingen.document:0 +#: selection:pingen.document,state:0 +msgid "Sent" +msgstr "Envoyé" + +#. module: pingen +#: field:pingen.document,post_status:0 +msgid "Post Status" +msgstr "État de la lettre" + +#. module: pingen +#: code:addons/pingen/pingen_document.py:163 +#: code:addons/pingen/pingen_document.py:292 +#, python-format +msgid "Connection Error when asking for sending the document %s to Pingen" +msgstr "Erreur de connexion avec Pingen lors de l'envoi de %s" + +#. module: pingen +#: view:res.company:0 +msgid "Configuration" +msgstr "Configuration" + +#. module: pingen +#: view:pingen.document:0 +msgid "Data" +msgstr "Données" + +#. module: pingen +#: view:pingen.document:0 +msgid "Options" +msgstr "Options" + +#. module: pingen +#: field:res.company,pingen_token:0 +msgid "Pingen Token" +msgstr "Token Pingen" + +#. module: pingen +#: field:ir.attachment,send_to_pingen:0 +msgid "Send to Pingen.com" +msgstr "Ajouter sur Pingen.com" + +#. module: pingen +#: model:ir.model,name:pingen.model_pingen_document +msgid "pingen.document" +msgstr "pingen.document" + +#. module: pingen +#: view:pingen.document:0 +msgid "Dates" +msgstr "Dates" + +#. module: pingen +#: view:pingen.document:0 +msgid "Sendcenter" +msgstr "Sendcenter" + +#. module: pingen +#: sql_constraint:res.company:0 +msgid "The company name must be unique !" +msgstr "The company name must be unique !" + +#. module: pingen +#: field:pingen.document,parsed_address:0 +msgid "Parsed Address" +msgstr "Adresse analysée" + +#. module: pingen +#: view:ir.attachment:0 +#: view:pingen.document:0 +#: view:res.company:0 +msgid "Pingen.com" +msgstr "Pingen.com" + +#. module: pingen +#: field:pingen.document,country_id:0 +msgid "Country" +msgstr "Pays" + +#. module: pingen +#: view:ir.attachment:0 +msgid "Notes" +msgstr "Notes" + +#. module: pingen +#: view:pingen.document:0 +#: selection:pingen.document,state:0 +msgid "Pushed" +msgstr "Ajouté" + +#. module: pingen +#: model:ir.model,name:pingen.model_res_company +msgid "Companies" +msgstr "Compagnies" + +#. module: pingen +#: code:addons/pingen/ir_attachment.py:90 +#, python-format +msgid "The attachment %s is already pushed to pingen.com." +msgstr "L'attachement %s est déjà envoyé sur pingen.com." + +#. module: pingen +#: view:pingen.document:0 +msgid "Attached To" +msgstr "Attaché à" + +#. module: pingen +#: code:addons/pingen/pingen_document.py:136 +#, python-format +msgid "The document does not meet the Pingen requirements." +msgstr "Le document ne remplit pas les exigences de Pingen" + +#. module: pingen +#: code:addons/pingen/ir_attachment.py:89 +#: code:addons/pingen/pingen_document.py:176 +#: code:addons/pingen/pingen_document.py:306 +#: code:addons/pingen/pingen_document.py:413 +#: view:pingen.document:0 +#, python-format +msgid "Error" +msgstr "Erreur" + +#. module: pingen +#: code:addons/pingen/pingen_document.py:162 +#: code:addons/pingen/pingen_document.py:291 +#: code:addons/pingen/pingen_document.py:398 +#, python-format +msgid "Pingen Connection Error" +msgstr "Erreur de connexion avec Pingen" + +#. module: pingen +#: field:pingen.document,send_date:0 +msgid "Date of sending" +msgstr "Date d'envoi" + +#. module: pingen +#: selection:ir.attachment,pingen_speed:0 +msgid "Priority" +msgstr "Priorité" + +#. module: pingen +#: selection:ir.attachment,pingen_color:0 +msgid "Color" +msgstr "Color" + +#. module: pingen +#: model:ir.model,name:pingen.model_pingen_task +msgid "pingen.task" +msgstr "pingen.task" + +#. module: pingen +#: help:pingen.document,pingen_id:0 +msgid "ID of the document in the Pingen Documents" +msgstr "ID du document sur Pingen" + +#. module: pingen +#: code:addons/pingen/pingen_document.py:167 +#: code:addons/pingen/pingen_document.py:297 +#: code:addons/pingen/pingen_document.py:404 +#: view:pingen.document:0 +#: selection:pingen.document,state:0 +#, python-format +msgid "Pingen Error" +msgstr "Erreur Pingen" + +#. module: pingen +#: view:pingen.document:0 +msgid "Actions" +msgstr "Actions" + +#. module: pingen +#: field:pingen.document,pages:0 +msgid "Pages" +msgstr "Pages" + +#. module: pingen +#: field:pingen.document,currency_id:0 +msgid "Currency" +msgstr "Devise" + +#. module: pingen +#: field:pingen.document,cost:0 +msgid "Cost" +msgstr "Coût" + +#. module: pingen +#: view:pingen.document:0 +msgid "Push to pingen.com" +msgstr "Ajouter sur pingen.com" + +#. module: pingen +#: view:pingen.document:0 +msgid "Ask pingen.com to send the document" +msgstr "Demander à pingen.com d'envoyer le document" + +#. module: pingen +#: help:pingen.document,post_id:0 +msgid "ID of the document in the Pingen Sendcenter" +msgstr "ID du document dans le Sendcenter Pingen" + +#. module: pingen +#: field:ir.attachment,pingen_speed:0 +msgid "Speed" +msgstr "Vitesse" + +#. module: pingen +#: field:pingen.document,post_id:0 +msgid "Pingen Post ID" +msgstr "ID de lettre Pingen" + +#. module: pingen +#: help:ir.attachment,pingen_speed:0 +msgid "Defines the sending speed if the document is automatically sent" +msgstr "Définit la vitesse d'envoi si le document est automatiquement envoyé" diff --git a/pingen/i18n/pingen.pot b/pingen/i18n/pingen.pot new file mode 100644 index 0000000..ce80661 --- /dev/null +++ b/pingen/i18n/pingen.pot @@ -0,0 +1,388 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * pingen +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 6.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2012-11-26 10:55+0000\n" +"PO-Revision-Date: 2012-11-26 10:55+0000\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: pingen +#: code:addons/pingen/pingen_document.py:177 +#: code:addons/pingen/pingen_document.py:307 +#: code:addons/pingen/pingen_document.py:414 +#, python-format +msgid "Unexcepted Error when updating the status of Document %s" +msgstr "" + +#. module: pingen +#: field:pingen.document,push_date:0 +msgid "Push Date" +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +msgid "Errors" +msgstr "" + +#. module: pingen +#: field:pingen.document,pingen_id:0 +msgid "Pingen ID" +msgstr "" + +#. module: pingen +#: constraint:res.company:0 +msgid "Error! You can not create recursive companies." +msgstr "" + +#. module: pingen +#: field:ir.attachment,pingen_send:0 +msgid "Send" +msgstr "" + +#. module: pingen +#: code:addons/pingen/pingen_document.py:399 +#, python-format +msgid "Connection Error when updating the status of Document %s from Pingen" +msgstr "" + +#. module: pingen +#: field:pingen.document,state:0 +msgid "State" +msgstr "" + +#. module: pingen +#: field:ir.attachment,pingen_color:0 +msgid "Type of print" +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +msgid "Attachment" +msgstr "" + +#. module: pingen +#: code:addons/pingen/pingen_document.py:405 +#, python-format +msgid "Error when updating the status of Document %s from Pingen: \n" +"%s" +msgstr "" + +#. module: pingen +#: model:ir.actions.act_window,name:pingen.act_attachment_to_pingen_document +#: field:ir.attachment,pingen_document_ids:0 +#: view:pingen.document:0 +msgid "Pingen Document" +msgstr "" + +#. module: pingen +#: field:pingen.document,attachment_id:0 +msgid "Document" +msgstr "" + +#. module: pingen +#: help:ir.attachment,pingen_send:0 +msgid "Defines if a document is merely uploaded or also sent" +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +#: selection:pingen.document,state:0 +msgid "Pending" +msgstr "" + +#. module: pingen +#: selection:ir.attachment,pingen_speed:0 +msgid "Economy" +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +msgid "Errors resolved" +msgstr "" + +#. module: pingen +#: sql_constraint:pingen.document:0 +msgid "Only one Pingen document is allowed per attachment." +msgstr "" + +#. module: pingen +#: code:addons/pingen/pingen_document.py:168 +#: code:addons/pingen/pingen_document.py:298 +#, python-format +msgid "Error when asking Pingen to send the document %s: \n" +"%s" +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +msgid "Update the letter's informations" +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +#: selection:pingen.document,state:0 +msgid "Canceled" +msgstr "" + +#. module: pingen +#: selection:pingen.document,state:0 +msgid "Connection Error" +msgstr "" + +#. module: pingen +#: model:ir.actions.act_window,name:pingen.action_pingen_document +#: model:ir.ui.menu,name:pingen.menu_pingen_document +msgid "Pingen Documents" +msgstr "" + +#. module: pingen +#: field:pingen.document,last_error_message:0 +msgid "Error Message" +msgstr "" + +#. module: pingen +#: selection:ir.attachment,pingen_color:0 +msgid "B/W" +msgstr "" + +#. module: pingen +#: field:res.company,pingen_staging:0 +msgid "Pingen Staging" +msgstr "" + +#. module: pingen +#: model:ir.model,name:pingen.model_ir_attachment +msgid "ir.attachment" +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +#: selection:pingen.document,state:0 +msgid "In Sendcenter" +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +#: selection:pingen.document,state:0 +msgid "Sent" +msgstr "" + +#. module: pingen +#: field:pingen.document,post_status:0 +msgid "Post Status" +msgstr "" + +#. module: pingen +#: code:addons/pingen/pingen_document.py:163 +#: code:addons/pingen/pingen_document.py:292 +#, python-format +msgid "Connection Error when asking for sending the document %s to Pingen" +msgstr "" + +#. module: pingen +#: view:res.company:0 +msgid "Configuration" +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +msgid "Data" +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +msgid "Options" +msgstr "" + +#. module: pingen +#: field:res.company,pingen_token:0 +msgid "Pingen Token" +msgstr "" + +#. module: pingen +#: field:ir.attachment,send_to_pingen:0 +msgid "Send to Pingen.com" +msgstr "" + +#. module: pingen +#: model:ir.model,name:pingen.model_pingen_document +msgid "pingen.document" +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +msgid "Dates" +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +msgid "Sendcenter" +msgstr "" + +#. module: pingen +#: sql_constraint:res.company:0 +msgid "The company name must be unique !" +msgstr "" + +#. module: pingen +#: field:pingen.document,parsed_address:0 +msgid "Parsed Address" +msgstr "" + +#. module: pingen +#: view:ir.attachment:0 +#: view:pingen.document:0 +#: view:res.company:0 +msgid "Pingen.com" +msgstr "" + +#. module: pingen +#: field:pingen.document,country_id:0 +msgid "Country" +msgstr "" + +#. module: pingen +#: view:ir.attachment:0 +msgid "Notes" +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +#: selection:pingen.document,state:0 +msgid "Pushed" +msgstr "" + +#. module: pingen +#: model:ir.model,name:pingen.model_res_company +msgid "Companies" +msgstr "" + +#. module: pingen +#: code:addons/pingen/ir_attachment.py:90 +#, python-format +msgid "The attachment %s is already pushed to pingen.com." +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +msgid "Attached To" +msgstr "" + +#. module: pingen +#: code:addons/pingen/pingen_document.py:136 +#, python-format +msgid "The document does not meet the Pingen requirements." +msgstr "" + +#. module: pingen +#: code:addons/pingen/ir_attachment.py:89 +#: code:addons/pingen/pingen_document.py:176 +#: code:addons/pingen/pingen_document.py:306 +#: code:addons/pingen/pingen_document.py:413 +#: view:pingen.document:0 +#, python-format +msgid "Error" +msgstr "" + +#. module: pingen +#: code:addons/pingen/pingen_document.py:162 +#: code:addons/pingen/pingen_document.py:291 +#: code:addons/pingen/pingen_document.py:398 +#, python-format +msgid "Pingen Connection Error" +msgstr "" + +#. module: pingen +#: field:pingen.document,send_date:0 +msgid "Date of sending" +msgstr "" + +#. module: pingen +#: selection:ir.attachment,pingen_speed:0 +msgid "Priority" +msgstr "" + +#. module: pingen +#: selection:ir.attachment,pingen_color:0 +msgid "Color" +msgstr "" + +#. module: pingen +#: model:ir.model,name:pingen.model_pingen_task +msgid "pingen.task" +msgstr "" + +#. module: pingen +#: help:pingen.document,pingen_id:0 +msgid "ID of the document in the Pingen Documents" +msgstr "" + +#. module: pingen +#: code:addons/pingen/pingen_document.py:167 +#: code:addons/pingen/pingen_document.py:297 +#: code:addons/pingen/pingen_document.py:404 +#: view:pingen.document:0 +#: selection:pingen.document,state:0 +#, python-format +msgid "Pingen Error" +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +msgid "Actions" +msgstr "" + +#. module: pingen +#: field:pingen.document,pages:0 +msgid "Pages" +msgstr "" + +#. module: pingen +#: field:pingen.document,currency_id:0 +msgid "Currency" +msgstr "" + +#. module: pingen +#: field:pingen.document,cost:0 +msgid "Cost" +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +msgid "Push to pingen.com" +msgstr "" + +#. module: pingen +#: view:pingen.document:0 +msgid "Ask pingen.com to send the document" +msgstr "" + +#. module: pingen +#: help:pingen.document,post_id:0 +msgid "ID of the document in the Pingen Sendcenter" +msgstr "" + +#. module: pingen +#: field:ir.attachment,pingen_speed:0 +msgid "Speed" +msgstr "" + +#. module: pingen +#: field:pingen.document,post_id:0 +msgid "Pingen Post ID" +msgstr "" + +#. module: pingen +#: help:ir.attachment,pingen_speed:0 +msgid "Defines the sending speed if the document is automatically sent" +msgstr "" + diff --git a/pingen/ir_attachment.py b/pingen/ir_attachment.py new file mode 100644 index 0000000..ba00c47 --- /dev/null +++ b/pingen/ir_attachment.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Guewen Baconnier +# Copyright 2012 Camptocamp SA +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import requests +import base64 + +from openerp.osv import osv, orm, fields +from openerp.tools.translate import _ + + +class ir_attachment(orm.Model): + + _inherit = 'ir.attachment' + + _columns = { + 'send_to_pingen': fields.boolean('Send to Pingen.com'), + 'pingen_document_ids': fields.one2many( + 'pingen.document', 'attachment_id', + string='Pingen Document', readonly=True), + 'pingen_send': fields.boolean( + 'Send', + help="Defines if a document is merely uploaded or also sent"), + 'pingen_speed': fields.selection( + [('1', 'Priority'), ('2', 'Economy')], + 'Speed', + help="Defines the sending speed if the document is automatically sent"), + 'pingen_color': fields.selection([('0', 'B/W'), ('1', 'Color')], 'Type of print'), + } + + _defaults = { + 'pingen_send': True, + 'pingen_color': '0', + 'pingen_speed': '2', + } + + def _prepare_pingen_document_vals(self, cr, uid, attachment, context=None): + return {'attachment_id': attachment.id, + 'config': 'created from attachment'} + + def _handle_pingen_document(self, cr, uid, attachment_id, context=None): + """ Reponsible of the related ``pingen.document`` when the ``send_to_pingen`` + field is modified. + + Only one pingen document can be created per attachment. + + When ``send_to_pingen`` is activated: + * Create a ``pingen.document`` if it does not already exist + * Put the related ``pingen.document`` to ``pending`` if it already exist + When it is deactivated: + * Do nothing if no related ``pingen.document`` exists + * Or cancel it + * If it has already been pushed to pingen.com, raises + an `osv.except_osv` exception + """ + pingen_document_obj = self.pool.get('pingen.document') + attachment = self.browse(cr, uid, attachment_id, context=context) + document = attachment.pingen_document_ids[0] if attachment.pingen_document_ids else None + if attachment.send_to_pingen: + if document: + document.write({'state': 'pending'}, context=context) + else: + pingen_document_obj.create( + cr, uid, + self._prepare_pingen_document_vals( + cr, uid, attachment, context=context), + context=context) + else: + if document: + if document.state == 'pushed': + raise osv.except_osv( + _('Error'), + _('The attachment %s is already pushed to pingen.com.') % + attachment.name) + document.write({'state': 'canceled'}, context=context) + return + + def create(self, cr, uid, vals, context=None): + attachment_id = super(ir_attachment, self).create(cr, uid, vals, context=context) + if 'send_to_pingen' in vals: + self._handle_pingen_document(cr, uid, attachment_id, context=context) + return attachment_id + + def write(self, cr, uid, ids, vals, context=None): + res = super(ir_attachment, self).write(cr, uid, ids, vals, context=context) + if 'send_to_pingen' in vals: + for attachment_id in ids: + self._handle_pingen_document(cr, uid, attachment_id, context=context) + return res + + def _decoded_content(self, cr, uid, attachment, context=None): + """ Returns the decoded content of an attachment (stored or url) + + Returns None if the type is 'url' and the url is not reachable. + """ + decoded_document = None + if attachment.type == 'binary': + decoded_document = base64.decodestring(attachment.datas) + elif attachment.type == 'url': + response = requests.get(attachment.url) + if response.ok: + decoded_document = requests.content + else: + raise Exception( + 'The type of attachment %s is not handled' % attachment.type) + return decoded_document diff --git a/pingen/ir_attachment_view.xml b/pingen/ir_attachment_view.xml new file mode 100644 index 0000000..d51a906 --- /dev/null +++ b/pingen/ir_attachment_view.xml @@ -0,0 +1,31 @@ + + + + + + ir.attachment.pingen.view + ir.attachment + form + + + + + + + + + + + + + + + + + diff --git a/pingen/pingen.py b/pingen/pingen.py new file mode 100644 index 0000000..475407b --- /dev/null +++ b/pingen/pingen.py @@ -0,0 +1,227 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Guewen Baconnier +# Copyright 2012 Camptocamp SA +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import requests +import logging +import urlparse +import json +import pytz + +from datetime import datetime +from requests.packages.urllib3.filepost import encode_multipart_formdata + +_logger = logging.getLogger(__name__) + +POST_SENDING_STATUS = { + 100: 'Ready/Pending', + 101: 'Processing', + 102: 'Waiting for confirmation', + 200: 'Sent', + 300: 'Some error occured and object wasn\'t sent', + 400: 'Sending cancelled', +} + +DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S' # this is the format used by pingen API + +TZ = pytz.timezone('Europe/Zurich') # this is the timezone of the pingen API + + +def pingen_datetime_to_utc(dt): + """ Convert a date/time used by pingen.com to UTC timezone + + :param dt: pingen date/time as string (as received from the API) + to convert to UTC + :return: datetime in the UTC timezone + """ + utc = pytz.utc + dt = datetime.strptime(dt, DATETIME_FORMAT) + localized_dt = TZ.localize(dt, is_dst=True) + return localized_dt.astimezone(utc) + + +class PingenException(RuntimeError): + """There was an ambiguous exception that occurred while handling your + request.""" + + +class ConnectionError(PingenException): + """An Error occured with the pingen API""" + + +class APIError(PingenException): + """An Error occured with the pingen API""" + + +class Pingen(object): + """ Interface to the pingen.com API """ + + def __init__(self, token, staging=True): + self._token = token + self.staging = staging + self._session = None + super(Pingen, self).__init__() + + @property + def url(self): + if self.staging: + return 'https://stage-api.pingen.com' + return 'https://api.pingen.com' + + @property + def session(self): + """ Build a requests session """ + if self._session is not None: + return self._session + self._session = requests.Session( + params={'token': self._token}, + # with safe_mode, requests catch errors and + # returns a blank response with an error + config={'safe_mode': True}, + # verify = False required for staging environment + # because the SSL certificate is wrong + verify=not self.staging) + return self._session + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + def close(self): + """Dispose of any internal state. """ + if self._session: + self._session.close() + + def _send(self, method, endpoint, **kwargs): + """ Send a request to the pingen API using requests + + Add necessary boilerplate to call pingen.com API + (authentication, configuration, ...) + + :param boundmethod method: requests method to call + :param str endpoint: endpoint to call + :param kwargs: additional arguments forwarded to the requests method + """ + complete_url = urlparse.urljoin(self.url, endpoint) + + response = method(complete_url, **kwargs) + + if not response.ok: + raise ConnectionError( + "%s: %s" % (response.json['errorcode'], + response.json['errormessage'])) + + if response.json['error']: + raise APIError( + "%s: %s" % (response.json['errorcode'], response.json['errormessage'])) + + return response + + def push_document(self, filename, filestream, send=None, speed=None, color=None): + """ Upload a document to pingen.com and eventually ask to send it + + :param str filename: name of the file to push + :param StringIO filestream: file to push + :param boolean send: if True, the document will be sent by pingen.com + :param int/str speed: sending speed of the document if it is send + 1 = Priority, 2 = Economy + :param int/str color: type of print, 0 = B/W, 1 = Color + :return: tuple with 3 items: + 1. document_id on pingen.com + 2. post_id on pingen.com if it has been sent or None + 3. dict of the created item on pingen (details) + """ + data = { + 'send': send, + 'speed': speed, + 'color': color, + } + + # we cannot use the `files` param alongside + # with the `datas`param when data is a + # JSON-encoded data. We have to construct + # the entire body and send it to `data` + # https://github.com/kennethreitz/requests/issues/950 + formdata = { + 'file': (filename, filestream.read()), + 'data': json.dumps(data), + } + + multipart, content_type = encode_multipart_formdata(formdata) + + response = self._send( + self.session.post, + 'document/upload', + headers={'Content-Type': content_type}, + data=multipart) + + rjson = response.json + + document_id = rjson['id'] + if rjson.get('send'): + # confusing name but send_id is the posted id + posted_id = rjson['send'][0]['send_id'] + item = rjson['item'] + + return document_id, posted_id, item + + def send_document(self, document_id, speed=None, color=None): + """ Send a uploaded document to pingen.com + + :param int document_id: id of the document to send + :param int/str speed: sending speed of the document if it is send + 1 = Priority, 2 = Economy + :param int/str color: type of print, 0 = B/W, 1 = Color + :return: id of the post on pingen.com + """ + data = { + 'speed': speed, + 'color': color, + } + response = self._send( + self.session.post, + 'document/send', + params={'id': document_id}, + data={'data': json.dumps(data)}) + + return response.json['id'] + + def post_infos(self, post_id): + """ Return the information of a post + + :param int post_id: id of the document to send + :return: dict of infos of the post + """ + response = self._send( + self.session.get, + 'post/get', + params={'id': post_id}) + + return response.json['item'] + + @staticmethod + def is_posted(post_infos): + """ return True if the post has been sent + + :param dict post_infos: post infos returned by `post_infos` + """ + return post_infos['status'] == 200 diff --git a/pingen/pingen_data.xml b/pingen/pingen_data.xml new file mode 100644 index 0000000..5227210 --- /dev/null +++ b/pingen/pingen_data.xml @@ -0,0 +1,32 @@ + + + + + + Run Pingen Document Push + + + 1 + hours + -1 + + pingen.document + _push_and_send_to_pingen_cron + (None,) + + + + Run Pingen Document Update + + + 1 + days + -1 + + pingen.document + _update_post_infos_cron + (None,) + + + + diff --git a/pingen/pingen_document.py b/pingen/pingen_document.py new file mode 100644 index 0000000..ac59a02 --- /dev/null +++ b/pingen/pingen_document.py @@ -0,0 +1,425 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Author: Guewen Baconnier +# Copyright 2012 Camptocamp SA +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +import logging + +from cStringIO import StringIO + +from contextlib import closing +from openerp.osv import osv, orm, fields +from openerp.tools.translate import _ +from openerp import pooler, tools +from .pingen import APIError, ConnectionError, POST_SENDING_STATUS, \ + pingen_datetime_to_utc + +_logger = logging.getLogger(__name__) + + +class pingen_document(orm.Model): + """ A pingen document is the state of the synchronization of + an attachment with pingen.com + + It stores the configuration and the current state of the synchronization. + It also serves as a queue of documents to push to pingen.com + """ + + _name = 'pingen.document' + _inherits = {'ir.attachment': 'attachment_id'} + + _columns = { + 'attachment_id': fields.many2one( + 'ir.attachment', 'Document', + required=True, readonly=True, + ondelete='cascade'), + 'state': fields.selection( + [('pending', 'Pending'), + ('pushed', 'Pushed'), + ('sendcenter', 'In Sendcenter'), + ('sent', 'Sent'), + ('error', 'Connection Error'), + ('pingen_error', 'Pingen Error'), + ('canceled', 'Canceled')], + string='State', readonly=True, required=True), + 'push_date': fields.datetime('Push Date', readonly=True), + + # for `error` and `pingen_error` states when we push + 'last_error_message': fields.text('Error Message', readonly=True), + + # pingen IDs + 'pingen_id': fields.integer( + 'Pingen ID', readonly=True, + help="ID of the document in the Pingen Documents"), + 'post_id': fields.integer( + 'Pingen Post ID', readonly=True, + help="ID of the document in the Pingen Sendcenter"), + + # sendcenter infos + 'post_status': fields.char('Post Status', size=128, readonly=True), + 'parsed_address': fields.text('Parsed Address', readonly=True), + 'cost': fields.float('Cost', readonly=True), + 'currency_id': fields.many2one('res.currency', 'Currency', readonly=True), + 'country_id': fields.many2one('res.country', 'Country', readonly=True), + 'send_date': fields.datetime('Date of sending', readonly=True), + 'pages': fields.integer('Pages', readonly=True), + } + + _defaults = { + 'state': 'pending', + } + + _sql_constraints = [ + ('pingen_document_attachment_uniq', + 'unique (attachment_id)', + 'Only one Pingen document is allowed per attachment.'), + ] + + def _get_pingen_session(self, cr, uid, context=None): + """ Returns a pingen session for a user """ + company = self.pool.get('res.users').browse( + cr, uid, uid, context=context).company_id + return self.pool.get('res.company')._pingen(cr, uid, company, context=context) + + def _push_to_pingen(self, cr, uid, document, pingen=None, context=None): + """ Push a document to pingen.com + + :param Pingen pingen: optional pingen object to reuse session + """ + attachment_obj = self.pool.get('ir.attachment') + + decoded_document = attachment_obj._decoded_content( + cr, uid, document.attachment_id, context=context) + + if pingen is None: + pingen = self._get_pingen_session(cr, uid, context=context) + try: + doc_id, post_id, infos = pingen.push_document( + document.datas_fname, + StringIO(decoded_document), + document.pingen_send, + document.pingen_speed, + document.pingen_color) + except ConnectionError: + _logger.exception( + 'Connection Error when pushing Pingen Document %s to %s.' % + (document.id, pingen.url)) + raise + + except APIError: + _logger.error( + 'API Error when pushing Pingen Document %s to %s.' % + (document.id, pingen.url)) + raise + + error = False + state = 'pushed' + if post_id: + state = 'sendcenter' + elif infos['requirement_failure']: + state = 'pingen_error' + error = _('The document does not meet the Pingen requirements.') + + push_date = pingen_datetime_to_utc(infos['date']) + + document.write( + {'last_error_message': error, + 'state': state, + 'push_date': push_date.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT), + 'pingen_id': doc_id, + 'post_id': post_id}, + context=context) + _logger.info('Pingen Document %s: pushed to %s' % (document.id, pingen.url)) + + def push_to_pingen(self, cr, uid, ids, context=None): + """ Push a document to pingen.com + + Convert errors to osv.except_osv to be handled by the client. + + Wrapper method for multiple ids (when triggered from button for + instance) for public interface. + """ + assert len(ids) == 1, "Only 1 id is allowed" + with self._get_pingen_session(cr, uid, context=context) as session: + for document in self.browse(cr, uid, ids, context=context): + try: + self._push_to_pingen( + cr, uid, document, pingen=session, context=context) + except ConnectionError as e: + raise osv.except_osv( + _('Pingen Connection Error'), + _('Connection Error when asking for sending the document %s to Pingen') % document.name) + + except APIError as e: + raise osv.except_osv( + _('Pingen Error'), + _('Error when asking Pingen to send the document %s: ' + '\n%s') % (document.name, e)) + + except: + _logger.exception( + 'Unexcepted Error when updating the status of pingen.document %s: ' % + document.id) + raise osv.except_osv( + _('Error'), + _('Unexcepted Error when updating the status of Document %s') % document.name) + return True + + def _push_and_send_to_pingen_cron(self, cr, uid, ids, context=None): + """ Push a document to pingen.com + + Intended to be used in a cron. + + Commit after each record + + Instead of raising, store the error in the pingen.document + """ + if not ids: + ids = self.search( + cr, uid, + # do not retry pingen_error, they should be treated manually + [('state', 'in', ['pending', 'pushed', 'error'])], + limit=100, + context=context) + + with closing(pooler.get_db(cr.dbname).cursor()) as loc_cr, \ + self._get_pingen_session(cr, uid, context=context) as session: + for document in self.browse(loc_cr, uid, ids, context=context): + + if document.state == 'error': + self._resolve_error(loc_cr, uid, document, context=context) + document.refresh() + + try: + if document.state == 'pending': + self._push_to_pingen( + loc_cr, uid, document, pingen=session, context=context) + + elif document.state == 'pushed': + self._ask_pingen_send( + loc_cr, uid, document, pingen=session, context=context) + except ConnectionError as e: + document.write({'last_error_message': e, + 'state': 'error'}, + context=context) + except APIError as e: + document.write({'last_error_message': e, + 'state': 'pingen_error'}, + context=context) + except: + _logger.error('Unexcepted error in pingen cron') + loc_cr.rollback() + raise + + else: + loc_cr.commit() + + return True + + def _resolve_error(self, cr, uid, document, context=None): + """ A document as resolved, put in the correct state """ + if document.post_id: + state = 'sendcenter' + elif document.pingen_id: + state = 'pushed' + else: + state = 'pending' + document.write({'state': state}, context=context) + + def resolve_error(self, cr, uid, ids, context=None): + """ A document as resolved, put in the correct state """ + for document in self.browse(cr, uid, ids, context=context): + self._resolve_error(cr, uid, document, context=context) + return True + + def _ask_pingen_send(self, cr, uid, document, pingen, context=None): + """ For a document already pushed to pingen, ask to send it. + + :param Pingen pingen: pingen object to reuse + """ + # sending has been explicitely asked so we change the option + # for consistency + if not document.pingen_send: + document.write({'pingen_send': True}, context=context) + + try: + post_id = pingen.send_document( + document.pingen_id, + document.pingen_speed, + document.pingen_color) + except ConnectionError: + _logger.exception('Connection Error when asking for sending Pingen Document %s to %s.' % + (document.id, pingen.url)) + raise + except APIError: + _logger.exception('API Error when asking for sending Pingen Document %s to %s.' % + (document.id, pingen.url)) + raise + + document.write( + {'last_error_message': False, + 'state': 'sendcenter', + 'post_id': post_id}, + context=context) + _logger.info('Pingen Document %s: asked for sending to %s' % (document.id, pingen.url)) + + return True + + def ask_pingen_send(self, cr, uid, ids, context=None): + """ For a document already pushed to pingen, ask to send it. + + Wrapper method for multiple ids (when triggered from button for + instance) for public interface. + """ + assert len(ids) == 1, "Only 1 id is allowed" + with self._get_pingen_session(cr, uid, context=context) as session: + for document in self.browse(cr, uid, ids, context=context): + try: + self._ask_pingen_send(cr, uid, document, pingen=session, context=context) + except ConnectionError as e: + raise osv.except_osv( + _('Pingen Connection Error'), + _('Connection Error when asking for ' + 'sending the document %s to Pingen') % document.name) + + except APIError as e: + raise osv.except_osv( + _('Pingen Error'), + _('Error when asking Pingen to send the document %s: ' + '\n%s') % (document.name, e)) + + except: + _logger.exception( + 'Unexcepted Error when updating the status of pingen.document %s: ' % + document.id) + raise osv.except_osv( + _('Error'), + _('Unexcepted Error when updating the status of Document %s') % document.name) + return True + + def _update_post_infos(self, cr, uid, document, pingen, context=None): + """ Update the informations from pingen of a document in the Sendcenter + + :param Pingen pingen: pingen object to reuse + """ + if not document.post_id: + return + + try: + post_infos = pingen.post_infos(document.post_id) + except ConnectionError: + _logger.exception( + 'Connection Error when asking for ' + 'sending Pingen Document %s to %s.' % + (document.id, pingen.url)) + raise + except APIError: + _logger.exception( + 'API Error when asking for sending Pingen Document %s to %s.' % + (document.id, pingen.url)) + raise + + currency_ids = self.pool.get('res.currency').search( + cr, uid, [('name', '=', post_infos['currency'])], context=context) + country_ids = self.pool.get('res.country').search( + cr, uid, [('code', '=', post_infos['country'])], context=context) + + send_date = pingen_datetime_to_utc(post_infos['date']) + + vals = { + 'post_status': POST_SENDING_STATUS[post_infos['status']], + 'cost': post_infos['cost'], + 'currency_id': currency_ids[0] if currency_ids else False, + 'parsed_address': post_infos['address'], + 'country_id': country_ids[0] if country_ids else False, + 'send_date': send_date.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT), + 'pages': post_infos['pages'], + 'last_error_message': False, + } + if pingen.is_posted(post_infos): + vals['state'] = 'sent' + + document.write(vals, context=context) + _logger.info('Pingen Document %s: status updated' % document.id) + + def _update_post_infos_cron(self, cr, uid, ids, context=None): + """ Update the informations from pingen of a document in the Sendcenter + + Intended to be used in a cron. + + Commit after each record + + Do not raise errors, only skip the update of the record. + """ + if not ids: + ids = self.search( + cr, uid, + [('state', '=', 'sendcenter')], + context=context) + + with closing(pooler.get_db(cr.dbname).cursor()) as loc_cr, \ + self._get_pingen_session(cr, uid, context=context) as session: + for document in self.browse(loc_cr, uid, ids, context=context): + try: + self._update_post_infos( + loc_cr, uid, document, pingen=session, context=context) + except (ConnectionError, APIError): + # will be retried the next time + # In any case, the error has been logged by _update_post_infos + loc_cr.rollback() + except: + _logger.error('Unexcepted error in pingen cron') + loc_cr.rollback() + raise + else: + loc_cr.commit() + return True + + def update_post_infos(self, cr, uid, ids, context=None): + """ Update the informations from pingen of a document in the Sendcenter + + Wrapper method for multiple ids (when triggered from button for + instance) for public interface. + """ + assert len(ids) == 1, "Only 1 id is allowed" + with self._get_pingen_session(cr, uid, context=context) as session: + for document in self.browse(cr, uid, ids, context=context): + try: + self._update_post_infos( + cr, uid, document, pingen=session, context=context) + except ConnectionError as e: + raise osv.except_osv( + _('Pingen Connection Error'), + _('Connection Error when updating the status of Document %s' + ' from Pingen') % document.name) + + except APIError as e: + raise osv.except_osv( + _('Pingen Error'), + _('Error when updating the status of Document %s from Pingen: ' + '\n%s') % (document.name, e)) + + except: + _logger.exception( + 'Unexcepted Error when updating the status of pingen.document %s: ' % + document.id) + raise osv.except_osv( + _('Error'), + _('Unexcepted Error when updating the status of Document %s') % document.name) + return True diff --git a/pingen/pingen_document_view.xml b/pingen/pingen_document_view.xml new file mode 100644 index 0000000..1686167 --- /dev/null +++ b/pingen/pingen_document_view.xml @@ -0,0 +1,161 @@ + + + + + + pingen.document.tree + pingen.document + tree + + + + + + + + + + + + + + pingen.document.form + pingen.document + form + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +