[MERGE] sync with trunk

bzr revid: christophe@tinyerp.com-20090311142843-vtdmp16l3ijfhpy7
This commit is contained in:
Christophe Simonis 2009-03-11 15:28:43 +01:00
commit 59a6c48355
21 changed files with 306 additions and 232 deletions

View File

@ -1,3 +1,5 @@
./bin/addons/*
./bin/filestore*
*.pyc
.*.swp
.bzrignore
bin/addons/*
bin/filestore*

View File

@ -23,7 +23,6 @@
import os, sys, imp
from os.path import join as opj
import itertools
from sets import Set
import zipimport
import osv
@ -69,20 +68,56 @@ class Graph(dict):
father.addChild(name)
else:
Node(name, self)
def update_from_db(self, cr):
# update the graph with values from the database (if exist)
## First, we set the default values for each package in graph
additional_data = dict.fromkeys(self.keys(), {'id': 0, 'state': 'uninstalled', 'dbdemo': False, 'installed_version': None})
## Then we get the values from the database
cr.execute('SELECT name, id, state, demo AS dbdemo, latest_version AS installed_version'
' FROM ir_module_module'
' WHERE name in (%s)' % (','.join(['%s'] * len(self))),
additional_data.keys()
)
## and we update the default values with values from the database
additional_data.update(dict([(x.pop('name'), x) for x in cr.dictfetchall()]))
for package in self.values():
for k, v in additional_data[package.name].items():
setattr(package, k, v)
def __iter__(self):
level = 0
done = Set(self.keys())
while done:
level_modules = [(name, module) for name, module in self.items() if module.depth==level]
for name, module in level_modules:
done.remove(name)
yield module
level += 1
done = set()
# first pass: all modules that doesn't have a depend module (or
# themself) in 'to install' state.
first_pass = []
for name, mod in self.items():
if all(m.state != 'to install' for m in mod.depends(True)):
first_pass.append(mod)
first_pass.sort(key=lambda m: m.depth)
for m in first_pass:
done.add(m.name)
yield m
# second pass: all modules in 'to install' state
second_pass = [m for m in self.values() if m.state == 'to install']
second_pass.sort(key=lambda m: m.depth)
for m in second_pass:
done.add(m.name)
yield m
# third pass: all other modules
third_pass = [m for m in self.values() if m.name not in done]
third_pass.sort(key=lambda m: m.depth)
for m in third_pass:
yield m
class Singleton(object):
def __new__(cls, name, graph):
if name in graph:
inst = graph[name]
@ -97,57 +132,70 @@ class Node(Singleton):
def __init__(self, name, graph):
self.graph = graph
if not hasattr(self, 'childs'):
self.childs = []
if not hasattr(self, 'children'):
self.children = []
if not hasattr(self, 'depth'):
self.depth = 0
def addChild(self, name):
node = Node(name, self.graph)
node.depth = self.depth + 1
if node not in self.childs:
self.childs.append(node)
if node not in self.children:
self.children.append(node)
for attr in ('init', 'update', 'demo'):
if hasattr(self, attr):
setattr(node, attr, True)
self.childs.sort(lambda x, y: cmp(x.name, y.name))
def hasChild(self, name):
return Node(name, self.graph) in self.childs or \
bool([c for c in self.childs if c.hasChild(name)])
self.children.sort(lambda x, y: cmp(x.name, y.name))
def __setattr__(self, name, value):
super(Singleton, self).__setattr__(name, value)
if name in ('init', 'update', 'demo'):
tools.config[name][self.name] = 1
for child in self.childs:
for child in self.children:
setattr(child, name, value)
if name == 'depth':
for child in self.childs:
for child in self.children:
setattr(child, name, value + 1)
def __iter__(self):
return itertools.chain(iter(self.childs), *map(iter, self.childs))
return itertools.chain(iter(self.children), *map(iter, self.children))
def _depends(self):
"""direct depends"""
return list(self.data.get('depends', []))
def depends(self, include_self=False):
deps = self._depends()
res = set()
if include_self:
res.add(self)
while deps:
dep = Node(deps.pop(0), self.graph)
res.add(dep)
for d in dep._depends():
if d not in res:
deps.append(d)
return res
def __str__(self):
return self._pprint()
def _pprint(self, depth=0):
s = '%s\n' % self.name
for c in self.childs:
for c in self.children:
s += '%s`-> %s' % (' ' * depth, c._pprint(depth+1))
return s
def get_module_path(module):
def get_module_path(module, downloaded=False):
"""Return the path of the given module."""
if os.path.exists(opj(ad, module)) or os.path.exists(opj(ad, '%s.zip' % module)):
return opj(ad, module)
if os.path.exists(opj(_ad, module)) or os.path.exists(opj(_ad, '%s.zip' % module)):
return opj(_ad, module)
if downloaded:
return opj(_ad, module)
logger.notifyChannel('init', netsvc.LOG_WARNING, 'module %s: module not found' % (module,))
return False
@ -311,7 +359,7 @@ def upgrade_graph(graph, cr, module_list, force=None):
packages.append((module, info.get('depends', []), info))
dependencies = dict([(p, deps) for p, deps, data in packages])
current, later = Set([p for p, dep, data in packages]), Set()
current, later = set([p for p, dep, data in packages]), set()
while packages and current > later:
package, deps, data = packages[0]
@ -333,6 +381,8 @@ def upgrade_graph(graph, cr, module_list, force=None):
packages.append((package, deps, data))
packages.pop(0)
graph.update_from_db(cr)
for package in later:
unmet_deps = filter(lambda p: p not in graph, dependencies[package])
logger.notifyChannel('init', netsvc.LOG_ERROR, 'module %s: Unmet dependencies: %s' % (package, ', '.join(unmet_deps)))
@ -551,24 +601,6 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs):
statusi = 0
pool = pooler.get_pool(cr.dbname)
# update the graph with values from the database (if exist)
## First, we set the default values for each package in graph
additional_data = dict.fromkeys([p.name for p in graph], {'id': 0, 'state': 'uninstalled', 'dbdemo': False, 'installed_version': None})
## Then we get the values from the database
cr.execute('SELECT name, id, state, demo AS dbdemo, latest_version AS installed_version'
' FROM ir_module_module'
' WHERE name in (%s)' % (','.join(['%s'] * len(graph))),
additional_data.keys()
)
## and we update the default values with values from the database
additional_data.update(dict([(x.pop('name'), x) for x in cr.dictfetchall()]))
for package in graph:
for k, v in additional_data[package.name].items():
setattr(package, k, v)
migrations = MigrationManager(cr, graph)
has_updates = False
@ -603,9 +635,6 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs):
init_module_objects(cr, m, modules)
for kind in ('init', 'update'):
for filename in package.data.get('%s_xml' % kind, []):
# mode = 'update'
# if hasattr(package, 'init') or package.state == 'to install':
# mode = 'init'
logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading %s' % (m, filename))
name, ext = os.path.splitext(filename)
fp = tools.file_open(opj(m, filename))
@ -650,9 +679,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs):
if hasattr(package, kind):
delattr(package, kind)
statusi += 1
cr.execute('select model from ir_model where state=%s', ('manual',))
for model in cr.dictfetchall():
@ -748,7 +775,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
cr.execute('delete from ir_model_data where noupdate=%s and module=%s', (False, mod_name,))
cr.commit()
#
# TODO: remove menu without actions of childs
# TODO: remove menu without actions of children
#
while True:
cr.execute('''delete from
@ -772,4 +799,3 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -11,7 +11,7 @@ create table ir_values
id serial,
name varchar(128) not null,
key varchar(128) not null,
key2 varchar(128) not null,
key2 varchar(256) not null,
model varchar(128) not null,
value text,
meta text default NULL,
@ -55,7 +55,7 @@ CREATE TABLE ir_model_fields (
CREATE TABLE ir_actions (
id serial NOT NULL,
name varchar(64) DEFAULT ''::varchar NOT NULL,
"type" varchar(64) DEFAULT 'window'::varchar NOT NULL,
"type" varchar(32) DEFAULT 'window'::varchar NOT NULL,
usage varchar(32) DEFAULT null,
primary key(id)
);
@ -64,7 +64,7 @@ CREATE TABLE ir_act_window (
view_id integer,
res_model varchar(64),
view_type varchar(16),
"domain" varchar(127),
"domain" varchar(250),
primary key(id)
)
INHERITS (ir_actions);
@ -72,8 +72,8 @@ INHERITS (ir_actions);
CREATE TABLE ir_act_report_xml (
model varchar(64) NOT NULL,
report_name varchar(64) NOT NULL,
report_xsl varchar(64),
report_xml varchar(64),
report_xsl varchar(256),
report_xml varchar(256),
auto boolean default true,
primary key(id)
)
@ -140,7 +140,7 @@ CREATE TABLE res_users (
name varchar(64) not null,
active boolean default True,
login varchar(64) NOT NULL UNIQUE,
password varchar(32) default null,
password varchar(64) default null,
context_tz varchar(64) default null,
signature text,
-- action_id int references ir_act_window on delete set null,
@ -151,14 +151,14 @@ alter table res_users add constraint res_users_login_uniq unique (login);
CREATE TABLE res_groups (
id serial NOT NULL,
name varchar(32) NOT NULL,
name varchar(64) NOT NULL,
primary key(id)
);
create table res_roles (
id serial NOT NULL,
parent_id int references res_roles on delete set null,
name varchar(32) NOT NULL,
name varchar(64) NOT NULL,
primary key(id)
);

View File

@ -2748,7 +2748,6 @@
<field name="code">COP</field>
<field name="rounding">0.01</field>
<field name="accuracy">4</field>
<field eval="False" name="active"/>
</record>
<record id="CZK" model="res.currency">
@ -2756,7 +2755,6 @@
<field name="code">CZK</field>
<field name="rounding">0.01</field>
<field name="accuracy">4</field>
<field eval="False" name="active"/>
</record>
<record id="DKK" model="res.currency">
@ -2777,7 +2775,6 @@
<field name="code">HUF</field>
<field name="rounding">0.01</field>
<field name="accuracy">4</field>
<field eval="False" name="active"/>
</record>
<record id="IDR" model="res.currency">
@ -2785,7 +2782,6 @@
<field name="code">IDR</field>
<field name="rounding">0.01</field>
<field name="accuracy">4</field>
<field eval="False" name="active"/>
</record>
<record id="LVL" model="res.currency">
@ -2832,7 +2828,6 @@
<field name="code">PLN</field>
<field name="rounding">0.01</field>
<field name="accuracy">4</field>
<field eval="False" name="active"/>
</record>
<record id="SEK" model="res.currency">
@ -2840,7 +2835,6 @@
<field name="code">SEK</field>
<field name="rounding">0.01</field>
<field name="accuracy">4</field>
<field eval="False" name="active"/>
</record>
<record id="GBP" model="res.currency">
@ -2860,9 +2854,20 @@
<field name="code">ARS</field>
<field name="rounding">0.01</field>
<field name="accuracy">4</field>
<field eval="False" name="active"/>
</record>
<record id="INR" model="res.currency">
<field name="name">INR</field>
<field name="code">Rs</field>
<field name="rounding">0.01</field>
<field name="accuracy">4</field>
</record>
<record id="rateINR" model="res.currency.rate">
<field name="rate">0.634</field>
<field name="currency_id" ref="INR"/>
<field eval="time.strftime('%Y-01-01')" name="name"/>
</record>
<!-- Basic Company -->
<record id="main_company" model="res.company">
<field name="name">Tiny sprl</field>

View File

@ -77,45 +77,45 @@ class ir_cron(osv.osv, netsvc.Agent):
def _poolJobs(self, db_name, check=False):
try:
db, pool = pooler.get_db_and_pool(db_name)
if pool._init:
# retry in a few minutes
self.setAlarm(self._poolJobs, int(time.time())+10*60, [db_name])
cr = db.cursor()
except:
return False
now = DateTime.now()
#FIXME: multidb. Solution: a l'instanciation d'une nouvelle connection bd (ds pooler) fo que j'instancie
# un nouveau pooljob avec comme parametre la bd
try:
cr.execute('select * from ir_cron where numbercall<>0 and active and nextcall<=now() order by priority')
for job in cr.dictfetchall():
nextcall = DateTime.strptime(job['nextcall'], '%Y-%m-%d %H:%M:%S')
numbercall = job['numbercall']
if pool._init:
# retry in a few minutes
next_call = 600
else:
next_call = next_wait
cr = db.cursor()
now = DateTime.now()
try:
cr.execute('select * from ir_cron where numbercall<>0 and active and nextcall<=now() order by priority')
for job in cr.dictfetchall():
nextcall = DateTime.strptime(job['nextcall'], '%Y-%m-%d %H:%M:%S')
numbercall = job['numbercall']
ok = False
while nextcall<now and numbercall:
if numbercall > 0:
numbercall -= 1
if not ok or job['doall']:
self._callback(cr, job['user_id'], job['model'], job['function'], job['args'])
if numbercall:
nextcall += _intervalTypes[job['interval_type']](job['interval_number'])
ok = True
addsql=''
if not numbercall:
addsql = ', active=False'
cr.execute("update ir_cron set nextcall=%s, numbercall=%s"+addsql+" where id=%s", (nextcall.strftime('%Y-%m-%d %H:%M:%S'), numbercall, job['id']))
cr.commit()
finally:
cr.close()
ok = False
while nextcall < now and numbercall:
if numbercall > 0:
numbercall -= 1
if not ok or job['doall']:
self._callback(cr, job['user_id'], job['model'], job['function'], job['args'])
if numbercall:
nextcall += _intervalTypes[job['interval_type']](job['interval_number'])
ok = True
addsql=''
if not numbercall:
addsql = ', active=False'
cr.execute("update ir_cron set nextcall=%s, numbercall=%s"+addsql+" where id=%s", (nextcall.strftime('%Y-%m-%d %H:%M:%S'), numbercall, job['id']))
cr.commit()
finally:
cr.close()
#
# Can be improved to do at the min(min(nextcalls), time()+next_wait)
# Can be improved to do at the min(min(nextcalls), time()+next_call)
# But is this an improvement ?
#
if not check:
self.setAlarm(self._poolJobs, int(time.time())+next_wait, [db_name])
self.setAlarm(self._poolJobs, int(time.time()) + next_call, db_name, db_name)
ir_cron()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -437,14 +437,16 @@ class ir_model_data(osv.osv):
if (not xml_id) and (not self.doinit):
return False
action_id = False
if xml_id:
cr.execute('select id,res_id from ir_model_data where module=%s and name=%s', (module,xml_id))
results = cr.fetchall()
for action_id2,res_id2 in results:
cr.execute('select id from '+self.pool.get(model)._table+' where id=%s', (res_id2,))
cr.execute('select id from '+model_obj._table+' where id=%s', (res_id2,))
result3 = cr.fetchone()
if not result3:
cr.execute('delete from ir_model_data where id=%s', (action_id2,))
res_id = False
else:
res_id,action_id = res_id2,action_id2
@ -512,7 +514,7 @@ class ir_model_data(osv.osv):
#self.pool.get(model).unlink(cr, uid, ids)
for id in ids:
self.unlink_mark[(model, id)]=False
cr.execute('delete from ir_model_data where res_id=%s and model=\'%s\'', (id,model))
cr.execute('delete from ir_model_data where res_id=%s and model=%s', (id, model))
return True
def ir_set(self, cr, uid, key, key2, name, models, value, replace=True, isobject=False, meta=None, xml_id=False):
@ -563,18 +565,20 @@ class ir_model_data(osv.osv):
cr.commit()
if not config.get('import_partial', False):
for (model,id) in self.unlink_mark.keys():
logger = netsvc.Logger()
for (model, res_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))
logger.notifyChannel('init', netsvc.LOG_INFO, 'Deleting %s@%s' % (res_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),))
self.pool.get(model).unlink(cr, uid, [res_id])
id = self.unlink_mark[(model, res_id)]
if id:
self.unlink(cr, uid, [id])
cr.execute('DELETE FROM ir_values WHERE value=%s', ('%s,%s' % (model, res_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))
cr.rollback()
logger.notifyChannel('init', netsvc.LOG_ERROR, 'Could not delete id: %d of model %s\nThere should be some relation that points to this resource\nYou should manually fix this and restart --update=module' % (res_id, model))
return True
ir_model_data()

View File

@ -57,6 +57,7 @@ class view(osv.osv):
'type': fields.selection((
('tree','Tree'),
('form','Form'),
('mdx','mdx'),
('graph', 'Graph'),
('calendar', 'Calendar'),
('gantt', 'Gantt')), 'View Type', required=True),

View File

@ -398,12 +398,12 @@ class module(osv.osv):
if not download:
continue
zipfile = urllib.urlopen(mod.url).read()
fname = addons.get_module_path(mod.name+'.zip')
fname = addons.get_module_path(str(mod.name)+'.zip', downloaded=True)
try:
fp = file(fname, 'wb')
fp.write(zipfile)
fp.close()
except IOError, e:
except Exception, e:
raise orm.except_orm(_('Error'), _('Can not create the module file:\n %s') % (fname,))
terp = self.get_module_info(mod.name)
self.write(cr, uid, mod.id, {

View File

@ -163,10 +163,6 @@ class res_partner(osv.osv):
'customer': lambda *a: 1,
'category_id': _default_category,
}
_sql_constraints = [
('name_uniq', 'unique (name)', 'The name of the partner must be unique !')
]
def copy(self, cr, uid, id, default=None, context={}):
name = self.read(cr, uid, [id], ['name'])[0]['name']
default.update({'name': name+' (copy)'})

View File

@ -30,7 +30,7 @@ email_send_form = '''<?xml version="1.0"?>
<newline/>
<field name="subject"/>
<newline/>
<field name="text"/>
<field name="text" widget="text_html"/>
</form>'''
email_send_fields = {

View File

@ -191,15 +191,7 @@
<rng:optional><rng:attribute name="position"/></rng:optional>
<rng:zeroOrMore>
<rng:choice>
<rng:ref name="notebook" />
<rng:ref name="graph" />
<rng:ref name="calendar" />
<rng:ref name="gantt" />
<rng:ref name="form"/>
<rng:ref name="tree"/>
<rng:ref name="field"/>
<rng:ref name="separator"/>
<rng:ref name="page"/>
<rng:ref name="any"/>
</rng:choice>
</rng:zeroOrMore>
</rng:element>

View File

@ -141,6 +141,14 @@
</rng:element>
</rng:define>
<rng:define name="delete">
<rng:element name="delete">
<rng:attribute name="model" />
<rng:optional><rng:attribute name="id" /> </rng:optional>
<rng:optional><rng:attribute name="search" /></rng:optional>
</rng:element>
</rng:define>
<rng:define name="ir_set">
<rng:element name="ir_set">
<rng:oneOrMore>
@ -194,6 +202,7 @@
<rng:text/>
<rng:ref name="menuitem" />
<rng:ref name="record" />
<rng:ref name="delete" />
<rng:ref name="wizard" />
<rng:ref name="act_window" />
<rng:ref name="assert" />

View File

@ -182,29 +182,33 @@ import tools
init_logger()
class Agent(object):
_timers = []
_timers = {}
_logger = Logger()
def setAlarm(self, fn, dt, args=None, kwargs=None):
if not args:
args = []
if not kwargs:
kwargs = {}
def setAlarm(self, fn, dt, db_name, *args, **kwargs):
wait = dt - time.time()
if wait > 0:
self._logger.notifyChannel('timers', LOG_DEBUG, "Job scheduled in %s seconds for %s.%s" % (wait, fn.im_class.__name__, fn.func_name))
timer = threading.Timer(wait, fn, args, kwargs)
timer.start()
self._timers.append(timer)
for timer in self._timers[:]:
if not timer.isAlive():
self._timers.remove(timer)
self._timers.setdefault(db_name, []).append(timer)
for db in self._timers:
for timer in self._timers[db]:
if not timer.isAlive():
self._timers[db].remove(timer)
@classmethod
def cancel(cls, db_name):
"""Cancel all timers for a given database. If None passed, all timers are cancelled"""
for db in cls._timers:
if db_name is None or db == db_name:
for timer in cls._timers[db]:
timer.cancel()
@classmethod
def quit(cls):
for timer in cls._timers:
timer.cancel()
quit = classmethod(quit)
cls.cancel(None)
import traceback

View File

@ -308,11 +308,9 @@ class many2one(_column):
names = dict(obj.name_get(cr, user, filter(None, res.values()), context))
except except_orm:
names = {}
iids = filter(None, res.values())
cr.execute('select id,'+obj._rec_name+' from '+obj._table+' where id in ('+','.join(map(str, iids))+')')
for res22 in cr.fetchall():
names[res22[0]] = res22[1]
for iiid in iids:
names[iiid] = '// Access Denied //'
for r in res.keys():
if res[r] and res[r] in names:
@ -626,7 +624,7 @@ class function(_column):
if self._type == 'binary' and context.get('bin_size', False):
# convert the data returned by the function with the size of that data...
res = dict(map(lambda (x, y): (x, tools.human_size(len(y))), res.items()))
res = dict(map(lambda (x, y): (x, tools.human_size(len(y or ''))), res.items()))
return res
def set(self, cr, obj, id, name, value, user=None, context=None):

View File

@ -61,7 +61,7 @@ except ImportError:
from tools.config import config
regex_order = re.compile('^([a-zA-Z0-9_]+( desc)?( asc)?,?)+$', re.I)
regex_order = re.compile('^([a-z0-9_]+( *desc| *asc)?( *, *|))+$', re.I)
def last_day_of_current_month():
import datetime
@ -465,7 +465,7 @@ class orm_template(object):
datas += self.__export_row(cr, uid, row, fields, context)
return datas
def import_data(self, cr, uid, fields, datas, mode='init', current_module=None, noupdate=False, context=None, filename=None):
def import_data(self, cr, uid, fields, datas, mode='init', current_module='', noupdate=False, context=None, filename=None):
if not context:
context = {}
fields = map(lambda x: x.split('/'), fields)
@ -872,7 +872,7 @@ class orm_template(object):
rolesobj = self.pool.get('res.roles')
usersobj = self.pool.get('res.users')
buttons = xpath.Evaluate("//button[@type != 'object']", node)
buttons = (n for n in node.getElementsByTagName('button') if n.getAttribute('type') != 'object')
for button in buttons:
ok = True
if user != 1: # admin user has all roles
@ -1773,7 +1773,7 @@ class orm(orm_template):
import random
_rel1 = field['relation'].replace('.', '_')
_rel2 = field['model'].replace('.', '_')
_rel_name = 'x_%s_%s_%s_rel' %(_rel1, _rel2, random.randint(0, 10000))
_rel_name = 'x_%s_%s_%s_rel' %(_rel1, _rel2, field['name'])
self._columns[field['name']] = getattr(fields, field['ttype'])(field['relation'], _rel_name, 'id1', 'id2', **attrs)
else:
self._columns[field['name']] = getattr(fields, field['ttype'])(**attrs)
@ -2130,10 +2130,11 @@ class orm(orm_template):
for order, object, ids, fields in result_store:
if object<>self._name:
cr.execute('select id from '+self._table+' where id in ('+','.join(map(str, ids))+')')
obj = self.pool.get(object)
cr.execute('select id from '+obj._table+' where id in ('+','.join(map(str, ids))+')')
ids = map(lambda x: x[0], cr.fetchall())
if ids:
self.pool.get(object)._store_set_values(cr, uid, ids, fields, context)
obj._store_set_values(cr, uid, ids, fields, context)
return True
#
@ -2285,60 +2286,42 @@ class orm(orm_template):
self.pool._init_parent[self._name]=True
else:
for id in ids:
# Find Position of the element
if vals[self._parent_name]:
cr.execute('select parent_left,parent_right,id from '+self._table+' where '+self._parent_name+'=%s order by '+(self._parent_order or self._order), (vals[self._parent_name],))
pleft_old = pright_old = None
result_p = cr.fetchall()
for (pleft,pright,pid) in result_p:
if pid == id:
break
pleft_old = pleft
pright_old = pright
if not pleft_old:
cr.execute('select parent_left,parent_right from '+self._table+' where id=%s', (vals[self._parent_name],))
pleft_old,pright_old = cr.fetchone()
res = (pleft_old, pright_old)
else:
cr.execute('SELECT parent_left,parent_right FROM '+self._table+' WHERE id IS NULL')
res = cr.fetchone()
if res:
pleft,pright = res
else:
cr.execute('select max(parent_right),max(parent_right)+1 from '+self._table)
pleft,pright = cr.fetchone()
cr.execute('select parent_left,parent_right,id from '+self._table+' where id in ('+','.join(map(lambda x:'%s',ids))+')', ids)
dest = pleft + 1
for cleft,cright,cid in cr.fetchall():
if cleft > pleft:
treeshift = pleft - cleft + 1
leftbound = pleft+1
rightbound = cleft-1
cwidth = cright-cleft+1
leftrange = cright
rightrange = pleft
cr.execute('select parent_left,parent_right,id from '+self._table+' where '+self._parent_name+' is null order by '+(self._parent_order or self._order))
result_p = cr.fetchall()
position = None
for (pleft,pright,pid) in result_p:
if pid == id:
break
position = pright+1
# It's the first node of the parent: position = parent_left+1
if not position:
if not vals[self._parent_name]:
position = 1
else:
treeshift = pleft - cright
leftbound = cright + 1
rightbound = pleft
cwidth = cleft-cright-1
leftrange = pleft+1
rightrange = cleft
cr.execute('UPDATE '+self._table+'''
SET
parent_left = CASE
WHEN parent_left BETWEEN %s AND %s THEN parent_left + %s
WHEN parent_left BETWEEN %s AND %s THEN parent_left + %s
ELSE parent_left
END,
parent_right = CASE
WHEN parent_right BETWEEN %s AND %s THEN parent_right + %s
WHEN parent_right BETWEEN %s AND %s THEN parent_right + %s
ELSE parent_right
END
WHERE
parent_left<%s OR parent_right>%s;
''', (leftbound,rightbound,cwidth,cleft,cright,treeshift,leftbound,rightbound,
cwidth,cleft,cright,treeshift,leftrange,rightrange))
cr.execute('select parent_left from '+self._table+' where id=%s', (vals[self._parent_name],))
position = cr.fetchone()[0]+1
# We have the new position !
cr.execute('select parent_left,parent_right from '+self._table+' where id=%s', (id,))
pleft,pright = cr.fetchone()
distance = pright - pleft + 1
if position>pleft and position<=pright:
raise except_orm(_('UserError'), _('Recursivity Detected.'))
if pleft<position:
cr.execute('update '+self._table+' set parent_left=parent_left+%s where parent_left>=%s', (distance, position))
cr.execute('update '+self._table+' set parent_right=parent_right+%s where parent_right>=%s', (distance, position))
cr.execute('update '+self._table+' set parent_left=parent_left+%s, parent_right=parent_right+%s where parent_left>=%s and parent_left<%s', (position-pleft,position-pleft, pleft, pright))
else:
cr.execute('update '+self._table+' set parent_left=parent_left+%s where parent_left>=%s', (distance, position))
cr.execute('update '+self._table+' set parent_right=parent_right+%s where parent_right>=%s', (distance, position))
cr.execute('update '+self._table+' set parent_left=parent_left-%s, parent_right=parent_right-%s where parent_left>=%s and parent_left<%s', (pleft-position+distance,pleft-position+distance, pleft+distance, pright+distance))
result = self._store_get_values(cr, user, ids, vals.keys(), context)
for order, object, ids, fields in result:

View File

@ -57,6 +57,7 @@ def get_db_and_pool(db_name, force_demo=False, status=None, update_module=False)
def restart_pool(db_name, force_demo=False, status=None, update_module=False):
if db_name in pool_dic:
pool_dic[db_name].get('ir.cron').cancel(db_name)
del pool_dic[db_name]
return get_db_and_pool(db_name, force_demo, status, update_module=update_module)

View File

@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
@ -94,7 +94,6 @@ class _flowable(object):
if node.hasAttribute('style'):
node.setAttribute('class', node.getAttribute('style'))
return node.toxml()
def render(self, node):
result = self.template.start()
result += self.template.frame_start()
@ -107,8 +106,7 @@ class _flowable(object):
#print 'tag', n.localName, 'not yet implemented!'
result += self.template.frame_stop()
result += self.template.end()
return result
return result.encode('utf-8').replace('"',"\'").replace('°','&deg;')
class _rml_tmpl_tag(object):
def __init__(self, *args):
pass
@ -126,7 +124,7 @@ class _rml_tmpl_frame(_rml_tmpl_tag):
self.width = width
self.posx = posx
def tag_start(self):
return '<table border="0" width="%d"><tr><td width="%d">&nbsp;</td><td>' % (self.width+self.posx,self.posx)
return "<table border=\'0\' width=\'%d\'><tr><td width=\'%d\'>&nbsp;</td><td>" % (self.width+self.posx,self.posx)
def tag_end(self):
return True
def tag_stop(self):
@ -152,19 +150,19 @@ class _rml_tmpl_draw_string(_rml_tmpl_tag):
def tag_start(self):
self.pos.sort()
res = '<table border="0" cellpadding="0" cellspacing="0"><tr>'
res = "<table border='0' cellpadding='0' cellspacing='0'><tr>"
posx = 0
i = 0
for (x,y,align,txt, style, fs) in self.pos:
if align=="left":
pos2 = len(txt)*fs
res+='<td width="%d"></td><td style="%s" width="%d">%s</td>' % (x - posx, style, pos2, txt)
res+="<td width=\'%d\'></td><td style=\'%s\' width=\'%d\'>%s</td>" % (x - posx, style, pos2, txt)
posx = x+pos2
if align=="right":
res+='<td width="%d" align="right" style="%s">%s</td>' % (x - posx, style, txt)
res+="<td width=\'%d\' align=\'right\' style=\'%s\'>%s</td>" % (x - posx, style, txt)
posx = x
if align=="center":
res+='<td width="%d" align="center" style="%s">%s</td>' % ((x - posx)*2, style, txt)
res+="<td width=\'%d\' align=\'center\' style=\'%s\'>%s</td>" % ((x - posx)*2, style, txt)
posx = 2*x-posx
i+=1
res+='</tr></table>'
@ -185,7 +183,7 @@ class _rml_tmpl_draw_lines(_rml_tmpl_tag):
def tag_start(self):
if self.ok:
return '<table border="0" cellpadding="0" cellspacing="0" width="%d"><tr><td width="%d"></td><td><hr width="100%%" style="margin:0px; %s"></td></tr></table>' % (self.posx+self.width,self.posx,self.style)
return "<table border=\'0\' cellpadding=\'0\' cellspacing=\'0\' width=\'%d\'><tr><td width=\'%d\'></td><td><hr width=\'100%%\' style=\'margin:0px; %s\'></td></tr></table>" % (self.posx+self.width,self.posx,self.style)
else:
return ''
@ -207,9 +205,9 @@ class _rml_stylesheet(object):
attrs = []
for a in attr:
if a in self._tags:
attrs.append("%s:%s" % self._tags[a](attr[a]))
attrs.append('%s:%s' % self._tags[a](attr[a]))
if len(attrs):
result += "p."+attr['name']+" {"+'; '.join(attrs)+"}\n"
result += 'p.'+attr['name']+' {'+'; '.join(attrs)+'}\n'
self.result = result
def render(self):
@ -338,6 +336,7 @@ class _rml_doc(object):
self.result += '''<!DOCTYPE HTML PUBLIC "-//w3c//DTD HTML 4.0 Frameset//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
p {margin:0px; font-size:12px;}
td {font-size:14px;}
@ -347,14 +346,50 @@ class _rml_doc(object):
self.result += s.render()
self.result+='''
</style>
</head>
<body>'''
'''
template = _rml_template(self.dom.documentElement.getElementsByTagName('template')[0])
f = _flowable(template, self.dom)
self.result += f.render(self.dom.documentElement.getElementsByTagName('story')[0])
# f = _flowable(template, self.dom)
list_story =[]
storys= self.dom.documentElement.getElementsByTagName('story')
for story in storys :
template = _rml_template(self.dom.documentElement.getElementsByTagName('template')[0])
f = _flowable(template, self.dom)
story_text = f.render(story)
list_story.append(story_text)
del f
self.result += '</body></html>'
self.result +='''
<script type="text/javascript">
var indexer = 0;
var aryTest = %s ;
function nextData()
{
if(indexer < aryTest.length -1)
{
indexer += 1;
document.getElementById("tiny_data").innerHTML=aryTest[indexer];
}
}
function prevData()
{
if (indexer > 0)
{
indexer -= 1;
document.getElementById("tiny_data").innerHTML=aryTest[indexer];
}
}
</script>
</head>
<body>
<div id="tiny_data">
%s
</div>
<br>
<input type="button" value="next" onclick="nextData();">
<input type="button" value="prev" onclick="prevData();">
</body></html>'''%(list_story,list_story[0])
out.write( self.result)
def parseString(data, fout=None):
@ -383,5 +418,4 @@ if __name__=="__main__":
print 'Usage: trml2pdf input.rml >output.pdf'
print 'Try \'trml2pdf --help\' for more information.'
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -519,7 +519,7 @@ class rml_parse(object):
if not self.logo and rml_head.find('company.logo')>=0:
rml_head = rml_head.replace('<image','<!--image')
rml_head = rml_head.replace('</image>','</image-->')
head_dom = xml.dom.minidom.parseString(rml_head.encode('utf-8'))
#for frame in head_dom.getElementsByTagName('frame'):
# frame.parentNode.removeChild(frame)

View File

@ -40,11 +40,10 @@ def check_super(passwd):
return True
else:
raise Exception('AccessDenied')
def check(db, uid, passwd):
if _uid_cache.get(db, {}).get(uid) == passwd:
return True
cr = pooler.get_db(db).cursor()
cr.execute('select count(*) from res_users where id=%s and password=%s', (int(uid), passwd))
res = cr.fetchone()[0]

View File

@ -356,6 +356,7 @@ class configmanager(object):
os.makedirs(os.path.dirname(self.rcfile))
try:
p.write(file(self.rcfile, 'w'))
os.chmod(self.rcfile, 0600)
except IOError:
sys.stderr.write("ERROR: couldn't write the config file\n")

View File

@ -302,7 +302,8 @@ def reverse_enumerate(l):
#----------------------------------------------------------
# Emails
#----------------------------------------------------------
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'):
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', x_headers=None):
"""Send an email."""
import smtplib
from email.MIMEText import MIMEText
@ -313,9 +314,15 @@ def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=Non
from email.Utils import formatdate, COMMASPACE
from email import Encoders
if x_headers is None:
x_headers = {}
if not ssl:
ssl = config.get('smtp_ssl', False)
if not email_from and not config['email_from']:
raise Exception("No Email sender by default, see config file")
if not email_cc:
email_cc = []
if not email_bcc:
@ -326,11 +333,13 @@ def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=Non
else:
msg = MIMEMultipart()
msg['Subject'] = Header(subject.decode('utf8'), 'utf-8')
msg['Subject'] = Header(ustr(subject), 'utf-8')
msg['From'] = email_from
del msg['Reply-To']
if reply_to:
msg['Reply-To'] = msg['From']+', '+reply_to
msg['Reply-To'] = reply_to
else:
msg['Reply-To'] = msg['From']
msg['To'] = COMMASPACE.join(email_to)
if email_cc:
msg['Cc'] = COMMASPACE.join(email_cc)
@ -338,6 +347,15 @@ def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=Non
msg['Bcc'] = COMMASPACE.join(email_bcc)
msg['Date'] = formatdate(localtime=True)
# Add OpenERP Server information
msg['X-Generated-By'] = 'OpenERP (http://www.openerp.com)'
msg['X-OpenERP-Server-Host'] = socket.gethostname()
msg['X-OpenERP-Server-Version'] = release.version
# Add dynamic X Header
for key, value in x_headers.items():
msg['X-OpenERP-%s' % key] = str(value)
if tinycrm:
msg['Message-Id'] = "<%s-tinycrm-%s@%s>" % (time.time(), tinycrm, socket.gethostname())
@ -381,9 +399,10 @@ def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=Non
# text must be latin-1 encoded
def sms_send(user, password, api_id, text, to):
import urllib
params = urllib.urlencode({'user': user, 'password': password, 'api_id': api_id, 'text': text, 'to':to})
#f = urllib.urlopen("http://api.clickatell.com/http/sendmsg", params)
f = urllib.urlopen("http://196.7.150.220/http/sendmsg", params)
url = "http://api.urlsms.com/SendSMS.aspx"
#url = "http://196.7.150.220/http/sendmsg"
params = urllib.urlencode({'UserID': user, 'Password': password, 'SenderID': api_id, 'MsgText': text, 'RecipientMobileNo':to})
f = urllib.urlopen(url+"?"+params)
# FIXME: Use the logger if there is an error
return True