Remove request

review720002
This commit is contained in:
Cédric Krier
2013-05-21 12:09:46 +02:00
parent b1e50bfaf0
commit e73367b9d0
18 changed files with 48 additions and 531 deletions
+2
View File
@@ -1,3 +1,5 @@
* Remove request
Version 2.8.0 - 2013-04-22
* Bug fixes (see mercurial logs for details)
* Allow to search on target of Reference field
+1
View File
@@ -58,6 +58,7 @@ jsonrpc = localhost:8000
#smtp_tls = False
#smtp_password = False
#smtp_user = False
#smtp_default_from_email = False
# Configure the path to store attachments and sqlite database
#data_path = /var/lib/trytond
+4
View File
@@ -12,6 +12,8 @@ except ImportError:
import os
import ConfigParser
import time
import getpass
import socket
def get_hostname(netloc):
@@ -69,6 +71,8 @@ class ConfigManager(object):
'smtp_tls': False,
'smtp_user': False,
'smtp_password': False,
'smtp_default_from_email': '%s@%s' % (
getpass.getuser(), socket.getfqdn()),
'data_path': '/var/lib/trytond',
'multi_server': False,
'session_timeout': 600,
+31 -28
View File
@@ -6,12 +6,14 @@ from dateutil.relativedelta import relativedelta
import traceback
import sys
import logging
from email.mime.text import MIMEText
from ..model import ModelView, ModelSQL, fields
from ..tools import safe_eval
from ..tools import safe_eval, get_smtp_server
from ..transaction import Transaction
from ..pool import Pool
from ..backend import TableHandler
from ..config import CONFIG
__all__ = [
'Cron',
@@ -60,10 +62,10 @@ class Cron(ModelSQL, ModelView):
def __setup__(cls):
super(Cron, cls).__setup__()
cls._error_messages.update({
'request_title': 'Scheduled action failed',
'request_body': "The following action failed to execute "
"properly: \"%s\"\n Traceback: \n\n%s\n"
})
'request_title': 'Scheduled action failed',
'request_body': ("The following action failed to execute "
"properly: \"%s\"\n%s\n Traceback: \n\n%s\n")
})
@classmethod
def __register__(cls, module_name):
@@ -120,29 +122,33 @@ class Cron(ModelSQL, ModelView):
return _INTERVALTYPES[cron.interval_type](cron.interval_number)
@classmethod
def _get_request_values(cls, cron):
def send_error_message(cls, cron):
tb_s = ''.join(traceback.format_exception(*sys.exc_info()))
tb_s = tb_s.decode('utf-8', 'ignore')
name = cls.raise_user_error('request_title',
subject = cls.raise_user_error('request_title',
raise_exception=False)
body = cls.raise_user_error('request_body', (cron.name, tb_s),
body = cls.raise_user_error('request_body',
(cron.name, cron.__url__, tb_s),
raise_exception=False)
values = {
'name': name,
'priority': '2',
'act_from': cron.user.id,
'act_to': cron.request_user.id,
'body': body,
'date_sent': datetime.datetime.now(),
'references': [
('create', [{
'reference': '%s,%s' % (cls.__name__, cron.id),
}]),
],
'state': 'waiting',
'trigger_date': datetime.datetime.now(),
}
return values
from_addr = CONFIG['smtp_default_from_email']
to_addr = cron.request_user.email
msg = MIMEText(body)
msg['To'] = to_addr
msg['From'] = from_addr
msg['Subject'] = subject
logger = logging.getLogger(__name__)
if not to_addr:
logger.error(msg.as_string())
else:
try:
server = get_smtp_server()
server.sendmail(from_addr, to_addr, msg.as_string())
server.quit()
except Exception, exception:
logger.error('Unable to deliver email (%s):\n %s'
% (exception, msg.as_string()))
@classmethod
def _callback(cls, cron):
@@ -156,15 +162,12 @@ class Cron(ModelSQL, ModelView):
except Exception:
Transaction().cursor.rollback()
Request = pool.get('res.request')
req_user = cron.request_user
language = (req_user.language.code if req_user.language
else Config.get_language())
with contextlib.nested(Transaction().set_user(cron.user.id),
Transaction().set_context(language=language)):
values = cls._get_request_values(cron)
Request.create([values])
Transaction().cursor.commit()
cls.send_error_message(cron)
@classmethod
def run(cls, db_name):
+10 -11
View File
@@ -183,17 +183,16 @@ def dispatch(host, port, protocol, database_name, user, session, object_type,
database_name) + tb_s)
transaction.cursor.rollback()
raise
if not (object_name == 'res.request' and method == 'request_get'):
with Transaction().start(database_name, 0) as transaction:
pool = Pool(database_name)
Session = pool.get('ir.session')
try:
Session.reset(session)
except DatabaseOperationalError:
# Silently fail when reseting session
transaction.cursor.rollback()
else:
transaction.cursor.commit()
with Transaction().start(database_name, 0) as transaction:
pool = Pool(database_name)
Session = pool.get('ir.session')
try:
Session.reset(session)
except DatabaseOperationalError:
# Silently fail when reseting session
transaction.cursor.rollback()
else:
transaction.cursor.commit()
Cache.resets(database_name)
return result
-5
View File
@@ -3,7 +3,6 @@
from ..pool import Pool
from .group import *
from .user import *
from .request import *
from .ir import *
@@ -17,10 +16,6 @@ def register():
UserGroup,
Warning_,
UserConfigStart,
Request,
RequestLink,
RequestHistory,
RequestReference,
UIMenuGroup,
ActionGroup,
ModelFieldGroup,
-5
View File
@@ -746,11 +746,6 @@ this repository contains the full copyright notices and license terms. -->
<field name="group" ref="group_admin"/>
</record>
<record model="res.request.link" id="request_link_cron">
<field name="name">Scheduler</field>
<field name="model">ir.cron</field>
</record>
<record model="ir.ui.view" id="sequence_type_view_form">
<field name="model">ir.sequence.type</field>
<field name="inherit" ref="ir.sequence_type_view_form"/>
-266
View File
@@ -1,266 +0,0 @@
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
import datetime
from ..model import ModelView, ModelSQL, fields
from ..pyson import Eval, If
from ..transaction import Transaction
from ..pool import Pool
from ..rpc import RPC
__all__ = [
'Request', 'RequestLink', 'RequestHistory', 'RequestReference',
]
_STATES = [
('draft', 'Draft'),
('waiting', 'Waiting'),
('chatting', 'Chatting'),
('closed', 'Closed'),
]
_PRIORITIES = [
('0', 'Low'),
('1', 'Normal'),
('2', 'High'),
]
_READONLY = If(Eval('state').in_(['waiting', 'closed']),
True,
If(Eval('state') == 'chatting',
Eval('act_from') != Eval('_user'),
False))
_DEPENDS = ['state', 'act_from']
class Request(ModelSQL, ModelView):
"Request"
__name__ = 'res.request'
name = fields.Char('Subject', states={
'readonly': _READONLY,
}, required=True, depends=_DEPENDS)
active = fields.Boolean('Active')
priority = fields.Selection(_PRIORITIES, 'Priority', states={
'readonly': _READONLY,
}, required=True, order_field='priority', depends=_DEPENDS)
act_from = fields.Many2One('res.user', 'From', required=True,
readonly=True)
act_to = fields.Many2One('res.user', 'To', required=True,
domain=[('active', '=', True)],
states={
'readonly': _READONLY,
}, depends=_DEPENDS)
body = fields.Text('Body', states={
'readonly': _READONLY,
}, depends=_DEPENDS)
date_sent = fields.DateTime('Date', readonly=True)
trigger_date = fields.DateTime('Trigger Date', states={
'readonly': _READONLY,
}, depends=_DEPENDS)
references = fields.One2Many('res.request.reference', 'request',
'References', states={
'readonly': If(Eval('state') == 'closed',
True,
Eval('act_from', 0) != Eval('_user', 0)),
}, depends=['state', 'act_from'])
number_references = fields.Function(fields.Integer('Number of References',
on_change_with=['references']), 'on_change_with_number_references')
state = fields.Selection(_STATES, 'State', required=True, readonly=True)
history = fields.One2Many('res.request.history', 'request',
'History', readonly=True)
@classmethod
def __setup__(cls):
super(Request, cls).__setup__()
cls.__rpc__.update({
'request_get': RPC(),
})
cls._order.insert(0, ('priority', 'DESC'))
cls._order.insert(1, ('trigger_date', 'DESC'))
cls._order.insert(2, ('create_date', 'DESC'))
cls._buttons.update({
'send': {
'invisible': ~Eval('state').in_(['draft', 'chatting']),
'readonly': Eval('act_from') != Eval('_user'),
},
'reply': {
'invisible': Eval('state') != 'waiting',
'readonly': Eval('act_to') != Eval('_user'),
},
'close': {
'invisible': ~Eval('state').in_(['waiting', 'draft',
'chatting']),
},
})
@staticmethod
def default_act_from():
return int(Transaction().user)
@staticmethod
def default_state():
return 'draft'
@staticmethod
def default_active():
return True
@staticmethod
def default_priority():
return '1'
def on_change_with_number_references(self, name=None):
return len(self.references or '')
@classmethod
@ModelView.button
def send(cls, requests):
pool = Pool()
RequestHistory = pool.get('res.request.history')
to_create = []
for request in requests:
values = {
'request': request.id,
'act_from': request.act_from.id,
'act_to': request.act_to.id,
'body': request.body,
'state': request.state,
'subject': request.name,
'number_references': request.number_references,
'priority': request.priority,
}
if values['body'] and len(values['body']) > 128:
values['name'] = values['body'][:125] + '...'
else:
values['name'] = values['body'] or '/'
to_create.append(values)
if to_create:
RequestHistory.create(to_create)
cls.write(requests, {
'state': 'waiting',
'date_sent': datetime.datetime.now(),
})
@classmethod
@ModelView.button
def reply(cls, requests):
user = Transaction().user
for request in requests:
cls.write([request], {
'state': 'chatting',
'act_from': user,
'act_to': request.act_from.id,
'trigger_date': None,
'body': '',
})
@classmethod
@ModelView.button
def close(cls, requests):
cls.write(requests, {'state': 'closed', 'active': False})
@classmethod
def request_get(cls):
user = Transaction().user
requests = cls.search([
('act_to', '=', user),
['OR',
('trigger_date', '<=', datetime.datetime.now()),
('trigger_date', '=', None),
],
('active', '=', True),
])
requests2 = cls.search([
('act_from', '=', user),
('act_to', '!=', user),
('state', '!=', 'draft'),
('active', '=', True),
])
return ([r.id for r in requests], [r.id for r in requests2])
class RequestLink(ModelSQL, ModelView):
"Request link"
__name__ = 'res.request.link'
name = fields.Char('Name', required=True, translate=True)
model = fields.Selection('models_get', 'Model', required=True)
priority = fields.Integer('Priority', required=True)
@classmethod
def __setup__(cls):
super(RequestLink, cls).__setup__()
cls._order.insert(0, ('priority', 'ASC'))
@staticmethod
def default_priority():
return 5
@staticmethod
def models_get():
pool = Pool()
Model = pool.get('ir.model')
models = Model.search([])
res = []
for model in models:
res.append((model.model, model.name))
return res
class RequestHistory(ModelSQL, ModelView):
"Request history"
__name__ = 'res.request.history'
name = fields.Char('Summary', required=True, readonly=True)
request = fields.Many2One('res.request', 'Request', required=True,
ondelete='CASCADE', select=True, readonly=True)
act_from = fields.Many2One('res.user', 'From', required=True,
readonly=True)
act_to = fields.Many2One('res.user', 'To', required=True, readonly=True)
body = fields.Text('Body', readonly=True)
date_sent = fields.DateTime('Date sent', required=True, readonly=True)
state = fields.Selection(_STATES, 'State', required=True, readonly=True)
subject = fields.Char('Subject', required=True, readonly=True)
number_references = fields.Integer('References', readonly=True)
priority = fields.Selection(_PRIORITIES, 'Priority', required=True,
readonly=True)
@classmethod
def __setup__(cls):
super(RequestHistory, cls).__setup__()
cls._order.insert(0, ('date_sent', 'DESC'))
@staticmethod
def default_name():
return 'No Name'
@staticmethod
def default_act_from():
return int(Transaction().user)
@staticmethod
def default_act_to():
return int(Transaction().user)
@staticmethod
def default_date_sent():
return datetime.datetime.now()
@staticmethod
def write(records, vals):
pass
class RequestReference(ModelSQL, ModelView):
"Request Reference"
__name__ = 'res.request.reference'
_rec_name = 'reference'
request = fields.Many2One('res.request', 'Request', required=True,
ondelete="CASCADE", select=True)
reference = fields.Reference('Reference', selection='links_get',
required=True)
@staticmethod
def links_get():
pool = Pool()
RequestLink = pool.get('res.request.link')
request_links = RequestLink.search([])
return [(x.model, x.name) for x in request_links]
-94
View File
@@ -1,94 +0,0 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tryton>
<data>
<record model="ir.ui.view" id="request_view_tree">
<field name="model">res.request</field>
<field name="type">tree</field>
<field name="name">request_list</field>
</record>
<record model="ir.ui.view" id="request_view_form">
<field name="model">res.request</field>
<field name="type">form</field>
<field name="name">request_form</field>
</record>
<record model="ir.action.act_window" id="act_request_form">
<field name="name">Requests</field>
<field name="res_model">res.request</field>
</record>
<record model="ir.action.act_window.view"
id="act_request_form_view1">
<field name="sequence" eval="1"/>
<field name="view" ref="request_view_tree"/>
<field name="act_window" ref="act_request_form"/>
</record>
<record model="ir.action.act_window.view"
id="act_request_form_view2">
<field name="sequence" eval="2"/>
<field name="view" ref="request_view_form"/>
<field name="act_window" ref="act_request_form"/>
</record>
<menuitem parent="res.menu_res"
action="act_request_form" id="menu_request_form"/>
<record model="ir.ui.menu-res.group" id="menu_request_form_group_admin">
<field name="menu" ref="menu_request_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.view" id="request_link_view_form">
<field name="model">res.request.link</field>
<field name="type">form</field>
<field name="name">request_link_form</field>
</record>
<record model="ir.ui.view" id="request_link_view_tree">
<field name="model">res.request.link</field>
<field name="type">tree</field>
<field name="name">request_link_list</field>
</record>
<record model="ir.action.act_window" id="act_request_link_form">
<field name="name">Request Links</field>
<field name="res_model">res.request.link</field>
</record>
<record model="ir.action.act_window.view"
id="act_request_link_form_view1">
<field name="sequence" eval="10"/>
<field name="view" ref="request_link_view_tree"/>
<field name="act_window" ref="act_request_link_form"/>
</record>
<record model="ir.action.act_window.view"
id="act_request_link_form_view2">
<field name="sequence" eval="20"/>
<field name="view" ref="request_link_view_form"/>
<field name="act_window" ref="act_request_link_form"/>
</record>
<menuitem parent="res.menu_res"
action="act_request_link_form" id="menu_request_link_form"/>
<record model="ir.ui.menu-res.group" id="menu_request_link_form_group_admin">
<field name="menu" ref="menu_request_link_form"/>
<field name="group" ref="group_admin"/>
</record>
<record model="ir.ui.view" id="request_history_view_tree">
<field name="model">res.request.history</field>
<field name="type">tree</field>
<field name="name">request_history_list</field>
</record>
<record model="ir.ui.view" id="request_history_view_form">
<field name="model">res.request.history</field>
<field name="type">form</field>
<field name="name">request_history_form</field>
</record>
<record model="ir.ui.view" id="request_reference_view_tree">
<field name="model">res.request.reference</field>
<field name="type">tree</field>
<field name="name">request_reference_list</field>
</record>
<record model="ir.ui.view" id="request_reference_view_form">
<field name="model">res.request.reference</field>
<field name="type">form</field>
<field name="name">request_reference_form</field>
</record>
</data>
</tryton>
-1
View File
@@ -5,5 +5,4 @@ xml:
res.xml
group.xml
user.xml
request.xml
ir.xml
-40
View File
@@ -1,40 +0,0 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form string="Requests" col="6" cursor="act_to">
<label name="act_from"/>
<field name="act_from"/>
<label name="act_to"/>
<field name="act_to"/>
<group colspan="2" col="4" id="active_ref">
<label name="active"/>
<field name="active"/>
<label name="references"/>
<field name="number_references"/>
</group>
<label name="name"/>
<field name="name" colspan="3"/>
<label name="priority"/>
<field name="priority"/>
<notebook colspan="6">
<page string="Request" id="request">
<separator name="body" colspan="4"/>
<field name="body" colspan="4" widget="richtext"/>
<field name="history" colspan="4"/>
<label name="trigger_date"/>
<field name="trigger_date"/>
<group col="2" colspan="2" id="buttons">
<button name="send" string="Send"/>
<button name="reply" string="Reply"/>
</group>
<label name="state"/>
<field name="state"/>
<group col="3" colspan="2" id="button">
<button name="close" string="Close"/>
</group>
</page>
<page string="References" col="1" id="references">
<field name="references"/>
</page>
</notebook>
</form>
-21
View File
@@ -1,21 +0,0 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form string="Request History" col="6">
<label name="act_from"/>
<field name="act_from"/>
<label name="act_to"/>
<field name="act_to"/>
<label name="number_references"/>
<field name="number_references"/>
<label name="subject"/>
<field name="subject" colspan="3"/>
<label name="priority"/>
<field name="priority"/>
<field name="body" colspan="6" widget="richtext"/>
<label name="date_sent"/>
<field name="date_sent" colspan="3"/>
<newline/>
<label name="state"/>
<field name="state" colspan="3"/>
</form>
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree string="Request History">
<field name="act_from"/>
<field name="act_to"/>
<field name="name"/>
<field name="number_references"/>
<field name="date_sent"/>
<field name="state"/>
</tree>
-11
View File
@@ -1,11 +0,0 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form string="Request Link" col="6">
<label name="name"/>
<field name="name"/>
<label name="model"/>
<field name="model"/>
<label name="priority"/>
<field name="priority"/>
</form>
-7
View File
@@ -1,7 +0,0 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree string="Request Link">
<field name="name"/>
<field name="model"/>
</tree>
-15
View File
@@ -1,15 +0,0 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree string="Requests">
<field name="create_date"/>
<field name="act_from"/>
<field name="act_to"/>
<field name="name"/>
<field name="priority"/>
<field name="trigger_date"/>
<field name="number_references"/>
<field name="state"/>
<field name="active"/>
<field name="body" tree_invisible="1"/>
</tree>
@@ -1,9 +0,0 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form string="Request Reference" col="2">
<label name="request"/>
<field name="request"/>
<label name="reference"/>
<field name="reference"/>
</form>
@@ -1,7 +0,0 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tree string="Request References">
<field name="request"/>
<field name="reference"/>
</tree>