[IMP] update of the posts

This commit is contained in:
Guewen Baconnier @ Camptocamp
2012-11-23 16:56:00 +01:00
parent b4c2fbc7fa
commit 51feae800d
3 changed files with 184 additions and 29 deletions

View File

@@ -28,6 +28,14 @@ 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',
}
class PingenException(RuntimeError):
"""There was an ambiguous exception that occurred while handling your
@@ -42,7 +50,6 @@ class APIError(PingenException):
"""An Error occured with the pingen API"""
class Pingen(object):
""" Interface to pingen.com API
"""
@@ -90,7 +97,9 @@ class Pingen(object):
response = method(complete_url, **kwargs)
if not response.ok:
raise ConnectionError(response.error)
raise ConnectionError(
"%s: %s" % (response.json['errorcode'],
response.json['errormessage']))
if response.json['error']:
raise APIError(
@@ -167,3 +176,24 @@ class Pingen(object):
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(
requests.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

View File

@@ -20,17 +20,17 @@
##############################################################################
import logging
import datetime
from cStringIO import StringIO
from openerp.osv import osv, orm, fields
from openerp import tools
from openerp.tools.translate import _
from .pingen import Pingen, APIError, ConnectionError
from .pingen import Pingen, APIError, ConnectionError, POST_SENDING_STATUS
# TODO should be configurable
TOKEN = '6bc041af6f02854461ef31c2121ef853'
STAGING = True
_logger = logging.getLogger(__name__)
@@ -58,15 +58,28 @@ class pingen_task(orm.Model):
('pingen_error', 'Pingen Error'),
('canceled', 'Canceled')],
string='State', readonly=True, required=True),
'date': fields.datetime('Creation Date'),
'push_date': fields.datetime('Push Date'),
'date': fields.datetime('Creation Date', readonly=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',
'Pingen ID', readonly=True,
help="ID of the document in the Pingen Documents"),
'post_id': fields.integer(
'Pingen Post ID',
'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 = {
@@ -79,6 +92,12 @@ class pingen_task(orm.Model):
'Only one Pingen task is allowed per attachment.'),
]
def _pingen(self, cr, uid, ids, context=None):
""" Return a Pingen instance to work on """
assert not ids, "ids is there by convention, should not be used"
# TODO parameterize
return Pingen(TOKEN, staging=STAGING)
def _push_to_pingen(self, cr, uid, task, context=None):
""" Push a document to pingen.com """
attachment_obj = self.pool.get('ir.attachment')
@@ -88,31 +107,32 @@ class pingen_task(orm.Model):
pingen = self._pingen(cr, uid, [], context=context)
try:
doc_id, post_id, __ = pingen.push_document(
doc_id, post_id, infos = pingen.push_document(
task.datas_fname,
StringIO(decoded_document),
task.pingen_send,
task.pingen_speed,
task.pingen_color)
except ConnectionError as e:
_logger.exception('Connection Error when pushing Pingen Task %s to %s.' %
_logger.exception(
'Connection Error when pushing Pingen Task %s to %s.' %
(task.id, pingen.url))
raise
except APIError as e:
_logger.error('API Error when pushing Pingen Task %s to %s.' %
_logger.error(
'API Error when pushing Pingen Task %s to %s.' %
(task.id, pingen.url))
raise
now = datetime.datetime.now().strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
task.write(
{'last_error_message': False,
'state': 'sendcenter' if post_id else 'pushed',
'push_date': now,
'push_date': infos['date'],
'pingen_id': doc_id,
'post_id': post_id},
context=context)
_logger.info('Pingen Task %s pushed to %s' % (task.id, pingen.url))
_logger.info('Pingen Task %s: pushed to %s' % (task.id, pingen.url))
def push_to_pingen(self, cr, uid, ids, context=None):
""" Push a document to pingen.com
@@ -137,26 +157,29 @@ class pingen_task(orm.Model):
'\n%s') % (task.name, e))
return True
def _push_to_pingen_with_logs(self, cr, uid, ids, context=None):
def _push_and_send_to_pingen_silent(self, cr, uid, ids, context=None):
""" Push a document to pingen.com
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'])],
context=context)
for task in self.browse(cr, uid, ids, context=context):
try:
if not task.pingen_id:
self._push_to_pingen(cr, uid, task, context=context)
if not task.post_id and task.pingen_send:
self._ask_pingen_send(cr, uid, task, context=context)
except ConnectionError as e:
task.write({'last_error_message': e, 'state': 'error'}, context=context)
except APIError as e:
task.write({'last_error_message': e, 'state': 'pingen_error'}, context=context)
return True
def _pingen(self, cr, uid, ids, context=None):
"""
"""
assert not ids, "ids is there by convention, should not be used"
# TODO parameterize
return Pingen(TOKEN, staging=True)
return True
def _ask_pingen_send(self, cr, uid, task, context=None):
""" For a document already pushed to pingen, ask to send it.
@@ -186,7 +209,7 @@ class pingen_task(orm.Model):
'state': 'sendcenter',
'post_id': post_id},
context=context)
_logger.info('Pingen Task %s asked for sending to %s' % (task.id, pingen.url))
_logger.info('Pingen Task %s: asked for sending to %s' % (task.id, pingen.url))
return True
@@ -211,3 +234,84 @@ class pingen_task(orm.Model):
'\n%s') % (task.name, e))
return True
def _update_post_infos(self, cr, uid, task, context=None):
""" Update the informations from pingen of a document in the Sendcenter
"""
if not task.post_id:
return
pingen = self._pingen(cr, uid, [], context=context)
try:
post_infos = pingen.post_infos(task.post_id)
except ConnectionError as e:
_logger.exception('Connection Error when asking for sending Pingen Task %s to %s.' %
(task.id, pingen.url))
raise
except APIError as e:
_logger.exception('API Error when asking for sending Pingen Task %s to %s.' %
(task.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)
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': post_infos['date'],
'pages': post_infos['pages'],
}
if pingen.is_posted(post_infos):
vals['state'] = 'sent'
task.write(vals, context=context)
_logger.info('Pingen Task %s: status updated' % task.id)
def _update_post_infos_silent(self, cr, uid, ids, context=None):
""" Update the informations from pingen of a document in the Sendcenter
Do not raise errors, only skip the update of the record.
"""
if not ids:
ids = self.search(
cr, uid,
[('state', '=', 'sendcenter')],
context=context)
for task in self.browse(cr, uid, ids, context=context):
try:
self._update_post_infos(cr, uid, task, context=context)
except (ConnectionError, APIError):
# Intended silented exception, we can consider that it's not
# important if the update not worked, that's
# only informative, and it will be retried the next time
# In any case, the error has been by _update_post_infos
pass
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.
"""
for task in self.browse(cr, uid, ids, context=context):
try:
self._update_post_infos(cr, uid, task, context=context)
except ConnectionError as e:
raise osv.except_osv(
_('Pingen Connection Error'),
_('Connection Error when updating the status of Document %s'
' from Pingen') % task.name)
except APIError as e:
raise osv.except_osv(
_('Pingen Error'),
_('Error when updating the status of Document %s from Pingen: '
'\n%s') % (task.name, e))
return True

View File

@@ -46,15 +46,33 @@
<field name="push_date"/>
</group>
<group colspan="4" attrs="{'invisible': [('last_error_message', '=', False)]}">
<separator string="Errors" colspan="4"/>
<newline />
<group col="2" colspan="2">
<field nolabel="1" name="last_error_message"/>
</group>
</group>
<group colspan="4" attrs="{'invisible': [('state', 'not in', ['sendcenter', 'sent'])]}">
<separator string="Sendcenter" colspan="4"/>
<newline />
<group col="4" colspan="2">
<field colspan="4" name="post_status"/>
<group col="3" colspan="2">
<field name="cost"/>
<field colspan="1" nolabel="1" name="currency_id"/>
</group>
<newline/>
<field name="parsed_address"/>
<field name="country_id"/>
<field name="send_date"/>
<field name="pages"/>
</group>
</group>
<separator string="Actions" colspan="4"/>
<newline />
<group col="2" colspan="2">
<button name="push_to_pingen" type="object"
states="pending,error,pingen_error"
@@ -62,6 +80,9 @@
<button name="ask_pingen_send" type="object"
states="pushed"
string="Ask pingen.com to send the document" icon="terp-camera_test"/>
<button name="update_post_infos" type="object"
states="sendcenter"
string="Update the letter's informations" icon="terp-camera_test"/>
</group>
</page>
<page string="Attachment">