Merge lp:~camptocamp/report-print-send/6.1-pingen into lp:~report-print-send-core-editors/report-print-send/6.1

Proposed by Guewen Baconnier @ Camptocamp
Status: Merged
Merged at revision: 3
Proposed branch: lp:~camptocamp/report-print-send/6.1-pingen
Merge into: lp:~report-print-send-core-editors/report-print-send/6.1
Diff against target: 2325 lines (+2214/-0)
21 files modified
pingen/__init__.py (+26/-0)
pingen/__openerp__.py (+119/-0)
pingen/i18n/fr.po (+390/-0)
pingen/i18n/pingen.pot (+388/-0)
pingen/ir_attachment.py (+124/-0)
pingen/ir_attachment_view.xml (+31/-0)
pingen/pingen.py (+209/-0)
pingen/pingen_data.xml (+32/-0)
pingen/pingen_document.py (+420/-0)
pingen/pingen_document_view.xml (+161/-0)
pingen/res_company.py (+42/-0)
pingen/res_company_view.xml (+20/-0)
pingen/security/ir.model.access.csv (+3/-0)
pingen_document/__init__.py (+21/-0)
pingen_document/__openerp__.py (+41/-0)
pingen_document/i18n/de.po (+32/-0)
pingen_document/i18n/en.po (+32/-0)
pingen_document/i18n/es.po (+32/-0)
pingen_document/i18n/fr.po (+32/-0)
pingen_document/i18n/pingen_document.pot (+32/-0)
pingen_document/pingen_document_view.xml (+27/-0)
To merge this branch: bzr merge lp:~camptocamp/report-print-send/6.1-pingen
Reviewer Review Type Date Requested Status
Stefan Rijnhart (Opener) Approve
Review via email: mp+138657@code.launchpad.net

Description of the change

This is an integration of the pingen.com online service in OpenERP.

It contains 2 addons:
 - a main addon which has no OpenERP dependencies
 - a 'pingen_document' module which is a glue addon automatically installed when the addons 'pingen' and 'document' are installed.

It requires the python module: requests

To post a comment you must log in.
Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Nice addition! Looks good on the whole. Just a couple of remarks:

Would it not be better to encode the dependency on 'requests' in the manifest file as

    'external_dependencies' : {
        'python' : ['requests'],
    }

That would give a friendly error message upon installation in OpenERP if this module is not available.

l.988,991: Are the integer dictionary keys stringified on purpose? Judging by the docstring of push_document you also accept integers there, so I would find it more intuitive to use native integers here. May be a matter of style though.

review: Needs Fixing
19. By Guewen Baconnier @ Camptocamp <email address hidden>

[FIX] express the external dependency on the 'request' lib in the manifest file

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Oh yes you are right for the external_dependencies in the manifest file, that's fixed now.

Concerning the keys as str in the fields.selection, keys as int are just not supported (by the web client?). I think that OpenERP assumes that the keys are strings. I gave it a try ;-)

Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Thanks for the fix!

About integer keys in the web client, that is odd given that this is used in Accounting -> Configuration -> Financial Accounting -> Account Reports -> Account Reports. The model of this action, account.financial.report contains the 'sign' field that has the following selection:

    [[-1,"Reverse balance sign"],[1,"Preserve balance sign"]]

But I ran a test and the problem is having an zero integer key, evaluating to false obviously somewhere in the client so that it shows no value at all in the dropdown. I'd say let's just leave it at this.

review: Approve
Revision history for this message
Stefan Rijnhart (Opener) (stefan-opener) wrote :

Guewen,

There has been a race condition between the branches for this project. I tried to merge your branch but it has no common anchestor with lp:report-print-send. Could you rebase your branch on the head branch?

20. By Guewen Baconnier @ Camptocamp <email address hidden>

[FIX] manifest typos

21. By Guewen Baconnier @ Camptocamp <email address hidden>

[MRG] from 6.1 main branch

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Stefan,

I updated my branch from the main branch, it should be merge-ready.

That's a good thing to know for this integer keys in the fields.selection, I did not noticed that it was due to the 0, but it makes sense.

