diff --git a/bin/addons/__init__.py b/bin/addons/__init__.py
index 8d630b267b1..fcc60ca1809 100644
--- a/bin/addons/__init__.py
+++ b/bin/addons/__init__.py
@@ -275,12 +275,14 @@ def get_modules():
def create_graph(module_list, force=None):
graph = Graph()
- return upgrade_graph(graph, module_list, force)
+ upgrade_graph(graph, module_list, force)
+ return graph
def upgrade_graph(graph, module_list, force=None):
if force is None:
force = []
packages = []
+ len_graph = len(graph)
for module in module_list:
try:
mod_path = get_module_path(module)
@@ -326,8 +328,11 @@ def upgrade_graph(graph, module_list, force=None):
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)))
-
- return graph
+
+ result = len(graph) - len_graph
+ if result != len(module_list):
+ logger.notifyChannel('init', netsvc.LOG_WARNING, 'Not all modules have loaded.')
+ return result
def init_module_objects(cr, module_name, obj_list):
@@ -682,14 +687,23 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
STATES_TO_LOAD += ['to install']
+ loop_guardrail = 0
while True:
+ loop_guardrail += 1
+ if loop_guardrail > 100:
+ raise ProgrammingError()
cr.execute("SELECT name from ir_module_module WHERE state in (%s)" % ','.join(['%s']*len(STATES_TO_LOAD)), STATES_TO_LOAD)
module_list = [name for (name,) in cr.fetchall() if name not in graph]
if not module_list:
break
-
- upgrade_graph(graph, module_list, force)
+
+ new_modules_in_graph = upgrade_graph(graph, module_list, force)
+ if new_modules_in_graph == 0:
+ # nothing to load
+ break
+
+ logger.notifyChannel('init', netsvc.LOG_DEBUG, 'Updating graph with %d more modules' % (len(module_list)))
r = load_module_graph(cr, graph, status, report=report)
has_updates = has_updates or r
@@ -703,7 +717,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
obj = pool.get(model)
if obj:
obj._check_removed_columns(cr, log=True)
-
+
if report.get_report():
logger.notifyChannel('init', netsvc.LOG_INFO, report)
diff --git a/bin/addons/base/res/partner/partner.py b/bin/addons/base/res/partner/partner.py
index f9e6d74c515..cfe1cb41710 100644
--- a/bin/addons/base/res/partner/partner.py
+++ b/bin/addons/base/res/partner/partner.py
@@ -32,12 +32,12 @@ class res_partner_function(osv.osv):
_description = 'Function of the contact'
_columns = {
'name': fields.char('Function Name', size=64, required=True),
- 'code': fields.char('Code', size=8),
- 'ref':fields.char('Notes', size=32, required=True),
+ 'code': fields.char('Code', size=8, required=True),
+ 'ref':fields.char('Notes', size=32,),
}
_order = 'name'
_sql_constraints = [
- ('ref_uniq', 'unique (ref)', 'The Notes of the Partner Function must be unique !')
+ ('code_uniq', 'unique (code)', 'The Code of the Partner Function must be unique !')
]
res_partner_function()
diff --git a/bin/addons/base/res/partner/partner_data.xml b/bin/addons/base/res/partner/partner_data.xml
index 1e66a8f2183..61286b755d3 100644
--- a/bin/addons/base/res/partner/partner_data.xml
+++ b/bin/addons/base/res/partner/partner_data.xml
@@ -10,13 +10,13 @@
Corp.
Corp.
-
+
partner
Ltd
ltd
-
+
contact
Madam
@@ -32,18 +32,18 @@
Sir
M.
-
+
Director
- CEO
+ CEO
Chief Technical Officer
- CTO
+ CTO
Salesman
- SAL
+ SAL
diff --git a/bin/addons/base/rng/view.rng b/bin/addons/base/rng/view.rng
index 6255c9f7650..40db5265c92 100644
--- a/bin/addons/base/rng/view.rng
+++ b/bin/addons/base/rng/view.rng
@@ -272,6 +272,7 @@
+
diff --git a/bin/netsvc.py b/bin/netsvc.py
index e4df96a2b0d..b9e4a589fab 100644
--- a/bin/netsvc.py
+++ b/bin/netsvc.py
@@ -93,7 +93,8 @@ def init_logger():
logger = logging.getLogger()
# create a format for log messages and dates
formatter = logging.Formatter('[%(asctime)s] %(levelname)s:%(name)s:%(message)s', '%a %b %d %Y %H:%M:%S')
-
+
+ logging_to_stdout = False
if tools.config['syslog']:
# SysLog Handler
if os.name == 'nt':
@@ -113,11 +114,13 @@ def init_logger():
os.makedirs(dirname)
handler = logging.handlers.TimedRotatingFileHandler(logf,'D',1,30)
except Exception, ex:
- sys.stderr.write("ERROR: couldn't create the logfile directory\n")
- handler = logging.StreamHandler(sys.stdout)
+ sys.stderr.write("ERROR: couldn't create the logfile directory. Logging to the standard output.\n")
+ handler = logging.StreamHandler(sys.stdout)
+ logging_to_stdout = True
else:
# Normal Handler on standard output
handler = logging.StreamHandler(sys.stdout)
+ logging_to_stdout = True
# tell the handler to use this format
@@ -127,7 +130,7 @@ def init_logger():
logger.addHandler(handler)
logger.setLevel(tools.config['log_level'] or '0')
- if isinstance(handler, logging.StreamHandler) and os.name != 'nt':
+ if logging_to_stdout and os.name != 'nt':
# change color of level names
# uses of ANSI color codes
# see http://pueblo.sourceforge.net/doc/manual/ansi_color_codes.html
diff --git a/bin/osv/orm.py b/bin/osv/orm.py
index 737fc40c194..ff48da700a0 100644
--- a/bin/osv/orm.py
+++ b/bin/osv/orm.py
@@ -40,6 +40,7 @@
#
import time
+import calendar
import types
import string
import netsvc
@@ -62,6 +63,12 @@ from tools.config import config
regex_order = re.compile('^([a-zA-Z0-9_]+( desc)?( asc)?,?)+$', re.I)
+def last_day_of_current_month():
+ import datetime
+ import calendar
+ today = datetime.date.today()
+ last_day = str(calendar.monthrange(today.year, today.month)[1])
+ return time.strftime('%Y-%m-' + last_day)
def intersect(la, lb):
return filter(lambda x: x in lb, la)
diff --git a/bin/report/printscreen/ps_list.py b/bin/report/printscreen/ps_list.py
index b59be30f1c8..d75d2ecad20 100644
--- a/bin/report/printscreen/ps_list.py
+++ b/bin/report/printscreen/ps_list.py
@@ -156,8 +156,15 @@ class report_printscreen_list(report_int):
if fields[f]['type']=='many2one' and line[f]:
line[f]= line[f][1]
+ if fields[f]['type']=='selection' and line[f]:
+ for key, value in fields[f]['selection']:
+ if key == line[f]:
+ line[f] = value
+ break
+
if fields[f]['type'] in ('one2many','many2many') and line[f]:
line[f] = '( '+tools.ustr(len(line[f])) + ' )'
+
if fields[f]['type'] == 'float':
precision=(('digits' in fields[f]) and fields[f]['digits'][1]) or 2
line[f]='%.2f'%(line[f])
diff --git a/bin/service/web_services.py b/bin/service/web_services.py
index 44c853a6d4b..10a11a4819f 100644
--- a/bin/service/web_services.py
+++ b/bin/service/web_services.py
@@ -69,9 +69,9 @@ class db(netsvc.Service):
self.actions[id] = {'clean': False}
db = sql_db.db_connect('template1')
- cr = db.cursor()
+ cr = db.serialized_cursor()
try:
- cr.autocommit(True)
+ cr.autocommit(True) # XXX inhibit the effect of a serialized cursor. is it what we want ?
cr.execute('CREATE DATABASE "%s" ENCODING \'unicode\'' % db_name)
finally:
cr.close()
@@ -149,8 +149,8 @@ class db(netsvc.Service):
logger = netsvc.Logger()
db = sql_db.db_connect('template1')
- cr = db.cursor()
- cr.autocommit(True)
+ cr = db.serialized_cursor()
+ cr.autocommit(True) # XXX inhibit the effect of a serialized cursor. is it what we want ?
try:
try:
cr.execute('DROP DATABASE "%s"' % db_name)
@@ -201,10 +201,10 @@ class db(netsvc.Service):
raise Exception, "Database already exists"
db = sql_db.db_connect('template1')
- cr = db.cursor()
- cr.autocommit(True)
+ cr = db.serialized_cursor()
+ cr.autocommit(True) # XXX inhibit the effect of a serialized cursor. is it what we want ?
try:
- cr.execute('CREATE DATABASE "%s" ENCODING \'unicode\'' % db_name)
+ cr.execute("""CREATE DATABASE "%s" ENCODING 'unicode' TEMPLATE "template0" """ % db_name)
finally:
cr.close()
sql_db.close_db('template1')
diff --git a/bin/sql_db.py b/bin/sql_db.py
index b0212ac1ea4..ff9a6b0c2c6 100644
--- a/bin/sql_db.py
+++ b/bin/sql_db.py
@@ -21,7 +21,7 @@
##############################################################################
import netsvc
-from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_SERIALIZABLE
+from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_SERIALIZABLE
from psycopg2.pool import ThreadedConnectionPool
from psycopg2.psycopg1 import cursor as psycopg1cursor
@@ -76,8 +76,9 @@ class Cursor(object):
return f(self, *args, **kwargs)
return wrapper
- def __init__(self, pool):
+ def __init__(self, pool, serialized=False):
self._pool = pool
+ self._serialized = serialized
self._cnx = pool.getconn()
self._obj = self._cnx.cursor(cursor_factory=psycopg1cursor)
self.autocommit(False)
@@ -168,7 +169,8 @@ class Cursor(object):
@check
def autocommit(self, on):
- self._cnx.set_isolation_level([ISOLATION_LEVEL_SERIALIZABLE, ISOLATION_LEVEL_AUTOCOMMIT][bool(on)])
+ offlevel = [ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_SERIALIZABLE][bool(self._serialized)]
+ self._cnx.set_isolation_level([offlevel, ISOLATION_LEVEL_AUTOCOMMIT][bool(on)])
@check
def commit(self):
@@ -190,6 +192,9 @@ class ConnectionPool(object):
def cursor(self):
return Cursor(self)
+ def serialized_cursor(self):
+ return Cursor(self, True)
+
def __getattr__(self, name):
return getattr(self._pool, name)
diff --git a/rpminstall_sh.txt b/rpminstall_sh.txt
index 5694f250b5d..bb7bb3fc10c 100644
--- a/rpminstall_sh.txt
+++ b/rpminstall_sh.txt
@@ -7,6 +7,7 @@
# Need to overwrite the install-part of the RPM to append the
# compression-suffix onto the filenames for the man-pages.
#
+python -c "import compileall, os; compileall.compile_dir(os.path.join(os.environ['PWD'], 'doc'), force=True)"
python -O -c "import compileall, os; compileall.compile_dir(os.path.join(os.environ['PWD'], 'doc'), force=True)"
python setup.py install --optimize 1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES