Naresh Choksy
2008-11-28 11:41:50 +05:30
55 changed files with 45650 additions and 7182 deletions
+48 -30
View File
@@ -45,6 +45,9 @@ sys.path.insert(1, _ad)
if ad != _ad:
sys.path.insert(1, ad)
# Modules already loaded
loaded = []
class Graph(dict):
def addNode(self, name, deps):
@@ -152,12 +155,15 @@ def get_module_resource(module, *args):
def get_modules():
"""Returns the list of module names
"""
def listdir(dir):
def clean(name):
name = os.path.basename(name)
if name[-4:] == '.zip':
name = name[:-4]
return name
return map(clean, os.listdir(dir))
module_list = os.listdir(ad)
module_names = [os.path.basename(m) for m in module_list]
module_list += [m for m in os.listdir(_ad) if m not in module_names]
return module_list
return list(set(listdir(ad) + listdir(_ad)))
def create_graph(module_list, force=None):
if not force:
@@ -166,8 +172,6 @@ def create_graph(module_list, force=None):
packages = []
for module in module_list:
if module[-4:]=='.zip':
module = module[:-4]
try:
mod_path = get_module_path(module)
if not mod_path:
@@ -184,8 +188,9 @@ def create_graph(module_list, force=None):
raise
if info.get('installable', True):
packages.append((module, info.get('depends', []), info))
current,later = Set([p for p, dep, data in packages]), Set()
dependencies = dict([(p, deps) for p, deps, data in packages])
current, later = Set([p for p, dep, data in packages]), Set()
while packages and current > later:
package, deps, datas = packages[0]
@@ -206,9 +211,10 @@ def create_graph(module_list, force=None):
later.add(package)
packages.append((package, deps, datas))
packages.pop(0)
for package in later:
logger.notifyChannel('init', netsvc.LOG_ERROR, 'addon:%s:Unmet dependency' % package)
unmet_deps = filter(lambda p: p not in graph, dependencies[package])
logger.notifyChannel('init', netsvc.LOG_ERROR, 'addon:%s:Unmet dependencies: %s' % (package, ', '.join(unmet_deps)))
return graph
@@ -221,6 +227,36 @@ def init_module_objects(cr, module_name, obj_list):
obj._auto_init(cr, {'module': module_name})
cr.commit()
#
# Register module named m, if not already registered
#
def register_class(m):
global loaded
if m in loaded:
return
logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:registering classes' % m)
sys.stdout.flush()
loaded.append(m)
mod_path = get_module_path(m)
if not os.path.isfile(mod_path+'.zip'):
imp.load_module(m, *imp.find_module(m))
else:
import zipimport
try:
zimp = zipimport.zipimporter(mod_path+'.zip')
zimp.load_module(m)
except zipimport.ZipImportError:
logger.notifyChannel('init', netsvc.LOG_ERROR, 'Couldn\'t find module %s' % m)
def register_classes():
return
module_list = get_modules()
for package in create_graph(module_list):
m = package.name
register_class(m)
logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:registering classes' % m)
sys.stdout.flush()
def load_module_graph(cr, graph, status=None, **kwargs):
# **kwargs is passed directly to convert_xml_import
if not status:
@@ -232,6 +268,7 @@ def load_module_graph(cr, graph, status=None, **kwargs):
for package in graph:
status['progress'] = (float(statusi)+0.1)/len(graph)
m = package.name
register_class(m)
logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s' % m)
sys.stdout.flush()
pool = pooler.get_pool(cr.dbname)
@@ -298,25 +335,6 @@ def load_module_graph(cr, graph, status=None, **kwargs):
pool.get('ir.model.data')._process_end(cr, 1, package_todo)
cr.commit()
def register_classes():
module_list = get_modules()
for package in create_graph(module_list):
m = package.name
logger.notifyChannel('init', netsvc.LOG_INFO, 'addon:%s:registering classes' % m)
sys.stdout.flush()
mod_path = get_module_path(m)
if not os.path.isfile(mod_path+'.zip'):
# XXX must restrict to only addons paths
imp.load_module(m, *imp.find_module(m))
else:
import zipimport
try:
zimp = zipimport.zipimporter(mod_path+'.zip')
zimp.load_module(m)
except zipimport.ZipImportError:
logger.notifyChannel('init', netsvc.LOG_ERROR, 'Couldn\'t find module %s' % m)
def load_modules(db, force_demo=False, status=None, update_module=False):
if not status:
status={}
+2 -2
View File
@@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
@@ -23,7 +23,7 @@
import ir
import module
import res
import maintenance
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+4 -2
View File
@@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
@@ -32,6 +32,7 @@
"base_menu.xml",
"security/base_security.xml",
"res/res_security.xml",
"maintenance/maintenance_security.xml",
],
"demo_xml" : [
"base_demo.xml",
@@ -43,9 +44,9 @@
"ir/wizard/wizard_menu_view.xml",
"ir/ir.xml",
"ir/workflow/workflow_view.xml",
"module/module_data.xml",
"module/module_wizard.xml",
"module/module_view.xml",
"module/module_data.xml",
"module/module_report.xml",
"res/res_request_view.xml",
"res/res_lang_view.xml",
@@ -59,6 +60,7 @@
"res/partner/partner_data.xml",
"res/ir_property_view.xml",
"security/base_security.xml",
"maintenance/maintenance_view.xml",
"security/ir.model.access.csv",
],
"active": True,
+1
View File
@@ -27,6 +27,7 @@ CREATE TABLE ir_model (
id serial,
model varchar(64) DEFAULT ''::varchar NOT NULL,
name varchar(64),
state varchar(16),
info text,
primary key(id)
);
+8 -3
View File
@@ -220,10 +220,15 @@
<field name="name">Costa Rica</field>
<field name="code">cr</field>
</record>
<record id="cs" model="res.country">
<field name="name">Serbia and Montenegro</field>
<field name="code">cs</field>
<record id="rs" model="res.country">
<field name="name">Serbia</field>
<field name="code">rs</field>
</record>
<record id="me" model="res.country">
<field name="name">Montenegro</field>
<field name="code">me</field>
</record>
<record id="cu" model="res.country">
<field name="name">Cuba</field>
<field name="code">cu</field>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1134 -1111
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1121 -1092
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1041 -1029
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+26 -8
View File
@@ -70,9 +70,26 @@
<field name="number_increment"/>
<field name="number_next"/>
<separator colspan="4" string="Legend (for prefix, suffix)"/>
<label colspan="4" string="Year: %%(year)s"/>
<label colspan="4" string="Month: %%(month)s"/>
<label colspan="4" string="Day: %%(day)s"/>
<group col="8" colspan="4">
<group>
<label colspan="4" string="Year with century: %%(year)s"/>
<label colspan="4" string="Year without century: %%(y)s"/>
<label colspan="4" string="Month: %%(month)s"/>
<label colspan="4" string="Day: %%(day)s"/>
</group>
<group>
<label colspan="4" string="Day of the year: %%(doy)s"/>
<label colspan="4" string="Week of the year: %%(woy)s"/>
<label colspan="4" string="Day of the week (0:Monday): %%(weekday)s"/>
</group>
<group>
<label colspan="4" string="Hour 00->24: %%(h24)s"/>
<label colspan="4" string="Hour 00->12: %%(h12)s"/>
<label colspan="4" string="Minute: %%(min)s"/>
<label colspan="4" string="Seconde: %%(sec)s"/>
</group>
</group>
<separator colspan="4" string=""/>
</form>
</field>
</record>
@@ -487,8 +504,8 @@
<form string="Attachments">
<group colspan="4" col="6">
<field name="name" select="1" />
<field name="create_uid" select="1"/>
<field name="create_date" select="1"/>
<field name="create_uid" select="2"/>
<field name="create_date" select="2"/>
</group>
<notebook colspan="4">
<page string="Attachment">
@@ -499,7 +516,7 @@
</group>
<group col="2" colspan="2">
<separator string="Attached To" colspan="2"/>
<field name="res_model" select="1"/>
<field name="res_model" select="2"/>
<field name="res_id"/>
</group>
<separator string="Preview" colspan="4"/>
@@ -1143,7 +1160,7 @@
<field name="sms" colspan="4" attrs="{'readonly':[('state','=','python'), ('state','=','email'), ('state','=','dummy'),('state','=','trigger'), ('state','=','object_create'), ('state','=','object_write'), ('state','=','client_action'), ('state','=','other')]}"/>
<field name="message" select="2" colspan="4" attrs="{'readonly':[('state','=','python'), ('state','=','dummy'),('state','=','trigger'), ('state','=','object_create'), ('state','=','object_write'), ('state','=','sms'), ('state','=','client_action'), ('state','=','other')]}" />
<newline/>
<label colspan="4" string="Access all the fields related to the current object easily just by defining name of the attribute, i.e. [[partner_id.name]] for Invoice Object"/>
<label colspan="4" string="Access all the fields related to the current object using expression in double brackets, i.e. [[ object.partner_id.name ]]" align="0.0"/>
</page>
<page string="Create / Write" attrs="{'invisible':[('state','=','python'),('state','=','dummy'),('state','=','trigger'), ('state','=','sms'), ('state','=','email'), ('state','=','client_action'), ('state','=','other')]}">
@@ -1162,6 +1179,7 @@
<field name="value" colsapan="4"/>
</form>
</field>
<label colspan="4" string="If you use a formula type, use a python expression using the variable 'object'." align="0.0"/>
</page>
<page string="Other Actions" attrs="{'invisible':[('state','!=','other')]}">
@@ -1272,7 +1290,7 @@
<separator colspan="4" string=""/>
<label string="" colspan="2"/>
<group colspan="2" col="2">
<button icon="gtk-cancel" special="cancel" string="Skip Step"/>
<button icon="gtk-cancel" name="button_skip" string="Skip Step" type="object"/>
<button icon="gtk-go-forward" name="button_continue" string="Continue" type="object"/>
</group>
</group>
+36 -47
View File
@@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
@@ -438,26 +438,12 @@ class actions_server(osv.osv):
def merge_message(self, cr, uid, keystr, action, context):
logger = netsvc.Logger()
def merge(match):
obj_pool = self.pool.get(action.model_id.model)
id = context.get('active_id')
obj = obj_pool.browse(cr, uid, id)
return eval(match[2:-2], {'object':obj, 'context': context,'time':time})
field = match.group()
field = field.replace('[','')
field = field.replace(']','')
field = field.strip()
fields = field.split('.')
for field in fields:
try:
obj = getattr(obj, field)
except Exception,e :
logger.notifyChannel('Workflow', netsvc.LOG_ERROR, 'Failed to parse : %s' % (match.group()))
return str(obj)
com = re.compile('\[\[(.+?)\]\]')
com = re.compile('(\[\[.+?\]\])')
message = com.sub(merge, keystr)
return message
@@ -490,9 +476,7 @@ class actions_server(osv.osv):
address = self.get_field_value(cr, uid, action, context)
if not address:
raise osv.except_osv(_('Error'), _("Please specify the Partner Email address !"))
body = self.merge_message(cr, uid, str(action.message), action, context)
if tools.email_send_attach(user, address, subject, body, debug=False) == True:
logger.notifyChannel('email', netsvc.LOG_INFO, 'Email successfully send to : %s' % (address))
else:
@@ -537,8 +521,9 @@ class actions_server(osv.osv):
for exp in action.fields_lines:
euq = exp.value
if exp.type == 'equation':
expr = self.merge_message(cr, uid, euq, action, context)
expr = eval(expr)
obj_pool = self.pool.get(action.model_id.model)
obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
expr = eval(euq, {'context':context, 'object': obj})
else:
expr = exp.value
res[exp.col1.name] = expr
@@ -550,8 +535,9 @@ class actions_server(osv.osv):
for exp in action.fields_lines:
euq = exp.value
if exp.type == 'equation':
expr = self.merge_message(cr, uid, euq, action, context)
expr = eval(expr)
obj_pool = self.pool.get(action.model_id.model)
obj = obj_pool.browse(cr, uid, context['active_id'], context=context)
expr = eval(euq, {'context':context, 'object': obj})
else:
expr = exp.value
res[exp.col1.name] = expr
@@ -588,26 +574,26 @@ act_window_close()
# - if start_type='auto', it will be start on auto starting from start date, and stop on stop date
# - if start_type="manual", it will start and stop on manually
class ir_actions_todo(osv.osv):
_name = 'ir.actions.todo'
_name = 'ir.actions.todo'
_columns={
'name':fields.char('Name',size=64,required=True, select=True),
'note':fields.text('Text'),
'start_date': fields.datetime('Start Date'),
'end_date': fields.datetime('End Date'),
'start_date': fields.datetime('Start Date'),
'end_date': fields.datetime('End Date'),
'action_id':fields.many2one('ir.actions.act_window', 'Action', select=True,required=True, ondelete='cascade'),
'sequence':fields.integer('Sequence'),
'active': fields.boolean('Active'),
'type':fields.selection([('configure', 'Configure'),('service', 'Service'),('other','Other')], string='Type', required=True),
'start_on':fields.selection([('at_once', 'At Once'),('auto', 'Auto'),('manual','Manual')], string='Start On'),
'groups_id': fields.many2many('res.groups', 'res_groups_act_todo_rel', 'act_todo_id', 'group_id', 'Groups'),
'users_id': fields.many2many('res.users', 'res_users_act_todo_rel', 'act_todo_id', 'user_id', 'Users'),
'active': fields.boolean('Active'),
'type':fields.selection([('configure', 'Configure'),('service', 'Service'),('other','Other')], string='Type', required=True),
'start_on':fields.selection([('at_once', 'At Once'),('auto', 'Auto'),('manual','Manual')], string='Start On'),
'groups_id': fields.many2many('res.groups', 'res_groups_act_todo_rel', 'act_todo_id', 'group_id', 'Groups'),
'users_id': fields.many2many('res.users', 'res_users_act_todo_rel', 'act_todo_id', 'user_id', 'Users'),
'state':fields.selection([('open', 'Not Started'),('done', 'Done'),('skip','Skipped'),('cancel','Cancel')], string='State', required=True)
}
_defaults={
'state': lambda *a: 'open',
'sequence': lambda *a: 10,
'active':lambda *a:True,
'type':lambda *a:'configure'
'active':lambda *a:True,
'type':lambda *a:'configure'
}
_order="sequence"
ir_actions_todo()
@@ -651,6 +637,21 @@ class ir_actions_configuration_wizard(osv.osv_memory):
'item_id':_get_action,
'name':_get_action_name,
}
def button_next(self,cr,uid,ids,context=None):
user_action=self.pool.get('res.users').browse(cr,uid,uid)
act_obj=self.pool.get(user_action.menu_id.type)
action_ids=act_obj.search(cr,uid,[('name','=',user_action.menu_id.name)])
action_open=act_obj.browse(cr,uid,action_ids)[0]
if context.get('menu',False):
return{
'view_type': action_open.view_type,
'view_id':action_open.view_id and [action_open.view_id.id] or False,
'res_model': action_open.res_model,
'type': action_open.type,
'domain':action_open.domain
}
return {'type':'ir.actions.act_window_close'}
def button_skip(self,cr,uid,ids,context=None):
item_obj = self.pool.get('ir.actions.todo')
item_id=self.read(cr,uid,ids)[0]['item_id']
@@ -666,7 +667,7 @@ class ir_actions_configuration_wizard(osv.osv_memory):
'type': 'ir.actions.act_window',
'target':'new',
}
return {'type':'ir.actions.act_window_close'}
return self.button_next(cr, uid, ids, context)
def button_continue(self, cr, uid, ids, context=None):
item_obj = self.pool.get('ir.actions.todo')
@@ -684,19 +685,7 @@ class ir_actions_configuration_wizard(osv.osv_memory):
'type': item.action_id.type,
'target':item.action_id.target,
}
user_action=self.pool.get('res.users').browse(cr,uid,uid)
act_obj=self.pool.get(user_action.menu_id.type)
action_ids=act_obj.search(cr,uid,[('name','=',user_action.menu_id.name)])
action_open=act_obj.browse(cr,uid,action_ids)[0]
if context.get('menu',False):
return{
'view_type': action_open.view_type,
'view_id':action_open.view_id and [action_open.view_id.id] or False,
'res_model': action_open.res_model,
'type': action_open.type,
'domain':action_open.domain
}
return {'type':'ir.actions.act_window_close' }
return self.button_next(cr, uid, ids, context)
ir_actions_configuration_wizard()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+19 -17
View File
@@ -27,6 +27,7 @@ from osv.orm import except_orm, browse_record
import time
import tools
from tools import config
import pooler
def _get_fields_type(self, cr, uid, context=None):
@@ -74,7 +75,10 @@ class ir_model(osv.osv):
vals['state']='manual'
res = super(ir_model,self).create(cr, user, vals, context)
if vals.get('state','base')=='manual':
pooler.restart_pool(cr.dbname)
self.instanciate(cr, user, vals['model'], context)
self.pool.get(vals['model']).__init__(self.pool, cr)
self.pool.get(vals['model'])._auto_init(cr,{})
#pooler.restart_pool(cr.dbname)
return res
def instanciate(self, cr, user, model, context={}):
@@ -83,10 +87,7 @@ class ir_model(osv.osv):
x_custom_model._name = model
x_custom_model._module = False
x_custom_model.createInstance(self.pool, '', cr)
if 'x_name' in x_custom_model._columns:
x_custom_model._rec_name = 'x_name'
else:
x_custom_model._rec_name = x_custom_model._columns.keys()[0]
x_custom_model._rec_name = 'x_name'
ir_model()
@@ -561,18 +562,19 @@ class ir_model_data(osv.osv):
wf_service.trg_write(uid, model, id, cr)
cr.commit()
for (model,id) in self.unlink_mark.keys():
if self.pool.get(model):
logger = netsvc.Logger()
logger.notifyChannel('init', netsvc.LOG_INFO, 'Deleting %s@%s' % (id, model))
try:
self.pool.get(model).unlink(cr, uid, [id])
if self.unlink_mark[(model,id)]:
self.unlink(cr, uid, [self.unlink_mark[(model,id)]])
cr.execute('DELETE FROM ir_values WHERE value=%s', (model+','+str(id),))
cr.commit()
except:
logger.notifyChannel('init', netsvc.LOG_ERROR, 'Could not delete id: %d of model %s\tThere should be some relation that points to this resource\tYou should manually fix this and restart --update=module' % (id, model))
if not config.get('import_partial', False):
for (model,id) in self.unlink_mark.keys():
if self.pool.get(model):
logger = netsvc.Logger()
logger.notifyChannel('init', netsvc.LOG_INFO, 'Deleting %s@%s' % (id, model))
try:
self.pool.get(model).unlink(cr, uid, [id])
if self.unlink_mark[(model,id)]:
self.unlink(cr, uid, [self.unlink_mark[(model,id)]])
cr.execute('DELETE FROM ir_values WHERE value=%s', (model+','+str(id),))
cr.commit()
except:
logger.notifyChannel('init', netsvc.LOG_ERROR, 'Could not delete id: %d of model %s\tThere should be some relation that points to this resource\tYou should manually fix this and restart --update=module' % (id, model))
return True
ir_model_data()
+13 -1
View File
@@ -55,7 +55,19 @@ class ir_sequence(osv.osv):
}
def _process(self, s):
return (s or '') % {'year':time.strftime('%Y'), 'month': time.strftime('%m'), 'day':time.strftime('%d')}
return (s or '') % {
'year':time.strftime('%Y'),
'month': time.strftime('%m'),
'day':time.strftime('%d'),
'y': time.strftime('%y'),
'doy': time.strftime('%j'),
'woy': time.strftime('%W'),
'weekday': time.strftime('%w'),
'h24': time.strftime('%H'),
'h12': time.strftime('%I'),
'min': time.strftime('%M'),
'sec': time.strftime('%S'),
}
def get_id(self, cr, uid, sequence_id, test='id=%d'):
cr.execute('select id,number_next,number_increment,prefix,suffix,padding from ir_sequence where '+test+' and active=True FOR UPDATE', (sequence_id,))
+1 -1
View File
@@ -48,7 +48,7 @@ class ir_translation(osv.osv, Cacheable):
lang_ids = lang_obj.search(cr, uid, [('translatable', '=', True)],
context=context)
langs = lang_obj.browse(cr, uid, lang_ids, context=context)
res = [(lang.code, lang.name) for lang in langs]
res = [(lang.code, unicode(lang.name,'utf-8')) for lang in langs]
for lang_dict in tools.scan_languages():
if lang_dict not in res:
res.append(lang_dict)
@@ -21,8 +21,8 @@
</field>
<label colspan="2" string=""/>
<group col="2" colspan="2">
<button special="cancel" string="Cancel"/>
<button name="menu_create" string="Create Menu" type="object"/>
<button special="cancel" string="Cancel" icon="gtk-cancel"/>
<button name="menu_create" string="Create Menu" type="object" icon="gtk-ok"/>
</group>
</form>
</field>
@@ -38,7 +38,7 @@ def graph_get(cr, graph, wkf_id, nested=False, workitem={}):
if n['subflow_id'] and nested:
cr.execute('select * from wkf where id=%d', (n['subflow_id'],))
wkfinfo = cr.dictfetchone()
graph2 = pydot.Cluster('subflow'+str(n['subflow_id']), fontsize='12', label = "Subflow: "+n['name']+'\\nOSV: '+wkfinfo['osv'])
graph2 = pydot.Cluster('subflow'+str(n['subflow_id']), fontsize='12', label = """\"Subflow: %s\\nOSV: %s\"""" % ( n['name'], wkfinfo['osv']) )
(s1,s2) = graph_get(cr, graph2, n['subflow_id'], nested,workitem)
graph.add_subgraph(graph2)
actfrom[n['id']] = s2
@@ -143,12 +143,9 @@ showpage'''
showpage'''
else:
inst_id = inst_id[0]
graph = pydot.Dot(fontsize='16', label="""\\\n\\nWorkflow: %s\\n OSV: %s""" % (wkfinfo['name'],wkfinfo['osv']))
graph.set('size', '10.7,7.3')
graph.set('center', '1')
graph.set('ratio', 'auto')
graph.set('rotate', '90')
graph.set('rankdir', 'LR')
graph = pydot.Dot(fontsize='16', label="""\\\n\\nWorkflow: %s\\n OSV: %s""" % (wkfinfo['name'],wkfinfo['osv']),
size='10.7, 7.3', center='1', ratio='auto', rotate='90', rankdir='LR'
)
graph_instance_get(cr, graph, inst_id, data.get('nested', False))
ps_string = graph.create(prog='dot', format='ps')
except Exception, e:
+33
View File
@@ -0,0 +1,33 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2004-2008 Tiny SPRL (http://tiny.be) All Rights Reserved.
#
# $Id$
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
###############################################################################
import maintenance
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+111
View File
@@ -0,0 +1,111 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2004-2008 TINY SPRL. (http://tiny.be) All Rights Reserved.
#
# $Id$
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from osv import osv, fields
import pooler
import time
import math
from tools import config
import xmlrpclib
class maintenance_contract(osv.osv):
_name = "maintenance.contract"
_description = "Maintenance Contract"
_columns = {
'name' : fields.char('Contract ID', size=256, required=True),
'password' : fields.char('Password', size=64, invisible=True, required=True),
'date_start' : fields.date('Starting Date', readonly=True),
'date_stop' : fields.date('Ending Date', readonly=True),
'modules': fields.text('Covered Modules')
}
_defaults = {
'password' : lambda obj,cr,uid,context={} : '',
}
def _test_maintenance(self, cr, uid, ids, context):
remote_db='trunk'
remote_server='localhost'
port=8069
module_obj=self.pool.get('ir.module.module')
contract_obj=self.pool.get('maintenance.contract')
module_ids=module_obj.search(cr, uid, [('state','=','installed')])
modules=module_obj.read(cr, uid, module_ids, ['name','installed_version'])
contract_obj=contract_obj.read(cr, uid, ids[0])
local_url = 'http://%s:%d/xmlrpc/common'%(remote_server,port)
rpc = xmlrpclib.ServerProxy(local_url)
ruid = rpc.login(remote_db, 'admin', 'admin')
local_url = 'http://%s:%d/xmlrpc/object'%(remote_server,port)
rrpc = xmlrpclib.ServerProxy(local_url)
try:
result=rrpc.execute(remote_db, ruid, 'admin', 'maintenance.maintenance', 'check_contract' , modules,contract_obj)
except:
raise osv.except_osv(_('Maintenance Error !'),('''Module Maintenance_Editor is not installed at server : %s Database : %s'''%(remote_server,remote_db)))
if context.get('active_id',False):
if result['status']=='ko':
raise osv.except_osv(_('Maintenance Error !'),('''Maintenance Contract
-----------------------------------------------------------
You have no valid maintenance contract! If you are using
Open ERP, it is highly suggested to take maintenance contract.
The maintenance program offers you:
* Migrations on new versions,
* Bugfix guarantee,
* Monthly announces of bugs,
* Security alerts,
* Access to the customer portal.
* Check the maintenance contract (www.openerp.com)'''))
elif result['status']=='partial':
raise osv.except_osv(_('Maintenance Error !'),('''Maintenance Contract
-----------------------------------------------------------
You have a maintenance contract, But you installed modules those
are not covered by your maintenance contract:
'''+','.join(result['modules'])+'''
It means we can not offer you the garantee of maintenance on
your whole installation.
The maintenance program includes:
* Migrations on new versions,
* Bugfix guarantee,
* Monthly announces of bugs,
* Security alerts,
* Access to the customer portal.
To include these modules in your maintenance contract, you should
extend your contract with the editor. We will review and validate
your installed modules.
* Extend your maintenance to the modules you used.
* Check your maintenance contract'''))
else:
raise osv.except_osv(_('Valid Maintenance Contract !'),('''Your Maintenance Contract is up to date'''))
return result
maintenance_contract()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<record model="res.groups" id="group_maintenance_manager">
<field name="name">Maintenance Manager</field>
</record>
<record model="ir.ui.menu" id="menu_maintenance_contract">
<field eval="[(6,0,[ref('group_maintenance_manager')])]" name="groups_id"/>
</record>
</data>
</openerp>
+61
View File
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="maintenance_contract_tree_view" model="ir.ui.view">
<field name="name">maintenance.contract.tree</field>
<field name="model">maintenance.contract</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Maintenance Contract">
<field name="name"/>
<field name="date_start"/>
<field name="date_stop"/>
</tree>
</field>
</record>
<record id="maintenance_contract_form_view" model="ir.ui.view">
<field name="name">maintenance.contract.form</field>
<field name="model">maintenance.contract</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Maintenance Contract">
<separator string="Information" colspan="4"/>
<field name="name" select="1"/>
<field name="password" password="True"/>
<field name="date_start" select="1"/>
<field name="date_stop" select="1"/>
<button name="_test_maintenance" string="Check Maintenance" type="object" colspan="2"/>
<separator string="Covered Modules" colspan="4"/>
<field name="modules" nolabel="1" colspan="4"/>
</form>
</field>
</record>
<record id="action_maintenance_contract_form" model="ir.actions.act_window">
<field name="name">Your Maintenance Contracts</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">maintenance.contract</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<record id="action_maintenance_contract_form" model="ir.actions.act_window">
<field name="name">Encode a New Maintenance Contract</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">maintenance.contract</field>
<field name="view_type">form</field>
<field name="view_mode">form,tree</field>
</record>
<menuitem
name="Maintenance"
id="maintenance"
parent="base.menu_administration"/>
<menuitem
action="action_maintenance_contract_form"
id="menu_maintenance_contract"
parent="maintenance"/>
</data>
</openerp>
-11
View File
@@ -573,17 +573,6 @@ class module(osv.osv):
categs = categs[1:]
self.write(cr, uid, [id], {'category_id': p_id})
def action_install(self,cr,uid,ids,context=None):
for module in self.browse(cr, uid, ids, context):
if module.state <> 'uninstalled':
continue
self.write(cr , uid, [module.id] ,{'state' : 'to install'})
self.download(cr, uid, [module.id], context=context)
cr.execute("select m.id as id from ir_module_module_dependency d inner join ir_module_module m on (m.name=d.name) where d.module_id=%d and m.state='uninstalled'",(module.id,))
dep_ids = map(lambda x:x[0],cr.fetchall())
if len(dep_ids):
self.action_install(cr,uid,dep_ids,context=context)
def update_translations(self, cr, uid, ids, filter_lang=None):
logger = netsvc.Logger()
+7
View File
@@ -7,5 +7,12 @@
<field eval="False" name="active"/>
<field eval="'href=&quot;([a-zA-Z0-9_]+)-('+version+'.(\\d+)((\\.\\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\\d*)*)(-r(\\d+))?)(\.zip)&quot;'" name="filter"/>
</record>
<record id="ir_ui_view_sc_modules0" model="ir.ui.view_sc">
<field name="name">Modules</field>
<field name="resource">ir.ui.menu</field>
<field name="user_id" ref="base.user_root"/>
<field name="res_id" ref="base.menu_module_tree"/>
</record>
</data>
</openerp>
@@ -136,7 +136,7 @@
</td>
</tr>
</blockTable>
<para style="P6">[[ module.description ]]</para>
<para style="P6">[[ format(module.description or '') ]]</para>
<section>
<para style="Standard">[[ repeatIn(findobj(module.name) ,'object') ]]</para>
<blockTable colWidths="510.0" repeatRows="1" style="Tableau3">
@@ -144,14 +144,14 @@
<td>
<para style="P10">Object: [[ object.model ]]</para>
<para style="P11">Description : [[ object.name ]]</para>
<para style="P5">[[ objdoc(object.model) ]]</para>
<para style="P5">[[ format(objdoc(object.model)) ]]</para>
</td>
</tr>
</blockTable>
<blockTable colWidths="113.0,397.0" repeatRows="1" style="Tableau4">
<tr>
<td>
<para style="P7">[[ repeatIn(findflds(object.model), 'field') ]] [[ field[0] ]]</para>
<para style="P7">[[ repeatIn(findflds(object.model), 'field') ]] <i>[[ field[0] ]]</i></para>
</td>
<td>
<para style="P8">[[ field[1].get('string', 'Unknown') ]], [[ field[1]['type'] ]] [[field[1].get('required',False) and ', required']] [[field[1].get('readonly',False) and ', readonly']] </para>
@@ -37,12 +37,11 @@ class ir_module_reference_print(report_sxw.rml_parse):
return modobj.__doc__
def _object_find(self, module):
ids2 = self.pool.get('ir.model.data').search(self.cr, self.uid, [('module','=',module), ('model','=','ir.model')])
ids = []
for mod in self.pool.get('ir.model.data').browse(self.cr, self.uid, ids2):
ids.append(mod.res_id)
modobj = self.pool.get('ir.model')
if module=='base':
ids = modobj.search(self.cr, self.uid, [('model','=like','res%')])
ids += modobj.search(self.cr, self.uid, [('model','=like','ir%')])
else:
ids = modobj.search(self.cr, self.uid, [('model','=like',module+'%')])
return modobj.browse(self.cr, self.uid, ids)
def _fields_find(self, obj):
@@ -31,11 +31,14 @@ view_form="""<?xml version="1.0"?>
<image name="gtk-dialog-info" colspan="2"/>
<group colspan="2" col="4">
<separator string="Import new language" colspan="4"/>
<field name="name"/>
<field name="name" width="200"/>
<field name="code"/>
<field name="data" colspan="3"/>
<label string="You have to import a .CSV file wich is encoded in UTF-8.\nPlease check that the first line of your file is:" colspan="4" align="0.0"/>
<field name="data" colspan="4"/>
<label string="You have to import a .CSV file wich is encoded in UTF-8.\n
Please check that the first line of your file is one of the following:" colspan="4" align="0.0"/>
<label string="type,name,res_id,src,value" colspan="4"/>
<label string="module,type,name,res_id,src,value" colspan="4"/>
<label string="You can also import .po files." colspan="4" align="0.0"/>
</group>
</form>"""
@@ -54,7 +57,7 @@ class wizard_import_lang(wizard.interface):
# now we determine the file format
fileobj.seek(0)
first_line = fileobj.readline().strip()
first_line = fileobj.readline().strip().replace('"', '').replace(' ', '')
fileformat = first_line.endswith("type,name,res_id,src,value") and 'csv' or 'po'
fileobj.seek(0)
@@ -146,5 +146,99 @@ class wizard_info_get(wizard.interface):
wizard_info_get('module.upgrade')
class wizard_info_get_simple(wizard.interface):
def _get_install(self, cr, uid, data, context):
pool=pooler.get_pool(cr.dbname)
mod_obj = pool.get('ir.module.module')
ids = mod_obj.search(cr, uid, [
('state', 'in', ['to upgrade', 'to remove', 'to install'])])
res = mod_obj.read(cr, uid, ids, ['name','state'], context)
url = mod_obj.download(cr, uid, ids, download=False, context=context)
return {'module_info': '\n'.join(map(lambda x: x['name']+' : '+x['state'], res)),
'module_download': '\n'.join(url)}
def _check_upgrade_module(self,cr,uid,data,context):
db, pool = pooler.get_db_and_pool(cr.dbname)
cr = db.cursor()
mod_obj = pool.get('ir.module.module')
ids = mod_obj.search(cr, uid, [
('state', 'in', ['to upgrade', 'to remove', 'to install'])])
if ids and len(ids):
return 'next'
else:
return 'end'
def _upgrade_module(self, cr, uid, data, context):
db, pool = pooler.get_db_and_pool(cr.dbname)
cr = db.cursor()
mod_obj = pool.get('ir.module.module')
ids = mod_obj.search(cr, uid, [('state', 'in', ['to upgrade', 'to remove', 'to install'])])
unmet_packages = []
mod_dep_obj = pool.get('ir.module.module.dependency')
for mod in mod_obj.browse(cr, uid, ids):
depends_mod_ids = mod_dep_obj.search(cr, uid, [('module_id', '=', mod.id)])
for dep_mod in mod_dep_obj.browse(cr, uid, depends_mod_ids):
if dep_mod.state in ('unknown','uninstalled'):
unmet_packages.append(dep_mod.name)
if len(unmet_packages):
raise wizard.except_wizard('Unmet dependency !', 'Following modules are uninstalled or unknown. \n\n'+'\n'.join(unmet_packages))
mod_obj.download(cr, uid, ids, context=context)
cr.commit()
db, pool = pooler.restart_pool(cr.dbname, update_module=True)
return {}
def _config(self, cr, uid, data, context=None):
return {
'view_type': 'form',
"view_mode": 'form',
'res_model': 'ir.actions.configuration.wizard',
'type': 'ir.actions.act_window',
'target':'new',
}
states = {
'init': {
'actions': [],
'result' : {'type': 'choice', 'next_state': _check_upgrade_module }
},
'next': {
'actions': [_get_install],
'result': {'type':'form', 'arch':view_form, 'fields': view_field,
'state':[
('end', 'Cancel', 'gtk-cancel'),
('start', 'Start Upgrade', 'gtk-ok', True)
]
}
},
'start': {
'actions': [_upgrade_module],
'result': {'type':'form', 'arch':view_form_end, 'fields': {},
'state':[
('end', 'Close', 'gtk-close', True),
('config', 'Start configuration', 'gtk-ok', True)
]
}
},
'end': {
'actions': [],
'result': {'type':'form', 'arch':view_form_end, 'fields': {},
'state':[
('end', 'Close', 'gtk-close', True),
('config', 'Start configuration', 'gtk-ok', True)
]
}
},
'config':{
'result': {
'type': 'action',
'action': _config,
'state': 'end',
},
}
}
wizard_info_get_simple('module.upgrade.simple')
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+13 -7
View File
@@ -14,19 +14,21 @@
<xsl:template name="stylesheet">
<paraStyle name="title" fontName="Helvetica-Bold" fontSize="22" alignment="center"/>
<blockTableStyle id="products">
<blockBackground colorName="grey" start="0,0" stop="-1,0"/>
<!--<blockBackground colorName="grey" start="0,0" stop="-1,0"/> -->
<lineStyle kind="LINEBELOW" colorName="#000000" start="0,0" stop="-1,0"/>
<blockValign value="TOP"/>
<blockAlignment value="RIGHT"/>
<lineStyle kind="GRID" colorName="black"/>
<lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,1" stop="-1,-1"/>
<!-- <lineStyle kind="GRID" colorName="black"/> -->
</blockTableStyle>
</xsl:template>
<xsl:template name="story">
<xsl:apply-templates select="report"/>
</xsl:template>
<xsl:template match="report">
<xsl:apply-templates select="config"/>
<!--<setNextTemplate name="other_pages"/>-->
@@ -36,7 +38,7 @@
<xsl:value-of select="./config/tableSize"/>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="header"/>
<xsl:apply-templates select="lines"/>
</blockTable>
@@ -53,8 +55,8 @@
<tr>
<xsl:for-each select="field">
<td>
<para>
<xsl:value-of select="."/>
<para><font fontName="Helvetica-Bold" fontSize="9">
<xsl:value-of select="."/></font>
</para>
</td>
</xsl:for-each>
@@ -79,12 +81,16 @@
<xsl:when test="@tree='yes'">
<para>
<xsl:attribute name="leftIndent"><xsl:value-of select="@space"/></xsl:attribute>
<font fontName="Helvetica" fontSize="9">
<xsl:value-of select="."/>
</font>
</para>
</xsl:when>
<xsl:otherwise>
<para>
<font fontName="Helvetica" fontSize="9">
<xsl:value-of select="."/>
</font>
</para>
</xsl:otherwise>
</xsl:choose>
@@ -81,6 +81,7 @@
<field name="supplier">1</field>
</record>
<record id="res_partner_sednacom" model="res.partner">
<field name="website">http://www.syleam.fr</field>
<field name="name">Syleam</field>
<field eval="[(6, 0, [ref('res_partner_category_5')])]" name="category_id"/>
</record>
@@ -201,6 +202,16 @@
<field name="type">default</field>
<field name="partner_id" ref="res_partner_10"/>
</record>
<record id="res_partner_address_3000" model="res.partner.address">
<field name="city">Champs sur Marne</field>
<field name="name">Laith Jubair</field>
<field name="zip">77420</field>
<field model="res.country" name="country_id" search="[('name','=','France')]"/>
<field name="email">info@axelor.com</field>
<field name="phone">+33 1 64 61 04 01</field>
<field name="street">12 rue Albert Einstein</field>
<field name="partner_id" ref="res_partner_desertic_hispafuentes"/>
</record>
<record id="res_partner_address_3" model="res.partner.address">
<field name="city">Louvain-la-Neuve</field>
<field name="name">Thomas Passot</field>
@@ -271,6 +282,18 @@
<field name="type">default</field>
<field name="partner_id" ref="res_partner_2"/>
</record>
<record id="res_partner_address_11" model="res.partner.address">
<field name="city">Alencon</field>
<field name="name">Sebastien LANGE</field>
<field name="zip">61000</field>
<field name="title">M.</field>
<field name="email">contact@syleam.fr</field>
<field name="street">1 place de l'Église</field>
<field name="phone">+33 (0) 2 33 31 22 10</field>
<field model="res.country" name="country_id" search="[('name','=','France')]"/>
<field name="type">default</field>
<field name="partner_id" ref="res_partner_sednacom"/>
</record>
<record id="res_partner_address_10" model="res.partner.address">
<field name="city">Liege</field>
<field name="name">Karine Lesbrouffe</field>
+6 -1
View File
@@ -96,7 +96,7 @@ class users(osv.osv):
_columns = {
'name': fields.char('Name', size=64, required=True, select=True),
'login': fields.char('Login', size=64, required=True),
'password': fields.char('Password', size=64, invisible=True),
'password': fields.char('Password', size=64, invisible=True, help="Keep empty if you don't want the user to be able to connect on the system."),
'signature': fields.text('Signature', size=64),
'address_id': fields.many2one('res.partner.address', 'Address'),
'active': fields.boolean('Active'),
@@ -138,6 +138,10 @@ class users(osv.osv):
ids = self.pool.get('ir.actions.act_window').search(cr, uid, [('usage','=','menu')])
return ids and ids[0] or False
def _get_group(self,cr, uid, context={}):
ids = self.pool.get('res.groups').search(cr, uid, [('name','=','Employee')])
return ids or False
_defaults = {
'password' : lambda obj,cr,uid,context={} : '',
'context_lang': lambda *args: 'en_US',
@@ -145,6 +149,7 @@ class users(osv.osv):
'menu_id': _get_menu,
'action_id': _get_menu,
'company_id': _get_company,
'groups_id': _get_group,
}
def company_get(self, cr, uid, uid2):
company_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.id
@@ -127,3 +127,4 @@
"access_res_config_view_all","res_config_view_all","model_res_config_view",,1,0,0,0
"access_res_bank_group_partner_manager","res_bank_group_partner_manager","model_res_bank","group_partner_manager",1,1,1,1
"access_res_bank_user","res_bank user","model_res_bank","group_user",1,0,0,0
"access_maintenance_group_user","maintenance_contract group_user","model_maintenance_contract","group_maintenance_manager",1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
127 access_res_config_view_all res_config_view_all model_res_config_view 1 0 0 0
128 access_res_bank_group_partner_manager res_bank_group_partner_manager model_res_bank group_partner_manager 1 1 1 1
129 access_res_bank_user res_bank user model_res_bank group_user 1 0 0 0
130 access_maintenance_group_user maintenance_contract group_user model_maintenance_contract group_maintenance_manager 1 1 1 1
+22 -21
View File
@@ -28,6 +28,7 @@ import SimpleXMLRPCServer, signal, sys, xmlrpclib
import SocketServer
import socket
import logging
import logging.handlers
import os
_service = {}
@@ -121,10 +122,15 @@ class Service(object):
class LocalService(Service):
def __init__(self, name):
self.__name = name
s = _service[name]
self._service = s
for m in s._method:
setattr(self, m, s._method[m])
try:
s = _service[name]
self._service = s
for m in s._method:
setattr(self, m, s._method[m])
except KeyError, keyError:
Logger().notifyChannel('module', LOG_ERROR, 'This service does not exists: %s' % (str(keyError),) )
raise
class ServiceUnavailable(Exception):
@@ -153,6 +159,9 @@ def init_logger():
logf = config['logfile']
# test if the directories exist, else create them
try:
dirname = os.path.dirname(logf)
if not os.path.isdir(dirname):
res = os.makedirs(dirname)
handler = logging.handlers.TimedRotatingFileHandler(logf,'D',1,30)
except:
sys.stderr.write("ERROR: couldn't create the logfile directory\n")
@@ -271,24 +280,19 @@ class GenericXMLRPCRequestHandler:
raise xmlrpclib.Fault(s, tb_s)
class SimpleXMLRPCRequestHandler(GenericXMLRPCRequestHandler,
SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
class SimpleXMLRPCRequestHandler(GenericXMLRPCRequestHandler, SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.rpc_paths = get_rpc_paths()
class SimpleThreadedXMLRPCServer(SocketServer.ThreadingMixIn,
SimpleXMLRPCServer.SimpleXMLRPCServer):
class SimpleThreadedXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer.SimpleXMLRPCServer):
def server_bind(self):
try:
self.socket.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR, 1)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
SimpleXMLRPCServer.SimpleXMLRPCServer.server_bind(self)
except:
sys.stderr.write("ERROR: address already in use\n")
Logger().notifyChannel('init', LOG_ERROR, 'Address already in use')
sys.exit(1)
class HttpDaemon(threading.Thread):
def __init__(self, interface, port, secure=False):
@@ -298,22 +302,19 @@ class HttpDaemon(threading.Thread):
self.secure = secure
if secure:
from ssl import SecureXMLRPCServer
class SecureXMLRPCRequestHandler(GenericXMLRPCRequestHandler,
SecureXMLRPCServer.SecureXMLRPCRequestHandler):
SecureXMLRPCServer.SecureXMLRPCRequestHandler.rpc_paths = get_rpc_paths()
class SecureThreadedXMLRPCServer(SocketServer.ThreadingMixIn,
SecureXMLRPCServer.SecureXMLRPCServer):
class SecureXMLRPCRequestHandler(GenericXMLRPCRequestHandler, SecureXMLRPCServer.SecureXMLRPCRequestHandler):
SecureXMLRPCServer.SecureXMLRPCRequestHandler.rpc_paths = get_rpc_paths()
class SecureThreadedXMLRPCServer(SocketServer.ThreadingMixIn, SecureXMLRPCServer.SecureXMLRPCServer):
def server_bind(self):
try:
self.socket.setsockopt(socket.SOL_SOCKET,
socket.SO_REUSEADDR, 1)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
SecureXMLRPCServer.SecureXMLRPCServer.server_bind(self)
except:
sys.stderr.write("ERROR: address already in use\n")
sys.exit(1)
self.server = SecureThreadedXMLRPCServer((interface, port),
SecureXMLRPCRequestHandler, 0)
else:
+1 -4
View File
@@ -81,8 +81,6 @@ dispatcher.monitor(signal.SIGINT)
#---------------------------------------------------------------
# connect to the database and initialize it with base if needed
#---------------------------------------------------------------
logger.notifyChannel("init", netsvc.LOG_INFO, 'connecting to database')
import psycopg
import pooler
@@ -129,7 +127,6 @@ import osv, workflow, report, service
#----------------------------------------------------------
import addons
addons.register_classes()
if tools.config['init'] or tools.config['update']:
pooler.get_db_and_pool(tools.config['db_name'], update_module=True)
@@ -203,7 +200,7 @@ if tools.config['netrpc']:
netinterface = tools.config["netinterface"]
tinySocket = netsvc.TinySocketServerThread(netinterface, netport, False)
logger.notifyChannel("web-services", netsvc.LOG_INFO, "starting netrpc service, port "+str(netport))
logger.notifyChannel("web-services", netsvc.LOG_INFO, "starting NET-RPC service, port "+str(netport))
def handler(signum, frame):
+5 -4
View File
@@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
@@ -160,7 +160,7 @@ class char(_column):
u_symb = symb
else:
u_symb = unicode(symb)
return u_symb.encode('utf8')[:self.size]
return u_symb[:self.size].encode('utf8')
class text(_column):
@@ -678,7 +678,8 @@ class related(function):
where += " %s.%s %s '%s' and" % (obj_child._table, self._arg[i], context[0][1], context[0][2])
if field_detail[1] in ['integer', 'long', 'float','integer_big']:
where += " %s.%s %s '%d' and" % (obj_child._table, self._arg[i], context[0][1], context[0][2])
query += where.rstrip('and')
if len(where)>10:
query += where.rstrip('and')
cr.execute(query)
ids = []
for id in cr.fetchall():
@@ -707,7 +708,7 @@ class related(function):
else:
t_data = t_data[self.arg[i]]
if type(t_data) == type(objlst[0]):
res[data.id] = t_data.id
res[data.id] = (t_data.id,t_data.name)
else:
res[data.id] = t_data
return res
+62 -50
View File
@@ -116,7 +116,7 @@ class browse_record(object):
'''
if not context:
context = {}
assert id, _('Wrong ID for the browse record, got %s, expected an integer.') % str(id)
assert id and isinstance(id, (int, long,)), _('Wrong ID for the browse record, got %r, expected an integer.') % (id,)
self._list_class = list_class or browse_record_list
self._cr = cr
self._uid = uid
@@ -128,9 +128,12 @@ class browse_record(object):
cache.setdefault(table._name, {})
self._data = cache[table._name]
if not id in self._data:
self._data[id] = {'id': id}
self._cache = cache
pass
def __getitem__(self, name):
if name == 'id':
@@ -183,7 +186,7 @@ class browse_record(object):
if data[n]:
obj = self._table.pool.get(f._obj)
compids = False
if not f._classic_write:
if type(data[n]) in (type([]),type( (1,) )):
ids2 = data[n][0]
else:
ids2 = data[n]
@@ -297,17 +300,20 @@ class orm_template(object):
_description = None
_inherits = {}
_table = None
_invalids = set()
def _field_create(self, cr, context={}):
cr.execute("SELECT id FROM ir_model_data WHERE name='%s'" % ('model_'+self._name.replace('.','_'),))
cr.execute("SELECT id FROM ir_model WHERE model='%s'" % self._name)
if not cr.rowcount:
cr.execute('SELECT nextval(%s)', ('ir_model_id_seq',))
id = cr.fetchone()[0]
cr.execute("INSERT INTO ir_model (id,model, name, info) VALUES (%s, %s, %s, %s)", (id, self._name, self._description, self.__doc__))
model_id = cr.fetchone()[0]
cr.execute("INSERT INTO ir_model (id,model, name, info,state) VALUES (%s, %s, %s, %s,%s)", (model_id, self._name, self._description, self.__doc__, 'base'))
if 'module' in context:
cr.execute("INSERT INTO ir_model_data (name,date_init,date_update,module,model,res_id) VALUES (%s, now(), now(), %s, %s, %s)", \
('model_'+self._name.replace('.','_'), context['module'], 'ir.model', id)
('model_'+self._name.replace('.','_'), context['module'], 'ir.model', model_id)
)
else:
model_id = cr.fetchone()[0]
cr.commit()
cr.execute("SELECT * FROM ir_model_fields WHERE model=%s", (self._name,))
@@ -315,9 +321,6 @@ class orm_template(object):
for rec in cr.dictfetchall():
cols[rec['name']] = rec
cr.execute("SELECT id FROM ir_model WHERE model='%s'" % self._name)
model_id = cr.fetchone()[0]
for (k, f) in self._columns.items():
vals = {
'model_id': model_id,
@@ -648,6 +651,9 @@ class orm_template(object):
def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
raise _('The read method is not implemented on this object !')
def get_invalid_fields(self,cr,uid):
return list(self._invalids)
def _validate(self, cr, uid, ids, context=None):
context = context or {}
lng = context.get('lang', False) or 'en_US'
@@ -660,9 +666,12 @@ class orm_template(object):
error_msgs.append(
_("Error occured while validating the field(s) %s: %s") % (','.join(fields), translated_msg)
)
self._invalids.update(fields)
if error_msgs:
cr.rollback()
raise except_orm('ValidateError', '\n'.join(error_msgs))
else:
self._invalids.clear()
def default_get(self, cr, uid, fields_list, context=None):
return {}
@@ -1020,6 +1029,9 @@ class orm_template(object):
xml += "<newline/>"
xml += "</form>"
elif view_type == 'tree':
_rec_name = self._rec_name
if _rec_name not in self._columns:
_rec_name = self._columns.keys()[0]
xml = '''<?xml version="1.0" encoding="utf-8"?>''' \
'''<tree string="%s"><field name="%s"/></tree>''' \
% (self._description, self._rec_name)
@@ -1095,6 +1107,47 @@ class orm_template(object):
def copy(self, cr, uid, id, default=None, context=None):
raise _('The copy method is not implemented on this object !')
def read_string(self, cr, uid, id, langs, fields=None, context=None):
if not context:
context = {}
res = {}
res2 = {}
self.pool.get('ir.model.access').check(cr, uid, 'ir.translation', 'read')
if not fields:
fields = self._columns.keys() + self._inherit_fields.keys()
for lang in langs:
res[lang] = {'code': lang}
for f in fields:
if f in self._columns:
res_trans = self.pool.get('ir.translation')._get_source(cr, uid, self._name+','+f, 'field', lang)
if res_trans:
res[lang][f] = res_trans
else:
res[lang][f] = self._columns[f].string
for table in self._inherits:
cols = intersect(self._inherit_fields.keys(), fields)
res2 = self.pool.get(table).read_string(cr, uid, id, langs, cols, context)
for lang in res2:
if lang in res:
res[lang] = {'code': lang}
for f in res2[lang]:
res[lang][f] = res2[lang][f]
return res
def write_string(self, cr, uid, id, langs, vals, context=None):
if not context:
context = {}
self.pool.get('ir.model.access').check(cr, uid, 'ir.translation', 'write')
for lang in langs:
for field in vals:
if field in self._columns:
self.pool.get('ir.translation')._set_ids(cr, uid, self._name+','+field, 'field', lang, [0], vals[field])
for table in self._inherits:
cols = intersect(self._inherit_fields.keys(), vals)
if cols:
self.pool.get(table).write_string(cr, uid, id, langs, vals, context)
return True
class orm_memory(orm_template):
_protected = ['read', 'write', 'create', 'default_get', 'perm_read', 'unlink', 'fields_get', 'fields_view_get', 'search', 'name_get', 'distinct_field_get', 'name_search', 'copy', 'import_data', 'search_count']
@@ -2531,47 +2584,6 @@ class orm(orm_template):
return new_id
def read_string(self, cr, uid, id, langs, fields=None, context=None):
if not context:
context = {}
res = {}
res2 = {}
self.pool.get('ir.model.access').check(cr, uid, 'ir.translation', 'read')
if not fields:
fields = self._columns.keys() + self._inherit_fields.keys()
for lang in langs:
res[lang] = {'code': lang}
for f in fields:
if f in self._columns:
res_trans = self.pool.get('ir.translation')._get_source(cr, uid, self._name+','+f, 'field', lang)
if res_trans:
res[lang][f] = res_trans
else:
res[lang][f] = self._columns[f].string
for table in self._inherits:
cols = intersect(self._inherit_fields.keys(), fields)
res2 = self.pool.get(table).read_string(cr, uid, id, langs, cols, context)
for lang in res2:
if lang in res:
res[lang] = {'code': lang}
for f in res2[lang]:
res[lang][f] = res2[lang][f]
return res
def write_string(self, cr, uid, id, langs, vals, context=None):
if not context:
context = {}
self.pool.get('ir.model.access').check(cr, uid, 'ir.translation', 'write')
for lang in langs:
for field in vals:
if field in self._columns:
self.pool.get('ir.translation')._set_ids(cr, uid, self._name+','+field, 'field', lang, [0], vals[field])
for table in self._inherits:
cols = intersect(self._inherit_fields.keys(), vals)
if cols:
self.pool.get(table).write_string(cr, uid, id, langs, vals, context)
return True
def check_recursion(self, cr, uid, ids, parent=None):
if not parent:
parent = self._parent_name
+16 -7
View File
@@ -90,16 +90,14 @@ class osv_pool(netsvc.Service):
except psycopg.IntegrityError, inst:
for key in self._sql_error.keys():
if key in inst[0]:
self.abortResponse(1, 'Constraint Error', 'warning',
self._sql_error[key])
self.abortResponse(1, 'Constraint Error', 'warning', self._sql_error[key])
self.abortResponse(1, 'Integrity Error', 'warning', inst[0])
except Exception, e:
import traceback
tb_s = reduce(lambda x, y: x+y, traceback.format_exception(
sys.exc_type, sys.exc_value, sys.exc_traceback))
tb_s = reduce(lambda x, y: x+y, traceback.format_exception( sys.exc_type, sys.exc_value, sys.exc_traceback))
logger = Logger()
logger.notifyChannel("web-services", LOG_ERROR,
'Exception in call: ' + tb_s)
for idx, s in enumerate(tb_s.split('\n')):
logger.notifyChannel("web-services", LOG_ERROR, '[%2d]: %s' % (idx, s,))
raise
def execute(self, db, uid, obj, method, *args, **kw):
@@ -229,7 +227,18 @@ class osv(orm.orm):
if hasattr(new, 'update'):
new.update(cls.__dict__.get(s, {}))
else:
new.extend(cls.__dict__.get(s, []))
if s=='_constraints':
for c in cls.__dict__.get(s, []):
exist = False
for c2 in range(len(new)):
if new[c2][2]==c[2]:
new[c2] = c
exist = True
break
if not exist:
new.append(c)
else:
new.extend(cls.__dict__.get(s, []))
nattr[s] = new
name = hasattr(cls, '_name') and cls._name or cls._inherit
cls = type(name, (cls, parent_class), nattr)
+18 -6
View File
@@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
@@ -129,6 +129,7 @@ class report_printscreen_list(report_int):
new_doc.childNodes[0].appendChild(config)
header = new_doc.createElement("header")
for f in fields_order:
field = new_doc.createElement("field")
field_txt = new_doc.createTextNode(str(fields[f]['string'] or ''))
@@ -143,25 +144,31 @@ class report_printscreen_list(report_int):
count = len(fields_order)
for i in range(0,count):
tsum.append(0)
for line in results:
node_line = new_doc.createElement("row")
count = -1
for f in fields_order:
count += 1
if fields[f]['type']=='many2one' and line[f]:
line[f] = line[f][1]
line[f]= line[f][1]
if fields[f]['type'] in ('one2many','many2many') and line[f]:
line[f] = '( '+str(len(line[f])) + ' )'
if fields[f]['type'] == 'float':
precision=(('digits' in fields[f]) and fields[f]['digits'][1]) or 2
line[f]=round(line[f],precision)
line[f]='%.2f'%(line[f])
col = new_doc.createElement("col")
col.setAttribute('para','yes')
col.setAttribute('tree','no')
if line[f] != None:
txt = new_doc.createTextNode(str(line[f] or ''))
if temp[count] == 1:
tsum[count] = tsum[count] + line[f];
tsum[count] = float(tsum[count]) + float(line[f]);
else:
txt = new_doc.createTextNode('/')
@@ -176,7 +183,11 @@ class report_printscreen_list(report_int):
col.setAttribute('para','yes')
col.setAttribute('tree','no')
if tsum[f] != None:
txt = new_doc.createTextNode(str(tsum[f] or ''))
if tsum[f] >= 0.01 :
total = '%.2f'%(tsum[f])
txt = new_doc.createTextNode(str(total or ''))
else :
txt = new_doc.createTextNode(str(tsum[f] or ''))
else:
txt = new_doc.createTextNode('/')
if f == 0:
@@ -184,8 +195,10 @@ class report_printscreen_list(report_int):
col.appendChild(txt)
node_line.appendChild(col)
lines.appendChild(node_line)
new_doc.childNodes[0].appendChild(lines)
styledoc = libxml2.parseFile(os.path.join(tools.config['root_path'],'addons/base/report/custom_new.xsl'))
@@ -200,4 +213,3 @@ report_printscreen_list('report.printscreen.list')
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+1 -1
View File
@@ -385,7 +385,7 @@ class rml_parse(object):
def _eval(self, expr):
try:
res = eval(expr, self.localcontext)
if not res:
if (res is None) or (res=='') or (res is False):
res = ''
except Exception,e:
import traceback, sys
+5 -15
View File
@@ -149,7 +149,7 @@ class db(netsvc.Service):
try:
cr.execute('DROP DATABASE ' + db_name)
except:
logger.notifyChannel("web-service", netsvc.LOG_ERROR,
logger.notifyChannel("web-services", netsvc.LOG_ERROR,
'DROP DB: %s failed' % (db_name,))
raise
else:
@@ -163,11 +163,6 @@ class db(netsvc.Service):
security.check_super(password)
logger = netsvc.Logger()
if tools.config['db_password']:
logger.notifyChannel("web-service", netsvc.LOG_ERROR,
'DUMP DB: %s doesn\'t work with password' % (db_name,))
raise Exception, "Couldn't dump database with password"
cmd = ['pg_dump', '--format=c']
if tools.config['db_user']:
cmd.append('--username=' + tools.config['db_user'])
@@ -182,7 +177,7 @@ class db(netsvc.Service):
data = stdout.read()
res = stdout.close()
if res:
logger.notifyChannel("web-service", netsvc.LOG_ERROR,
logger.notifyChannel("web-services", netsvc.LOG_ERROR,
'DUMP DB: %s failed\n%s' % (db_name, data))
raise Exception, "Couldn't dump database"
logger.notifyChannel("web-services", netsvc.LOG_INFO,
@@ -194,15 +189,10 @@ class db(netsvc.Service):
logger = netsvc.Logger()
if self.db_exist(db_name):
logger.notifyChannel("web-service", netsvc.LOG_WARNING,
logger.notifyChannel("web-services", netsvc.LOG_WARNING,
'RESTORE DB: %s already exists' % (db_name,))
raise Exception, "Database already exists"
if tools.config['db_password']:
logger.notifyChannel("web-service", netsvc.LOG_ERROR,
'RESTORE DB: %s doesn\'t work with password' % (db_name,))
raise Exception, "Couldn't restore database with password"
db = sql_db.db_connect('template1', serialize=1)
db.truedb.autocommit()
cr = db.cursor()
@@ -328,7 +318,7 @@ class common(netsvc.Service):
res = security.login(db, login, password)
logger = netsvc.Logger()
msg = res and 'successful login' or 'bad login or password'
logger.notifyChannel("web-service", netsvc.LOG_INFO, "%s from '%s' using database '%s'" % (msg, login, db.lower()))
logger.notifyChannel("web-services", netsvc.LOG_INFO, "%s from '%s' using database '%s'" % (msg, login, db.lower()))
return res or False
def about(self, extended=False):
@@ -480,7 +470,7 @@ class report_spool(netsvc.Service):
tb_s = reduce(lambda x, y: x+y, traceback.format_exception(
sys.exc_type, sys.exc_value, sys.exc_traceback))
logger = netsvc.Logger()
logger.notifyChannel('web-service', netsvc.LOG_ERROR,
logger.notifyChannel('web-services', netsvc.LOG_ERROR,
'Exception: %s\n%s' % (str(exception), tb_s))
self._reports[id]['exception'] = exception
self._reports[id]['state'] = True
Executable → Regular
View File
+21 -13
View File
@@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
@@ -282,7 +282,7 @@ form: module.record_id""" % (xml_id,)
groups_value.append((4, group_id))
res['groups_id'] = groups_value
id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.report.xml", self.module, res, xml_id, mode=self.mode)
id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.report.xml", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
self.idref[xml_id] = int(id)
if not rec.hasAttribute('menu') or eval(rec.getAttribute('menu')):
keyword = str(rec.getAttribute('keyword') or 'client_print_multi')
@@ -322,7 +322,7 @@ form: module.record_id""" % (xml_id,)
groups_value.append((4, group_id))
res['groups_id'] = groups_value
id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.wizard", self.module, res, xml_id, mode=self.mode)
id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.wizard", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
self.idref[xml_id] = int(id)
# ir_set
if (not rec.hasAttribute('menu') or eval(rec.getAttribute('menu'))) and id:
@@ -343,7 +343,7 @@ form: module.record_id""" % (xml_id,)
res = {'name': name, 'url': url, 'target':target}
id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.url", self.module, res, xml_id, mode=self.mode)
id = self.pool.get('ir.model.data')._update(cr, self.uid, "ir.actions.url", self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
self.idref[xml_id] = int(id)
# ir_set
if (not rec.hasAttribute('menu') or eval(rec.getAttribute('menu'))) and id:
@@ -375,6 +375,14 @@ form: module.record_id""" % (xml_id,)
and rec.getAttribute('auto_refresh').encode('utf-8')
# groups_id = rec.hasAttribute('groups') and rec.getAttribute('groups').encode('utf-8')
# def ref() added because , if context has ref('id') eval wil use this ref
active_id=str("active_id") # for further reference in client/bin/tools/__init__.py
def ref(str_id):
return self.id_get(cr, None, str_id)
context=eval(context)
res = {
'name': name,
'type': type,
@@ -406,7 +414,7 @@ form: module.record_id""" % (xml_id,)
if rec.hasAttribute('target'):
res['target'] = rec.getAttribute('target')
id = self.pool.get('ir.model.data')._update(cr, self.uid, 'ir.actions.act_window', self.module, res, xml_id, mode=self.mode)
id = self.pool.get('ir.model.data')._update(cr, self.uid, 'ir.actions.act_window', self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode)
self.idref[xml_id] = int(id)
if src_model:
@@ -554,7 +562,7 @@ form: module.record_id""" % (xml_id,)
xml_id = rec.getAttribute('id').encode('utf8')
self._test_xml_id(xml_id)
pid = self.pool.get('ir.model.data')._update(cr, self.uid, 'ir.ui.menu', self.module, values, xml_id, True, mode=self.mode, res_id=res and res[0] or False)
pid = self.pool.get('ir.model.data')._update(cr, self.uid, 'ir.ui.menu', self.module, values, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode, res_id=res and res[0] or False)
if rec_id and pid:
self.idref[rec_id] = int(pid)
@@ -582,7 +590,7 @@ form: module.record_id""" % (xml_id,)
rec_src = rec.getAttribute("search").encode('utf8')
rec_src_count = rec.getAttribute("count")
severity = rec.getAttribute("severity").encode('ascii') or netsvc.LOG_ERROR
severity = rec.getAttribute("severity").encode('ascii') or netsvc.LOG_ERROR
rec_string = rec.getAttribute("string").encode('utf8') or 'unknown'
@@ -744,15 +752,17 @@ form: module.record_id""" % (xml_id,)
raise
return True
def __init__(self, cr, module, idref, mode, report=assertion_report(), noupdate = False):
def __init__(self, cr, module, idref, mode, report=None, noupdate=False):
self.logger = netsvc.Logger()
self.mode = mode
self.module = module
self.cr = cr
self.idref = idref
self.pool = pooler.get_pool(cr.dbname)
# self.pool = osv.osv.FakePool(module)
self.uid = 1
if report is None:
report = assertion_report()
self.assert_report = report
self.noupdate = noupdate
self._tags = {
@@ -822,7 +832,7 @@ def convert_csv_import(cr, module, fname, csvcontent, idref=None, mode='init',
#
# xml import/export
#
def convert_xml_import(cr, module, xmlfile, idref=None, mode='init', noupdate = False, report=None):
def convert_xml_import(cr, module, xmlfile, idref=None, mode='init', noupdate=False, report=None):
xmlstr = xmlfile.read()
xmlfile.seek(0)
relaxng_doc = etree.parse(file(os.path.join( config['root_path'], 'import_xml.rng' )))
@@ -839,9 +849,7 @@ def convert_xml_import(cr, module, xmlfile, idref=None, mode='init', noupdate =
if idref is None:
idref={}
if report is None:
report=assertion_report()
obj = xml_import(cr, module, idref, mode, report=report, noupdate = noupdate)
obj = xml_import(cr, module, idref, mode, report=report, noupdate=noupdate)
obj.parse(xmlstr)
del obj
return True
+64 -91
View File
@@ -323,19 +323,30 @@ def reverse_enumerate(l):
#----------------------------------------------------------
# Emails
#----------------------------------------------------------
def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=None, on_error=False, reply_to=False, tinycrm=False, ssl=False, debug=False,subtype='plain'):
def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=None, reply_to=False, attach=None, tinycrm=False, ssl=False, debug=False,subtype='plain'):
"""Send an email."""
if not email_cc:
email_cc=[]
if not email_bcc:
email_bcc=[]
import smtplib
from email.MIMEText import MIMEText
from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
from email.Header import Header
from email.Utils import formatdate, COMMASPACE
from email.Utils import formatdate, COMMASPACE
from email import Encoders
if not ssl:
ssl = config.get('smtp_ssl', False)
if not email_cc:
email_cc = []
if not email_bcc:
email_bcc = []
if not attach:
msg = MIMEText(body or '',_subtype=subtype,_charset='utf-8')
else:
msg = MIMEMultipart()
msg = MIMEText(body or '',_subtype=subtype,_charset='utf-8')
msg['Subject'] = Header(subject.decode('utf8'), 'utf-8')
msg['From'] = email_from
del msg['Reply-To']
@@ -347,8 +358,19 @@ def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=Non
if email_bcc:
msg['Bcc'] = COMMASPACE.join(email_bcc)
msg['Date'] = formatdate(localtime=True)
if tinycrm:
msg['Message-Id'] = '<'+str(time.time())+'-tinycrm-'+str(tinycrm)+'@'+socket.gethostname()+'>'
msg['Message-Id'] = "<%s-tinycrm-%s@%s>" % (time.time(), tinycrm, socket.gethostname())
if attach:
msg.attach( MIMEText(body or '', _charset='utf-8', _subtype=subtype) )
for (fname,fcontent) in attach:
part = MIMEBase('application', "octet-stream")
part.set_payload( fcontent )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % (fname,))
msg.attach(part)
try:
s = smtplib.SMTP()
@@ -362,78 +384,16 @@ def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=Non
if config['smtp_user'] or config['smtp_password']:
s.login(config['smtp_user'], config['smtp_password'])
s.sendmail(email_from, flatten([email_to, email_cc, email_bcc]), msg.as_string())
s.quit()
except Exception, e:
import logging
logging.getLogger().error(str(e))
return True
#----------------------------------------------------------
# Emails
#----------------------------------------------------------
def email_send_attach(email_from, email_to, subject, body, email_cc=None, email_bcc=None, on_error=False, reply_to=False, attach=None, tinycrm=False, ssl=False, debug=False):
"""Send an email."""
if not email_cc:
email_cc=[]
if not email_bcc:
email_bcc=[]
if not attach:
attach=[]
import smtplib
from email.MIMEText import MIMEText
from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
from email.Header import Header
from email.Utils import formatdate, COMMASPACE
from email import Encoders
msg = MIMEMultipart()
if not ssl:
ssl = config.get('smtp_ssl', False)
msg['Subject'] = Header(subject.decode('utf8'), 'utf-8')
msg['From'] = email_from
del msg['Reply-To']
if reply_to:
msg['Reply-To'] = reply_to
msg['To'] = COMMASPACE.join(email_to)
if email_cc:
msg['Cc'] = COMMASPACE.join(email_cc)
if email_bcc:
msg['Bcc'] = COMMASPACE.join(email_bcc)
if tinycrm:
msg['Message-Id'] = '<'+str(time.time())+'-tinycrm-'+str(tinycrm)+'@'+socket.gethostname()+'>'
msg['Date'] = formatdate(localtime=True)
msg.attach( MIMEText(body or '', _charset='utf-8', _subtype="html"))
for (fname,fcontent) in attach:
part = MIMEBase('application', "octet-stream")
part.set_payload( fcontent )
Encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="%s"' % (fname,))
msg.attach(part)
try:
s = smtplib.SMTP()
if debug:
s.debuglevel = 5
s.connect(config['smtp_server'], config['smtp_port'])
if ssl:
s.ehlo()
s.starttls()
s.ehlo()
if config['smtp_user'] or config['smtp_password']:
s.login(config['smtp_user'], config['smtp_password'])
s.sendmail(email_from, flatten([email_to, email_cc, email_bcc]), msg.as_string())
s.sendmail(email_from,
flatten([email_to, email_cc, email_bcc]),
msg.as_string()
)
s.quit()
except Exception, e:
import logging
logging.getLogger().error(str(e))
return False
return True
#----------------------------------------------------------
@@ -642,23 +602,34 @@ def to_xml(s):
def get_languages():
languages={
'zh_CN': 'Chinese (CN)',
'zh_TW': 'Chinese (TW)',
'cs_CZ': 'Czech',
'de_DE': 'Deutsch',
'es_AR': 'Español (Argentina)',
'es_ES': 'Español (España)',
'fr_FR': 'Français',
'fr_CH': 'Français (Suisse)',
'en_EN': 'English (default)',
'hu_HU': 'Hungarian',
'it_IT': 'Italiano',
'pt_BR': 'Portugese (Brasil)',
'pt_PT': 'Portugese (Portugal)',
'nl_NL': 'Nederlands',
'ro_RO': 'Romanian',
'ru_RU': 'Russian',
'sv_SE': 'Swedish',
'bg_BG': u'Bulgarian / български',
'ca_ES': u'Catalan / Català',
'cs_CZ': u'Czech / Čeština',
'de_DE': u'German / Deutsch',
'en_CA': u'English (CA)',
'en_EN': u'English (default)',
'en_GB': u'English (UK)',
'en_US': u'English (US)',
'es_AR': u'Spanish (AR) / Español (AR)',
'es_ES': u'Spanish / Español',
'et_ET': u'Estonian / Eesti keel',
'fr_BE': u'French (BE) / Français (BE)',
'fr_CH': u'French (CH) / Français (CH)',
'fr_FR': u'French / Français',
'hr_HR': u'Croatian / hrvatski jezik',
'hu_HU': u'Hungarian / Magyar',
'it_IT': u'Italian / Italiano',
'lt_LT': u'Lithuanian / Lietuvių kalba',
'nl_NL': u'Dutch / Nederlands',
'pt_BR': u'Portugese (BR) / português (BR)',
'pt_PT': u'Portugese / português',
'ro_RO': u'Romanian / limba română',
'ru_RU': u'Russian / русский язык',
'sl_SL': u'Slovenian / slovenščina',
'sv_SE': u'Swedish / svenska',
'uk_UK': u'Ukrainian / украї́нська мо́ва',
'zh_CN': u'Chinese (CN) / 简体中文' ,
'zh_TW': u'Chinese (TW) / 正體字',
}
return languages
@@ -666,7 +637,9 @@ def scan_languages():
import glob
file_list = [os.path.splitext(os.path.basename(f))[0] for f in glob.glob(os.path.join(config['root_path'],'addons', 'base', 'i18n', '*.po'))]
lang_dict = get_languages()
return [(lang, lang_dict.get(lang, lang)) for lang in file_list]
ret = [(lang, lang_dict.get(lang, lang)) for lang in file_list]
ret.sort(key=lambda k:k[1])
return ret
def get_user_companies(cr, user):
+5 -8
View File
@@ -100,18 +100,15 @@ class TinyPoFile(object):
else:
tmp_tnrs = []
line = None
while not line:
while (not line):
if 0 == len(self.lines):
raise StopIteration()
line = self.lines.pop(0).strip()
while line.startswith('#'):
if line.startswith('#:'):
if line.startswith('#:'):
tmp_tnrs.append( line[2:].strip().split(':') )
line = self.lines.pop(0).strip()
while not line:
# allow empty lines between comments and msgid
line = self.lines.pop(0).strip()
if line.startswith('#'):
line = None
if not line.startswith('msgid'):
raise Exception("malformed file: bad line: %s" % line)
source = unquote(line[6:])
+6
View File
@@ -96,6 +96,12 @@ def _execute(cr, workitem, activity, ident, stack):
if activity['kind']=='dummy':
if workitem['state']=='active':
_state_set(cr, workitem, activity, 'complete', ident)
if activity['action_id']:
print 'ICI'
res2 = wkf_expr.execute_action(cr, ident, workitem, activity)
if res2:
stack.append(res2)
result=res2
elif activity['kind']=='function':
if workitem['state']=='active':
_state_set(cr, workitem, activity, 'running', ident)
+16 -12
View File
@@ -35,7 +35,8 @@ import glob
from stat import ST_MODE
from distutils.core import setup, Command
from distutils.command.install_scripts import install_scripts
from distutils.command.install import install
#from distutils.command.install_scripts import install_scripts
from distutils.file_util import copy_file
if os.name == 'nt':
@@ -147,24 +148,26 @@ def data_files():
check_modules()
# create startup script
start_script = \
"#!/bin/sh\n\
cd %s/lib/python%s/site-packages/openerp-server\n\
exec %s ./openerp-server.py $@\n" % (sys.prefix, py_short_version, sys.executable)
# write script
f = open('openerp-server', 'w')
f.write(start_script)
f.close()
class openerp_server_install(install):
def run(self):
# create startup script
start_script = "#!/bin/sh\ncd %s\nexec %s ./openerp-server.py $@\n" % (opj(self.install_libbase, "openerp-server"), sys.executable)
# write script
f = open('openerp-server', 'w')
f.write(start_script)
f.close()
install.run(self)
options = {
"py2exe": {
"compressed": 0,
"compressed": 1,
"optimize": 2,
"packages": ["lxml", "lxml.builder", "lxml._elementpath", "lxml.etree",
"lxml.objectify", "decimal", "xml", "xml.dom", "xml.xpath",
"encodings","mx.DateTime","wizard","pychart","PIL", "pyparsing",
"pydot","asyncore","asynchat", "reportlab"],
"pydot","asyncore","asynchat", "reportlab", "vobject", "HTMLParser"],
"excludes" : ["Tkconstants","Tkinter","tcl"],
}
}
@@ -179,6 +182,7 @@ setup(name = name,
classifiers = filter(None, classifiers.split("\n")),
license = license,
data_files = data_files(),
cmdclass = { 'install' : openerp_server_install },
scripts = ['openerp-server'],
packages = ['openerp-server',
'openerp-server.addons',