Thanks for your review!

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Thanks for the merge

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== renamed file 'README' => 'README'
2=== renamed directory 'base_report_to_printer' => 'base_report_to_printer'
3=== added directory 'pingen'
4=== added file 'pingen/__init__.py'
5--- pingen/__init__.py 1970-01-01 00:00:00 +0000
6+++ pingen/__init__.py 2012-12-07 13:35:25 +0000
7@@ -0,0 +1,26 @@
8+# -*- coding: utf-8 -*-
9+##############################################################################
10+#
11+# Author: Guewen Baconnier
12+# Copyright 2012 Camptocamp SA
13+#
14+# This program is free software: you can redistribute it and/or modify
15+# it under the terms of the GNU Affero General Public License as
16+# published by the Free Software Foundation, either version 3 of the
17+# License, or (at your option) any later version.
18+#
19+# This program is distributed in the hope that it will be useful,
20+# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+# GNU Affero General Public License for more details.
23+#
24+# You should have received a copy of the GNU Affero General Public License
25+# along with this program. If not, see <http://www.gnu.org/licenses/>.
26+#
27+##############################################################################
28+
29+import ir_attachment
30+import pingen
31+import pingen_document
32+import res_company
33+
34
35=== added file 'pingen/__openerp__.py'
36--- pingen/__openerp__.py 1970-01-01 00:00:00 +0000
37+++ pingen/__openerp__.py 2012-12-07 13:35:25 +0000
38@@ -0,0 +1,119 @@
39+# -*- coding: utf-8 -*-
40+##############################################################################
41+#
42+# Author: Guewen Baconnier
43+# Copyright 2012 Camptocamp SA
44+#
45+# This program is free software: you can redistribute it and/or modify
46+# it under the terms of the GNU Affero General Public License as
47+# published by the Free Software Foundation, either version 3 of the
48+# License, or (at your option) any later version.
49+#
50+# This program is distributed in the hope that it will be useful,
51+# but WITHOUT ANY WARRANTY; without even the implied warranty of
52+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53+# GNU Affero General Public License for more details.
54+#
55+# You should have received a copy of the GNU Affero General Public License
56+# along with this program. If not, see <http://www.gnu.org/licenses/>.
57+#
58+##############################################################################
59+
60+{
61+ 'name': 'pingen.com integration',
62+ 'version': '1.0',
63+ 'author': 'Camptocamp',
64+ 'maintainer': 'Camptocamp',
65+ 'license': 'AGPL-3',
66+ 'category': 'Reporting',
67+ 'complexity': 'easy',
68+ 'depends': [],
69+ 'external_dependencies': {
70+ 'python': ['requests'],
71+ },
72+ 'description': """
73+Integration with pingen.com
74+===========================
75+
76+What is pingen.com
77+------------------
78+
79+Pingen.com is a paid online service.
80+It sends uploaded documents by letter post.
81+
82+Scope of the integration
83+------------------------
84+
85+One can decide, per document / attachment, if it should be pushed
86+to pingen.com. The documents are pushed asynchronously.
87+
88+A second cron updates the informations of the documents from pingen.com, so we
89+know which of them have been sent.
90+
91+Configuration
92+-------------
93+
94+The authentication token is configured on the company's view. You can also
95+tick a checkbox if the staging environment (https://stage-api.pingen.com)
96+should be used.
97+
98+The setup of the 2 crons can be changed as well:
99+
100+ * Run Pingen Document Push
101+ * Run Pingen Document Update
102+
103+Usage
104+-----
105+
106+On the attachment view, a new pingen.com tab has been added.
107+You can tick a box to push the document to pingen.com.
108+
109+There is 3 additional options:
110+
111+ * Send: the document will not be only uploaded, but will be also be sent
112+ * Speed: priority or economy
113+ * Type of print: color or black and white
114+
115+Once the configuration is done and the attachment saved, a Pingen Document
116+is created. You can directly access to the latter on the Link on the right on
117+the attachment view.
118+
119+You can find them in `Settings > Customization > Low Level Objets > Pingen
120+Documents` or in the more convenient `Documents` menu if you have installed the
121+`document` module.
122+
123+Errors
124+------
125+
126+Sometimes, pingen.com will refuse to send a document because it does not meet
127+its requirements. In such case, the document's state becomes "Pingen Error" and
128+you will need to manually handle the case, either from the pingen.com backend,
129+or by changing the document on OpenERP and resolving the error on the Pingen
130+Document.
131+
132+When a connection error occurs, the action will be retried on the next scheduler
133+run.
134+
135+Dependencies
136+------------
137+
138+ * Require the Python library `requests <http://docs.python-requests.org/>`_
139+ * The PDF files sent to pingen.com have to respect some `formatting rules
140+ <https://stage-app.pingen.com/resources/pingen_requirements_v1_en.pdf>`_.
141+ * The address must be in a format accepted by pingen.com: the last line
142+ is the country in English or German.
143+
144+""",
145+ 'website': 'http://www.camptocamp.com',
146+ 'data': [
147+ 'ir_attachment_view.xml',
148+ 'pingen_document_view.xml',
149+ 'pingen_data.xml',
150+ 'res_company_view.xml',
151+ 'security/ir.model.access.csv',
152+ ],
153+ 'tests': [],
154+ 'installable': True,
155+ 'auto_install': False,
156+ 'application': True,
157+}
158
159=== added directory 'pingen/i18n'
160=== added file 'pingen/i18n/fr.po'
161--- pingen/i18n/fr.po 1970-01-01 00:00:00 +0000
162+++ pingen/i18n/fr.po 2012-12-07 13:35:25 +0000
163@@ -0,0 +1,390 @@
164+# Translation of OpenERP Server.
165+# This file contains the translation of the following modules:
166+# * pingen
167+#
168+msgid ""
169+msgstr ""
170+"Project-Id-Version: OpenERP Server 6.1\n"
171+"Report-Msgid-Bugs-To: \n"
172+"POT-Creation-Date: 2012-11-26 10:54+0000\n"
173+"PO-Revision-Date: 2012-11-26 10:54+0000\n"
174+"Last-Translator: <>\n"
175+"Language-Team: \n"
176+"MIME-Version: 1.0\n"
177+"Content-Type: text/plain; charset=UTF-8\n"
178+"Content-Transfer-Encoding: \n"
179+"Plural-Forms: \n"
180+
181+#. module: pingen
182+#: code:addons/pingen/pingen_document.py:177
183+#: code:addons/pingen/pingen_document.py:307
184+#: code:addons/pingen/pingen_document.py:414
185+#, python-format
186+msgid "Unexcepted Error when updating the status of Document %s"
187+msgstr "Erreur inattendue lors de la mise à jour du document %s"
188+
189+#. module: pingen
190+#: field:pingen.document,push_date:0
191+msgid "Push Date"
192+msgstr "Date d'ajout"
193+
194+#. module: pingen
195+#: view:pingen.document:0
196+msgid "Errors"
197+msgstr "Erreurs"
198+
199+#. module: pingen
200+#: field:pingen.document,pingen_id:0
201+msgid "Pingen ID"
202+msgstr "ID Pingen"
203+
204+#. module: pingen
205+#: constraint:res.company:0
206+msgid "Error! You can not create recursive companies."
207+msgstr "Error! You can not create recursive companies."
208+
209+#. module: pingen
210+#: field:ir.attachment,pingen_send:0
211+msgid "Send"
212+msgstr "Envoyer"
213+
214+#. module: pingen
215+#: code:addons/pingen/pingen_document.py:399
216+#, python-format
217+msgid "Connection Error when updating the status of Document %s from Pingen"
218+msgstr "Erreur de connexion lors de la mise à jour de l'état du document %s depuis Pingen"
219+
220+#. module: pingen
221+#: field:pingen.document,state:0
222+msgid "State"
223+msgstr "État"
224+
225+#. module: pingen
226+#: field:ir.attachment,pingen_color:0
227+msgid "Type of print"
228+msgstr "Type d'impression"
229+
230+#. module: pingen
231+#: view:pingen.document:0
232+msgid "Attachment"
233+msgstr "Attachement"
234+
235+#. module: pingen
236+#: code:addons/pingen/pingen_document.py:405
237+#, python-format
238+msgid "Error when updating the status of Document %s from Pingen: \n"
239+"%s"
240+msgstr "Erreur lors de la mise à jour de l'état du document %s depuis Pingen: \n"
241+"%s"
242+
243+#. module: pingen
244+#: model:ir.actions.act_window,name:pingen.act_attachment_to_pingen_document
245+#: field:ir.attachment,pingen_document_ids:0
246+#: view:pingen.document:0
247+msgid "Pingen Document"
248+msgstr "Document Pingen"
249+
250+#. module: pingen
251+#: field:pingen.document,attachment_id:0
252+msgid "Document"
253+msgstr "Document"
254+
255+#. module: pingen
256+#: help:ir.attachment,pingen_send:0
257+msgid "Defines if a document is merely uploaded or also sent"
258+msgstr "Définit si un fichier est juste ajouté ou également envoyé"
259+
260+#. module: pingen
261+#: view:pingen.document:0
262+#: selection:pingen.document,state:0
263+msgid "Pending"
264+msgstr "En attente"
265+
266+#. module: pingen
267+#: selection:ir.attachment,pingen_speed:0
268+msgid "Economy"
269+msgstr "Économique"
270+
271+#. module: pingen
272+#: view:pingen.document:0
273+msgid "Errors resolved"
274+msgstr "Erreurs résolues"
275+
276+#. module: pingen
277+#: sql_constraint:pingen.document:0
278+msgid "Only one Pingen document is allowed per attachment."
279+msgstr "Uniquement un document Pingen est autorisé par attachement."
280+
281+#. module: pingen
282+#: code:addons/pingen/pingen_document.py:168
283+#: code:addons/pingen/pingen_document.py:298
284+#, python-format
285+msgid "Error when asking Pingen to send the document %s: \n"
286+"%s"
287+msgstr "Erreurs lors de l'envoi du document par Pingen %s: \n"
288+"%s"
289+
290+#. module: pingen
291+#: view:pingen.document:0
292+msgid "Update the letter's informations"
293+msgstr "Mettre à jour les informations de la lettre"
294+
295+#. module: pingen
296+#: view:pingen.document:0
297+#: selection:pingen.document,state:0
298+msgid "Canceled"
299+msgstr "Annulé"
300+
301+#. module: pingen
302+#: selection:pingen.document,state:0
303+msgid "Connection Error"
304+msgstr "Erreur de connexion"
305+
306+#. module: pingen
307+#: model:ir.actions.act_window,name:pingen.action_pingen_document
308+#: model:ir.ui.menu,name:pingen.menu_pingen_document
309+msgid "Pingen Documents"
310+msgstr "Documents Pingen"
311+
312+#. module: pingen
313+#: field:pingen.document,last_error_message:0
314+msgid "Error Message"
315+msgstr "Message d'erreur"
316+
317+#. module: pingen
318+#: selection:ir.attachment,pingen_color:0
319+msgid "B/W"
320+msgstr "N/B"
321+
322+#. module: pingen
323+#: field:res.company,pingen_staging:0
324+msgid "Pingen Staging"
325+msgstr "Staging Pingen"
326+
327+#. module: pingen
328+#: model:ir.model,name:pingen.model_ir_attachment
329+msgid "ir.attachment"
330+msgstr "ir.attachment"
331+
332+#. module: pingen
333+#: view:pingen.document:0
334+#: selection:pingen.document,state:0
335+msgid "In Sendcenter"
336+msgstr "Dans le Sendcenter"
337+
338+#. module: pingen
339+#: view:pingen.document:0
340+#: selection:pingen.document,state:0
341+msgid "Sent"
342+msgstr "Envoyé"
343+
344+#. module: pingen
345+#: field:pingen.document,post_status:0
346+msgid "Post Status"
347+msgstr "État de la lettre"
348+
349+#. module: pingen
350+#: code:addons/pingen/pingen_document.py:163
351+#: code:addons/pingen/pingen_document.py:292
352+#, python-format
353+msgid "Connection Error when asking for sending the document %s to Pingen"
354+msgstr "Erreur de connexion avec Pingen lors de l'envoi de %s"
355+
356+#. module: pingen
357+#: view:res.company:0
358+msgid "Configuration"
359+msgstr "Configuration"
360+
361+#. module: pingen
362+#: view:pingen.document:0
363+msgid "Data"
364+msgstr "Données"
365+
366+#. module: pingen
367+#: view:pingen.document:0
368+msgid "Options"
369+msgstr "Options"
370+
371+#. module: pingen
372+#: field:res.company,pingen_token:0
373+msgid "Pingen Token"
374+msgstr "Token Pingen"
375+
376+#. module: pingen
377+#: field:ir.attachment,send_to_pingen:0
378+msgid "Send to Pingen.com"
379+msgstr "Ajouter sur Pingen.com"
380+
381+#. module: pingen
382+#: model:ir.model,name:pingen.model_pingen_document
383+msgid "pingen.document"
384+msgstr "pingen.document"
385+
386+#. module: pingen
387+#: view:pingen.document:0
388+msgid "Dates"
389+msgstr "Dates"
390+
391+#. module: pingen
392+#: view:pingen.document:0
393+msgid "Sendcenter"
394+msgstr "Sendcenter"
395+
396+#. module: pingen
397+#: sql_constraint:res.company:0
398+msgid "The company name must be unique !"
399+msgstr "The company name must be unique !"
400+
401+#. module: pingen
402+#: field:pingen.document,parsed_address:0
403+msgid "Parsed Address"
404+msgstr "Adresse analysée"
405+
406+#. module: pingen
407+#: view:ir.attachment:0
408+#: view:pingen.document:0
409+#: view:res.company:0
410+msgid "Pingen.com"
411+msgstr "Pingen.com"
412+
413+#. module: pingen
414+#: field:pingen.document,country_id:0
415+msgid "Country"
416+msgstr "Pays"
417+
418+#. module: pingen
419+#: view:ir.attachment:0
420+msgid "Notes"
421+msgstr "Notes"
422+
423+#. module: pingen
424+#: view:pingen.document:0
425+#: selection:pingen.document,state:0
426+msgid "Pushed"
427+msgstr "Ajouté"
428+
429+#. module: pingen
430+#: model:ir.model,name:pingen.model_res_company
431+msgid "Companies"
432+msgstr "Compagnies"
433+
434+#. module: pingen
435+#: code:addons/pingen/ir_attachment.py:90
436+#, python-format
437+msgid "The attachment %s is already pushed to pingen.com."
438+msgstr "L'attachement %s est déjà envoyé sur pingen.com."
439+
440+#. module: pingen
441+#: view:pingen.document:0
442+msgid "Attached To"
443+msgstr "Attaché à "
444+
445+#. module: pingen
446+#: code:addons/pingen/pingen_document.py:136
447+#, python-format
448+msgid "The document does not meet the Pingen requirements."
449+msgstr "Le document ne remplit pas les exigences de Pingen"
450+
451+#. module: pingen
452+#: code:addons/pingen/ir_attachment.py:89
453+#: code:addons/pingen/pingen_document.py:176
454+#: code:addons/pingen/pingen_document.py:306
455+#: code:addons/pingen/pingen_document.py:413
456+#: view:pingen.document:0
457+#, python-format
458+msgid "Error"
459+msgstr "Erreur"
460+
461+#. module: pingen
462+#: code:addons/pingen/pingen_document.py:162
463+#: code:addons/pingen/pingen_document.py:291
464+#: code:addons/pingen/pingen_document.py:398
465+#, python-format
466+msgid "Pingen Connection Error"
467+msgstr "Erreur de connexion avec Pingen"
468+
469+#. module: pingen
470+#: field:pingen.document,send_date:0
471+msgid "Date of sending"
472+msgstr "Date d'envoi"
473+
474+#. module: pingen
475+#: selection:ir.attachment,pingen_speed:0
476+msgid "Priority"
477+msgstr "Priorité"
478+
479+#. module: pingen
480+#: selection:ir.attachment,pingen_color:0
481+msgid "Color"
482+msgstr "Color"
483+
484+#. module: pingen
485+#: model:ir.model,name:pingen.model_pingen_task
486+msgid "pingen.task"
487+msgstr "pingen.task"
488+
489+#. module: pingen
490+#: help:pingen.document,pingen_id:0
491+msgid "ID of the document in the Pingen Documents"
492+msgstr "ID du document sur Pingen"
493+
494+#. module: pingen
495+#: code:addons/pingen/pingen_document.py:167
496+#: code:addons/pingen/pingen_document.py:297
497+#: code:addons/pingen/pingen_document.py:404
498+#: view:pingen.document:0
499+#: selection:pingen.document,state:0
500+#, python-format
501+msgid "Pingen Error"
502+msgstr "Erreur Pingen"
503+
504+#. module: pingen
505+#: view:pingen.document:0
506+msgid "Actions"
507+msgstr "Actions"
508+
509+#. module: pingen
510+#: field:pingen.document,pages:0
511+msgid "Pages"
512+msgstr "Pages"
513+
514+#. module: pingen
515+#: field:pingen.document,currency_id:0
516+msgid "Currency"
517+msgstr "Devise"
518+
519+#. module: pingen
520+#: field:pingen.document,cost:0
521+msgid "Cost"
522+msgstr "Coût"
523+
524+#. module: pingen
525+#: view:pingen.document:0
526+msgid "Push to pingen.com"
527+msgstr "Ajouter sur pingen.com"
528+
529+#. module: pingen
530+#: view:pingen.document:0
531+msgid "Ask pingen.com to send the document"
532+msgstr "Demander à pingen.com d'envoyer le document"
533+
534+#. module: pingen
535+#: help:pingen.document,post_id:0
536+msgid "ID of the document in the Pingen Sendcenter"
537+msgstr "ID du document dans le Sendcenter Pingen"
538+
539+#. module: pingen
540+#: field:ir.attachment,pingen_speed:0
541+msgid "Speed"
542+msgstr "Vitesse"
543+
544+#. module: pingen
545+#: field:pingen.document,post_id:0
546+msgid "Pingen Post ID"
547+msgstr "ID de lettre Pingen"
548+
549+#. module: pingen
550+#: help:ir.attachment,pingen_speed:0
551+msgid "Defines the sending speed if the document is automatically sent"
552+msgstr "Définit la vitesse d'envoi si le document est automatiquement envoyé"
553+
554
555=== added file 'pingen/i18n/pingen.pot'
556--- pingen/i18n/pingen.pot 1970-01-01 00:00:00 +0000
557+++ pingen/i18n/pingen.pot 2012-12-07 13:35:25 +0000
558@@ -0,0 +1,388 @@
559+# Translation of OpenERP Server.
560+# This file contains the translation of the following modules:
561+# * pingen
562+#
563+msgid ""
564+msgstr ""
565+"Project-Id-Version: OpenERP Server 6.1\n"
566+"Report-Msgid-Bugs-To: \n"
567+"POT-Creation-Date: 2012-11-26 10:55+0000\n"
568+"PO-Revision-Date: 2012-11-26 10:55+0000\n"
569+"Last-Translator: <>\n"
570+"Language-Team: \n"
571+"MIME-Version: 1.0\n"
572+"Content-Type: text/plain; charset=UTF-8\n"
573+"Content-Transfer-Encoding: \n"
574+"Plural-Forms: \n"
575+
576+#. module: pingen
577+#: code:addons/pingen/pingen_document.py:177
578+#: code:addons/pingen/pingen_document.py:307
579+#: code:addons/pingen/pingen_document.py:414
580+#, python-format
581+msgid "Unexcepted Error when updating the status of Document %s"
582+msgstr ""
583+
584+#. module: pingen
585+#: field:pingen.document,push_date:0
586+msgid "Push Date"
587+msgstr ""
588+
589+#. module: pingen
590+#: view:pingen.document:0
591+msgid "Errors"
592+msgstr ""
593+
594+#. module: pingen
595+#: field:pingen.document,pingen_id:0
596+msgid "Pingen ID"
597+msgstr ""
598+
599+#. module: pingen
600+#: constraint:res.company:0
601+msgid "Error! You can not create recursive companies."
602+msgstr ""
603+
604+#. module: pingen
605+#: field:ir.attachment,pingen_send:0
606+msgid "Send"
607+msgstr ""
608+
609+#. module: pingen
610+#: code:addons/pingen/pingen_document.py:399
611+#, python-format
612+msgid "Connection Error when updating the status of Document %s from Pingen"
613+msgstr ""
614+
615+#. module: pingen
616+#: field:pingen.document,state:0
617+msgid "State"
618+msgstr ""
619+
620+#. module: pingen
621+#: field:ir.attachment,pingen_color:0
622+msgid "Type of print"
623+msgstr ""
624+
625+#. module: pingen
626+#: view:pingen.document:0
627+msgid "Attachment"
628+msgstr ""
629+
630+#. module: pingen
631+#: code:addons/pingen/pingen_document.py:405
632+#, python-format
633+msgid "Error when updating the status of Document %s from Pingen: \n"
634+"%s"
635+msgstr ""
636+
637+#. module: pingen
638+#: model:ir.actions.act_window,name:pingen.act_attachment_to_pingen_document
639+#: field:ir.attachment,pingen_document_ids:0
640+#: view:pingen.document:0
641+msgid "Pingen Document"
642+msgstr ""
643+
644+#. module: pingen
645+#: field:pingen.document,attachment_id:0
646+msgid "Document"
647+msgstr ""
648+
649+#. module: pingen
650+#: help:ir.attachment,pingen_send:0
651+msgid "Defines if a document is merely uploaded or also sent"
652+msgstr ""
653+
654+#. module: pingen
655+#: view:pingen.document:0
656+#: selection:pingen.document,state:0
657+msgid "Pending"
658+msgstr ""
659+
660+#. module: pingen
661+#: selection:ir.attachment,pingen_speed:0
662+msgid "Economy"
663+msgstr ""
664+
665+#. module: pingen
666+#: view:pingen.document:0
667+msgid "Errors resolved"
668+msgstr ""
669+
670+#. module: pingen
671+#: sql_constraint:pingen.document:0
672+msgid "Only one Pingen document is allowed per attachment."
673+msgstr ""
674+
675+#. module: pingen
676+#: code:addons/pingen/pingen_document.py:168
677+#: code:addons/pingen/pingen_document.py:298
678+#, python-format
679+msgid "Error when asking Pingen to send the document %s: \n"
680+"%s"
681+msgstr ""
682+
683+#. module: pingen
684+#: view:pingen.document:0
685+msgid "Update the letter's informations"
686+msgstr ""
687+
688+#. module: pingen
689+#: view:pingen.document:0
690+#: selection:pingen.document,state:0
691+msgid "Canceled"
692+msgstr ""
693+
694+#. module: pingen
695+#: selection:pingen.document,state:0
696+msgid "Connection Error"
697+msgstr ""
698+
699+#. module: pingen
700+#: model:ir.actions.act_window,name:pingen.action_pingen_document
701+#: model:ir.ui.menu,name:pingen.menu_pingen_document
702+msgid "Pingen Documents"
703+msgstr ""
704+
705+#. module: pingen
706+#: field:pingen.document,last_error_message:0
707+msgid "Error Message"
708+msgstr ""
709+
710+#. module: pingen
711+#: selection:ir.attachment,pingen_color:0
712+msgid "B/W"
713+msgstr ""
714+
715+#. module: pingen
716+#: field:res.company,pingen_staging:0
717+msgid "Pingen Staging"
718+msgstr ""
719+
720+#. module: pingen
721+#: model:ir.model,name:pingen.model_ir_attachment
722+msgid "ir.attachment"
723+msgstr ""
724+
725+#. module: pingen
726+#: view:pingen.document:0
727+#: selection:pingen.document,state:0
728+msgid "In Sendcenter"
729+msgstr ""
730+
731+#. module: pingen
732+#: view:pingen.document:0
733+#: selection:pingen.document,state:0
734+msgid "Sent"
735+msgstr ""
736+
737+#. module: pingen
738+#: field:pingen.document,post_status:0
739+msgid "Post Status"
740+msgstr ""
741+
742+#. module: pingen
743+#: code:addons/pingen/pingen_document.py:163
744+#: code:addons/pingen/pingen_document.py:292
745+#, python-format
746+msgid "Connection Error when asking for sending the document %s to Pingen"
747+msgstr ""
748+
749+#. module: pingen
750+#: view:res.company:0
751+msgid "Configuration"
752+msgstr ""
753+
754+#. module: pingen
755+#: view:pingen.document:0
756+msgid "Data"
757+msgstr ""
758+
759+#. module: pingen
760+#: view:pingen.document:0
761+msgid "Options"
762+msgstr ""
763+
764+#. module: pingen
765+#: field:res.company,pingen_token:0
766+msgid "Pingen Token"
767+msgstr ""
768+
769+#. module: pingen
770+#: field:ir.attachment,send_to_pingen:0
771+msgid "Send to Pingen.com"
772+msgstr ""
773+
774+#. module: pingen
775+#: model:ir.model,name:pingen.model_pingen_document
776+msgid "pingen.document"
777+msgstr ""
778+
779+#. module: pingen
780+#: view:pingen.document:0
781+msgid "Dates"
782+msgstr ""
783+
784+#. module: pingen
785+#: view:pingen.document:0
786+msgid "Sendcenter"
787+msgstr ""
788+
789+#. module: pingen
790+#: sql_constraint:res.company:0
791+msgid "The company name must be unique !"
792+msgstr ""
793+
794+#. module: pingen
795+#: field:pingen.document,parsed_address:0
796+msgid "Parsed Address"
797+msgstr ""
798+
799+#. module: pingen
800+#: view:ir.attachment:0
801+#: view:pingen.document:0
802+#: view:res.company:0
803+msgid "Pingen.com"
804+msgstr ""
805+
806+#. module: pingen
807+#: field:pingen.document,country_id:0
808+msgid "Country"
809+msgstr ""
810+
811+#. module: pingen
812+#: view:ir.attachment:0
813+msgid "Notes"
814+msgstr ""
815+
816+#. module: pingen
817+#: view:pingen.document:0
818+#: selection:pingen.document,state:0
819+msgid "Pushed"
820+msgstr ""
821+
822+#. module: pingen
823+#: model:ir.model,name:pingen.model_res_company
824+msgid "Companies"
825+msgstr ""
826+
827+#. module: pingen
828+#: code:addons/pingen/ir_attachment.py:90
829+#, python-format
830+msgid "The attachment %s is already pushed to pingen.com."
831+msgstr ""
832+
833+#. module: pingen
834+#: view:pingen.document:0
835+msgid "Attached To"
836+msgstr ""
837+
838+#. module: pingen
839+#: code:addons/pingen/pingen_document.py:136
840+#, python-format
841+msgid "The document does not meet the Pingen requirements."
842+msgstr ""
843+
844+#. module: pingen
845+#: code:addons/pingen/ir_attachment.py:89
846+#: code:addons/pingen/pingen_document.py:176
847+#: code:addons/pingen/pingen_document.py:306
848+#: code:addons/pingen/pingen_document.py:413
849+#: view:pingen.document:0
850+#, python-format
851+msgid "Error"
852+msgstr ""
853+
854+#. module: pingen
855+#: code:addons/pingen/pingen_document.py:162
856+#: code:addons/pingen/pingen_document.py:291
857+#: code:addons/pingen/pingen_document.py:398
858+#, python-format
859+msgid "Pingen Connection Error"
860+msgstr ""
861+
862+#. module: pingen
863+#: field:pingen.document,send_date:0
864+msgid "Date of sending"
865+msgstr ""
866+
867+#. module: pingen
868+#: selection:ir.attachment,pingen_speed:0
869+msgid "Priority"
870+msgstr ""
871+
872+#. module: pingen
873+#: selection:ir.attachment,pingen_color:0
874+msgid "Color"
875+msgstr ""
876+
877+#. module: pingen
878+#: model:ir.model,name:pingen.model_pingen_task
879+msgid "pingen.task"
880+msgstr ""
881+
882+#. module: pingen
883+#: help:pingen.document,pingen_id:0
884+msgid "ID of the document in the Pingen Documents"
885+msgstr ""
886+
887+#. module: pingen
888+#: code:addons/pingen/pingen_document.py:167
889+#: code:addons/pingen/pingen_document.py:297
890+#: code:addons/pingen/pingen_document.py:404
891+#: view:pingen.document:0
892+#: selection:pingen.document,state:0
893+#, python-format
894+msgid "Pingen Error"
895+msgstr ""
896+
897+#. module: pingen
898+#: view:pingen.document:0
899+msgid "Actions"
900+msgstr ""
901+
902+#. module: pingen
903+#: field:pingen.document,pages:0
904+msgid "Pages"
905+msgstr ""
906+
907+#. module: pingen
908+#: field:pingen.document,currency_id:0
909+msgid "Currency"
910+msgstr ""
911+
912+#. module: pingen
913+#: field:pingen.document,cost:0
914+msgid "Cost"
915+msgstr ""
916+
917+#. module: pingen
918+#: view:pingen.document:0
919+msgid "Push to pingen.com"
920+msgstr ""
921+
922+#. module: pingen
923+#: view:pingen.document:0
924+msgid "Ask pingen.com to send the document"
925+msgstr ""
926+
927+#. module: pingen
928+#: help:pingen.document,post_id:0
929+msgid "ID of the document in the Pingen Sendcenter"
930+msgstr ""
931+
932+#. module: pingen
933+#: field:ir.attachment,pingen_speed:0
934+msgid "Speed"
935+msgstr ""
936+
937+#. module: pingen
938+#: field:pingen.document,post_id:0
939+msgid "Pingen Post ID"
940+msgstr ""
941+
942+#. module: pingen
943+#: help:ir.attachment,pingen_speed:0
944+msgid "Defines the sending speed if the document is automatically sent"
945+msgstr ""
946+
947
948=== added file 'pingen/ir_attachment.py'
949--- pingen/ir_attachment.py 1970-01-01 00:00:00 +0000
950+++ pingen/ir_attachment.py 2012-12-07 13:35:25 +0000
951@@ -0,0 +1,124 @@
952+# -*- coding: utf-8 -*-
953+##############################################################################
954+#
955+# Author: Guewen Baconnier
956+# Copyright 2012 Camptocamp SA
957+#
958+# This program is free software: you can redistribute it and/or modify
959+# it under the terms of the GNU Affero General Public License as
960+# published by the Free Software Foundation, either version 3 of the
961+# License, or (at your option) any later version.
962+#
963+# This program is distributed in the hope that it will be useful,
964+# but WITHOUT ANY WARRANTY; without even the implied warranty of
965+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
966+# GNU Affero General Public License for more details.
967+#
968+# You should have received a copy of the GNU Affero General Public License
969+# along with this program. If not, see <http://www.gnu.org/licenses/>.
970+#
971+##############################################################################
972+
973+import requests
974+import base64
975+
976+from openerp.osv import osv, orm, fields
977+from openerp.tools.translate import _
978+
979+
980+class ir_attachment(orm.Model):
981+
982+ _inherit = 'ir.attachment'
983+
984+ _columns = {
985+ 'send_to_pingen': fields.boolean('Send to Pingen.com'),
986+ 'pingen_document_ids': fields.one2many(
987+ 'pingen.document', 'attachment_id',
988+ string='Pingen Document', readonly=True),
989+ 'pingen_send': fields.boolean(
990+ 'Send',
991+ help="Defines if a document is merely uploaded or also sent"),
992+ 'pingen_speed': fields.selection(
993+ [('1', 'Priority'), ('2', 'Economy')],
994+ 'Speed',
995+ help="Defines the sending speed if the document is automatically sent"),
996+ 'pingen_color': fields.selection( [('0', 'B/W'), ('1', 'Color')], 'Type of print'),
997+ }
998+
999+ _defaults = {
1000+ 'pingen_send': True,
1001+ 'pingen_color': '0',
1002+ 'pingen_speed': '2',
1003+ }
1004+
1005+ def _prepare_pingen_document_vals(self, cr, uid, attachment, context=None):
1006+ return {'attachment_id': attachment.id,
1007+ 'config': 'created from attachment'}
1008+
1009+ def _handle_pingen_document(self, cr, uid, attachment_id, context=None):
1010+ """ Reponsible of the related ``pingen.document`` when the ``send_to_pingen``
1011+ field is modified.
1012+
1013+ Only one pingen document can be created per attachment.
1014+
1015+ When ``send_to_pingen`` is activated:
1016+ * Create a ``pingen.document`` if it does not already exist
1017+ * Put the related ``pingen.document`` to ``pending`` if it already exist
1018+ When it is deactivated:
1019+ * Do nothing if no related ``pingen.document`` exists
1020+ * Or cancel it
1021+ * If it has already been pushed to pingen.com, raises
1022+ an `osv.except_osv` exception
1023+ """
1024+ pingen_document_obj = self.pool.get('pingen.document')
1025+ attachment = self.browse(cr, uid, attachment_id, context=context)
1026+ document = attachment.pingen_document_ids[0] if attachment.pingen_document_ids else None
1027+ if attachment.send_to_pingen:
1028+ if document:
1029+ document.write({'state': 'pending'}, context=context)
1030+ else:
1031+ pingen_document_obj.create(
1032+ cr, uid,
1033+ self._prepare_pingen_document_vals(
1034+ cr, uid, attachment, context=context),
1035+ context=context)
1036+ else:
1037+ if document:
1038+ if document.state == 'pushed':
1039+ raise osv.except_osv(
1040+ _('Error'),
1041+ _('The attachment %s is already pushed to pingen.com.') % \
1042+ attachment.name)
1043+ document.write({'state': 'canceled'}, context=context)
1044+ return
1045+
1046+ def create(self, cr, uid, vals, context=None):
1047+ attachment_id = super(ir_attachment, self).create(cr, uid, vals, context=context)
1048+ if 'send_to_pingen' in vals:
1049+ self._handle_pingen_document(cr, uid, attachment_id, context=context)
1050+ return attachment_id
1051+
1052+ def write(self, cr, uid, ids, vals, context=None):
1053+ res = super(ir_attachment, self).write(cr, uid, ids, vals, context=context)
1054+ if 'send_to_pingen' in vals:
1055+ for attachment_id in ids:
1056+ self._handle_pingen_document(cr, uid, attachment_id, context=context)
1057+ return res
1058+
1059+ def _decoded_content(self, cr, uid, attachment, context=None):
1060+ """ Returns the decoded content of an attachment (stored or url)
1061+
1062+ Returns None if the type is 'url' and the url is not reachable.
1063+ """
1064+ decoded_document = None
1065+ if attachment.type == 'binary':
1066+ decoded_document = base64.decodestring(attachment.datas)
1067+ elif attachment.type == 'url':
1068+ response = requests.get(attachment.url)
1069+ if response.ok:
1070+ decoded_document = requests.content
1071+ else:
1072+ raise Exception(
1073+ 'The type of attachment %s is not handled' % attachment.type)
1074+ return decoded_document
1075+
1076
1077=== added file 'pingen/ir_attachment_view.xml'
1078--- pingen/ir_attachment_view.xml 1970-01-01 00:00:00 +0000
1079+++ pingen/ir_attachment_view.xml 2012-12-07 13:35:25 +0000
1080@@ -0,0 +1,31 @@
1081+<?xml version="1.0" encoding="utf-8"?>
1082+<openerp>
1083+ <data noupdate="0">
1084+
1085+ <record id="view_attachment_form" model="ir.ui.view">
1086+ <field name="name">ir.attachment.pingen.view</field>
1087+ <field name="model">ir.attachment</field>
1088+ <field name="type">form</field>
1089+ <field name="inherit_id" ref="base.view_attachment_form"/>
1090+ <field name="arch" type="xml">
1091+ <page string="Notes" position="before">
1092+ <page string="Pingen.com">
1093+ <field name="send_to_pingen"/>
1094+ <field name="pingen_send" attrs="{'required': [('send_to_pingen', '=', True)]}"/>
1095+ <field name="pingen_speed" attrs="{'required': [('pingen_send', '=', True)]}"/>
1096+ <field name="pingen_color" />
1097+ </page>
1098+ </page>
1099+ </field>
1100+ </record>
1101+
1102+ <act_window
1103+ context="{'search_default_attachment_id': [active_id], 'default_attachment_id': active_id}"
1104+ id="act_attachment_to_pingen_document"
1105+ name="Pingen Document"
1106+ groups=""
1107+ res_model="pingen.document"
1108+ src_model="ir.attachment"/>
1109+
1110+ </data>
1111+</openerp>
1112
1113=== added file 'pingen/pingen.py'
1114--- pingen/pingen.py 1970-01-01 00:00:00 +0000
1115+++ pingen/pingen.py 2012-12-07 13:35:25 +0000
1116@@ -0,0 +1,209 @@
1117+# -*- coding: utf-8 -*-
1118+##############################################################################
1119+#
1120+# Author: Guewen Baconnier
1121+# Copyright 2012 Camptocamp SA
1122+#
1123+# This program is free software: you can redistribute it and/or modify
1124+# it under the terms of the GNU Affero General Public License as
1125+# published by the Free Software Foundation, either version 3 of the
1126+# License, or (at your option) any later version.
1127+#
1128+# This program is distributed in the hope that it will be useful,
1129+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1130+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1131+# GNU Affero General Public License for more details.
1132+#
1133+# You should have received a copy of the GNU Affero General Public License
1134+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1135+#
1136+##############################################################################
1137+
1138+import requests
1139+import logging
1140+import urlparse
1141+import json
1142+
1143+from requests.packages.urllib3.filepost import encode_multipart_formdata
1144+
1145+_logger = logging.getLogger(__name__)
1146+
1147+POST_SENDING_STATUS = {
1148+ 100: 'Ready/Pending',
1149+ 101: 'Processing',
1150+ 102: 'Waiting for confirmation',
1151+ 200: 'Sent',
1152+ 300: 'Some error occured and object wasn\'t sent',
1153+ 400: 'Sending cancelled',
1154+}
1155+
1156+
1157+class PingenException(RuntimeError):
1158+ """There was an ambiguous exception that occurred while handling your
1159+ request."""
1160+
1161+
1162+class ConnectionError(PingenException):
1163+ """An Error occured with the pingen API"""
1164+
1165+
1166+class APIError(PingenException):
1167+ """An Error occured with the pingen API"""
1168+
1169+
1170+class Pingen(object):
1171+ """ Interface to the pingen.com API """
1172+
1173+ def __init__(self, token, staging=True):
1174+ self._token = token
1175+ self.staging = staging
1176+ self._session = None
1177+ super(Pingen, self).__init__()
1178+
1179+ @property
1180+ def url(self):
1181+ if self.staging:
1182+ return 'https://stage-api.pingen.com'
1183+ return 'https://api.pingen.com'
1184+
1185+ @property
1186+ def session(self):
1187+ """ Build a requests session """
1188+ if self._session is not None:
1189+ return self._session
1190+ self._session = requests.Session(
1191+ params={'token': self._token},
1192+ # with safe_mode, requests catch errors and
1193+ # returns a blank response with an error
1194+ config={'safe_mode': True},
1195+ # verify = False required for staging environment
1196+ # because the SSL certificate is wrong
1197+ verify=not self.staging)
1198+ return self._session
1199+
1200+ def __enter__(self):
1201+ return self
1202+
1203+ def __exit__(self, *args):
1204+ self.close()
1205+
1206+ def close(self):
1207+ """Dispose of any internal state. """
1208+ if self._session:
1209+ self._session.close()
1210+
1211+ def _send(self, method, endpoint, **kwargs):
1212+ """ Send a request to the pingen API using requests
1213+
1214+ Add necessary boilerplate to call pingen.com API
1215+ (authentication, configuration, ...)
1216+
1217+ :param boundmethod method: requests method to call
1218+ :param str endpoint: endpoint to call
1219+ :param kwargs: additional arguments forwarded to the requests method
1220+ """
1221+ complete_url = urlparse.urljoin(self.url, endpoint)
1222+
1223+ response = method(complete_url, **kwargs)
1224+
1225+ if not response.ok:
1226+ raise ConnectionError(
1227+ "%s: %s" % (response.json['errorcode'],
1228+ response.json['errormessage']))
1229+
1230+ if response.json['error']:
1231+ raise APIError(
1232+ "%s: %s" % (response.json['errorcode'], response.json['errormessage']))
1233+
1234+ return response
1235+
1236+ def push_document(self, filename, filestream, send=None, speed=None, color=None):
1237+ """ Upload a document to pingen.com and eventually ask to send it
1238+
1239+ :param str filename: name of the file to push
1240+ :param StringIO filestream: file to push
1241+ :param boolean send: if True, the document will be sent by pingen.com
1242+ :param int/str speed: sending speed of the document if it is send
1243+ 1 = Priority, 2 = Economy
1244+ :param int/str color: type of print, 0 = B/W, 1 = Color
1245+ :return: tuple with 3 items:
1246+ 1. document_id on pingen.com
1247+ 2. post_id on pingen.com if it has been sent or None
1248+ 3. dict of the created item on pingen (details)
1249+ """
1250+ data = {
1251+ 'send': send,
1252+ 'speed': speed,
1253+ 'color': color,
1254+ }
1255+
1256+ # we cannot use the `files` param alongside
1257+ # with the `datas`param when data is a
1258+ # JSON-encoded data. We have to construct
1259+ # the entire body and send it to `data`
1260+ # https://github.com/kennethreitz/requests/issues/950
1261+ formdata = {
1262+ 'file': (filename, filestream.read()),
1263+ 'data': json.dumps(data),
1264+ }
1265+
1266+ multipart, content_type = encode_multipart_formdata(formdata)
1267+
1268+ response = self._send(
1269+ self.session.post,
1270+ 'document/upload',
1271+ headers={'Content-Type': content_type},
1272+ data=multipart)
1273+
1274+ rjson = response.json
1275+
1276+ document_id = rjson['id']
1277+ if rjson.get('send'):
1278+ # confusing name but send_id is the posted id
1279+ posted_id = rjson['send'][0]['send_id']
1280+ item = rjson['item']
1281+
1282+ return document_id, posted_id, item
1283+
1284+ def send_document(self, document_id, speed=None, color=None):
1285+ """ Send a uploaded document to pingen.com
1286+
1287+ :param int document_id: id of the document to send
1288+ :param int/str speed: sending speed of the document if it is send
1289+ 1 = Priority, 2 = Economy
1290+ :param int/str color: type of print, 0 = B/W, 1 = Color
1291+ :return: id of the post on pingen.com
1292+ """
1293+ data = {
1294+ 'speed': speed,
1295+ 'color': color,
1296+ }
1297+ response = self._send(
1298+ self.session.post,
1299+ 'document/send',
1300+ params={'id': document_id},
1301+ data={'data': json.dumps(data)})
1302+
1303+ return response.json['id']
1304+
1305+ def post_infos(self, post_id):
1306+ """ Return the information of a post
1307+
1308+ :param int post_id: id of the document to send
1309+ :return: dict of infos of the post
1310+ """
1311+ response = self._send(
1312+ self.session.get,
1313+ 'post/get',
1314+ params={'id': post_id})
1315+
1316+ return response.json['item']
1317+
1318+ @staticmethod
1319+ def is_posted(post_infos):
1320+ """ return True if the post has been sent
1321+
1322+ :param dict post_infos: post infos returned by `post_infos`
1323+ """
1324+ return post_infos['status'] == 200
1325+
1326
1327=== added file 'pingen/pingen_data.xml'
1328--- pingen/pingen_data.xml 1970-01-01 00:00:00 +0000
1329+++ pingen/pingen_data.xml 2012-12-07 13:35:25 +0000
1330@@ -0,0 +1,32 @@
1331+<?xml version="1.0" encoding="utf-8"?>
1332+<openerp>
1333+ <data noupdate="1">
1334+
1335+ <record forcecreate="True" id="ir_cron_push_pingen" model="ir.cron">
1336+ <field name="name">Run Pingen Document Push</field>
1337+ <field eval="True" name="active"/>
1338+ <field name="user_id" ref="base.user_root"/>
1339+ <field name="interval_number">1</field>
1340+ <field name="interval_type">hours</field>
1341+ <field name="numbercall">-1</field>
1342+ <field eval="False" name="doall"/>
1343+ <field name="model">pingen.document</field>
1344+ <field name="function">_push_and_send_to_pingen_cron</field>
1345+ <field name="args">(None,)</field>
1346+ </record>
1347+
1348+ <record forcecreate="True" id="ir_cron_update_pingen" model="ir.cron">
1349+ <field name="name">Run Pingen Document Update</field>
1350+ <field eval="True" name="active"/>
1351+ <field name="user_id" ref="base.user_root"/>
1352+ <field name="interval_number">1</field>
1353+ <field name="interval_type">days</field>
1354+ <field name="numbercall">-1</field>
1355+ <field eval="False" name="doall"/>
1356+ <field name="model">pingen.document</field>
1357+ <field name="function">_update_post_infos_cron</field>
1358+ <field name="args">(None,)</field>
1359+ </record>
1360+
1361+ </data>
1362+</openerp>
1363
1364=== added file 'pingen/pingen_document.py'
1365--- pingen/pingen_document.py 1970-01-01 00:00:00 +0000
1366+++ pingen/pingen_document.py 2012-12-07 13:35:25 +0000
1367@@ -0,0 +1,420 @@
1368+# -*- coding: utf-8 -*-
1369+##############################################################################
1370+#
1371+# Author: Guewen Baconnier
1372+# Copyright 2012 Camptocamp SA
1373+#
1374+# This program is free software: you can redistribute it and/or modify
1375+# it under the terms of the GNU Affero General Public License as
1376+# published by the Free Software Foundation, either version 3 of the
1377+# License, or (at your option) any later version.
1378+#
1379+# This program is distributed in the hope that it will be useful,
1380+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1381+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1382+# GNU Affero General Public License for more details.
1383+#
1384+# You should have received a copy of the GNU Affero General Public License
1385+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1386+#
1387+##############################################################################
1388+
1389+import logging
1390+
1391+from cStringIO import StringIO
1392+
1393+from contextlib import closing
1394+from openerp.osv import osv, orm, fields
1395+from openerp.tools.translate import _
1396+from openerp import pooler
1397+from .pingen import APIError, ConnectionError, POST_SENDING_STATUS
1398+
1399+_logger = logging.getLogger(__name__)
1400+
1401+
1402+class pingen_document(orm.Model):
1403+ """ A pingen document is the state of the synchronization of
1404+ an attachment with pingen.com
1405+
1406+ It stores the configuration and the current state of the synchronization.
1407+ It also serves as a queue of documents to push to pingen.com
1408+ """
1409+
1410+ _name = 'pingen.document'
1411+ _inherits = {'ir.attachment': 'attachment_id'}
1412+
1413+ _columns = {
1414+ 'attachment_id': fields.many2one(
1415+ 'ir.attachment', 'Document',
1416+ required=True, readonly=True,
1417+ ondelete='cascade'),
1418+ 'state': fields.selection(
1419+ [('pending', 'Pending'),
1420+ ('pushed', 'Pushed'),
1421+ ('sendcenter', 'In Sendcenter'),
1422+ ('sent', 'Sent'),
1423+ ('error', 'Connection Error'),
1424+ ('pingen_error', 'Pingen Error'),
1425+ ('canceled', 'Canceled')],
1426+ string='State', readonly=True, required=True),
1427+ 'push_date': fields.datetime('Push Date', readonly=True),
1428+
1429+ # for `error` and `pingen_error` states when we push
1430+ 'last_error_message': fields.text('Error Message', readonly=True),
1431+
1432+ # pingen IDs
1433+ 'pingen_id': fields.integer(
1434+ 'Pingen ID', readonly=True,
1435+ help="ID of the document in the Pingen Documents"),
1436+ 'post_id': fields.integer(
1437+ 'Pingen Post ID', readonly=True,
1438+ help="ID of the document in the Pingen Sendcenter"),
1439+
1440+ # sendcenter infos
1441+ 'post_status': fields.char('Post Status', size=128, readonly=True),
1442+ 'parsed_address': fields.text('Parsed Address', readonly=True),
1443+ 'cost': fields.float('Cost', readonly=True),
1444+ 'currency_id': fields.many2one('res.currency', 'Currency', readonly=True),
1445+ 'country_id': fields.many2one('res.country', 'Country', readonly=True),
1446+ 'send_date': fields.datetime('Date of sending', readonly=True),
1447+ 'pages': fields.integer('Pages', readonly=True),
1448+ }
1449+
1450+ _defaults = {
1451+ 'state': 'pending',
1452+ }
1453+
1454+ _sql_constraints = [
1455+ ('pingen_document_attachment_uniq',
1456+ 'unique (attachment_id)',
1457+ 'Only one Pingen document is allowed per attachment.'),
1458+ ]
1459+
1460+ def _get_pingen_session(self, cr, uid, context=None):
1461+ """ Returns a pingen session for a user """
1462+ company = self.pool.get('res.users').browse(
1463+ cr, uid, uid, context=context).company_id
1464+ return self.pool.get('res.company')._pingen(cr, uid, company, context=context)
1465+
1466+ def _push_to_pingen(self, cr, uid, document, pingen=None, context=None):
1467+ """ Push a document to pingen.com
1468+
1469+ :param Pingen pingen: optional pingen object to reuse session
1470+ """
1471+ attachment_obj = self.pool.get('ir.attachment')
1472+
1473+ decoded_document = attachment_obj._decoded_content(
1474+ cr, uid, document.attachment_id, context=context)
1475+
1476+ if pingen is None:
1477+ pingen = self._get_pingen_session(cr, uid, context=context)
1478+ try:
1479+ doc_id, post_id, infos = pingen.push_document(
1480+ document.datas_fname,
1481+ StringIO(decoded_document),
1482+ document.pingen_send,
1483+ document.pingen_speed,
1484+ document.pingen_color)
1485+ except ConnectionError as e:
1486+ _logger.exception(
1487+ 'Connection Error when pushing Pingen Document %s to %s.' %
1488+ (document.id, pingen.url))
1489+ raise
1490+
1491+ except APIError as e:
1492+ _logger.error(
1493+ 'API Error when pushing Pingen Document %s to %s.' %
1494+ (document.id, pingen.url))
1495+ raise
1496+
1497+ error = False
1498+ state = 'pushed'
1499+ if post_id:
1500+ state = 'sendcenter'
1501+ elif infos['requirement_failure']:
1502+ state = 'pingen_error'
1503+ error = _('The document does not meet the Pingen requirements.')
1504+
1505+ document.write(
1506+ {'last_error_message': error,
1507+ 'state': state,
1508+ 'push_date': infos['date'],
1509+ 'pingen_id': doc_id,
1510+ 'post_id': post_id},
1511+ context=context)
1512+ _logger.info('Pingen Document %s: pushed to %s' % (document.id, pingen.url))
1513+
1514+ def push_to_pingen(self, cr, uid, ids, context=None):
1515+ """ Push a document to pingen.com
1516+
1517+ Convert errors to osv.except_osv to be handled by the client.
1518+
1519+ Wrapper method for multiple ids (when triggered from button for
1520+ instance) for public interface.
1521+ """
1522+ assert len(ids) == 1, "Only 1 id is allowed"
1523+ with self._get_pingen_session(cr, uid, context=context) as session:
1524+ for document in self.browse(cr, uid, ids, context=context):
1525+ try:
1526+ self._push_to_pingen(
1527+ cr, uid, document, pingen=session, context=context)
1528+ except ConnectionError as e:
1529+ raise osv.except_osv(
1530+ _('Pingen Connection Error'),
1531+ _('Connection Error when asking for sending the document %s to Pingen') % document.name)
1532+
1533+ except APIError as e:
1534+ raise osv.except_osv(
1535+ _('Pingen Error'),
1536+ _('Error when asking Pingen to send the document %s: '
1537+ '\n%s') % (document.name, e))
1538+
1539+ except:
1540+ _logger.exception(
1541+ 'Unexcepted Error when updating the status of pingen.document %s: ' %
1542+ document.id)
1543+ raise osv.except_osv(
1544+ _('Error'),
1545+ _('Unexcepted Error when updating the status of Document %s') % document.name)
1546+ return True
1547+
1548+ def _push_and_send_to_pingen_cron(self, cr, uid, ids, context=None):
1549+ """ Push a document to pingen.com
1550+
1551+ Intended to be used in a cron.
1552+
1553+ Commit after each record
1554+
1555+ Instead of raising, store the error in the pingen.document
1556+ """
1557+ if not ids:
1558+ ids = self.search(
1559+ cr, uid,
1560+ # do not retry pingen_error, they should be treated manually
1561+ [('state', 'in', ['pending', 'pushed', 'error'])],
1562+ limit=100,
1563+ context=context)
1564+
1565+ with closing(pooler.get_db(cr.dbname).cursor()) as loc_cr, \
1566+ self._get_pingen_session(cr, uid, context=context) as session:
1567+ for document in self.browse(loc_cr, uid, ids, context=context):
1568+
1569+ if document.state == 'error':
1570+ self._resolve_error(loc_cr, uid, document, context=context)
1571+ document.refresh()
1572+
1573+ try:
1574+ if document.state == 'pending':
1575+ self._push_to_pingen(
1576+ loc_cr, uid, document, pingen=session, context=context)
1577+
1578+ elif document.state == 'pushed':
1579+ self._ask_pingen_send(
1580+ loc_cr, uid, document, pingen=session, context=context)
1581+ except ConnectionError as e:
1582+ document.write({'last_error_message': e,
1583+ 'state': 'error'},
1584+ context=context)
1585+ except APIError as e:
1586+ document.write({'last_error_message': e,
1587+ 'state': 'pingen_error'},
1588+ context=context)
1589+ except:
1590+ _logger.error('Unexcepted error in pingen cron')
1591+ loc_cr.rollback()
1592+ raise
1593+
1594+ else:
1595+ loc_cr.commit()
1596+
1597+ return True
1598+
1599+ def _resolve_error(self, cr, uid, document, context=None):
1600+ """ A document as resolved, put in the correct state """
1601+ if document.post_id:
1602+ state = 'sendcenter'
1603+ elif document.pingen_id:
1604+ state = 'pushed'
1605+ else:
1606+ state = 'pending'
1607+ document.write({'state': state}, context=context)
1608+
1609+ def resolve_error(self, cr, uid, ids, context=None):
1610+ """ A document as resolved, put in the correct state """
1611+ for document in self.browse(cr, uid, ids, context=context):
1612+ self._resolve_error(cr, uid, document, context=context)
1613+ return True
1614+
1615+ def _ask_pingen_send(self, cr, uid, document, pingen, context=None):
1616+ """ For a document already pushed to pingen, ask to send it.
1617+
1618+ :param Pingen pingen: pingen object to reuse
1619+ """
1620+ # sending has been explicitely asked so we change the option
1621+ # for consistency
1622+ if not document.pingen_send:
1623+ document.write({'pingen_send': True}, context=context)
1624+
1625+ try:
1626+ post_id = pingen.send_document(
1627+ document.pingen_id,
1628+ document.pingen_speed,
1629+ document.pingen_color)
1630+ except ConnectionError as e:
1631+ _logger.exception('Connection Error when asking for sending Pingen Document %s to %s.' %
1632+ (document.id, pingen.url))
1633+ raise
1634+ except APIError as e:
1635+ _logger.exception('API Error when asking for sending Pingen Document %s to %s.' %
1636+ (document.id, pingen.url))
1637+ raise
1638+
1639+ document.write(
1640+ {'last_error_message': False,
1641+ 'state': 'sendcenter',
1642+ 'post_id': post_id},
1643+ context=context)
1644+ _logger.info('Pingen Document %s: asked for sending to %s' % (document.id, pingen.url))
1645+
1646+ return True
1647+
1648+ def ask_pingen_send(self, cr, uid, ids, context=None):
1649+ """ For a document already pushed to pingen, ask to send it.
1650+
1651+ Wrapper method for multiple ids (when triggered from button for
1652+ instance) for public interface.
1653+ """
1654+ assert len(ids) == 1, "Only 1 id is allowed"
1655+ with self._get_pingen_session(cr, uid, context=context) as session:
1656+ for document in self.browse(cr, uid, ids, context=context):
1657+ try:
1658+ self._ask_pingen_send(cr, uid, document, pingen=session, context=context)
1659+ except ConnectionError as e:
1660+ raise osv.except_osv(
1661+ _('Pingen Connection Error'),
1662+ _('Connection Error when asking for '
1663+ 'sending the document %s to Pingen') % document.name)
1664+
1665+ except APIError as e:
1666+ raise osv.except_osv(
1667+ _('Pingen Error'),
1668+ _('Error when asking Pingen to send the document %s: '
1669+ '\n%s') % (document.name, e))
1670+
1671+ except:
1672+ _logger.exception(
1673+ 'Unexcepted Error when updating the status of pingen.document %s: ' %
1674+ document.id)
1675+ raise osv.except_osv(
1676+ _('Error'),
1677+ _('Unexcepted Error when updating the status of Document %s') % document.name)
1678+ return True
1679+
1680+ def _update_post_infos(self, cr, uid, document, pingen, context=None):
1681+ """ Update the informations from pingen of a document in the Sendcenter
1682+
1683+ :param Pingen pingen: pingen object to reuse
1684+ """
1685+ if not document.post_id:
1686+ return
1687+
1688+ try:
1689+ post_infos = pingen.post_infos(document.post_id)
1690+ except ConnectionError as e:
1691+ _logger.exception(
1692+ 'Connection Error when asking for '
1693+ 'sending Pingen Document %s to %s.' %
1694+ (document.id, pingen.url))
1695+ raise
1696+ except APIError as e:
1697+ _logger.exception(
1698+ 'API Error when asking for sending Pingen Document %s to %s.' %
1699+ (document.id, pingen.url))
1700+ raise
1701+
1702+ currency_ids = self.pool.get('res.currency').search(
1703+ cr, uid, [('name', '=', post_infos['currency'])], context=context)
1704+ country_ids = self.pool.get('res.country').search(
1705+ cr, uid, [('code', '=', post_infos['country'])], context=context)
1706+ vals = {
1707+ 'post_status': POST_SENDING_STATUS[post_infos['status']],
1708+ 'cost': post_infos['cost'],
1709+ 'currency_id': currency_ids[0] if currency_ids else False,
1710+ 'parsed_address': post_infos['address'],
1711+ 'country_id': country_ids[0] if country_ids else False,
1712+ 'send_date': post_infos['date'],
1713+ 'pages': post_infos['pages'],
1714+ 'last_error_message': False,
1715+ }
1716+ if pingen.is_posted(post_infos):
1717+ vals['state'] = 'sent'
1718+
1719+ document.write(vals, context=context)
1720+ _logger.info('Pingen Document %s: status updated' % document.id)
1721+
1722+ def _update_post_infos_cron(self, cr, uid, ids, context=None):
1723+ """ Update the informations from pingen of a document in the Sendcenter
1724+
1725+ Intended to be used in a cron.
1726+
1727+ Commit after each record
1728+
1729+ Do not raise errors, only skip the update of the record.
1730+ """
1731+ if not ids:
1732+ ids = self.search(
1733+ cr, uid,
1734+ [('state', '=', 'sendcenter')],
1735+ context=context)
1736+
1737+ with closing(pooler.get_db(cr.dbname).cursor()) as loc_cr, \
1738+ self._get_pingen_session(cr, uid, context=context) as session:
1739+ for document in self.browse(loc_cr, uid, ids, context=context):
1740+ try:
1741+ self._update_post_infos(
1742+ loc_cr, uid, document, pingen=session, context=context)
1743+ except (ConnectionError, APIError):
1744+ # will be retried the next time
1745+ # In any case, the error has been logged by _update_post_infos
1746+ loc_cr.rollback()
1747+ except:
1748+ _logger.error('Unexcepted error in pingen cron')
1749+ loc_cr.rollback()
1750+ raise
1751+ else:
1752+ loc_cr.commit()
1753+ return True
1754+
1755+ def update_post_infos(self, cr, uid, ids, context=None):
1756+ """ Update the informations from pingen of a document in the Sendcenter
1757+
1758+ Wrapper method for multiple ids (when triggered from button for
1759+ instance) for public interface.
1760+ """
1761+ assert len(ids) == 1, "Only 1 id is allowed"
1762+ with self._get_pingen_session(cr, uid, context=context) as session:
1763+ for document in self.browse(cr, uid, ids, context=context):
1764+ try:
1765+ self._update_post_infos(
1766+ cr, uid, document, pingen=session, context=context)
1767+ except ConnectionError as e:
1768+ raise osv.except_osv(
1769+ _('Pingen Connection Error'),
1770+ _('Connection Error when updating the status of Document %s'
1771+ ' from Pingen') % document.name)
1772+
1773+ except APIError as e:
1774+ raise osv.except_osv(
1775+ _('Pingen Error'),
1776+ _('Error when updating the status of Document %s from Pingen: '
1777+ '\n%s') % (document.name, e))
1778+
1779+ except:
1780+ _logger.exception(
1781+ 'Unexcepted Error when updating the status of pingen.document %s: ' %
1782+ document.id)
1783+ raise osv.except_osv(
1784+ _('Error'),
1785+ _('Unexcepted Error when updating the status of Document %s') % document.name)
1786+ return True
1787+
1788
1789=== added file 'pingen/pingen_document_view.xml'
1790--- pingen/pingen_document_view.xml 1970-01-01 00:00:00 +0000
1791+++ pingen/pingen_document_view.xml 2012-12-07 13:35:25 +0000
1792@@ -0,0 +1,161 @@
1793+<?xml version="1.0" encoding="utf-8"?>
1794+<openerp>
1795+ <data noupdate="0">
1796+
1797+ <record id="view_pingen_document_tree" model="ir.ui.view">
1798+ <field name="name">pingen.document.tree</field>
1799+ <field name="model">pingen.document</field>
1800+ <field name="type">tree</field>
1801+ <field name="arch" type="xml">
1802+ <tree string="Pingen Document">
1803+ <field name="name"/>
1804+ <field name="datas_fname"/>
1805+ <field name="pingen_send"/>
1806+ <field name="pingen_speed"/>
1807+ <field name="pingen_color"/>
1808+ <field name="state"/>
1809+ </tree>
1810+ </field>
1811+ </record>
1812+
1813+ <record id="view_pingen_document_form" model="ir.ui.view">
1814+ <field name="name">pingen.document.form</field>
1815+ <field name="model">pingen.document</field>
1816+ <field name="type">form</field>
1817+ <field name="arch" type="xml">
1818+ <form string="Pingen Document">
1819+ <group colspan="4" col="6">
1820+ <field name="name" readonly="True"/>
1821+ <field name="type" readonly="True"/>
1822+ <field name="company_id" readonly="True" groups="base.group_multi_company" widget="selection"/>
1823+ </group>
1824+ <notebook colspan="4">
1825+ <page string="Pingen.com">
1826+ <separator string="Options" colspan="4"/>
1827+ <newline />
1828+ <group col="2" colspan="2">
1829+ <field name="pingen_send" attrs="{'readonly': [('state', 'in', ['sendcenter', 'sent'])]}"/>
1830+ <field name="pingen_speed" attrs="{'readonly': [('state', 'in', ['sendcenter', 'sent'])], 'required': [('pingen_send', '=', True)]}"/>
1831+ <field name="pingen_color" attrs="{'readonly': [('state', 'in', ['sendcenter', 'sent'])]}"/>
1832+ </group>
1833+
1834+ <separator string="Dates" colspan="4"/>
1835+ <newline />
1836+ <group col="2" colspan="2">
1837+ <field name="push_date"/>
1838+ </group>
1839+
1840+ <group colspan="4" attrs="{'invisible': [('last_error_message', '=', False)]}">
1841+ <separator string="Errors" colspan="4"/>
1842+ <newline />
1843+ <group col="2" colspan="2">
1844+ <field nolabel="1" name="last_error_message"/>
1845+ </group>
1846+ </group>
1847+
1848+ <group colspan="4" attrs="{'invisible': [('state', 'not in', ['sendcenter', 'sent'])]}">
1849+ <separator string="Sendcenter" colspan="4"/>
1850+ <newline />
1851+ <group col="4" colspan="2">
1852+ <field colspan="4" name="post_status"/>
1853+ <group col="3" colspan="2">
1854+ <field name="cost"/>
1855+ <field colspan="1" nolabel="1" name="currency_id"/>
1856+ </group>
1857+ <newline/>
1858+ <field name="parsed_address"/>
1859+ <field name="country_id"/>
1860+ <field name="send_date"/>
1861+ <field name="pages"/>
1862+ </group>
1863+ </group>
1864+
1865+ <separator string="Actions" colspan="4"/>
1866+ <newline />
1867+ <group col="2" colspan="2">
1868+ <button name="push_to_pingen" type="object"
1869+ states="pending"
1870+ string="Push to pingen.com" icon="terp-stage"/>
1871+ <button name="ask_pingen_send" type="object"
1872+ states="pushed"
1873+ string="Ask pingen.com to send the document" icon="gtk-print"/>
1874+ <button name="resolve_error" type="object"
1875+ states="error,pingen_error"
1876+ string="Errors resolved" icon="gtk-redo"/>
1877+ <button name="update_post_infos" type="object"
1878+ states="sendcenter"
1879+ string="Update the letter's informations" icon="gtk-refresh"/>
1880+ </group>
1881+ </page>
1882+ <page string="Attachment">
1883+ <group col="4" colspan="4">
1884+ <separator string="Data" colspan="4"/>
1885+ <newline />
1886+ <group col="2" colspan="4" attrs="{'invisible':[('type','=','url')]}">
1887+ <field name="datas" filename="datas_fname" readonly="True"/>
1888+ <field name="datas_fname" select="1" readonly="True"/>
1889+ </group>
1890+ <group col="2" colspan="4" attrs="{'invisible':[('type','=','binary')]}">
1891+ <field name="url" widget="url" readonly="True"/>
1892+ </group>
1893+ </group>
1894+ <group col="2" colspan="4">
1895+ <separator string="Attached To" colspan="2"/>
1896+ <field name="attachment_id"/>
1897+ </group>
1898+ </page>
1899+ </notebook>
1900+
1901+ <field name="state" widget="statusbar"
1902+ statusbar_visible="pending,pushed,sent"
1903+ statusbar_colors='{"error":"red","pingen_error":"red","canceled":"grey","pushed":"blue","sent":"green"}'/>
1904+ </form>
1905+ </field>
1906+ </record>
1907+
1908+ <record id="view_pingen_document_search" model="ir.ui.view">
1909+ <field name="name">pingen.document.search</field>
1910+ <field name="model">pingen.document</field>
1911+ <field name="type">search</field>
1912+ <field name="arch" type="xml">
1913+ <search string="Pingen Document">
1914+ <filter icon="terp-project"
1915+ string="Pending"
1916+ domain="[('state','=','pending')]"/>
1917+ <filter icon="terp-stage"
1918+ string="Pushed"
1919+ domain="[('state','=','pushed')]"/>
1920+ <filter icon="gtk-print"
1921+ string="In Sendcenter"
1922+ domain="[('state','=','sendcenter')]"/>
1923+ <filter icon="kanban-apply"
1924+ string="Sent"
1925+ domain="[('state','=','sent')]"/>
1926+ <filter icon="kanban-stop"
1927+ string="Error"
1928+ domain="[('state','=','error')]"/>
1929+ <filter icon="STOCK_NO"
1930+ string="Pingen Error"
1931+ domain="[('state','=','pingen_error')]"/>
1932+ <filter icon="terp-dialog-close"
1933+ string="Canceled"
1934+ domain="[('state','=','canceled')]"/>
1935+ <separator orientation="vertical"/>
1936+ <field name="attachment_id" />
1937+ </search>
1938+ </field>
1939+ </record>
1940+
1941+ <record id="action_pingen_document" model="ir.actions.act_window">
1942+ <field name="name">Pingen Documents</field>
1943+ <field name="type">ir.actions.act_window</field>
1944+ <field name="res_model">pingen.document</field>
1945+ <field name="view_type">form</field>
1946+ <field name="view_mode">tree,form</field>
1947+ <field name="search_view_id" ref="view_pingen_document_search"/>
1948+ </record>
1949+
1950+ <menuitem action="action_pingen_document" id="menu_pingen_document" parent="base.next_id_4"/>
1951+
1952+ </data>
1953+</openerp>
1954
1955=== added file 'pingen/res_company.py'
1956--- pingen/res_company.py 1970-01-01 00:00:00 +0000
1957+++ pingen/res_company.py 2012-12-07 13:35:25 +0000
1958@@ -0,0 +1,42 @@
1959+# -*- coding: utf-8 -*-
1960+##############################################################################
1961+#
1962+# Author: Guewen Baconnier
1963+# Copyright 2012 Camptocamp SA
1964+#
1965+# This program is free software: you can redistribute it and/or modify
1966+# it under the terms of the GNU Affero General Public License as
1967+# published by the Free Software Foundation, either version 3 of the
1968+# License, or (at your option) any later version.
1969+#
1970+# This program is distributed in the hope that it will be useful,
1971+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1972+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1973+# GNU Affero General Public License for more details.
1974+#
1975+# You should have received a copy of the GNU Affero General Public License
1976+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1977+#
1978+##############################################################################
1979+
1980+from openerp.osv import orm, fields
1981+from openerp.osv.orm import browse_record
1982+from .pingen import Pingen
1983+
1984+class res_company(orm.Model):
1985+
1986+ _inherit = 'res.company'
1987+
1988+ _columns = {
1989+ 'pingen_token': fields.char('Pingen Token', size=32),
1990+ 'pingen_staging': fields.boolean('Pingen Staging')
1991+ }
1992+
1993+ def _pingen(self, cr, uid, company, context=None):
1994+ """ Return a Pingen instance to work on """
1995+ assert isinstance(company, (int, long, browse_record)), \
1996+ "one id or browse_record expected"
1997+ if not isinstance(company, browse_record):
1998+ company = self.browse(cr, uid, company_id, context=context)
1999+ return Pingen(company.pingen_token, staging=company.pingen_staging)
2000+
2001
2002=== added file 'pingen/res_company_view.xml'
2003--- pingen/res_company_view.xml 1970-01-01 00:00:00 +0000
2004+++ pingen/res_company_view.xml 2012-12-07 13:35:25 +0000
2005@@ -0,0 +1,20 @@
2006+<?xml version="1.0" encoding="utf-8"?>
2007+<openerp>
2008+ <data noupdate="0">
2009+
2010+ <record model="ir.ui.view" id="view_company_inherit_form">
2011+ <field name="name">res.company.form.inherit</field>
2012+ <field name="model">res.company</field>
2013+ <field name="type">form</field>
2014+ <field name="inherit_id" ref="base.view_company_form"/>
2015+ <field name="arch" type="xml">
2016+ <page string="Configuration" position="inside">
2017+ <separator string="Pingen.com" colspan="4"/>
2018+ <field name="pingen_token" groups="base.group_system"/>
2019+ <field name="pingen_staging" groups="base.group_system"/>
2020+ </page>
2021+ </field>
2022+ </record>
2023+
2024+ </data>
2025+</openerp>
2026
2027=== added directory 'pingen/security'
2028=== added file 'pingen/security/ir.model.access.csv'
2029--- pingen/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
2030+++ pingen/security/ir.model.access.csv 2012-12-07 13:35:25 +0000
2031@@ -0,0 +1,3 @@
2032+"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
2033+"access_pingen_document_all","pingen_document all","model_pingen_document",,1,0,0,0
2034+"access_pingen_document_group_user","pingen_document group_user","model_pingen_document","base.group_user",1,1,1,1
2035
2036=== added directory 'pingen_document'
2037=== added file 'pingen_document/__init__.py'
2038--- pingen_document/__init__.py 1970-01-01 00:00:00 +0000
2039+++ pingen_document/__init__.py 2012-12-07 13:35:25 +0000
2040@@ -0,0 +1,21 @@
2041+# -*- coding: utf-8 -*-
2042+##############################################################################
2043+#
2044+# Author: Guewen Baconnier
2045+# Copyright 2012 Camptocamp SA
2046+#
2047+# This program is free software: you can redistribute it and/or modify
2048+# it under the terms of the GNU Affero General Public License as
2049+# published by the Free Software Foundation, either version 3 of the
2050+# License, or (at your option) any later version.
2051+#
2052+# This program is distributed in the hope that it will be useful,
2053+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2054+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2055+# GNU Affero General Public License for more details.
2056+#
2057+# You should have received a copy of the GNU Affero General Public License
2058+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2059+#
2060+##############################################################################
2061+
2062
2063=== added file 'pingen_document/__openerp__.py'
2064--- pingen_document/__openerp__.py 1970-01-01 00:00:00 +0000
2065+++ pingen_document/__openerp__.py 2012-12-07 13:35:25 +0000
2066@@ -0,0 +1,41 @@
2067+# -*- coding: utf-8 -*-
2068+##############################################################################
2069+#
2070+# Author: Guewen Baconnier
2071+# Copyright 2012 Camptocamp SA
2072+#
2073+# This program is free software: you can redistribute it and/or modify
2074+# it under the terms of the GNU Affero General Public License as
2075+# published by the Free Software Foundation, either version 3 of the
2076+# License, or (at your option) any later version.
2077+#
2078+# This program is distributed in the hope that it will be useful,
2079+# but WITHOUT ANY WARRANTY; without even the implied warranty of
2080+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2081+# GNU Affero General Public License for more details.
2082+#
2083+# You should have received a copy of the GNU Affero General Public License
2084+# along with this program. If not, see <http://www.gnu.org/licenses/>.
2085+#
2086+##############################################################################
2087+
2088+{
2089+ 'name' : 'pingen.com integration (document)',
2090+ 'version' : '1.0',
2091+ 'author' : 'Camptocamp',
2092+ 'maintainer': 'Camptocamp',
2093+ 'license': 'AGPL-3',
2094+ 'category': 'Reporting',
2095+ 'complexity': 'easy',
2096+ 'depends' : ['document', 'pingen'],
2097+ 'description': """
2098+Glue module between the `pingen` and the `document` modules.
2099+""",
2100+ 'website': 'http://www.camptocamp.com',
2101+ 'data': [
2102+ 'pingen_document_view.xml',
2103+ ],
2104+ 'tests': [],
2105+ 'installable': True,
2106+ 'auto_install': True,
2107+}
2108
2109=== added directory 'pingen_document/i18n'
2110=== added file 'pingen_document/i18n/de.po'
2111--- pingen_document/i18n/de.po 1970-01-01 00:00:00 +0000
2112+++ pingen_document/i18n/de.po 2012-12-07 13:35:25 +0000
2113@@ -0,0 +1,32 @@
2114+# Translation of OpenERP Server.
2115+# This file contains the translation of the following modules:
2116+# * pingen_document
2117+#
2118+msgid ""
2119+msgstr ""
2120+"Project-Id-Version: OpenERP Server 6.1\n"
2121+"Report-Msgid-Bugs-To: \n"
2122+"POT-Creation-Date: 2012-11-26 10:54+0000\n"
2123+"PO-Revision-Date: 2012-11-26 10:54+0000\n"
2124+"Last-Translator: <>\n"
2125+"Language-Team: \n"
2126+"MIME-Version: 1.0\n"
2127+"Content-Type: text/plain; charset=UTF-8\n"
2128+"Content-Transfer-Encoding: \n"
2129+"Plural-Forms: \n"
2130+
2131+#. module: pingen_document
2132+#: view:ir.attachment:0
2133+msgid "Notes"
2134+msgstr "Notes"
2135+
2136+#. module: pingen_document
2137+#: model:ir.ui.menu,name:pingen_document.menu_pingen_document_document
2138+msgid "Pingen Documents"
2139+msgstr "Pingen Documents"
2140+
2141+#. module: pingen_document
2142+#: view:ir.attachment:0
2143+msgid "Pingen.com"
2144+msgstr "Pingen.com"
2145+
2146
2147=== added file 'pingen_document/i18n/en.po'
2148--- pingen_document/i18n/en.po 1970-01-01 00:00:00 +0000
2149+++ pingen_document/i18n/en.po 2012-12-07 13:35:25 +0000
2150@@ -0,0 +1,32 @@
2151+# Translation of OpenERP Server.
2152+# This file contains the translation of the following modules:
2153+# * pingen_document
2154+#
2155+msgid ""
2156+msgstr ""
2157+"Project-Id-Version: OpenERP Server 6.1\n"
2158+"Report-Msgid-Bugs-To: \n"
2159+"POT-Creation-Date: 2012-11-26 10:54+0000\n"
2160+"PO-Revision-Date: 2012-11-26 10:54+0000\n"
2161+"Last-Translator: <>\n"
2162+"Language-Team: \n"
2163+"MIME-Version: 1.0\n"
2164+"Content-Type: text/plain; charset=UTF-8\n"
2165+"Content-Transfer-Encoding: \n"
2166+"Plural-Forms: \n"
2167+
2168+#. module: pingen_document
2169+#: view:ir.attachment:0
2170+msgid "Notes"
2171+msgstr "Notes"
2172+
2173+#. module: pingen_document
2174+#: model:ir.ui.menu,name:pingen_document.menu_pingen_document_document
2175+msgid "Pingen Documents"
2176+msgstr "Pingen Documents"
2177+
2178+#. module: pingen_document
2179+#: view:ir.attachment:0
2180+msgid "Pingen.com"
2181+msgstr "Pingen.com"
2182+
2183
2184=== added file 'pingen_document/i18n/es.po'
2185--- pingen_document/i18n/es.po 1970-01-01 00:00:00 +0000
2186+++ pingen_document/i18n/es.po 2012-12-07 13:35:25 +0000
2187@@ -0,0 +1,32 @@
2188+# Translation of OpenERP Server.
2189+# This file contains the translation of the following modules:
2190+# * pingen_document
2191+#
2192+msgid ""
2193+msgstr ""
2194+"Project-Id-Version: OpenERP Server 6.1\n"
2195+"Report-Msgid-Bugs-To: \n"
2196+"POT-Creation-Date: 2012-11-26 10:54+0000\n"
2197+"PO-Revision-Date: 2012-11-26 10:54+0000\n"
2198+"Last-Translator: <>\n"
2199+"Language-Team: \n"
2200+"MIME-Version: 1.0\n"
2201+"Content-Type: text/plain; charset=UTF-8\n"
2202+"Content-Transfer-Encoding: \n"
2203+"Plural-Forms: \n"
2204+
2205+#. module: pingen_document
2206+#: view:ir.attachment:0
2207+msgid "Notes"
2208+msgstr "Notes"
2209+
2210+#. module: pingen_document
2211+#: model:ir.ui.menu,name:pingen_document.menu_pingen_document_document
2212+msgid "Pingen Documents"
2213+msgstr "Pingen Documents"
2214+
2215+#. module: pingen_document
2216+#: view:ir.attachment:0
2217+msgid "Pingen.com"
2218+msgstr "Pingen.com"
2219+
2220
2221=== added file 'pingen_document/i18n/fr.po'
2222--- pingen_document/i18n/fr.po 1970-01-01 00:00:00 +0000
2223+++ pingen_document/i18n/fr.po 2012-12-07 13:35:25 +0000
2224@@ -0,0 +1,32 @@
2225+# Translation of OpenERP Server.
2226+# This file contains the translation of the following modules:
2227+# * pingen_document
2228+#
2229+msgid ""
2230+msgstr ""
2231+"Project-Id-Version: OpenERP Server 6.1\n"
2232+"Report-Msgid-Bugs-To: \n"
2233+"POT-Creation-Date: 2012-11-26 10:56+0000\n"
2234+"PO-Revision-Date: 2012-11-26 10:56+0000\n"
2235+"Last-Translator: <>\n"
2236+"Language-Team: \n"
2237+"MIME-Version: 1.0\n"
2238+"Content-Type: text/plain; charset=UTF-8\n"
2239+"Content-Transfer-Encoding: \n"
2240+"Plural-Forms: \n"
2241+
2242+#. module: pingen_document
2243+#: view:ir.attachment:0
2244+msgid "Notes"
2245+msgstr "Notes"
2246+
2247+#. module: pingen_document
2248+#: model:ir.ui.menu,name:pingen_document.menu_pingen_document_document
2249+msgid "Pingen Documents"
2250+msgstr "Documents Pingen"
2251+
2252+#. module: pingen_document
2253+#: view:ir.attachment:0
2254+msgid "Pingen.com"
2255+msgstr "Pingen.com"
2256+
2257
2258=== added file 'pingen_document/i18n/pingen_document.pot'
2259--- pingen_document/i18n/pingen_document.pot 1970-01-01 00:00:00 +0000
2260+++ pingen_document/i18n/pingen_document.pot 2012-12-07 13:35:25 +0000
2261@@ -0,0 +1,32 @@
2262+# Translation of OpenERP Server.
2263+# This file contains the translation of the following modules:
2264+# * pingen_document
2265+#
2266+msgid ""
2267+msgstr ""
2268+"Project-Id-Version: OpenERP Server 6.1\n"
2269+"Report-Msgid-Bugs-To: \n"
2270+"POT-Creation-Date: 2012-11-26 10:56+0000\n"
2271+"PO-Revision-Date: 2012-11-26 10:56+0000\n"
2272+"Last-Translator: <>\n"
2273+"Language-Team: \n"
2274+"MIME-Version: 1.0\n"
2275+"Content-Type: text/plain; charset=UTF-8\n"
2276+"Content-Transfer-Encoding: \n"
2277+"Plural-Forms: \n"
2278+
2279+#. module: pingen_document
2280+#: view:ir.attachment:0
2281+msgid "Notes"
2282+msgstr ""
2283+
2284+#. module: pingen_document
2285+#: model:ir.ui.menu,name:pingen_document.menu_pingen_document_document
2286+msgid "Pingen Documents"
2287+msgstr ""
2288+
2289+#. module: pingen_document
2290+#: view:ir.attachment:0
2291+msgid "Pingen.com"
2292+msgstr ""
2293+
2294
2295=== added file 'pingen_document/pingen_document_view.xml'
2296--- pingen_document/pingen_document_view.xml 1970-01-01 00:00:00 +0000
2297+++ pingen_document/pingen_document_view.xml 2012-12-07 13:35:25 +0000
2298@@ -0,0 +1,27 @@
2299+<?xml version="1.0" encoding="utf-8"?>
2300+<openerp>
2301+ <data noupdate="0">
2302+
2303+ <record id="view_document_file_form" model="ir.ui.view">
2304+ <field name="name">ir.attachment.document.pingen.view</field>
2305+ <field name="model">ir.attachment</field>
2306+ <field name="type">form</field>
2307+ <field name="inherit_id" ref="document.view_document_file_form"/>
2308+ <field name="arch" type="xml">
2309+ <page string="Notes" position="before">
2310+ <page string="Pingen.com">
2311+ <field name="send_to_pingen"/>
2312+ <field name="pingen_send" attrs="{'required': [('send_to_pingen', '=', True)]}"/>
2313+ <field name="pingen_speed" attrs="{'required': [('pingen_send', '=', True)]}"/>
2314+ <field name="pingen_color" />
2315+ </page>
2316+ </page>
2317+ </field>
2318+ </record>
2319+
2320+ <menuitem action="pingen.action_pingen_document"
2321+ id="menu_pingen_document_document"
2322+ parent="document.menu_document_doc"/>
2323+
2324+ </data>
2325+</openerp>

Subscribers

People subscribed via source and target branches