[Merge ]Merge with lp:openobject-server
bzr revid: sbh@tinyerp.com-20110110132538-xabrrucftf9gt20v
This commit is contained in:
+90
-62
@@ -3,7 +3,7 @@
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2010 OpenERP s.a. (<http://openerp.com>).
|
||||
# Copyright (C) 2010-2011 OpenERP s.a. (<http://openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
@@ -47,8 +47,8 @@ import logging
|
||||
|
||||
logger = netsvc.Logger()
|
||||
|
||||
_ad = os.path.abspath(opj(tools.config['root_path'], 'addons')) # default addons path (base)
|
||||
ad_paths= map(lambda m: os.path.abspath(m.strip()),tools.config['addons_path'].split(','))
|
||||
_ad = os.path.abspath(opj(tools.ustr(tools.config['root_path']), u'addons')) # default addons path (base)
|
||||
ad_paths= map(lambda m: os.path.abspath(tools.ustr(m.strip())), tools.config['addons_path'].split(','))
|
||||
|
||||
sys.path.insert(1, _ad)
|
||||
|
||||
@@ -225,6 +225,10 @@ def zip_directory(directory, b64enc=True, src=True):
|
||||
|
||||
archname = StringIO()
|
||||
archive = PyZipFile(archname, "w", ZIP_DEFLATED)
|
||||
|
||||
# for Python 2.5, ZipFile.write() still expects 8-bit strings (2.6 converts to utf-8)
|
||||
directory = tools.ustr(directory).encode('utf-8')
|
||||
|
||||
archive.writepy(directory)
|
||||
_zippy(archive, directory, src=src)
|
||||
archive.close()
|
||||
@@ -312,7 +316,11 @@ def load_information_from_description_file(module):
|
||||
for filename in ['__openerp__.py', '__terp__.py']:
|
||||
description_file = get_module_resource(module, filename)
|
||||
if description_file :
|
||||
return eval(tools.file_open(description_file).read())
|
||||
desc_f = tools.file_open(description_file)
|
||||
try:
|
||||
return eval(desc_f.read())
|
||||
finally:
|
||||
desc_f.close()
|
||||
|
||||
#TODO: refactor the logger in this file to follow the logging guidelines
|
||||
# for 6.0
|
||||
@@ -351,11 +359,14 @@ def upgrade_graph(graph, cr, module_list, force=None):
|
||||
continue
|
||||
|
||||
if os.path.isfile(terp_file) or zipfile.is_zipfile(mod_path+'.zip'):
|
||||
terp_f = tools.file_open(terp_file)
|
||||
try:
|
||||
info = eval(tools.file_open(terp_file).read())
|
||||
except:
|
||||
info = eval(terp_f.read())
|
||||
except Exception:
|
||||
logger.notifyChannel('init', netsvc.LOG_ERROR, 'module %s: eval file %s' % (module, terp_file))
|
||||
raise
|
||||
finally:
|
||||
terp_f.close()
|
||||
if info.get('installable', True):
|
||||
packages.append((module, info.get('depends', []), info))
|
||||
else:
|
||||
@@ -599,18 +610,14 @@ class MigrationManager(object):
|
||||
|
||||
log = logging.getLogger('init')
|
||||
|
||||
def load_module_graph(cr, graph, status=None, perform_checks=True, skip_cleanup=False, **kwargs):
|
||||
def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=None, **kwargs):
|
||||
"""Migrates+Updates or Installs all module nodes from ``graph``
|
||||
:param graph: graph of module nodes to load
|
||||
:param status: status dictionary for keeping track of progress
|
||||
:param perform_checks: whether module descriptors should be checked for validity (prints warnings
|
||||
for same cases, and even raise osv_except if certificate is invalid)
|
||||
:param skip_cleanup: whether the auto-cleanup of records should be executed (unlinks any object that
|
||||
appears to be from one of the updated modules, but have not been loaded during
|
||||
last loading (i.e. records that seem to have been removed from the module).
|
||||
This is best left disabled when loading stand-alone modules that could contain
|
||||
records from dependent modules (i.e. other modules have put records in their
|
||||
namespace)
|
||||
:param skip_modules: optional list of module names (packages) which have previously been loaded and can be skipped
|
||||
:return: list of modules that were installed or updated
|
||||
"""
|
||||
def process_sql_file(cr, fp):
|
||||
queries = fp.read().split(';')
|
||||
@@ -624,29 +631,33 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_cleanup=
|
||||
logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading %s' % (m, filename))
|
||||
_, ext = os.path.splitext(filename)
|
||||
fp = tools.file_open(opj(m, filename))
|
||||
if ext == '.csv':
|
||||
noupdate = (kind == 'init')
|
||||
tools.convert_csv_import(cr, m, os.path.basename(filename), fp.read(), idref, mode=mode, noupdate=noupdate)
|
||||
elif ext == '.sql':
|
||||
process_sql_file(cr, fp)
|
||||
elif ext == '.yml':
|
||||
tools.convert_yaml_import(cr, m, fp, idref, mode=mode, **kwargs)
|
||||
else:
|
||||
tools.convert_xml_import(cr, m, fp, idref, mode=mode, **kwargs)
|
||||
fp.close()
|
||||
try:
|
||||
if ext == '.csv':
|
||||
noupdate = (kind == 'init')
|
||||
tools.convert_csv_import(cr, m, os.path.basename(filename), fp.read(), idref, mode=mode, noupdate=noupdate)
|
||||
elif ext == '.sql':
|
||||
process_sql_file(cr, fp)
|
||||
elif ext == '.yml':
|
||||
tools.convert_yaml_import(cr, m, fp, idref, mode=mode, **kwargs)
|
||||
else:
|
||||
tools.convert_xml_import(cr, m, fp, idref, mode=mode, **kwargs)
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
def load_demo_xml(cr, m, idref, mode):
|
||||
for xml in package.data.get('demo_xml', []):
|
||||
name, ext = os.path.splitext(xml)
|
||||
logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading %s' % (m, xml))
|
||||
fp = tools.file_open(opj(m, xml))
|
||||
if ext == '.csv':
|
||||
tools.convert_csv_import(cr, m, os.path.basename(xml), fp.read(), idref, mode=mode, noupdate=True)
|
||||
elif ext == '.yml':
|
||||
tools.convert_yaml_import(cr, m, fp, idref, mode=mode, noupdate=True, **kwargs)
|
||||
else:
|
||||
tools.convert_xml_import(cr, m, fp, idref, mode=mode, noupdate=True, **kwargs)
|
||||
fp.close()
|
||||
try:
|
||||
if ext == '.csv':
|
||||
tools.convert_csv_import(cr, m, os.path.basename(xml), fp.read(), idref, mode=mode, noupdate=True)
|
||||
elif ext == '.yml':
|
||||
tools.convert_yaml_import(cr, m, fp, idref, mode=mode, noupdate=True, **kwargs)
|
||||
else:
|
||||
tools.convert_xml_import(cr, m, fp, idref, mode=mode, noupdate=True, **kwargs)
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
def load_data(cr, module_name, id_map, mode):
|
||||
_load_data(cr, module_name, id_map, mode, 'data')
|
||||
@@ -660,7 +671,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_cleanup=
|
||||
try:
|
||||
_load_data(cr, module_name, id_map, mode, 'test')
|
||||
except Exception, e:
|
||||
logging.getLogger('test').exception('Tests failed to execute in %s module %s', module_name)
|
||||
logging.getLogger('test').exception('Tests failed to execute in module %s', module_name)
|
||||
finally:
|
||||
if tools.config.options['test_commit']:
|
||||
cr.commit()
|
||||
@@ -668,41 +679,40 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_cleanup=
|
||||
cr.rollback()
|
||||
|
||||
def _load_data(cr, module_name, id_map, mode, kind):
|
||||
noupdate = (kind == 'demo')
|
||||
for filename in package.data.get(kind, []):
|
||||
noupdate = (kind == 'demo')
|
||||
_, ext = os.path.splitext(filename)
|
||||
log.info("module %s: loading %s", module_name, filename)
|
||||
pathname = os.path.join(module_name, filename)
|
||||
file = tools.file_open(pathname)
|
||||
# TODO manage .csv file with noupdate == (kind == 'init')
|
||||
if ext == '.sql':
|
||||
process_sql_file(cr, file)
|
||||
elif ext == '.csv':
|
||||
noupdate = (kind == 'init')
|
||||
tools.convert_csv_import(cr, module_name, pathname, file.read(), id_map, mode, noupdate)
|
||||
elif ext == '.yml':
|
||||
tools.convert_yaml_import(cr, module_name, file, id_map, mode, noupdate)
|
||||
else:
|
||||
tools.convert_xml_import(cr, module_name, file, id_map, mode, noupdate)
|
||||
file.close()
|
||||
try:
|
||||
if ext == '.sql':
|
||||
process_sql_file(cr, file)
|
||||
elif ext == '.csv':
|
||||
noupdate = (kind == 'init')
|
||||
tools.convert_csv_import(cr, module_name, pathname, file.read(), id_map, mode, noupdate)
|
||||
elif ext == '.yml':
|
||||
tools.convert_yaml_import(cr, module_name, file, id_map, mode, noupdate)
|
||||
else:
|
||||
tools.convert_xml_import(cr, module_name, file, id_map, mode, noupdate)
|
||||
finally:
|
||||
file.close()
|
||||
|
||||
# **kwargs is passed directly to convert_xml_import
|
||||
if not status:
|
||||
status = {}
|
||||
|
||||
status = status.copy()
|
||||
package_todo = []
|
||||
processed_modules = []
|
||||
statusi = 0
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
|
||||
migrations = MigrationManager(cr, graph)
|
||||
|
||||
has_updates = False
|
||||
modobj = None
|
||||
|
||||
logger.notifyChannel('init', netsvc.LOG_DEBUG, 'loading %d packages..' % len(graph))
|
||||
|
||||
for package in graph:
|
||||
if skip_modules and package.name in skip_modules:
|
||||
continue
|
||||
logger.notifyChannel('init', netsvc.LOG_INFO, 'module %s: loading objects' % package.name)
|
||||
migrations.migrate_module(package, 'pre')
|
||||
register_class(package.name)
|
||||
@@ -716,6 +726,9 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_cleanup=
|
||||
m = package.name
|
||||
mid = package.id
|
||||
|
||||
if skip_modules and m in skip_modules:
|
||||
continue
|
||||
|
||||
if modobj is None:
|
||||
modobj = pool.get('ir.module.module')
|
||||
|
||||
@@ -730,7 +743,6 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_cleanup=
|
||||
mode = 'init'
|
||||
|
||||
if hasattr(package, 'init') or hasattr(package, 'update') or package.state in ('to install', 'to upgrade'):
|
||||
has_updates = True
|
||||
for kind in ('init', 'update'):
|
||||
if package.state=='to upgrade':
|
||||
# upgrading the module information
|
||||
@@ -749,7 +761,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_cleanup=
|
||||
# as there is no rollback.
|
||||
load_test(cr, m, idref, mode)
|
||||
|
||||
package_todo.append(package.name)
|
||||
processed_modules.append(package.name)
|
||||
|
||||
migrations.migrate_module(package, 'post')
|
||||
|
||||
@@ -769,16 +781,9 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_cleanup=
|
||||
|
||||
statusi += 1
|
||||
|
||||
cr.execute('select model from ir_model where state=%s', ('manual',))
|
||||
for model in cr.dictfetchall():
|
||||
pool.get('ir.model').instanciate(cr, 1, model['model'], {})
|
||||
|
||||
if not skip_cleanup:
|
||||
# Cleanup orphan records
|
||||
pool.get('ir.model.data')._process_end(cr, 1, package_todo)
|
||||
cr.commit()
|
||||
|
||||
return has_updates
|
||||
return processed_modules
|
||||
|
||||
def _check_module_names(cr, module_names):
|
||||
mod_names = set(module_names)
|
||||
@@ -810,17 +815,30 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
||||
force = []
|
||||
if force_demo:
|
||||
force.append('demo')
|
||||
|
||||
# This is a brand new pool, just created in pooler.get_db_and_pool()
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
|
||||
try:
|
||||
processed_modules = []
|
||||
report = tools.assertion_report()
|
||||
# NOTE: Try to also load the modules that have been marked as uninstallable previously...
|
||||
STATES_TO_LOAD = ['installed', 'to upgrade', 'uninstallable']
|
||||
if 'base' in tools.config['update']:
|
||||
cr.execute("update ir_module_module set state=%s where name=%s", ('to upgrade', 'base'))
|
||||
|
||||
# STEP 1: LOAD BASE (must be done before module dependencies can be computed for later steps)
|
||||
graph = create_graph(cr, ['base'], force)
|
||||
if not graph:
|
||||
logger.notifyChannel('init', netsvc.LOG_CRITICAL, 'module base cannot be loaded! (hint: verify addons-path)')
|
||||
raise osv.osv.except_osv(_('Could not load base module'), _('module base cannot be loaded! (hint: verify addons-path)'))
|
||||
has_updates = load_module_graph(cr, graph, status, perform_checks=(not update_module), report=report, skip_cleanup=True)
|
||||
processed_modules.extend(load_module_graph(cr, graph, status, perform_checks=(not update_module), report=report))
|
||||
|
||||
if tools.config['load_language']:
|
||||
for lang in tools.config['load_language'].split(','):
|
||||
tools.load_language(cr, lang)
|
||||
|
||||
# STEP 2: Mark other modules to be loaded/updated
|
||||
if update_module:
|
||||
modobj = pool.get('ir.module.module')
|
||||
logger.notifyChannel('init', netsvc.LOG_INFO, 'updating modules list')
|
||||
@@ -845,6 +863,8 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
||||
|
||||
STATES_TO_LOAD += ['to install']
|
||||
|
||||
|
||||
# STEP 3: Load marked modules (skipping base which was done in STEP 1)
|
||||
loop_guardrail = 0
|
||||
while True:
|
||||
loop_guardrail += 1
|
||||
@@ -862,10 +882,15 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
||||
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
|
||||
processed_modules.extend(load_module_graph(cr, graph, status, report=report, skip_modules=processed_modules))
|
||||
|
||||
# STEP 4: Finish and cleanup
|
||||
if processed_modules:
|
||||
# load custom models
|
||||
cr.execute('select model from ir_model where state=%s', ('manual',))
|
||||
for model in cr.dictfetchall():
|
||||
pool.get('ir.model').instanciate(cr, 1, model['model'], {})
|
||||
|
||||
if has_updates:
|
||||
cr.execute("""select model,name from ir_model where id NOT IN (select distinct model_id from ir_model_access)""")
|
||||
for (model, name) in cr.fetchall():
|
||||
model_obj = pool.get(model)
|
||||
@@ -888,6 +913,9 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
||||
else:
|
||||
logger.notifyChannel('init', netsvc.LOG_WARNING, "Model %s is referenced but not present in the orm pool!" % model)
|
||||
|
||||
# Cleanup orphan records
|
||||
pool.get('ir.model.data')._process_end(cr, 1, processed_modules)
|
||||
|
||||
if report.get_report():
|
||||
logger.notifyChannel('init', netsvc.LOG_INFO, report)
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
'test/base_test.yml',
|
||||
'test/test_context.xml',
|
||||
'test/bug_lp541545.xml',
|
||||
'test/test_osv_expression.yml',
|
||||
],
|
||||
'installable': True,
|
||||
'active': True,
|
||||
|
||||
+253
-27
@@ -28,6 +28,8 @@
|
||||
<field name="translatable">True</field>
|
||||
</record>
|
||||
|
||||
<function name="install_lang" model="res.lang"/>
|
||||
|
||||
<record id="ad" model="res.country">
|
||||
<field name="name">Andorra, Principality of</field>
|
||||
<field name="code">ad</field>
|
||||
@@ -1020,7 +1022,6 @@
|
||||
<!-- Currencies -->
|
||||
<record id="EUR" model="res.currency">
|
||||
<field name="name">EUR</field>
|
||||
<field name="code">EUR</field>
|
||||
<field name="symbol">€</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1073,7 +1074,6 @@
|
||||
</record>
|
||||
<record id="USD" model="res.currency">
|
||||
<field name="name">USD</field>
|
||||
<field name="code">USD</field>
|
||||
<field name="symbol">$</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1087,7 +1087,6 @@
|
||||
|
||||
<record id="VEB" model="res.currency">
|
||||
<field name="name">Bs</field>
|
||||
<field name="code">VEB</field>
|
||||
<field name="symbol">Bs</field>
|
||||
<field name="rounding">2.95</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1101,7 +1100,6 @@
|
||||
|
||||
<record id="CAD" model="res.currency">
|
||||
<field name="name">CAD</field>
|
||||
<field name="code">CAD</field>
|
||||
<field name="symbol">$</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1116,7 +1114,6 @@
|
||||
|
||||
<record id="CHF" model="res.currency">
|
||||
<field name="name">CHF</field>
|
||||
<field name="code">CHF</field>
|
||||
<field name="symbol">CHF</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1130,7 +1127,6 @@
|
||||
|
||||
<record id="BRL" model="res.currency">
|
||||
<field name="name">BRL</field>
|
||||
<field name="code">BRL</field>
|
||||
<field name="symbol">R$</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1144,7 +1140,6 @@
|
||||
|
||||
<record id="CNY" model="res.currency">
|
||||
<field name="name">CNY</field>
|
||||
<field name="code">CNY</field>
|
||||
<field name="symbol">¥</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1159,7 +1154,6 @@
|
||||
|
||||
<record id="COP" model="res.currency">
|
||||
<field name="name">COP</field>
|
||||
<field name="code">COP</field>
|
||||
<field name="symbol">$</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1173,7 +1167,6 @@
|
||||
|
||||
<record id="CZK" model="res.currency">
|
||||
<field name="name">Kč</field>
|
||||
<field name="code">CZK</field>
|
||||
<field name="symbol">Kč</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1187,7 +1180,6 @@
|
||||
|
||||
<record id="DKK" model="res.currency">
|
||||
<field name="name">kr</field>
|
||||
<field name="code">DKK</field>
|
||||
<field name="symbol">kr</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1202,7 +1194,6 @@
|
||||
|
||||
<record id="HUF" model="res.currency">
|
||||
<field name="name">Ft</field>
|
||||
<field name="code">HUF</field>
|
||||
<field name="symbol">Ft</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1215,27 +1206,25 @@
|
||||
</record>
|
||||
|
||||
<record id="IDR" model="res.currency">
|
||||
<field name="name">Rs</field>
|
||||
<field name="code">IDR</field>
|
||||
<field name="symbol">Rs</field>
|
||||
<field name="name">Rp</field>
|
||||
<field name="symbol">Rp</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateIDR1" model="res.currency.rate">
|
||||
<field name="rate">65.8287</field>
|
||||
<field name="rate">14352.00</field>
|
||||
<field name="currency_id" ref="IDR"/>
|
||||
<field eval="time.strftime('2009-01-01')" name="name"/>
|
||||
</record>
|
||||
<record id="rateIDR" model="res.currency.rate">
|
||||
<field name="rate">58.8287</field>
|
||||
<field name="rate">11796.39</field>
|
||||
<field name="currency_id" ref="IDR"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="LVL" model="res.currency">
|
||||
<field name="name">Ls</field>
|
||||
<field name="code">LVL</field>
|
||||
<field name="symbol">Ls</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1250,7 +1239,6 @@
|
||||
|
||||
<record id="NOK" model="res.currency">
|
||||
<field name="name">kr</field>
|
||||
<field name="code">NOK</field>
|
||||
<field name="symbol">kr</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1262,10 +1250,21 @@
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="XPF" model="res.currency">
|
||||
<field name="name">XPF</field>
|
||||
<field name="symbol">XPF</field>
|
||||
<field name="rounding">1.00</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateXPF" model="res.currency.rate">
|
||||
<field name="rate">119.331742</field>
|
||||
<field name="currency_id" ref="XPF"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="PAB" model="res.currency">
|
||||
<field name="name">PAB</field>
|
||||
<field name="code">PAB</field>
|
||||
<field name="symbol">B/.</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1279,7 +1278,6 @@
|
||||
|
||||
<record id="PLN" model="res.currency">
|
||||
<field name="name">zł</field>
|
||||
<field name="code">PLN</field>
|
||||
<field name="symbol">zł</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1293,7 +1291,6 @@
|
||||
|
||||
<record id="SEK" model="res.currency">
|
||||
<field name="name">kr</field>
|
||||
<field name="code">SEK</field>
|
||||
<field name="symbol">kr</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1307,7 +1304,6 @@
|
||||
|
||||
<record id="GBP" model="res.currency">
|
||||
<field name="name">GBP</field>
|
||||
<field name="code">GBP</field>
|
||||
<field name="symbol">₤</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1321,7 +1317,6 @@
|
||||
|
||||
<record id="ARS" model="res.currency">
|
||||
<field name="name">ARS</field>
|
||||
<field name="code">ARS</field>
|
||||
<field name="symbol">$</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1335,7 +1330,6 @@
|
||||
|
||||
<record id="INR" model="res.currency">
|
||||
<field name="name">Rs</field>
|
||||
<field name="code">INR</field>
|
||||
<field name="symbol">Rs</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1349,7 +1343,6 @@
|
||||
|
||||
<record id="AUD" model="res.currency">
|
||||
<field name="name">AUD</field>
|
||||
<field name="code">AUD</field>
|
||||
<field name="symbol">$</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1363,7 +1356,6 @@
|
||||
|
||||
<record id="UAH" model="res.currency">
|
||||
<field name="name">UAH</field>
|
||||
<field name="code">UAH</field>
|
||||
<field name="symbol">₴</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
@@ -1374,6 +1366,241 @@
|
||||
<field name="currency_id" ref="UAH"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="VND" model="res.currency">
|
||||
<field name="name">VND</field>
|
||||
<field name="symbol">₫</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateVND" model="res.currency.rate">
|
||||
<field name="rate">26330.01</field>
|
||||
<field name="currency_id" ref="VND"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="HKD" model="res.currency">
|
||||
<field name="name">HKD</field>
|
||||
<field name="symbol">$</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateHKD" model="res.currency.rate">
|
||||
<field name="rate">11.1608</field>
|
||||
<field name="currency_id" ref="HKD"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="JPY" model="res.currency">
|
||||
<field name="name">JPY</field>
|
||||
<field name="symbol">¥</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateJPY" model="res.currency.rate">
|
||||
<field name="rate">133.62</field>
|
||||
<field name="currency_id" ref="JPY"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="BGN" model="res.currency">
|
||||
<field name="name">BGN</field>
|
||||
<field name="symbol">лв</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateBGN" model="res.currency.rate">
|
||||
<field name="rate">1.9558</field>
|
||||
<field name="currency_id" ref="BGN"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="EEK" model="res.currency">
|
||||
<field name="name">EEK</field>
|
||||
<field name="symbol">kr</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateEEK" model="res.currency.rate">
|
||||
<field name="rate">15.6466</field>
|
||||
<field name="currency_id" ref="EEK"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="LTL" model="res.currency">
|
||||
<field name="name">LTL</field>
|
||||
<field name="symbol">Lt</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateLTL" model="res.currency.rate">
|
||||
<field name="rate">3.4528</field>
|
||||
<field name="currency_id" ref="LTL"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="RON" model="res.currency">
|
||||
<field name="name">RON</field>
|
||||
<field name="symbol">kr</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateRON" model="res.currency.rate">
|
||||
<field name="rate">4.2253</field>
|
||||
<field name="currency_id" ref="RON"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="HRK" model="res.currency">
|
||||
<field name="name">HRK</field>
|
||||
<field name="symbol">kn</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateHRK" model="res.currency.rate">
|
||||
<field name="rate">7.2936</field>
|
||||
<field name="currency_id" ref="HRK"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="RUB" model="res.currency">
|
||||
<field name="name">RUB</field>
|
||||
<field name="symbol">руб</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateRUB" model="res.currency.rate">
|
||||
<field name="rate">43.16</field>
|
||||
<field name="currency_id" ref="RUB"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="TRY" model="res.currency">
|
||||
<field name="name">TRY</field>
|
||||
<field name="symbol">TL</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateTRY" model="res.currency.rate">
|
||||
<field name="rate">2.1411</field>
|
||||
<field name="currency_id" ref="TRY"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="KRW" model="res.currency">
|
||||
<field name="name">KRW</field>
|
||||
<field name="symbol">₩</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateKRW" model="res.currency.rate">
|
||||
<field name="rate">1662.37</field>
|
||||
<field name="currency_id" ref="KRW"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="MXN" model="res.currency">
|
||||
<field name="name">MXN</field>
|
||||
<field name="symbol">$</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateMXN" model="res.currency.rate">
|
||||
<field name="rate">18.6664</field>
|
||||
<field name="currency_id" ref="MXN"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="MYR" model="res.currency">
|
||||
<field name="name">MYR</field>
|
||||
<field name="symbol">RM</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateMYR" model="res.currency.rate">
|
||||
<field name="rate">4.8887</field>
|
||||
<field name="currency_id" ref="MYR"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="NZD" model="res.currency">
|
||||
<field name="name">NZD</field>
|
||||
<field name="symbol">$</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateNZD" model="res.currency.rate">
|
||||
<field name="rate">1.9764</field>
|
||||
<field name="currency_id" ref="NZD"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="PHP" model="res.currency">
|
||||
<field name="name">PHP</field>
|
||||
<field name="symbol">Php</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="ratePHP" model="res.currency.rate">
|
||||
<field name="rate">66.1</field>
|
||||
<field name="currency_id" ref="PHP"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="SGD" model="res.currency">
|
||||
<field name="name">SGD</field>
|
||||
<field name="symbol">$</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateSGD" model="res.currency.rate">
|
||||
<field name="rate">2.0126</field>
|
||||
<field name="currency_id" ref="SGD"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="THB" model="res.currency">
|
||||
<field name="name">THB</field>
|
||||
<field name="symbol">฿</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateTHB" model="res.currency.rate">
|
||||
<field name="rate">47.779</field>
|
||||
<field name="currency_id" ref="THB"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="ZAR" model="res.currency">
|
||||
<field name="name">ZAR</field>
|
||||
<field name="symbol">R</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
</record>
|
||||
<record id="rateZAR" model="res.currency.rate">
|
||||
<field name="rate">10.5618</field>
|
||||
<field name="currency_id" ref="ZAR"/>
|
||||
<field eval="time.strftime('%Y-01-01')" name="name"/>
|
||||
</record>
|
||||
|
||||
<record id="res_bank_1" model="res.bank">
|
||||
<field name="name">Reserve</field>
|
||||
<field name="code">RSV</field>
|
||||
@@ -1381,7 +1608,6 @@
|
||||
|
||||
<record id="CRC" model="res.currency">
|
||||
<field name="name">CRC</field>
|
||||
<field name="code">CRC</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="accuracy">4</field>
|
||||
<field name="symbol">¢</field>
|
||||
|
||||
@@ -1,14 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="demo_address" model="res.partner.address">
|
||||
<field name="name">Fabien Dupont</field>
|
||||
<field name="street">Chaussee de Namur</field>
|
||||
<field name="zip">1367</field>
|
||||
<field name="city">Gerompont</field>
|
||||
<field name="phone">(+32).81.81.37.00</field>
|
||||
<field name="type">default</field>
|
||||
<field model="res.country" name="country_id" ref="be"/>
|
||||
<!-- Company ID will be set later -->
|
||||
<field name="company_id" eval="None"/>
|
||||
</record>
|
||||
|
||||
<record id="user_demo" model="res.users">
|
||||
<field name="login">demo</field>
|
||||
<field name="password">demo</field>
|
||||
<field name="name">Demo User</field>
|
||||
<field name="signature">Mr Demo</field>
|
||||
<field name="address_id" ref="main_address"/>
|
||||
<field name="address_id" ref="demo_address"/>
|
||||
<field name="company_id" ref="main_company"/>
|
||||
<field name="groups_id" eval="[(6,0,[ref('base.group_user')])]"/>
|
||||
<field name="groups_id" eval="[(6,0,[ref('base.group_user')])]"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -7,13 +7,12 @@
|
||||
web_icon_hover="data/administration-hover.png"/>
|
||||
|
||||
<menuitem icon="terp-administration" id="menu_administration_shortcut" parent="menu_administration" name="Custom Shortcuts" sequence="50"/>
|
||||
<menuitem id="next_id_4" name="Low Level Objects"
|
||||
parent="base.menu_administration" sequence="3"
|
||||
groups="base.group_no_one"/>
|
||||
<menuitem id="menu_low_workflow" name="Workflows" parent="base.next_id_4"/>
|
||||
<menuitem id="menu_custom" name="Customization"
|
||||
parent="base.menu_administration" sequence="2"
|
||||
groups="base.group_extended"/>
|
||||
<menuitem id="next_id_4" name="Low Level Objects"
|
||||
parent="base.menu_custom" sequence="30"/>
|
||||
<menuitem id="menu_low_workflow" name="Workflows" parent="base.next_id_4"/>
|
||||
<menuitem id="menu_custom_action" name="Actions" parent="base.menu_custom" groups="base.group_extended" sequence="20"/>
|
||||
<menuitem id="menu_config" name="Configuration" parent="base.menu_administration" sequence="1"/>
|
||||
<menuitem id="menu_translation" name="Translations" parent="base.menu_administration" sequence="4"/>
|
||||
@@ -31,6 +30,6 @@
|
||||
|
||||
<menuitem id="base.menu_reporting" name="Reporting" parent="base.menu_administration" sequence="11"
|
||||
groups="base.group_extended"/>
|
||||
<menuitem id="menu_audit" name="Audit" parent="base.menu_reporting" groups="base.group_extended" sequence="50"/>
|
||||
<menuitem id="menu_audit" name="Audit" parent="base.menu_reporting" sequence="50"/>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
Users
|
||||
======================
|
||||
-->
|
||||
|
||||
<record id="view_users_form_simple_modif" model="ir.ui.view">
|
||||
<field name="name">res.users.form.modif</field>
|
||||
<field name="model">res.users</field>
|
||||
@@ -79,7 +80,7 @@
|
||||
<notebook colspan="4">
|
||||
<page string="Current Activity">
|
||||
<field name="company_id" widget="selection" readonly="0"
|
||||
context="{'user_id': self, 'user_preference': 1}" groups="base.group_multi_company"
|
||||
groups="base.group_multi_company"
|
||||
on_change="on_change_company_id(company_id)" />
|
||||
<field name="view" readonly="0"/>
|
||||
<label string="" colspan="2"/>
|
||||
@@ -87,10 +88,7 @@
|
||||
<newline/>
|
||||
</page>
|
||||
<page string="Preferences">
|
||||
<field name="password" password="True" readonly="0" />
|
||||
<field name="context_lang" completion="1" readonly="0"/>
|
||||
<label string="" colspan="1"/>
|
||||
<label colspan="3" string="You must logout and login again after changing your password."/>
|
||||
<field name="context_tz" completion="1" readonly="0"/>
|
||||
<field name="menu_tips" colspan="2" readonly="0"/>
|
||||
<separator string="Email & Signature" colspan="4"/>
|
||||
@@ -111,14 +109,14 @@
|
||||
<field name="name" select="1"/>
|
||||
<field name="active"/>
|
||||
<field name="login" select="1"/>
|
||||
<field name="password" password="True"/>
|
||||
<field name="new_password" password="True"/>
|
||||
<newline/>
|
||||
<notebook colspan="4">
|
||||
<page string="User">
|
||||
<group colspan="1" col="2">
|
||||
<separator string="Contact" colspan="2"/>
|
||||
<field name="company_id" required="1"
|
||||
context="{'user_id': self, 'user_preference': 1}"
|
||||
context="{'user_preference': 0}"
|
||||
groups="base.group_multi_company"
|
||||
/>
|
||||
<field name="address_id"/>
|
||||
|
||||
+703
-261
File diff suppressed because it is too large
Load Diff
+703
-261
File diff suppressed because it is too large
Load Diff
+703
-261
File diff suppressed because it is too large
Load Diff
+652
-251
File diff suppressed because it is too large
Load Diff
+780
-279
File diff suppressed because it is too large
Load Diff
+714
-265
File diff suppressed because it is too large
Load Diff
+760
-329
File diff suppressed because it is too large
Load Diff
+709
-264
File diff suppressed because it is too large
Load Diff
+707
-262
File diff suppressed because it is too large
Load Diff
+961
-397
File diff suppressed because it is too large
Load Diff
+1985
-347
File diff suppressed because it is too large
Load Diff
+921
-364
File diff suppressed because it is too large
Load Diff
+913
-445
File diff suppressed because it is too large
Load Diff
+2926
-277
File diff suppressed because it is too large
Load Diff
+755
-279
File diff suppressed because it is too large
Load Diff
+703
-261
File diff suppressed because it is too large
Load Diff
+764
-283
File diff suppressed because it is too large
Load Diff
+2536
-339
File diff suppressed because it is too large
Load Diff
+1097
-445
File diff suppressed because it is too large
Load Diff
+737
-291
File diff suppressed because it is too large
Load Diff
+754
-352
File diff suppressed because it is too large
Load Diff
+735
-279
File diff suppressed because it is too large
Load Diff
+2324
-1594
File diff suppressed because it is too large
Load Diff
+711
-262
File diff suppressed because it is too large
Load Diff
+703
-261
File diff suppressed because it is too large
Load Diff
+872
-349
File diff suppressed because it is too large
Load Diff
+713
-261
File diff suppressed because it is too large
Load Diff
+741
-339
File diff suppressed because it is too large
Load Diff
+707
-265
File diff suppressed because it is too large
Load Diff
+967
-554
File diff suppressed because it is too large
Load Diff
+973
-285
File diff suppressed because it is too large
Load Diff
+704
-262
File diff suppressed because it is too large
Load Diff
+969
-345
File diff suppressed because it is too large
Load Diff
+1096
-540
File diff suppressed because it is too large
Load Diff
+813
-286
File diff suppressed because it is too large
Load Diff
+1381
-368
File diff suppressed because it is too large
Load Diff
+759
-283
File diff suppressed because it is too large
Load Diff
+841
-340
File diff suppressed because it is too large
Load Diff
+1200
-420
File diff suppressed because it is too large
Load Diff
+1163
-316
File diff suppressed because it is too large
Load Diff
+703
-261
File diff suppressed because it is too large
Load Diff
+772
-389
File diff suppressed because it is too large
Load Diff
+703
-261
File diff suppressed because it is too large
Load Diff
+1351
-736
File diff suppressed because it is too large
Load Diff
+703
-261
File diff suppressed because it is too large
Load Diff
+703
-261
File diff suppressed because it is too large
Load Diff
+767
-286
File diff suppressed because it is too large
Load Diff
+758
-352
File diff suppressed because it is too large
Load Diff
+6152
-384
File diff suppressed because it is too large
Load Diff
+1270
-617
File diff suppressed because it is too large
Load Diff
+732
-268
File diff suppressed because it is too large
Load Diff
@@ -829,7 +829,6 @@
|
||||
<field name="name"/>
|
||||
<field name="type"/>
|
||||
<field name="model"/>
|
||||
<field name="xml_id"/>
|
||||
<field name="inherit_id"/>
|
||||
<newline/>
|
||||
<group expand="0" string="Group By...">
|
||||
@@ -849,6 +848,52 @@
|
||||
</record>
|
||||
<menuitem action="action_ui_view" id="menu_action_ui_view" parent="base.next_id_2"/>
|
||||
|
||||
|
||||
<!-- View customizations -->
|
||||
<record id="view_view_custom_search" model="ir.ui.view">
|
||||
<field name="name">ir.ui.view.custom.search</field>
|
||||
<field name="model">ir.ui.view.custom</field>
|
||||
<field name="type">search</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Customized Views">
|
||||
<field name="user_id"/>
|
||||
<field name="ref_id"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_view_custom_form" model="ir.ui.view">
|
||||
<field name="name">ir.ui.view.custom.form</field>
|
||||
<field name="model">ir.ui.view.custom</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Customized Views">
|
||||
<field name="user_id"/>
|
||||
<field name="ref_id"/>
|
||||
<separator colspan="4" string="Customized Architecture"/>
|
||||
<field name="arch" colspan="4" nolabel="1"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_view_custom_tree" model="ir.ui.view">
|
||||
<field name="name">ir.ui.view.custom.tree</field>
|
||||
<field name="model">ir.ui.view.custom</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Customized Views">
|
||||
<field name="user_id"/>
|
||||
<field name="ref_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="action_ui_view_custom" model="ir.actions.act_window">
|
||||
<field name="name">Customized Views</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">ir.ui.view.custom</field>
|
||||
<field name="help">Customized views are used when users reorganize the content of their dashboard views (via web client)</field>
|
||||
</record>
|
||||
<menuitem action="action_ui_view_custom" id="menu_action_ui_view_custom" parent="base.next_id_4"/>
|
||||
|
||||
|
||||
<!-- Attachment -->
|
||||
<record id="view_attachment_form" model="ir.ui.view">
|
||||
<field name="name">ir.attachment.view</field>
|
||||
@@ -938,7 +983,7 @@
|
||||
<group expand="0" string="Group By...">
|
||||
<filter string="Owner" icon="terp-personal" domain="[]" context="{'group_by':'create_uid'}"/>
|
||||
<filter string="Type" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by':'type'}" groups="base.group_extended"/>
|
||||
<filter string="Company" icon="terp-personal" domain="[]" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
||||
<filter string="Company" icon="terp-gtk-home" domain="[]" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
||||
<separator orientation="vertical"/>
|
||||
<filter string="Month" help="Creation Month" icon="terp-go-month" domain="[]" context="{'group_by':'create_date'}"/>
|
||||
</group>
|
||||
@@ -1145,11 +1190,11 @@
|
||||
<field name="type">search</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Fields">
|
||||
<filter icon="terp-camera_test"
|
||||
<filter icon="terp-gnome-cpu-frequency-applet+"
|
||||
string="Required"
|
||||
domain="[('required', '=', True)]"/>
|
||||
<separator orientation="vertical"/>
|
||||
<filter icon="terp-stock_align_left_24"
|
||||
<filter icon="terp-dialog-close"
|
||||
string="Readonly"
|
||||
domain="[('readonly', '=', True)]"/>
|
||||
<separator orientation="vertical"/>
|
||||
@@ -1265,7 +1310,7 @@
|
||||
<field name="type">search</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Translations">
|
||||
<filter icon="terp-document-new"
|
||||
<filter icon="terp-gdu-smart-failing"
|
||||
string="Untranslated"
|
||||
domain="['|',('value', '=', False),('value','=','')]"/>
|
||||
<separator orientation="vertical"/>
|
||||
@@ -1683,7 +1728,7 @@
|
||||
<field name="name">Property multi-company</field>
|
||||
<field model="ir.model" name="model_id" ref="model_ir_property"/>
|
||||
<field eval="True" name="global"/>
|
||||
<field name="domain_force">['|',('company_id','child_of',user.company_id.id),('company_id','=',False)]</field>
|
||||
<field name="domain_force">['|',('company_id','=',user.company_id.id),('company_id','=',False)]</field>
|
||||
</record>
|
||||
|
||||
<!--server action view-->
|
||||
@@ -1873,6 +1918,7 @@
|
||||
<field name="res_model">ir.actions.todo</field>
|
||||
<field name="view_id" ref="ir_actions_todo_tree"/>
|
||||
<field name="view_type">form</field>
|
||||
<field name="help">The configuration wizards are used to help you configure a new instance of OpenERP. They are launched during the installation of new modules, but you can choose to restart some wizards manually from this menu.</field>
|
||||
</record>
|
||||
<menuitem id="next_id_11" name="Configuration Wizards" parent="base.menu_config" sequence="1"/>
|
||||
|
||||
|
||||
@@ -55,11 +55,15 @@ class report_xml(osv.osv):
|
||||
for report in self.browse(cursor, user, ids, context=context):
|
||||
data = report[name + '_data']
|
||||
if not data and report[name[:-8]]:
|
||||
fp = None
|
||||
try:
|
||||
fp = tools.file_open(report[name[:-8]], mode='rb')
|
||||
data = fp.read()
|
||||
except:
|
||||
data = False
|
||||
finally:
|
||||
if fp:
|
||||
fp.close()
|
||||
res[report.id] = data
|
||||
return res
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ class ir_cron(osv.osv, netsvc.Agent):
|
||||
cr.commit()
|
||||
|
||||
|
||||
cr.execute('select min(nextcall) as min_next_call from ir_cron where numbercall<>0 and active and nextcall>=now()')
|
||||
cr.execute('select min(nextcall) as min_next_call from ir_cron where numbercall<>0 and active')
|
||||
next_call = cr.dictfetchone()['min_next_call']
|
||||
if next_call:
|
||||
next_call = time.mktime(time.strptime(next_call, '%Y-%m-%d %H:%M:%S'))
|
||||
|
||||
@@ -36,7 +36,7 @@ ir_exports()
|
||||
|
||||
class ir_exports_line(osv.osv):
|
||||
_name = 'ir.exports.line'
|
||||
_order = 'sequence,name'
|
||||
_order = 'id'
|
||||
_columns = {
|
||||
'name': fields.char('Field Name', size=64),
|
||||
'export_id': fields.many2one('ir.exports', 'Export', select=True, ondelete='cascade'),
|
||||
|
||||
+181
-25
@@ -19,14 +19,16 @@
|
||||
#
|
||||
##############################################################################
|
||||
import logging
|
||||
import re
|
||||
import time
|
||||
from operator import itemgetter
|
||||
|
||||
from osv import fields,osv
|
||||
import ir, re
|
||||
import ir
|
||||
import netsvc
|
||||
from osv.orm import except_orm, browse_record
|
||||
|
||||
import time
|
||||
import tools
|
||||
from tools.safe_eval import safe_eval as eval
|
||||
from tools import config
|
||||
from tools.translate import _
|
||||
import pooler
|
||||
@@ -152,45 +154,78 @@ class ir_model_fields(osv.osv):
|
||||
_description = "Fields"
|
||||
_columns = {
|
||||
'name': fields.char('Name', required=True, size=64, select=1),
|
||||
'model': fields.char('Object Name', size=64, required=True, select=1),
|
||||
'relation': fields.char('Object Relation', size=64),
|
||||
'relation_field': fields.char('Relation Field', size=64),
|
||||
'model_id': fields.many2one('ir.model', 'Object ID', required=True, select=True, ondelete='cascade'),
|
||||
'model': fields.char('Object Name', size=64, required=True, select=1,
|
||||
help="The technical name of the model this field belongs to"),
|
||||
'relation': fields.char('Object Relation', size=64,
|
||||
help="For relationship fields, the technical name of the target model"),
|
||||
'relation_field': fields.char('Relation Field', size=64,
|
||||
help="For one2many fields, the field on the target model that implement the opposite many2one relationship"),
|
||||
'model_id': fields.many2one('ir.model', 'Model', required=True, select=True, ondelete='cascade',
|
||||
help="The model this field belongs to"),
|
||||
'field_description': fields.char('Field Label', required=True, size=256),
|
||||
'ttype': fields.selection(_get_fields_type, 'Field Type',size=64, required=True),
|
||||
'selection': fields.char('Field Selection',size=128),
|
||||
'selection': fields.char('Selection Options',size=128, help="List of options for a selection field, "
|
||||
"specified as a Python expression defining a list of (key, label) pairs. "
|
||||
"For example: [('blue','Blue'),('yellow','Yellow')]"),
|
||||
'required': fields.boolean('Required'),
|
||||
'readonly': fields.boolean('Readonly'),
|
||||
'select_level': fields.selection([('0','Not Searchable'),('1','Always Searchable'),('2','Advanced Search')],'Searchable', required=True),
|
||||
'translate': fields.boolean('Translate'),
|
||||
'select_level': fields.selection([('0','Not Searchable'),('1','Always Searchable'),('2','Advanced Search (deprecated)')],'Searchable', required=True),
|
||||
'translate': fields.boolean('Translate', help="Whether values for this field can be translated (enables the translation mechanism for that field)"),
|
||||
'size': fields.integer('Size'),
|
||||
'state': fields.selection([('manual','Custom Field'),('base','Base Field')],'Type', required=True, readonly=True, select=1),
|
||||
'on_delete': fields.selection([('cascade','Cascade'),('set null','Set NULL')], 'On delete', help='On delete property for many2one fields'),
|
||||
'domain': fields.char('Domain', size=256),
|
||||
'domain': fields.char('Domain', size=256, help="The optional domain to restrict possible values for relationship fields, "
|
||||
"specified as a Python expression defining a list of triplets. "
|
||||
"For example: [('color','=','red')]"),
|
||||
'groups': fields.many2many('res.groups', 'ir_model_fields_group_rel', 'field_id', 'group_id', 'Groups'),
|
||||
'view_load': fields.boolean('View Auto-Load'),
|
||||
'selectable': fields.boolean('Selectable'),
|
||||
}
|
||||
_rec_name='field_description'
|
||||
_defaults = {
|
||||
'view_load': lambda *a: 0,
|
||||
'selection': lambda *a: "[]",
|
||||
'domain': lambda *a: "[]",
|
||||
'name': lambda *a: 'x_',
|
||||
'view_load': 0,
|
||||
'selection': "",
|
||||
'domain': "[]",
|
||||
'name': 'x_',
|
||||
'state': lambda self,cr,uid,ctx={}: (ctx and ctx.get('manual',False)) and 'manual' or 'base',
|
||||
'on_delete': lambda *a: 'set null',
|
||||
'select_level': lambda *a: '0',
|
||||
'size': lambda *a: 64,
|
||||
'field_description': lambda *a: '',
|
||||
'selectable': lambda *a: 1,
|
||||
'on_delete': 'set null',
|
||||
'select_level': '0',
|
||||
'size': 64,
|
||||
'field_description': '',
|
||||
'selectable': 1,
|
||||
}
|
||||
_order = "name"
|
||||
|
||||
def _check_selection(self, cr, uid, selection, context=None):
|
||||
try:
|
||||
selection_list = eval(selection)
|
||||
except Exception:
|
||||
logging.getLogger('ir.model').warning('Invalid selection list definition for fields.selection', exc_info=True)
|
||||
raise except_orm(_('Error'),
|
||||
_("The Selection Options expression is not a valid Pythonic expression." \
|
||||
"Please provide an expression in the [('key','Label'), ...] format."))
|
||||
|
||||
check = True
|
||||
if not (isinstance(selection_list, list) and selection_list):
|
||||
check = False
|
||||
else:
|
||||
for item in selection_list:
|
||||
if not (isinstance(item, (tuple,list)) and len(item) == 2):
|
||||
check = False
|
||||
break
|
||||
|
||||
if not check:
|
||||
raise except_orm(_('Error'),
|
||||
_("The Selection Options expression is must be in the [('key','Label'), ...] format!"))
|
||||
return True
|
||||
|
||||
def _size_gt_zero_msg(self, cr, user, ids, context=None):
|
||||
return _('Size of the field can never be less than 1 !')
|
||||
|
||||
_sql_constraints = [
|
||||
('size_gt_zero', 'CHECK (size>0)',_size_gt_zero_msg ),
|
||||
]
|
||||
|
||||
def unlink(self, cr, user, ids, context=None):
|
||||
for field in self.browse(cr, user, ids, context):
|
||||
if field.state <> 'manual':
|
||||
@@ -210,6 +245,10 @@ class ir_model_fields(osv.osv):
|
||||
context = {}
|
||||
if context and context.get('manual',False):
|
||||
vals['state'] = 'manual'
|
||||
if vals.get('ttype', False) == 'selection':
|
||||
if not vals.get('selection',False):
|
||||
raise except_orm(_('Error'), _('For selection fields, the Selection Options must be given!'))
|
||||
self._check_selection(cr, user, vals['selection'], context=context)
|
||||
res = super(ir_model_fields,self).create(cr, user, vals, context)
|
||||
if vals.get('state','base') == 'manual':
|
||||
if not vals['name'].startswith('x_'):
|
||||
@@ -227,6 +266,113 @@ class ir_model_fields(osv.osv):
|
||||
|
||||
return res
|
||||
|
||||
def write(self, cr, user, ids, vals, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if context and context.get('manual',False):
|
||||
vals['state'] = 'manual'
|
||||
|
||||
column_rename = None # if set, *one* column can be renamed here
|
||||
obj = None
|
||||
models_patch = {} # structs of (obj, [(field, prop, change_to),..])
|
||||
# data to be updated on the orm model
|
||||
|
||||
# static table of properties
|
||||
model_props = [ # (our-name, fields.prop, set_fn)
|
||||
('field_description', 'string', lambda a: a),
|
||||
('required', 'required', bool),
|
||||
('readonly', 'readonly', bool),
|
||||
('domain', '_domain', lambda a: a),
|
||||
('size', 'size', int),
|
||||
('on_delete', 'ondelete', str),
|
||||
('translate', 'translate', bool),
|
||||
('view_load', 'view_load', bool),
|
||||
('selectable', 'selectable', bool),
|
||||
('select_level', 'select', int),
|
||||
('selection', 'selection', eval),
|
||||
]
|
||||
|
||||
if vals and ids:
|
||||
checked_selection = False # need only check it once, so defer
|
||||
|
||||
for item in self.browse(cr, user, ids, context=context):
|
||||
if not (obj and obj._name == item.model):
|
||||
obj = self.pool.get(item.model)
|
||||
|
||||
if item.state != 'manual':
|
||||
raise except_orm(_('Error!'),
|
||||
_('Properties of base fields cannot be altered in this manner! '
|
||||
'Please modify them through Python code, '
|
||||
'preferably through a custom addon!'))
|
||||
|
||||
if item.ttype == 'selection' and 'selection' in vals \
|
||||
and not checked_selection:
|
||||
self._check_selection(cr, user, vals['selection'], context=context)
|
||||
checked_selection = True
|
||||
|
||||
final_name = item.name
|
||||
if 'name' in vals and vals['name'] != item.name:
|
||||
# We need to rename the column
|
||||
if column_rename:
|
||||
raise except_orm(_('Error!'), _('Can only rename one column at a time!'))
|
||||
if vals['name'] in obj._columns:
|
||||
raise except_orm(_('Error!'), _('Cannot rename column to %s, because that column already exists!') % vals['name'])
|
||||
if vals.get('state', 'base') == 'manual' and not vals['name'].startswith('x_'):
|
||||
raise except_orm(_('Error!'), _('New column name must still start with x_ , because it is a custom field!'))
|
||||
if '\'' in vals['name'] or '"' in vals['name'] or ';' in vals['name']:
|
||||
raise ValueError('Invalid character in column name')
|
||||
column_rename = (obj, (obj._table, item.name, vals['name']))
|
||||
final_name = vals['name']
|
||||
|
||||
if 'model_id' in vals and vals['model_id'] != item.model_id:
|
||||
raise except_orm(_("Error!"), _("Changing the model of a field is forbidden!"))
|
||||
|
||||
if 'ttype' in vals and vals['ttype'] != item.ttype:
|
||||
raise except_orm(_("Error!"), _("Changing the type of a column is not yet supported. "
|
||||
"Please drop it and create it again!"))
|
||||
|
||||
# We don't check the 'state', because it might come from the context
|
||||
# (thus be set for multiple fields) and will be ignored anyway.
|
||||
if obj:
|
||||
models_patch.setdefault(obj._name, (obj,[]))
|
||||
# find out which properties (per model) we need to update
|
||||
for field_name, field_property, set_fn in model_props:
|
||||
if field_name in vals:
|
||||
property_value = set_fn(vals[field_name])
|
||||
if getattr(obj._columns[item.name], field_property) != property_value:
|
||||
models_patch[obj._name][1].append((final_name, field_property, property_value))
|
||||
# our dict is ready here, but no properties are changed so far
|
||||
|
||||
# These shall never be written (modified)
|
||||
for column_name in ('model_id', 'model', 'state'):
|
||||
if column_name in vals:
|
||||
del vals[column_name]
|
||||
|
||||
res = super(ir_model_fields,self).write(cr, user, ids, vals, context=context)
|
||||
|
||||
if column_rename:
|
||||
cr.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO "%s"' % column_rename[1])
|
||||
# This is VERY risky, but let us have this feature:
|
||||
# we want to change the key of column in obj._columns dict
|
||||
col = column_rename[0]._columns.pop(column_rename[1][1]) # take object out, w/o copy
|
||||
column_rename[0]._columns[column_rename[1][2]] = col
|
||||
|
||||
if models_patch:
|
||||
# We have to update _columns of the model(s) and then call their
|
||||
# _auto_init to sync the db with the model. Hopefully, since write()
|
||||
# was called earlier, they will be in-sync before the _auto_init.
|
||||
# Anything we don't update in _columns now will be reset from
|
||||
# the model into ir.model.fields (db).
|
||||
ctx = context.copy()
|
||||
ctx.update({'select': vals.get('select_level','0'),'update_custom_fields':True})
|
||||
|
||||
for model_key, patch_struct in models_patch.items():
|
||||
obj = patch_struct[0]
|
||||
for col_name, col_prop, val in patch_struct[1]:
|
||||
setattr(obj._columns[col_name], col_prop, val)
|
||||
obj._auto_init(cr, ctx)
|
||||
return res
|
||||
|
||||
ir_model_fields()
|
||||
|
||||
class ir_model_access(osv.osv):
|
||||
@@ -324,14 +470,24 @@ class ir_model_access(osv.osv):
|
||||
r = cr.fetchone()[0]
|
||||
|
||||
if not r and raise_exception:
|
||||
cr.execute('''select
|
||||
g.name
|
||||
from
|
||||
ir_model_access a
|
||||
left join ir_model m on (a.model_id=m.id)
|
||||
left join res_groups g on (a.group_id=g.id)
|
||||
where
|
||||
m.model=%s and
|
||||
a.group_id is not null and perm_''' + mode, (model_name, ))
|
||||
groups = ', '.join(map(lambda x: x[0], cr.fetchall())) or '/'
|
||||
msgs = {
|
||||
'read': _('You can not read this document! (%s)'),
|
||||
'write': _('You can not write in this document! (%s)'),
|
||||
'create': _('You can not create this kind of document! (%s)'),
|
||||
'unlink': _('You can not delete this document! (%s)'),
|
||||
'read': _("You can not read this document (%s) ! Be sure your user belongs to one of these groups: %s."),
|
||||
'write': _("You can not write in this document (%s) ! Be sure your user belongs to one of these groups: %s."),
|
||||
'create': _("You can not create this document (%s) ! Be sure your user belongs to one of these groups: %s."),
|
||||
'unlink': _("You can not delete this document (%s) ! Be sure your user belongs to one of these groups: %s."),
|
||||
}
|
||||
|
||||
raise except_orm(_('AccessError'), msgs[mode] % model_name )
|
||||
raise except_orm(_('AccessError'), msgs[mode] % (model_name, groups) )
|
||||
return r
|
||||
|
||||
check = tools.cache()(check)
|
||||
|
||||
@@ -61,6 +61,10 @@ class ir_translation(osv.osv):
|
||||
'type': fields.selection(TRANSLATION_TYPE, string='Type', size=16, select=True),
|
||||
'src': fields.text('Source'),
|
||||
'value': fields.text('Translation Value'),
|
||||
# These two columns map to ir_model_data.module and ir_model_data.name.
|
||||
# They are used to resolve the res_id above after loading is done.
|
||||
'module': fields.char('Module', size=64, help='Maps to the ir_model_data for which this translation is provided.'),
|
||||
'xml_id': fields.char('XML Id', size=128, help='Maps to the ir_model_data for which this translation is provided.'),
|
||||
}
|
||||
|
||||
def _auto_init(self, cr, context={}):
|
||||
@@ -88,8 +92,6 @@ class ir_translation(osv.osv):
|
||||
cr.execute('CREATE INDEX ir_translation_ltn ON ir_translation (name, lang, type)')
|
||||
cr.commit()
|
||||
|
||||
|
||||
|
||||
@tools.cache(skiparg=3, multi='ids')
|
||||
def _get_ids(self, cr, uid, name, tt, lang, ids):
|
||||
translations = dict.fromkeys(ids, False)
|
||||
@@ -158,7 +160,7 @@ class ir_translation(osv.osv):
|
||||
WHERE lang=%s
|
||||
AND type in %s
|
||||
AND src=%s"""
|
||||
params = (lang or '', types, source)
|
||||
params = (lang or '', types, tools.ustr(source))
|
||||
if name:
|
||||
query += " AND name=%s"
|
||||
params += (tools.ustr(name),)
|
||||
|
||||
@@ -35,25 +35,6 @@ def one_in(setA, setB):
|
||||
return True
|
||||
return False
|
||||
|
||||
def cond(C, X, Y):
|
||||
if C: return X
|
||||
return Y
|
||||
|
||||
class many2many_unique(fields.many2many):
|
||||
def set(self, cr, obj, id, name, values, user=None, context=None):
|
||||
if not values:
|
||||
return
|
||||
val = values[:]
|
||||
for act in values:
|
||||
if act[0]==4:
|
||||
cr.execute('SELECT * FROM '+self._rel+' \
|
||||
WHERE '+self._id1+'=%s AND '+self._id2+'=%s', (id, act[1]))
|
||||
if cr.fetchall():
|
||||
val.remove(act)
|
||||
return super(many2many_unique, self).set(cr, obj, id, name, val, user=user,
|
||||
context=context)
|
||||
|
||||
|
||||
class ir_ui_menu(osv.osv):
|
||||
_name = 'ir.ui.menu'
|
||||
|
||||
@@ -276,8 +257,14 @@ class ir_ui_menu(osv.osv):
|
||||
def read_image(self, path):
|
||||
path_info = path.split(',')
|
||||
icon_path = addons.get_module_resource(path_info[0],path_info[1])
|
||||
icon = tools.file_open(icon_path,'rb').read()
|
||||
return base64.encodestring(icon)
|
||||
icon_image = False
|
||||
if icon_path:
|
||||
try:
|
||||
icon_file = tools.file_open(icon_path,'rb')
|
||||
icon_image = base64.encodestring(icon_file.read())
|
||||
finally:
|
||||
icon_file.close()
|
||||
return icon_image
|
||||
|
||||
def _get_image_icon(self, cr, uid, ids, name, args, context=None):
|
||||
res = {}
|
||||
@@ -298,17 +285,17 @@ class ir_ui_menu(osv.osv):
|
||||
'sequence': fields.integer('Sequence'),
|
||||
'child_id' : fields.one2many('ir.ui.menu', 'parent_id','Child IDs'),
|
||||
'parent_id': fields.many2one('ir.ui.menu', 'Parent Menu', select=True),
|
||||
'groups_id': many2many_unique('res.groups', 'ir_ui_menu_group_rel',
|
||||
'groups_id': fields.many2many('res.groups', 'ir_ui_menu_group_rel',
|
||||
'menu_id', 'gid', 'Groups', help="If you have groups, the visibility of this menu will be based on these groups. "\
|
||||
"If this field is empty, OpenERP will compute visibility based on the related object's read access."),
|
||||
'complete_name': fields.function(_get_full_name, method=True,
|
||||
string='Complete Name', type='char', size=128),
|
||||
'icon': fields.selection(tools.icons, 'Icon', size=64),
|
||||
'icon_pict': fields.function(_get_icon_pict, method=True, type='char', size=32),
|
||||
'web_icon': fields.char('Icon File', size=128),
|
||||
'web_icon_hover':fields.char('Icon hover File', size=128),
|
||||
'web_icon_data': fields.function(_get_image_icon, string='Web Icons', type='binary', method=True, readonly=True, store=True, multi='icon'),
|
||||
'web_icon_hover_data':fields.function(_get_image_icon, string='Web Icons Hover', type='binary', method=True, readonly=True, store=True,multi='icon'),
|
||||
'web_icon': fields.char('Web Icon File', size=128),
|
||||
'web_icon_hover':fields.char('Web Icon File (hover)', size=128),
|
||||
'web_icon_data': fields.function(_get_image_icon, string='Web Icon Image', type='binary', method=True, readonly=True, store=True, multi='icon'),
|
||||
'web_icon_hover_data':fields.function(_get_image_icon, string='Web Icon Image (hover)', type='binary', method=True, readonly=True, store=True, multi='icon'),
|
||||
'action': fields.function(_action, fnct_inv=_action_inv,
|
||||
method=True, type='reference', string='Action',
|
||||
selection=[
|
||||
@@ -319,7 +306,7 @@ class ir_ui_menu(osv.osv):
|
||||
('ir.actions.server', 'ir.actions.server'),
|
||||
]),
|
||||
}
|
||||
|
||||
|
||||
def _rec_message(self, cr, uid, ids, context=None):
|
||||
return _('Error ! You can not create recursive Menu.')
|
||||
|
||||
|
||||
@@ -33,12 +33,15 @@ def _check_xml(self, cr, uid, ids, context=None):
|
||||
for view in self.browse(cr, uid, ids, context):
|
||||
eview = etree.fromstring(view.arch.encode('utf8'))
|
||||
frng = tools.file_open(os.path.join('base','rng','view.rng'))
|
||||
relaxng_doc = etree.parse(frng)
|
||||
relaxng = etree.RelaxNG(relaxng_doc)
|
||||
if not relaxng.validate(eview):
|
||||
for error in relaxng.error_log:
|
||||
logger.error(tools.ustr(error))
|
||||
return False
|
||||
try:
|
||||
relaxng_doc = etree.parse(frng)
|
||||
relaxng = etree.RelaxNG(relaxng_doc)
|
||||
if not relaxng.validate(eview):
|
||||
for error in relaxng.error_log:
|
||||
logger.error(tools.ustr(error))
|
||||
return False
|
||||
finally:
|
||||
frng.close()
|
||||
return True
|
||||
|
||||
class view_custom(osv.osv):
|
||||
@@ -92,45 +95,19 @@ class view(osv.osv):
|
||||
if not cr.fetchone():
|
||||
cr.execute('CREATE INDEX ir_ui_view_model_type_inherit_id ON ir_ui_view (model, type, inherit_id)')
|
||||
|
||||
def read(self, cr, uid, ids, fields=None, context={}, load='_classic_read'):
|
||||
|
||||
def write(self, cr, uid, ids, vals, context={}):
|
||||
if not isinstance(ids, (list, tuple)):
|
||||
ids = [ids]
|
||||
result = super(view, self).write(cr, uid, ids, vals, context)
|
||||
|
||||
result = super(view, self).read(cr, uid, ids, fields, context, load)
|
||||
|
||||
for rs in result:
|
||||
if rs.get('model') == 'board.board':
|
||||
cr.execute("select id,arch,ref_id from ir_ui_view_custom where user_id=%s and ref_id=%s", (uid, rs['id']))
|
||||
oview = cr.dictfetchall()
|
||||
if oview:
|
||||
rs['arch'] = oview[0]['arch']
|
||||
|
||||
# drop the corresponding view customizations (used for dashboards for example), otherwise
|
||||
# not all users would see the updated views
|
||||
custom_view_ids = self.pool.get('ir.ui.view.custom').search(cr, uid, [('ref_id','in',ids)])
|
||||
if custom_view_ids:
|
||||
self.pool.get('ir.ui.view.custom').unlink(cr, uid, custom_view_ids)
|
||||
|
||||
return result
|
||||
|
||||
def write(self, cr, uid, ids, vals, context={}):
|
||||
|
||||
if not isinstance(ids, (list, tuple)):
|
||||
ids = [ids]
|
||||
|
||||
exist = self.pool.get('ir.ui.view').browse(cr, uid, ids[0])
|
||||
if exist.model == 'board.board' and 'arch' in vals:
|
||||
vids = self.pool.get('ir.ui.view.custom').search(cr, uid, [('user_id','=',uid), ('ref_id','=',ids[0])])
|
||||
vals2 = {'user_id': uid, 'ref_id': ids[0], 'arch': vals.pop('arch')}
|
||||
|
||||
# write fields except arch to the `ir.ui.view`
|
||||
result = super(view, self).write(cr, uid, ids, vals, context)
|
||||
|
||||
if not vids:
|
||||
self.pool.get('ir.ui.view.custom').create(cr, uid, vals2)
|
||||
else:
|
||||
self.pool.get('ir.ui.view.custom').write(cr, uid, vids, vals2)
|
||||
|
||||
return result
|
||||
|
||||
return super(view, self).write(cr, uid, ids, vals, context)
|
||||
|
||||
def graph_get(self, cr, uid, id, model, node_obj, conn_obj, src_node, des_node,label,scale,context={}):
|
||||
if not label:
|
||||
label = []
|
||||
|
||||
@@ -31,8 +31,12 @@ class wizard_screen(osv.osv_memory):
|
||||
|
||||
def _get_image(self, cr, uid, context=None):
|
||||
path = os.path.join('base','res','config_pixmaps','%d.png'%random.randrange(1,4))
|
||||
file_data = tools.file_open(path,'rb').read()
|
||||
return base64.encodestring(file_data)
|
||||
image_file = file_data = tools.file_open(path,'rb')
|
||||
try:
|
||||
file_data = image_file.read()
|
||||
return base64.encodestring(file_data)
|
||||
finally:
|
||||
image_file.close()
|
||||
|
||||
def _get_image_fn(self, cr, uid, ids, name, args, context=None):
|
||||
image = self._get_image(cr, uid, context)
|
||||
|
||||
@@ -173,15 +173,15 @@ class wkf_instance(osv.osv):
|
||||
_log_access = False
|
||||
_columns = {
|
||||
'wkf_id': fields.many2one('workflow', 'Workflow', ondelete='cascade', select=True),
|
||||
'res_id': fields.integer('Resource ID', select=True),
|
||||
'res_type': fields.char('Resource Object', size=64, select=True),
|
||||
'state': fields.char('State', size=32, select=True),
|
||||
'res_id': fields.integer('Resource ID'),
|
||||
'res_type': fields.char('Resource Object', size=64),
|
||||
'state': fields.char('State', size=32),
|
||||
}
|
||||
def _auto_init(self, cr, context=None):
|
||||
super(wkf_instance, self)._auto_init(cr, context)
|
||||
cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'wkf_instance_res_id_res_type_state_index\'')
|
||||
cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'wkf_instance_res_type_res_id_state_index\'')
|
||||
if not cr.fetchone():
|
||||
cr.execute('CREATE INDEX wkf_instance_res_id_res_type_state_index ON wkf_instance (res_id, res_type, state)')
|
||||
cr.execute('CREATE INDEX wkf_instance_res_type_res_id_state_index ON wkf_instance (res_type, res_id, state)')
|
||||
cr.execute('SELECT indexname FROM pg_indexes WHERE indexname = \'wkf_instance_res_id_wkf_id_index\'')
|
||||
if not cr.fetchone():
|
||||
cr.execute('CREATE INDEX wkf_instance_res_id_wkf_id_index ON wkf_instance (res_id, wkf_id)')
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
<field name="action"/>
|
||||
<newline/>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter string="Workflow" icon="terp-stock_align_left_24" domain="[]" context="{'group_by':'wkf_id'}"/>
|
||||
<filter string="Workflow" icon="terp-stage" domain="[]" context="{'group_by':'wkf_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
|
||||
@@ -475,7 +475,7 @@ class module(osv.osv):
|
||||
categs = categs[1:]
|
||||
self.write(cr, uid, [mod_browse.id], {'category_id': p_id})
|
||||
|
||||
def update_translations(self, cr, uid, ids, filter_lang=None, context=None):
|
||||
def update_translations(self, cr, uid, ids, filter_lang=None, context={}):
|
||||
logger = logging.getLogger('i18n')
|
||||
if not filter_lang:
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
@@ -495,17 +495,26 @@ class module(osv.osv):
|
||||
for lang in filter_lang:
|
||||
iso_lang = tools.get_iso_codes(lang)
|
||||
f = addons.get_module_resource(mod.name, 'i18n', iso_lang + '.po')
|
||||
context2 = context and context.copy() or {}
|
||||
if f and '_' in iso_lang:
|
||||
iso_lang2 = iso_lang.split('_')[0]
|
||||
f2 = addons.get_module_resource(mod.name, 'i18n', iso_lang2 + '.po')
|
||||
if f2:
|
||||
logger.info('module %s: loading base translation file %s for language %s', mod.name, iso_lang2, lang)
|
||||
tools.trans_load(cr, f2, lang, verbose=False, context=context)
|
||||
context2['overwrite'] = True
|
||||
# Implementation notice: we must first search for the full name of
|
||||
# the language derivative, like "en_UK", and then the generic,
|
||||
# like "en".
|
||||
if (not f) and '_' in iso_lang:
|
||||
f = addons.get_module_resource(mod.name, 'i18n', iso_lang.split('_')[0] + '.po')
|
||||
iso_lang = iso_lang.split('_')[0]
|
||||
f = addons.get_module_resource(mod.name, 'i18n', iso_lang + '.po')
|
||||
if f:
|
||||
logger.info('module %s: loading translation file for language %s', mod.name, iso_lang)
|
||||
tools.trans_load(cr.dbname, f, lang, verbose=False, context=context)
|
||||
logger.info('module %s: loading translation file (%s) for language %s', mod.name, iso_lang, lang)
|
||||
tools.trans_load(cr, f, lang, verbose=False, context=context2)
|
||||
elif iso_lang != 'en':
|
||||
logger.warning('module %s: no translation for language %s', mod.name, iso_lang)
|
||||
tools.trans_update_res_ids(cr)
|
||||
|
||||
def check(self, cr, uid, ids, context=None):
|
||||
logger = logging.getLogger('init')
|
||||
@@ -522,13 +531,13 @@ class module(osv.osv):
|
||||
raise osv.except_osv(_('Error'), _('Module %s: Invalid Quality Certificate') % (mod.name,))
|
||||
|
||||
def list_web(self, cr, uid, context=None):
|
||||
""" list_web(cr, uid, context) -> [module_name]
|
||||
""" list_web(cr, uid, context) -> [(module_name, module_version)]
|
||||
Lists all the currently installed modules with a web component.
|
||||
|
||||
Returns a list of addon names.
|
||||
Returns a list of a tuple of addon names and addon versions.
|
||||
"""
|
||||
return [
|
||||
module['name']
|
||||
(module['name'], module['installed_version'])
|
||||
for module in self.browse(cr, uid,
|
||||
self.search(cr, uid,
|
||||
[('web', '=', True),
|
||||
@@ -561,6 +570,7 @@ class module(osv.osv):
|
||||
'to web client', names)
|
||||
return [
|
||||
{'name': module.name,
|
||||
'version': module.installed_version,
|
||||
'depends': list(self._web_dependencies(
|
||||
cr, uid, module, context=context)),
|
||||
'content': addons.zip_directory(
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain"/>
|
||||
<field name="search_view_id" ref="view_module_filter"/>
|
||||
<field name="help">List all certified modules available to configure your OpenERP. Modules that are installed are flagged as such. You can search for a specific module using the name or the description of the module. You do not need to install modules one by one, you can install many at the same time by clicking on the schedule button in this list. Then, apply the schedule upgrade from Action menu once for all the ones you have scheduled for installation.</field>
|
||||
<field name="help">You can install new modules in order to activate new features, menu, reports or data in your OpenERP instance. To install some modules, click on the button "Schedule for Installation" from the form view, then click on "Apply Scheduled Upgrades" to migrate your system.</field>
|
||||
</record>
|
||||
<menuitem action="open_module_tree" id="menu_module_tree" parent="base.menu_management"/>
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ class base_language_export(osv.osv_memory):
|
||||
mods = map(lambda m: m.name, this.modules) or ['all']
|
||||
mods.sort()
|
||||
buf=cStringIO.StringIO()
|
||||
tools.trans_export(this.lang, mods, buf, this.format, dbname=cr.dbname)
|
||||
tools.trans_export(this.lang, mods, buf, this.format, cr)
|
||||
if this.format == 'csv':
|
||||
this.advice = _("Save this document to a .CSV file and open it with your favourite spreadsheet software. The file encoding is UTF-8. You have to translate the latest column before reimporting it.")
|
||||
elif this.format == 'po':
|
||||
@@ -86,4 +86,4 @@ class base_language_export(osv.osv_memory):
|
||||
}
|
||||
base_language_export()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -56,8 +56,9 @@ class base_language_import(osv.osv_memory):
|
||||
fileformat = first_line.endswith("type,name,res_id,src,value") and 'csv' or 'po'
|
||||
fileobj.seek(0)
|
||||
|
||||
tools.trans_load_data(cr.dbname, fileobj, fileformat, import_data.code, lang_name=import_data.name)
|
||||
tools.trans_load_data(cr, fileobj, fileformat, import_data.code, lang_name=import_data.name)
|
||||
tools.trans_update_res_ids(cr)
|
||||
fileobj.close()
|
||||
return {}
|
||||
|
||||
base_language_import()
|
||||
base_language_import()
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<field name="name">Start Configuration</field>
|
||||
<field name="model_id" ref="model_base_module_configuration"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = obj.start([])</field>
|
||||
<field name="code">action = obj.start()</field>
|
||||
</record>
|
||||
|
||||
<menuitem name="Start Configuration"
|
||||
|
||||
@@ -82,12 +82,10 @@ class base_module_upgrade(osv.osv_memory):
|
||||
return {'module_info': '\n'.join(map(lambda x: x['name']+' : '+x['state'], res))}
|
||||
|
||||
def upgrade_module(self, cr, uid, ids, context=None):
|
||||
pool = pooler.get_pool(cr.dbname)
|
||||
mod_obj = self.pool.get('ir.module.module')
|
||||
data_obj = self.pool.get('ir.model.data')
|
||||
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')
|
||||
mod_dep_obj = self.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):
|
||||
@@ -97,8 +95,9 @@ class base_module_upgrade(osv.osv_memory):
|
||||
raise osv.except_osv(_('Unmet dependency !'), _('Following modules are not installed or unknown: %s') % ('\n\n' + '\n'.join(unmet_packages)))
|
||||
mod_obj.download(cr, uid, ids, context=context)
|
||||
cr.commit()
|
||||
_, pool = pooler.restart_pool(cr.dbname, update_module=True)
|
||||
_db, pool = pooler.restart_pool(cr.dbname, update_module=True)
|
||||
|
||||
data_obj = pool.get('ir.model.data')
|
||||
id2 = data_obj._get_id(cr, uid, 'base', 'view_base_module_upgrade_install')
|
||||
if id2:
|
||||
id2 = data_obj.browse(cr, uid, id2, context=context).res_id
|
||||
|
||||
@@ -45,8 +45,9 @@ class base_update_translations(osv.osv_memory):
|
||||
this = self.browse(cr, uid, ids)[0]
|
||||
lang_name = self._get_lang_name(cr, uid, this.lang)
|
||||
buf=cStringIO.StringIO()
|
||||
tools.trans_export(this.lang, ['all'], buf, 'csv', dbname=cr.dbname)
|
||||
tools.trans_load_data(cr.dbname, buf, 'csv', this.lang, lang_name=lang_name)
|
||||
tools.trans_export(this.lang, ['all'], buf, 'csv', cr)
|
||||
tools.trans_load_data(cr, buf, 'csv', this.lang, lang_name=lang_name)
|
||||
tools.trans_update_res_ids(cr)
|
||||
buf.close()
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
@@ -70,4 +71,4 @@ class base_update_translations(osv.osv_memory):
|
||||
'lang': fields.selection(_get_languages, 'Language', required=True),
|
||||
}
|
||||
|
||||
base_update_translations()
|
||||
base_update_translations()
|
||||
|
||||
@@ -317,14 +317,16 @@ def get_sys_logs(cr, uid):
|
||||
}
|
||||
|
||||
add_arg = {"timeout":30} if sys.version_info >= (2,6) else {}
|
||||
uo = urllib2.urlopen(config.get("publisher_warranty_url"),
|
||||
urllib.urlencode({'arg0': msg, "action": "update",}), **add_arg)
|
||||
arguments = {'arg0': msg, "action": "update",}
|
||||
arguments_raw = urllib.urlencode(arguments)
|
||||
url = config.get("publisher_warranty_url")
|
||||
uo = urllib2.urlopen(url, arguments_raw, **add_arg)
|
||||
try:
|
||||
submit_result = uo.read()
|
||||
finally:
|
||||
uo.close()
|
||||
|
||||
result = safe_eval(submit_result)
|
||||
result = safe_eval(submit_result) if submit_result else {}
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -24,23 +24,23 @@
|
||||
<form string="Publisher Warranty Contract">
|
||||
<group col="2" colspan="4">
|
||||
<group col="2">
|
||||
<field name="name"/>
|
||||
<field name="name"/>
|
||||
</group>
|
||||
<group col="2">
|
||||
<field name="date_start"/>
|
||||
<field name="date_stop"/>
|
||||
</group>
|
||||
<field name="date_start"/>
|
||||
<field name="date_stop"/>
|
||||
</group>
|
||||
<group col="2">
|
||||
<field name="state"/>
|
||||
<field name="kind"/>
|
||||
</group>
|
||||
<group col="2">
|
||||
<button name="check_validity" string="Validate" type="object"
|
||||
attrs="{'invisible':[('state','in',['valid', 'terminated', 'canceled'])]}"/>
|
||||
<button name="check_validity" string="Refresh Validation Dates" type="object"
|
||||
attrs="{'invisible':[('state','in',['unvalidated'])]}"/>
|
||||
<button name="check_validity" string="Validate" type="object"
|
||||
attrs="{'invisible':[('state','in',['valid', 'terminated', 'canceled'])]}"/>
|
||||
<button name="check_validity" string="Refresh Validation Dates" type="object"
|
||||
attrs="{'invisible':[('state','in',['unvalidated'])]}"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
@@ -80,10 +80,10 @@
|
||||
</record>
|
||||
|
||||
<menuitem name="Publisher Warranty" id="publisher_warranty"
|
||||
parent="base.menu_administration" groups="base.group_extended"/>
|
||||
parent="base.menu_administration"/>
|
||||
|
||||
<menuitem action="action_publisher_warranty_contract_form" id="menu_publisher_warranty_contract"
|
||||
parent="publisher_warranty" sequence="2"/>
|
||||
parent="publisher_warranty" sequence="2"/>
|
||||
|
||||
|
||||
<record id="publisher_warranty_contract_add_wizard" model="ir.ui.view">
|
||||
@@ -92,7 +92,7 @@
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Register a Contract">
|
||||
<group col="8">
|
||||
<group col="8">
|
||||
<group colspan="3" col="1">
|
||||
<field name="config_logo" widget="image" width="220" height="130" nolabel="1" colspan="1"/>
|
||||
<newline/>
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<field name="help">Manage bank records you want to be used in the system.</field>
|
||||
</record>
|
||||
|
||||
<menuitem action="action_res_bank_form" groups="group_extended,group_system" id="menu_action_res_bank_form"
|
||||
parent="base.menu_config_address_book" sequence="5"/>
|
||||
<menuitem action="action_res_bank_form" id="menu_action_res_bank_form"
|
||||
parent="base.menu_config_address_book" sequence="5"/>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -48,6 +48,20 @@ class res_partner_category(osv.osv):
|
||||
res.append((record['id'], name))
|
||||
return res
|
||||
|
||||
def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100):
|
||||
if not args:
|
||||
args=[]
|
||||
if not context:
|
||||
context={}
|
||||
if name:
|
||||
# Be sure name_search is symetric to name_get
|
||||
name = name.split(' / ')[-1]
|
||||
ids = self.search(cr, uid, [('name', operator, name)] + args, limit=limit, context=context)
|
||||
else:
|
||||
ids = self.search(cr, uid, args, limit=limit, context=context)
|
||||
return self.name_get(cr, uid, ids, context)
|
||||
|
||||
|
||||
def _name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
|
||||
res = self.name_get(cr, uid, ids, context=context)
|
||||
return dict(res)
|
||||
@@ -124,7 +138,7 @@ class res_partner(osv.osv):
|
||||
'email': fields.related('address', 'email', type='char', size=240, string='E-mail'),
|
||||
'company_id': fields.many2one('res.company', 'Company', select=1),
|
||||
}
|
||||
|
||||
|
||||
def _default_category(self, cr, uid, context={}):
|
||||
if 'category_id' in context and context['category_id']:
|
||||
return [context['category_id']]
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<filter string="Customer" name="customer" icon="terp-personal" domain="[('is_customer_add','=','1')]" />
|
||||
<filter string="Supplier" name="supplier" icon="terp-personal" domain="[('is_supplier_add','=','1')]" />
|
||||
<separator orientation="vertical"/>
|
||||
<field name="partner_id" />
|
||||
<field name="partner_id" string="Partner"/>
|
||||
<field name="name" />
|
||||
<field name="country_id" />
|
||||
</group>
|
||||
@@ -108,7 +108,7 @@
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">res.partner.address</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="context">{"search_default_customer":1}</field>
|
||||
<field name="context">{"search_default_customer":1,"search_default_partner_id":self}</field>
|
||||
<field name="search_view_id" ref="view_res_partner_address_filter"/>
|
||||
<field name="help">Customers (also called Partners in other areas of the system) helps you manage your address book of companies whether they are prospects, customers and/or suppliers. The partner form allows you to track and record all the necessary information to interact with your partners from the company address to their contacts as well as pricelists, and much more. If you installed the CRM, with the history tab, you can track all the interactions with a partner such as opportunities, emails, or sales orders issued.</field>
|
||||
</record>
|
||||
@@ -339,7 +339,7 @@
|
||||
<field name="name" select="1"/>
|
||||
<field name="address" select="1"/>
|
||||
<field name="country" select="1"/>
|
||||
<field name="category_id" select="1"/>
|
||||
<field name="category_id" select="1" groups="base.group_extended"/>
|
||||
<field name="user_id" select="1">
|
||||
<filter string="My Partners" icon="terp-personal+" domain="[('user_id','=',uid)]"/>
|
||||
</field>
|
||||
@@ -359,7 +359,7 @@
|
||||
<field name="view_type">form</field>
|
||||
<field name="context">{"search_default_customer":1}</field>
|
||||
<field name="search_view_id" ref="view_res_partner_filter"/>
|
||||
<field name="help">The Address book manages your customers list. The form for customer allows you to record detailed on your customers (address, contacts, pricelist, account, etc.). With the history tab, you can follow all moves transactions related to a customer, like sales order, claims.</field>
|
||||
<field name="help">A customer is an entity you do business with, like a company or an organization. A customer can have several contacts or addresses which are the people working for this company. You can use the history tab, to follow all transactions related to a customer: sales order, emails, opportunities, claims, etc. If you use the email gateway, the Outlook or the Thunderbird plugin, don't forget to register emails to each contact so that the gateway will automatically attach incoming emails to the right partner.</field>
|
||||
</record>
|
||||
<record id="action_partner_form_view1" model="ir.actions.act_window.view">
|
||||
<field eval="10" name="sequence"/>
|
||||
@@ -397,7 +397,7 @@
|
||||
<field name="domain">[]</field>
|
||||
<field name="context">{'default_customer':0, 'search_default_supplier': 1, 'default_supplier':1}</field>
|
||||
<field name="filter" eval="True"/>
|
||||
<field name="help">With the Suppliers menu, you have access to all informations regarding your suppliers, including an history to track event (crm) and his accounting properties.</field>
|
||||
<field name="help">You can access all information regarding your suppliers from the supplier form: accounting data, history of emails, meetings, purchases, etc. You can uncheck the 'Suppliers' filter button in order to search in all your partners, including customers and prospects.</field>
|
||||
</record>
|
||||
|
||||
<record id="action_partner_employee_form" model="ir.actions.act_window">
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<separator string="" colspan="4" />
|
||||
<group colspan="4" col="6">
|
||||
<button special="cancel" string="Cancel" icon="gtk-cancel"/>
|
||||
<button name="sms_send" string="Send SMS" type="object" icon="gtk-go-forward"/>
|
||||
<button name="sms_send" string="Send SMS" type="object" icon="terp-mail-message-new"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
import netsvc
|
||||
import tools
|
||||
from osv import fields, osv
|
||||
import re
|
||||
|
||||
class partner_wizard_spam(osv.osv_memory):
|
||||
""" Mass Mailing """
|
||||
@@ -51,14 +52,22 @@ class partner_wizard_spam(osv.osv_memory):
|
||||
event_pool = self.pool.get('res.partner.event')
|
||||
active_ids = context and context.get('active_ids', [])
|
||||
partners = partner_pool.browse(cr, uid, active_ids, context)
|
||||
type_ = 'plain'
|
||||
if re.search('(<(pre)|[pubi].*>)', data.text):
|
||||
type_ = 'html'
|
||||
for partner in partners:
|
||||
for adr in partner.address:
|
||||
if adr.email:
|
||||
name = adr.name or partner.name
|
||||
to = '%s <%s>' % (name, adr.email)
|
||||
to = '"%s" <%s>' % (name, adr.email)
|
||||
#TODO: add some tests to check for invalid email addresses
|
||||
#CHECKME: maybe we should use res.partner/email_send
|
||||
tools.email_send(data.email_from, [to], data.subject, data.text,subtype='html')
|
||||
tools.email_send(data.email_from,
|
||||
[to],
|
||||
data.subject,
|
||||
data.text,
|
||||
subtype=type_,
|
||||
openobject_id="res.partner-%s"%partner.id)
|
||||
nbr += 1
|
||||
event_pool.create(cr, uid,
|
||||
{'name': 'Email(s) sent through mass mailing',
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<separator string="" colspan="6"/>
|
||||
<group colspan="6" col="4" >
|
||||
<button special="cancel" string="Cancel" icon="gtk-cancel" />
|
||||
<button name="mass_mail_send" string="Send Email" type="object" icon="gtk-go-forward"/>
|
||||
<button name="mass_mail_send" string="Send Email" type="object" icon="terp-mail-message-new"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
|
||||
@@ -98,13 +98,7 @@ class res_company(osv.osv):
|
||||
context = {}
|
||||
user_preference = context.get('user_preference', False)
|
||||
if user_preference:
|
||||
# TODO: improve this as soon as the client sends the proper
|
||||
# combination of active_id and active_model we'll be able to
|
||||
# use active_id here to restrict to the user being modified instead
|
||||
# of current user.
|
||||
user_id = context.get('user_id', uid)
|
||||
|
||||
user = self.pool.get('res.users').browse(cr, uid, user_id, context=context)
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
cmp_ids = list(set([user.company_id.id] + [cmp.id for cmp in user.company_ids]))
|
||||
return cmp_ids
|
||||
return super(res_company, self)._search(cr, uid, args, offset=offset, limit=limit, order=order,
|
||||
@@ -226,7 +220,11 @@ class res_company(osv.osv):
|
||||
</header>"""
|
||||
def _get_header(self,cr,uid,ids):
|
||||
try :
|
||||
return tools.file_open(os.path.join('base', 'report', 'corporate_rml_header.rml')).read()
|
||||
header_file = tools.file_open(os.path.join('base', 'report', 'corporate_rml_header.rml'))
|
||||
try:
|
||||
return header_file.read()
|
||||
finally:
|
||||
header_file.close()
|
||||
except:
|
||||
return """
|
||||
<header>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<field name="priority" eval="8"/>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Multi Company">
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="company_id"/>
|
||||
<field name="object_id"/>
|
||||
<field name="field_id"/>
|
||||
<field name="expression" />
|
||||
@@ -29,7 +29,7 @@
|
||||
<group col="6" colspan="4">
|
||||
<field name="name" colspan="6"/>
|
||||
<separator string="Matching" colspan="6"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="company_id"/>
|
||||
<field name="object_id"/>
|
||||
<field name="field_id" domain="[('model_id','=',object_id)]"/>
|
||||
<separator string="Condition" colspan="6"/>
|
||||
|
||||
@@ -24,6 +24,7 @@ from operator import attrgetter
|
||||
from osv import osv, fields
|
||||
from tools.translate import _
|
||||
import netsvc
|
||||
from tools import ustr
|
||||
import pooler
|
||||
|
||||
|
||||
@@ -279,7 +280,7 @@ class res_config_installer(osv.osv_memory):
|
||||
``res.config``). Hooks and additionals *are not run* when skipping
|
||||
installation, even for already installed addons.
|
||||
|
||||
Again, setup your hooks accordinly.
|
||||
Again, setup your hooks accordingly.
|
||||
|
||||
.. [#] note that since a mapping key needs to be hashable, it's
|
||||
possible to use a tuple or a frozenset, but not a list or a
|
||||
@@ -379,9 +380,8 @@ class res_config_installer(osv.osv_memory):
|
||||
continue
|
||||
fields[module.name].update(
|
||||
readonly=True,
|
||||
help=fields[module.name].get('help', '') +
|
||||
help= ustr(fields[module.name].get('help', '')) +
|
||||
_('\n\nThis addon is already installed on your system'))
|
||||
|
||||
return fields
|
||||
|
||||
def execute(self, cr, uid, ids, context=None):
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group colspan="4" col="8">
|
||||
<group colspan="1" width="220" height="250">
|
||||
<group colspan="1" width="220">
|
||||
<field name="config_logo" widget="image" width="220" height="130" nolabel="1"/>
|
||||
<newline/>
|
||||
<label align="0.0" string="description" width="200" colspan="2"/>
|
||||
</group>
|
||||
<separator string="vsep" orientation="vertical" colspan="1" rowspan="12"/>
|
||||
<group colspan="4">
|
||||
<group colspan="6">
|
||||
<separator string="title" colspan="4"/>
|
||||
<group string="res_config_contents"/>
|
||||
</group>
|
||||
@@ -61,13 +61,13 @@
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group colspan="4" col="8">
|
||||
<group colspan="3" width="220" height="250">
|
||||
<group colspan="1" width="220" height="250">
|
||||
<field name="config_logo" widget="image" width="220" height="130" nolabel="1" colspan="1"/>
|
||||
<newline/>
|
||||
<label align="0.0" string="description" width="200" colspan="2"/>
|
||||
</group>
|
||||
<separator string="vsep" orientation="vertical" colspan="1" rowspan="12"/>
|
||||
<group colspan="4">
|
||||
<group colspan="6">
|
||||
<separator string="title" colspan="4"/>
|
||||
<group colspan="8"/>
|
||||
</group>
|
||||
|
||||
@@ -88,16 +88,9 @@ class res_currency(osv.osv):
|
||||
def is_zero(self, cr, uid, currency, amount):
|
||||
return abs(self.round(cr, uid, currency, amount)) < currency.rounding
|
||||
|
||||
def compute(self, cr, uid, from_currency_id, to_currency_id, from_amount, round=True, context=None, account=None, account_invert=False):
|
||||
def _get_conversion_rate(self, cr, uid, from_currency, to_currency, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if not from_currency_id:
|
||||
from_currency_id = to_currency_id
|
||||
if not to_currency_id:
|
||||
to_currency_id = from_currency_id
|
||||
xc = self.browse(cr, uid, [from_currency_id,to_currency_id], context=context)
|
||||
from_currency = (xc[0].id == from_currency_id and xc[0]) or xc[1]
|
||||
to_currency = (xc[0].id == to_currency_id and xc[0]) or xc[1]
|
||||
if from_currency['rate'] == 0 or to_currency['rate'] == 0:
|
||||
date = context.get('date', time.strftime('%Y-%m-%d'))
|
||||
if from_currency['rate'] == 0:
|
||||
@@ -107,22 +100,23 @@ class res_currency(osv.osv):
|
||||
raise osv.except_osv(_('Error'), _('No rate found \n' \
|
||||
'for the currency: %s \n' \
|
||||
'at the date: %s') % (currency_symbol, date))
|
||||
rate = to_currency.rate/from_currency.rate
|
||||
if account and (account.currency_mode=='average') and account.currency_id:
|
||||
q = self.pool.get('account.move.line')._query_get(cr, uid, context=context)
|
||||
cr.execute('select sum(debit-credit),sum(amount_currency) from account_move_line l ' \
|
||||
'where l.currency_id=%s and l.account_id=%s and '+q, (account.currency_id.id,account.id,))
|
||||
tot1,tot2 = cr.fetchone()
|
||||
if tot2 and not account_invert:
|
||||
rate = float(tot1)/float(tot2)
|
||||
elif tot1 and account_invert:
|
||||
rate = float(tot2)/float(tot1)
|
||||
if to_currency_id==from_currency_id:
|
||||
return to_currency.rate/from_currency.rate
|
||||
|
||||
def compute(self, cr, uid, from_currency_id, to_currency_id, from_amount, round=True, context=None):
|
||||
if not from_currency_id:
|
||||
from_currency_id = to_currency_id
|
||||
if not to_currency_id:
|
||||
to_currency_id = from_currency_id
|
||||
xc = self.browse(cr, uid, [from_currency_id,to_currency_id], context=context)
|
||||
from_currency = (xc[0].id == from_currency_id and xc[0]) or xc[1]
|
||||
to_currency = (xc[0].id == to_currency_id and xc[0]) or xc[1]
|
||||
if to_currency_id == from_currency_id:
|
||||
if round:
|
||||
return self.round(cr, uid, to_currency, from_amount)
|
||||
else:
|
||||
return from_amount
|
||||
else:
|
||||
rate = self._get_conversion_rate(cr, uid, from_currency, to_currency, context=context)
|
||||
if round:
|
||||
return self.round(cr, uid, to_currency, from_amount * rate)
|
||||
else:
|
||||
|
||||
@@ -24,10 +24,69 @@ from locale import localeconv
|
||||
import tools
|
||||
from tools.safe_eval import safe_eval as eval
|
||||
from tools.translate import _
|
||||
import locale
|
||||
import logging
|
||||
|
||||
class lang(osv.osv):
|
||||
_name = "res.lang"
|
||||
_description = "Languages"
|
||||
|
||||
def install_lang(self, cr, uid, **args):
|
||||
lang = tools.config.get('lang')
|
||||
if not lang:
|
||||
return False
|
||||
lang_ids = self.search(cr, uid, [('code','=', lang)])
|
||||
values_obj = self.pool.get('ir.values')
|
||||
if not lang_ids:
|
||||
lang_id = self.load_lang(cr, uid, lang)
|
||||
default_value = values_obj.get(cr, uid, 'default', False, 'res.partner')
|
||||
if not default_value:
|
||||
values_obj.set(cr, uid, 'default', False, 'lang', ['res.partner'], lang)
|
||||
return True
|
||||
|
||||
def load_lang(self, cr, uid, lang, lang_name=None):
|
||||
# create the language with locale information
|
||||
fail = True
|
||||
logger = logging.getLogger('i18n')
|
||||
iso_lang = tools.get_iso_codes(lang)
|
||||
for ln in tools.get_locales(lang):
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, str(ln))
|
||||
fail = False
|
||||
break
|
||||
except locale.Error:
|
||||
continue
|
||||
if fail:
|
||||
lc = locale.getdefaultlocale()[0]
|
||||
msg = 'Unable to get information for locale %s. Information from the default locale (%s) have been used.'
|
||||
logger.warning(msg, lang, lc)
|
||||
|
||||
if not lang_name:
|
||||
lang_name = tools.get_languages().get(lang, lang)
|
||||
|
||||
|
||||
def fix_xa0(s):
|
||||
if s == '\xa0':
|
||||
return '\xc2\xa0'
|
||||
return s
|
||||
|
||||
lang_info = {
|
||||
'code': lang,
|
||||
'iso_code': iso_lang,
|
||||
'name': lang_name,
|
||||
'translatable': 1,
|
||||
'date_format' : str(locale.nl_langinfo(locale.D_FMT).replace('%y', '%Y')),
|
||||
'time_format' : str(locale.nl_langinfo(locale.T_FMT)),
|
||||
'decimal_point' : fix_xa0(str(locale.localeconv()['decimal_point'])),
|
||||
'thousands_sep' : fix_xa0(str(locale.localeconv()['thousands_sep'])),
|
||||
}
|
||||
lang_id = False
|
||||
try:
|
||||
lang_id = self.create(cr, uid, lang_info)
|
||||
finally:
|
||||
tools.resetlocale()
|
||||
return lang_id
|
||||
|
||||
def _get_default_date_format(self,cursor,user,context={}):
|
||||
return '%m/%d/%Y'
|
||||
|
||||
@@ -69,7 +128,7 @@ class lang(osv.osv):
|
||||
thousands_sep = lang_obj.thousands_sep or conv[monetary and 'mon_thousands_sep' or 'thousands_sep']
|
||||
decimal_point = lang_obj.decimal_point
|
||||
grouping = lang_obj.grouping
|
||||
return (grouping, thousands_sep, decimal_point)
|
||||
return (grouping, thousands_sep, decimal_point)
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
for lang_id in ids :
|
||||
@@ -95,19 +154,19 @@ class lang(osv.osv):
|
||||
|
||||
def _group(self, cr, uid, ids, s, monetary=False, grouping=False, thousands_sep=''):
|
||||
grouping = eval(grouping)
|
||||
|
||||
|
||||
if not grouping:
|
||||
return (s, 0)
|
||||
|
||||
result = ""
|
||||
seps = 0
|
||||
spaces = ""
|
||||
|
||||
|
||||
if s[-1] == ' ':
|
||||
sp = s.find(' ')
|
||||
spaces = s[sp:]
|
||||
s = s[:sp]
|
||||
|
||||
|
||||
while s and grouping:
|
||||
# if grouping is -1, we are done
|
||||
if grouping[0] == -1:
|
||||
@@ -139,7 +198,7 @@ class lang(osv.osv):
|
||||
if percent[0] != '%':
|
||||
raise ValueError("format() must be given exactly one %char format specifier")
|
||||
|
||||
lang_grouping, thousands_sep, decimal_point = self._lang_data_get(cr, uid, ids[0], monetary)
|
||||
lang_grouping, thousands_sep, decimal_point = self._lang_data_get(cr, uid, ids[0], monetary)
|
||||
|
||||
formatted = percent % value
|
||||
# floats and decimal ints need special action!
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
<field name="type">search</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Logs">
|
||||
<filter icon="terp-stock_align_left_24" string="Read" domain="[('read','=',True)]" name="read"/>
|
||||
<filter icon="terp-stock_align_left_24" string="Unread" domain="[('read','<>',True)]" name="unread"/>
|
||||
<filter icon="terp-camera_test" string="Read" domain="[('read','=',True)]" name="read"/>
|
||||
<filter icon="terp-gtk-jump-to-ltr" string="Unread" domain="[('read','<>',True)]" name="unread"/>
|
||||
<separator orientation="vertical"/>
|
||||
<filter icon="terp-stock_align_left_24" string="My Logs" domain="[('user_id','=',uid)]" name="my"/>
|
||||
<filter icon="terp-personal" string="My Logs" domain="[('user_id','=',uid)]" name="my"/>
|
||||
<filter icon="terp-stock_align_left_24" string="System Logs"
|
||||
domain="[('res_model','=','publisher_warranty.contract')]" name="sys"/>
|
||||
domain="[('res_model','=','publisher_warranty.contract')]" name="sys"/>
|
||||
<separator orientation="vertical"/>
|
||||
<field name="name"/>
|
||||
<field name="user_id"/>
|
||||
@@ -52,7 +52,7 @@
|
||||
</record>
|
||||
|
||||
<record id="res_log_act_window" model="ir.actions.act_window">
|
||||
<field name="name">Logs</field>
|
||||
<field name="name">Client Logs</field>
|
||||
<field name="res_model">res.log</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="context">{'search_default_my': 1}</field>
|
||||
|
||||
@@ -65,11 +65,11 @@ class res_request(osv.osv):
|
||||
'name': fields.char('Subject', states={'waiting':[('readonly',True)],'active':[('readonly',True)],'closed':[('readonly',True)]}, required=True, size=128),
|
||||
'active': fields.boolean('Active'),
|
||||
'priority': fields.selection([('0','Low'),('1','Normal'),('2','High')], 'Priority', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}, required=True),
|
||||
'act_from': fields.many2one('res.users', 'From', required=True, readonly=True, states={'closed':[('readonly',True)]}),
|
||||
'act_to': fields.many2one('res.users', 'To', required=True, states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}),
|
||||
'act_from': fields.many2one('res.users', 'From', required=True, readonly=True, states={'closed':[('readonly',True)]}, select=1),
|
||||
'act_to': fields.many2one('res.users', 'To', required=True, states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}, select=1),
|
||||
'body': fields.text('Request', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}),
|
||||
'date_sent': fields.datetime('Date', readonly=True),
|
||||
'trigger_date': fields.datetime('Trigger Date', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}),
|
||||
'trigger_date': fields.datetime('Trigger Date', states={'waiting':[('readonly',True)],'closed':[('readonly',True)]}, select=1),
|
||||
'ref_partner_id':fields.many2one('res.partner', 'Partner Ref.', states={'closed':[('readonly',True)]}),
|
||||
'ref_doc1':fields.reference('Document Ref 1', selection=_links_get, size=128, states={'closed':[('readonly',True)]}),
|
||||
'ref_doc2':fields.reference('Document Ref 2', selection=_links_get, size=128, states={'closed':[('readonly',True)]}),
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
<field name="name">Partner Manager</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.menu" id="menu_config_address_book">
|
||||
<field eval="[(6,0,[ref('group_system'), ref('group_partner_manager')])]" name="groups_id"/>
|
||||
</record>
|
||||
<record model="ir.ui.menu" id="menu_base_config">
|
||||
<field eval="[(6,0,[ref('group_system'), ref('group_partner_manager')])]" name="groups_id"/>
|
||||
</record>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
# Copyright (C) 2010-2011 OpenERP s.a. (<http://openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
@@ -28,7 +29,6 @@ import pooler
|
||||
from tools.translate import _
|
||||
from service import security
|
||||
import netsvc
|
||||
import time
|
||||
|
||||
class groups(osv.osv):
|
||||
_name = "res.groups"
|
||||
@@ -194,6 +194,18 @@ class users(osv.osv):
|
||||
self.write(cr, uid, ids, {'address_id': address_id}, context)
|
||||
return True
|
||||
|
||||
def _set_new_password(self, cr, uid, id, name, value, args, context=None):
|
||||
if value is False:
|
||||
# Do not update the password if no value is provided, ignore silently.
|
||||
# For example web client submits False values for all empty fields.
|
||||
return
|
||||
if uid == id:
|
||||
# To change their own password users must use the client-specific change password wizard,
|
||||
# so that the new password is immediately used for further RPC requests, otherwise the user
|
||||
# will face unexpected 'Access Denied' exceptions.
|
||||
raise osv.except_osv(_('Operation Canceled'), _('Please use the change password wizard (in User Preferences or User menu) to change your own password.'))
|
||||
self.write(cr, uid, id, {'password': value})
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('User Name', size=64, required=True, select=True,
|
||||
help="The new user's real name, used for searching"
|
||||
@@ -201,6 +213,10 @@ class users(osv.osv):
|
||||
'login': fields.char('Login', size=64, required=True,
|
||||
help="Used to log into the system"),
|
||||
'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."),
|
||||
'new_password': fields.function(lambda *a:'', method=True, type='char', size=64,
|
||||
fnct_inv=_set_new_password,
|
||||
string='Change password', help="Only specify a value if you want to change the user password. "
|
||||
"This user will have to logout and login again!"),
|
||||
'email': fields.char('E-mail', size=64,
|
||||
help='If an email is provided, the user will be sent a message '
|
||||
'welcoming him.\n\nWarning: if "email_from" and "smtp_server"'
|
||||
@@ -395,11 +411,12 @@ class users(osv.osv):
|
||||
if default is None:
|
||||
default = {}
|
||||
copy_pattern = _("%s (copy)")
|
||||
default.update(login=(copy_pattern % user2copy['login']),
|
||||
copydef = dict(login=(copy_pattern % user2copy['login']),
|
||||
name=(copy_pattern % user2copy['name']),
|
||||
address_id=False, # avoid sharing the address of the copied user!
|
||||
)
|
||||
return super(users, self).copy(cr, uid, id, default, context)
|
||||
copydef.update(default)
|
||||
return super(users, self).copy(cr, uid, id, copydef, context)
|
||||
|
||||
def context_get(self, cr, uid, context=None):
|
||||
user = self.browse(cr, uid, uid, context)
|
||||
@@ -448,7 +465,7 @@ class users(osv.osv):
|
||||
return True
|
||||
cr = pooler.get_db(db).cursor()
|
||||
try:
|
||||
cr.execute('SELECT COUNT(1) FROM res_users WHERE id=%s AND password=%s AND active=%s',
|
||||
cr.execute('SELECT COUNT(1) FROM res_users WHERE id=%s AND password=%s AND active=%s',
|
||||
(int(uid), passwd, True))
|
||||
res = cr.fetchone()[0]
|
||||
if not bool(res):
|
||||
@@ -476,6 +493,20 @@ class users(osv.osv):
|
||||
finally:
|
||||
cr.close()
|
||||
|
||||
def change_password(self, cr, uid, old_passwd, new_passwd, context=None):
|
||||
"""Change current user password. Old password must be provided explicitly
|
||||
to prevent hijacking an existing user session, or for cases where the cleartext
|
||||
password is not used to authenticate requests.
|
||||
|
||||
:return: True
|
||||
:raise: security.ExceptionNoTb when old password is wrong
|
||||
:raise: except_osv when new password is not set or empty
|
||||
"""
|
||||
self.check(cr.dbname, uid, old_passwd)
|
||||
if new_passwd:
|
||||
return self.write(cr, uid, uid, {'password': new_passwd})
|
||||
raise osv.except_osv(_('Warning!'), _("Setting empty passwords is not allowed for security reasons!"))
|
||||
|
||||
users()
|
||||
|
||||
class config_users(osv.osv_memory):
|
||||
@@ -547,7 +578,7 @@ class groups2(osv.osv): ##FIXME: Is there a reason to inherit this object ?
|
||||
if len(user_names) >= 5:
|
||||
user_names = user_names[:5]
|
||||
user_names += '...'
|
||||
raise osv.except_osv(_('Warning !'),
|
||||
raise osv.except_osv(_('Warning !'),
|
||||
_('Group(s) cannot be deleted, because some user(s) still belong to them: %s !') % \
|
||||
', '.join(user_names))
|
||||
return super(groups2, self).unlink(cr, uid, ids, context=context)
|
||||
@@ -574,5 +605,4 @@ class res_config_view(osv.osv_memory):
|
||||
|
||||
res_config_view()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
@@ -52,14 +52,23 @@ class res_widget_user(osv.osv):
|
||||
|
||||
res_widget_user()
|
||||
|
||||
|
||||
class res_widget_wizard(osv.osv_memory):
|
||||
_name = "res.widget.wizard"
|
||||
_description = "Add a widget for User"
|
||||
|
||||
def widgets_list_get(self, cr, uid,context=None):
|
||||
widget_obj=self.pool.get('res.widget')
|
||||
ids=widget_obj.search(cr, uid,[],context=context)
|
||||
if not len(ids):
|
||||
return []
|
||||
reads = widget_obj.read(cr, uid, ids, ['title'], context=context)
|
||||
res = []
|
||||
for record in reads:
|
||||
res.append((record['id'], record['title']))
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'widget_id': fields.many2many("res.widget",
|
||||
"res_widget_user_rel", "uid", "wid",
|
||||
"Widget"),
|
||||
'widgets_list': fields.selection(widgets_list_get,string='Widget',required=True),
|
||||
}
|
||||
|
||||
def action_get(self, cr, uid, context=None):
|
||||
@@ -67,10 +76,10 @@ class res_widget_wizard(osv.osv_memory):
|
||||
cr, uid, 'base', 'action_res_widget_wizard', context=context)
|
||||
|
||||
def res_widget_add(self, cr, uid, ids, context=None):
|
||||
wizard = self.read(cr, uid, ids, context=context)[0]
|
||||
for wiz_id in wizard['widget_id']:
|
||||
widget_id = self.read(cr, uid, ids, context=context)[0]
|
||||
if widget_id.has_key('widgets_list') and widget_id['widgets_list']:
|
||||
self.pool.get('res.widget.user').create(
|
||||
cr, uid, {'user_id':uid, 'widget_id':wiz_id}, context=context)
|
||||
cr, uid, {'user_id':uid, 'widget_id':widget_id['widgets_list']}, context=context)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
res_widget_wizard()
|
||||
|
||||
@@ -39,189 +39,34 @@ new TWTR.Widget({
|
||||
</script>]]> </field>
|
||||
</record>
|
||||
|
||||
<record id="odony_twitter_widget" model="res.widget">
|
||||
<field name="title">Olivier Dony's tweets</field>
|
||||
<record id="events_widget" model="res.widget">
|
||||
<field name="title">Events</field>
|
||||
<field name="content"><![CDATA[<script src="http://widgets.twimg.com/j/2/widget.js"></script>
|
||||
<script>
|
||||
new TWTR.Widget({
|
||||
version: 2,
|
||||
type: 'profile',
|
||||
rpp: 10,
|
||||
interval: 6000,
|
||||
title: '',
|
||||
subject: '',
|
||||
width: 'auto',
|
||||
height: 300,
|
||||
theme: {
|
||||
shell: {
|
||||
background: '#F0EEEE',
|
||||
color: '#444444'
|
||||
},
|
||||
tweets: {
|
||||
background: '#F0EEEE',
|
||||
color: '#444444',
|
||||
links: '#9A0404'
|
||||
}
|
||||
},
|
||||
features: {
|
||||
scrollbar: false,
|
||||
loop: false,
|
||||
live: true,
|
||||
hashtags: true,
|
||||
timestamp: true,
|
||||
avatars: false,
|
||||
behavior: 'all'
|
||||
}
|
||||
}).render().setUser('odony').start();
|
||||
</script>]]></field>
|
||||
<div style="width:195px; text-align:center;" ><iframe src="http://www.eventbrite.com/calendar-widget?eid=852573069" frameborder="0" height="406" width="220" marginheight="0" marginwidth="0" scrolling="no" ></iframe><div style="font-family:Helvetica, Arial; font-size:10px; padding:5px 0 5px; margin:2px; width:195px; text-align:center;" ><a style="color:#ddd; text-decoration:none;" target="_blank" href="http://www.eventbrite.com/features?ref=ecal" >Online Ticketing</a><span style="color:#ddd;" > powered by </span><a style="color:#ddd; text-decoration:none;" target="_blank" href="http://www.eventbrite.com?ref=ecal" >Eventbrite</a></div>]]></field>
|
||||
</record>
|
||||
|
||||
<record id="matrixise_twitter_widget" model="res.widget">
|
||||
<field name="title">Stéphane Wirtel's tweets</field>
|
||||
<record id="facebook_widget" model="res.widget">
|
||||
<field name="title">Facebook</field>
|
||||
<field name="content"><![CDATA[<script src="http://widgets.twimg.com/j/2/widget.js"></script>
|
||||
<script>
|
||||
new TWTR.Widget({
|
||||
version: 2,
|
||||
type: 'profile',
|
||||
rpp: 10,
|
||||
interval: 6000,
|
||||
title: '',
|
||||
subject: '',
|
||||
width: 'auto',
|
||||
height: 300,
|
||||
theme: {
|
||||
shell: {
|
||||
background: '#F0EEEE',
|
||||
color: '#444444'
|
||||
},
|
||||
tweets: {
|
||||
background: '#F0EEEE',
|
||||
color: '#444444',
|
||||
links: '#9A0404'
|
||||
}
|
||||
},
|
||||
features: {
|
||||
scrollbar: false,
|
||||
loop: false,
|
||||
live: true,
|
||||
hashtags: true,
|
||||
timestamp: true,
|
||||
avatars: false,
|
||||
behavior: 'all'
|
||||
}
|
||||
}).render().setUser('matrixise').start();
|
||||
</script>]]></field>
|
||||
<iframe src="http://www.facebook.com/plugins/activity.php?site=www.facebook.com%2FOpenERP&width=300&height=300&header=true&colorscheme=light&recommendations=true" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:300px; height:300px;" allowTransparency="true"></iframe>]]></field>
|
||||
</record>
|
||||
|
||||
<record id="rvalyi_twitter_widget" model="res.widget">
|
||||
<field name="title">Raphaël Valyi's tweets</field>
|
||||
<record id="note_widget" model="res.widget">
|
||||
<field name="title">Notes</field>
|
||||
<field name="content"><![CDATA[<script src="http://widgets.twimg.com/j/2/widget.js"></script>
|
||||
<script>
|
||||
new TWTR.Widget({
|
||||
version: 2,
|
||||
type: 'profile',
|
||||
rpp: 10,
|
||||
interval: 6000,
|
||||
title: '',
|
||||
subject: '',
|
||||
width: 'auto',
|
||||
height: 300,
|
||||
theme: {
|
||||
shell: {
|
||||
background: '#F0EEEE',
|
||||
color: '#444444'
|
||||
},
|
||||
tweets: {
|
||||
background: '#F0EEEE',
|
||||
color: '#444444',
|
||||
links: '#9A0404'
|
||||
}
|
||||
},
|
||||
features: {
|
||||
scrollbar: false,
|
||||
loop: false,
|
||||
live: true,
|
||||
hashtags: true,
|
||||
timestamp: true,
|
||||
avatars: false,
|
||||
behavior: 'all'
|
||||
}
|
||||
}).render().setUser('rvalyi').start();
|
||||
</script>]]></field>
|
||||
<script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/ig/modules/sticky.xml&up_title=Note&up_bgcolor=white&up_textcolor=Black&up_stickydata=&synd=open&w=320&h=200&title=Notes&lang=all&country=ALL&border=%23ffffff%7C3px%2C1px+solid+%23999999&output=js"></script>]]></field>
|
||||
</record>
|
||||
|
||||
<record id="albertnan_twitter_widget" model="res.widget">
|
||||
<field name="title">Albert Cervera Areny's tweets</field>
|
||||
<record id="google_maps_widget" model="res.widget">
|
||||
<field name="title">Google Maps</field>
|
||||
<field name="content"><![CDATA[<script src="http://widgets.twimg.com/j/2/widget.js"></script>
|
||||
<script>
|
||||
new TWTR.Widget({
|
||||
version: 2,
|
||||
type: 'profile',
|
||||
rpp: 10,
|
||||
interval: 6000,
|
||||
title: '',
|
||||
subject: '',
|
||||
width: 'auto',
|
||||
height: 300,
|
||||
theme: {
|
||||
shell: {
|
||||
background: '#F0EEEE',
|
||||
color: '#444444'
|
||||
},
|
||||
tweets: {
|
||||
background: '#F0EEEE',
|
||||
color: '#444444',
|
||||
links: '#9A0404'
|
||||
}
|
||||
},
|
||||
features: {
|
||||
scrollbar: false,
|
||||
loop: false,
|
||||
live: true,
|
||||
hashtags: true,
|
||||
timestamp: true,
|
||||
avatars: false,
|
||||
behavior: 'all'
|
||||
}
|
||||
}).render().setUser('albertnan').start();
|
||||
</script>]]></field>
|
||||
<script src="http://www.gmodules.com/ig/ifr?url=http://www.google.com/uds/modules/elements/localsearch/localsearch.xml&up_location=Ramillies&up_largeMapMode=1&up_kml=1&up_traffic=&up_locationCacheString=&up_locationCacheLat=&up_locationCacheLng=&up_mapType=m&up_idleZoom=11&up_transitionQuery=&up_rawquery=&up_selectedtext=&synd=open&w=320&h=350&title=Map&lang=all&country=ALL&border=%23ffffff%7C3px%2C1px+solid+%23999999&output=js"></script>]]></field>
|
||||
</record>
|
||||
|
||||
<record id="nhomar_twitter_widget" model="res.widget">
|
||||
<field name="title">Nhomar Hernandez's tweets</field>
|
||||
<record id="currency_converter_widget" model="res.widget">
|
||||
<field name="title">Currency Converter</field>
|
||||
<field name="content"><![CDATA[<script src="http://widgets.twimg.com/j/2/widget.js"></script>
|
||||
<script>
|
||||
new TWTR.Widget({
|
||||
version: 2,
|
||||
type: 'profile',
|
||||
rpp: 10,
|
||||
interval: 6000,
|
||||
title: '',
|
||||
subject: '',
|
||||
width: 'auto',
|
||||
height: 300,
|
||||
theme: {
|
||||
shell: {
|
||||
background: '#F0EEEE',
|
||||
color: '#444444'
|
||||
},
|
||||
tweets: {
|
||||
background: '#F0EEEE',
|
||||
color: '#444444',
|
||||
links: '#9A0404'
|
||||
}
|
||||
},
|
||||
features: {
|
||||
scrollbar: false,
|
||||
loop: false,
|
||||
live: true,
|
||||
hashtags: true,
|
||||
timestamp: true,
|
||||
avatars: false,
|
||||
behavior: 'all'
|
||||
}
|
||||
}).render().setUser('nhomar').start();
|
||||
</script>]]></field>
|
||||
<script src="http://www.gmodules.com/ig/ifr?url=http://www.pixelmedia.nl/gmodules/ucc.xml&up_fromcur=USD&up_tocur=EUR&synd=open&w=320&h=110&title=Currency+Converter&lang=all&country=ALL&border=%23ffffff%7C3px%2C1px+solid+%23999999&output=js"></script>]]></field>
|
||||
</record>
|
||||
|
||||
<record id="openerp_favorites" model="res.widget.user">
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="openerp_admin_widgets" model="res.widget.user">
|
||||
<field name="widget_id" ref="odony_twitter_widget"/>
|
||||
<record id="events_admin_widgets" model="res.widget.user">
|
||||
<field name="widget_id" ref="events_widget"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
</record>
|
||||
<record id="openerp_demo_widgets" model="res.widget.user">
|
||||
<field name="widget_id" ref="albertnan_twitter_widget"/>
|
||||
<record id="events_demo_widgets" model="res.widget.user">
|
||||
<field name="widget_id" ref="events_widget"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
</record>
|
||||
</data>
|
||||
|
||||
@@ -72,8 +72,7 @@
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
<menuitem action="res_widget_user_act_window" id="menu_res_widget_user_act_window" parent="base.next_id_2"
|
||||
groups="base.group_no_one"/>
|
||||
<menuitem action="res_widget_user_act_window" id="menu_res_widget_user_act_window" parent="base.next_id_2"/>
|
||||
|
||||
<record id="view_res_widget_wizard" model="ir.ui.view">
|
||||
<field name="name">Homepage Widgets Management</field>
|
||||
@@ -81,7 +80,7 @@
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Widget Wizard" col="4">
|
||||
<field name="widget_id"/>
|
||||
<field name="widgets_list" colspan="4"/>
|
||||
<newline/>
|
||||
<separator string="" colspan="6"/>
|
||||
<group colspan="6" col="4" >
|
||||
|
||||
@@ -398,6 +398,7 @@
|
||||
<rng:ref name="xpath"/>
|
||||
<rng:ref name="button"/>
|
||||
<rng:ref name="group"/>
|
||||
<rng:ref name="filter"/>
|
||||
<rng:ref name="graph"/>
|
||||
<rng:ref name="html"/>
|
||||
<rng:element name="newline"><rng:empty/></rng:element>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
</record>
|
||||
|
||||
<record model="res.groups" id="group_user">
|
||||
<field name="name">Internal User</field>
|
||||
<field name="name">Employee</field>
|
||||
</record>
|
||||
|
||||
<record model="res.groups" context="{'noadmin':True}" id="group_multi_company">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
|
||||
"access_res_widget_user_all","res_widget_user all","model_res_widget_user",,1,0,0,0
|
||||
"access_res_widget_user_all","res_widget_user all","model_res_widget_user",,1,1,1,1
|
||||
"access_res_widget_user_group_user","res_widget_user group_user","model_res_widget_user","group_user",1,1,1,1
|
||||
"access_ir_attachment_all","ir_attachment all","model_ir_attachment",,1,0,0,0
|
||||
"access_ir_attachment_group_user","ir_attachment group_user","model_ir_attachment","group_user",1,1,1,1
|
||||
@@ -20,6 +20,7 @@
|
||||
"access_ir_module_module_group_user","ir_module_module group_user","model_ir_module_module","group_system",1,1,1,1
|
||||
"access_ir_module_module_user","ir_module_module user","model_ir_module_module",,1,0,0,0
|
||||
"access_ir_module_module_dependency_group_system","ir_module_module_dependency group_system","model_ir_module_module_dependency","group_system",1,1,1,1
|
||||
"access_ir_module_module_dependency_all","ir_module_module_dependency all","model_ir_module_module_dependency",,1,0,0,0
|
||||
"access_ir_property_group_user","ir_property group_user","model_ir_property",,1,0,0,0
|
||||
"access_ir_property_group_user_manager","ir_property group_manager","model_ir_property","base.group_partner_manager",1,1,1,0
|
||||
"access_ir_rule_group_user","ir_rule group_user","model_ir_rule",,1,0,0,0
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user