[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__) _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): class PingenException(RuntimeError):
"""There was an ambiguous exception that occurred while handling your """There was an ambiguous exception that occurred while handling your
@@ -42,7 +50,6 @@ class APIError(PingenException):
"""An Error occured with the pingen API""" """An Error occured with the pingen API"""
class Pingen(object): class Pingen(object):
""" Interface to pingen.com API """ Interface to pingen.com API
""" """
@@ -90,7 +97,9 @@ class Pingen(object):
response = method(complete_url, **kwargs) response = method(complete_url, **kwargs)
if not response.ok: if not response.ok:
raise ConnectionError(response.error) raise ConnectionError(
"%s: %s" % (response.json['errorcode'],
response.json['errormessage']))
if response.json['error']: if response.json['error']:
raise APIError( raise APIError(
@@ -167,3 +176,24 @@ class Pingen(object):
return response.json['id'] 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 logging
import datetime
from cStringIO import StringIO from cStringIO import StringIO
from openerp.osv import osv, orm, fields from openerp.osv import osv, orm, fields
from openerp import tools from openerp import tools
from openerp.tools.translate import _ from openerp.tools.translate import _
from .pingen import Pingen, APIError, ConnectionError from .pingen import Pingen, APIError, ConnectionError, POST_SENDING_STATUS
# TODO should be configurable # TODO should be configurable
TOKEN = '6bc041af6f02854461ef31c2121ef853' TOKEN = '6bc041af6f02854461ef31c2121ef853'
STAGING = True
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -58,15 +58,28 @@ class pingen_task(orm.Model):
('pingen_error', 'Pingen Error'), ('pingen_error', 'Pingen Error'),
('canceled', 'Canceled')], ('canceled', 'Canceled')],
string='State', readonly=True, required=True), string='State', readonly=True, required=True),
'date': fields.datetime('Creation Date'), 'date': fields.datetime('Creation Date', readonly=True),
'push_date': fields.datetime('Push Date'), '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), 'last_error_message': fields.text('Error Message', readonly=True),
# pingen IDs
'pingen_id': fields.integer( 'pingen_id': fields.integer(
'Pingen ID', 'Pingen ID', readonly=True,
help="ID of the document in the Pingen Documents"), help="ID of the document in the Pingen Documents"),
'post_id': fields.integer( 'post_id': fields.integer(
'Pingen Post ID', 'Pingen Post ID', readonly=True,
help="ID of the document in the Pingen Sendcenter"), 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 = { _defaults = {
@@ -79,6 +92,12 @@ class pingen_task(orm.Model):
'Only one Pingen task is allowed per attachment.'), '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): def _push_to_pingen(self, cr, uid, task, context=None):
""" Push a document to pingen.com """ """ Push a document to pingen.com """
attachment_obj = self.pool.get('ir.attachment') attachment_obj = self.pool.get('ir.attachment')
@@ -88,31 +107,32 @@ class pingen_task(orm.Model):
pingen = self._pingen(cr, uid, [], context=context) pingen = self._pingen(cr, uid, [], context=context)
try: try:
doc_id, post_id, __ = pingen.push_document( doc_id, post_id, infos = pingen.push_document(
task.datas_fname, task.datas_fname,
StringIO(decoded_document), StringIO(decoded_document),
task.pingen_send, task.pingen_send,
task.pingen_speed, task.pingen_speed,
task.pingen_color) task.pingen_color)
except ConnectionError as e: 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)) (task.id, pingen.url))
raise raise
except APIError as e: 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)) (task.id, pingen.url))
raise raise
now = datetime.datetime.now().strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
task.write( task.write(
{'last_error_message': False, {'last_error_message': False,
'state': 'sendcenter' if post_id else 'pushed', 'state': 'sendcenter' if post_id else 'pushed',
'push_date': now, 'push_date': infos['date'],
'pingen_id': doc_id, 'pingen_id': doc_id,
'post_id': post_id}, 'post_id': post_id},
context=context) 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): def push_to_pingen(self, cr, uid, ids, context=None):
""" Push a document to pingen.com """ Push a document to pingen.com
@@ -137,26 +157,29 @@ class pingen_task(orm.Model):
'\n%s') % (task.name, e)) '\n%s') % (task.name, e))
return True 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 """ Push a document to pingen.com
Instead of raising, store the error in the pingen.document 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): for task in self.browse(cr, uid, ids, context=context):
try: try:
if not task.pingen_id:
self._push_to_pingen(cr, uid, task, context=context) 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: except ConnectionError as e:
task.write({'last_error_message': e, 'state': 'error'}, context=context) task.write({'last_error_message': e, 'state': 'error'}, context=context)
except APIError as e: except APIError as e:
task.write({'last_error_message': e, 'state': 'pingen_error'}, context=context) task.write({'last_error_message': e, 'state': 'pingen_error'}, context=context)
return True
def _pingen(self, cr, uid, ids, context=None): return True
"""
"""
assert not ids, "ids is there by convention, should not be used"
# TODO parameterize
return Pingen(TOKEN, staging=True)
def _ask_pingen_send(self, cr, uid, task, context=None): def _ask_pingen_send(self, cr, uid, task, context=None):
""" For a document already pushed to pingen, ask to send it. """ For a document already pushed to pingen, ask to send it.
@@ -186,7 +209,7 @@ class pingen_task(orm.Model):
'state': 'sendcenter', 'state': 'sendcenter',
'post_id': post_id}, 'post_id': post_id},
context=context) 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 return True
@@ -211,3 +234,84 @@ class pingen_task(orm.Model):
'\n%s') % (task.name, e)) '\n%s') % (task.name, e))
return True 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"/> <field name="push_date"/>
</group> </group>
<group colspan="4" attrs="{'invisible': [('last_error_message', '=', False)]}">
<separator string="Errors" colspan="4"/> <separator string="Errors" colspan="4"/>
<newline /> <newline />
<group col="2" colspan="2"> <group col="2" colspan="2">
<field nolabel="1" name="last_error_message"/> <field nolabel="1" name="last_error_message"/>
</group> </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"/> <separator string="Actions" colspan="4"/>
<newline /> <newline />
<group col="2" colspan="2"> <group col="2" colspan="2">
<button name="push_to_pingen" type="object" <button name="push_to_pingen" type="object"
states="pending,error,pingen_error" states="pending,error,pingen_error"
@@ -62,6 +80,9 @@
<button name="ask_pingen_send" type="object" <button name="ask_pingen_send" type="object"
states="pushed" states="pushed"
string="Ask pingen.com to send the document" icon="terp-camera_test"/> 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> </group>
</page> </page>
<page string="Attachment"> <page string="Attachment">