[Merge ]Merge with lp:openobject-server

bzr revid: sbh@tinyerp.com-20110110132538-xabrrucftf9gt20v
This commit is contained in:
Sbh (OpenERP)
2011-01-10 18:55:38 +05:30
129 changed files with 56814 additions and 19668 deletions
+90 -62
View File
@@ -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)
+1
View File
@@ -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
View File
@@ -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>
+15 -2
View File
@@ -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>
+4 -5
View File
@@ -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>
+4 -6
View File
@@ -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 &amp; 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
View File
File diff suppressed because it is too large Load Diff
+703 -261
View File
File diff suppressed because it is too large Load Diff
+703 -261
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+780 -279
View File
File diff suppressed because it is too large Load Diff
+714 -265
View File
File diff suppressed because it is too large Load Diff
+760 -329
View File
File diff suppressed because it is too large Load Diff
+709 -264
View File
File diff suppressed because it is too large Load Diff
+707 -262
View File
File diff suppressed because it is too large Load Diff
+961 -397
View File
File diff suppressed because it is too large Load Diff
+1985 -347
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+913 -445
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+755 -279
View File
File diff suppressed because it is too large Load Diff
+703 -261
View File
File diff suppressed because it is too large Load Diff
+764 -283
View File
File diff suppressed because it is too large Load Diff
+2536 -339
View File
File diff suppressed because it is too large Load Diff
+1097 -445
View File
File diff suppressed because it is too large Load Diff
+737 -291
View File
File diff suppressed because it is too large Load Diff
+754 -352
View File
File diff suppressed because it is too large Load Diff
+735 -279
View File
File diff suppressed because it is too large Load Diff
+2324 -1594
View File
File diff suppressed because it is too large Load Diff
+711 -262
View File
File diff suppressed because it is too large Load Diff
+703 -261
View File
File diff suppressed because it is too large Load Diff
+872 -349
View File
File diff suppressed because it is too large Load Diff
+713 -261
View File
File diff suppressed because it is too large Load Diff
+741 -339
View File
File diff suppressed because it is too large Load Diff
+707 -265
View File
File diff suppressed because it is too large Load Diff
+967 -554
View File
File diff suppressed because it is too large Load Diff
+973 -285
View File
File diff suppressed because it is too large Load Diff
+704 -262
View File
File diff suppressed because it is too large Load Diff
+969 -345
View File
File diff suppressed because it is too large Load Diff
+1096 -540
View File
File diff suppressed because it is too large Load Diff
+813 -286
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+759 -283
View File
File diff suppressed because it is too large Load Diff
+841 -340
View File
File diff suppressed because it is too large Load Diff
+1200 -420
View File
File diff suppressed because it is too large Load Diff
+1163 -316
View File
File diff suppressed because it is too large Load Diff
+703 -261
View File
File diff suppressed because it is too large Load Diff
+772 -389
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1351 -736
View File
File diff suppressed because it is too large Load Diff
+703 -261
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+767 -286
View File
File diff suppressed because it is too large Load Diff
+758 -352
View File
File diff suppressed because it is too large Load Diff
+6152 -384
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+52 -6
View File
@@ -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"/>
+4
View File
@@ -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
+1 -1
View File
@@ -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'))
+1 -1
View File
@@ -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
View File
@@ -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)
+5 -3
View File
@@ -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),)
+14 -27
View File
@@ -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.')
+16 -39
View File
@@ -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 = []
+6 -2
View File
@@ -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)
+5 -5
View File
@@ -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>
+17 -7
View File
@@ -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(
+1 -1
View File
@@ -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/>
+2 -2
View File
@@ -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>
+15 -1
View File
@@ -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']]
+5 -5
View File
@@ -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>
+6 -8
View File
@@ -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>
+2 -2
View File
@@ -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"/>
+3 -3
View File
@@ -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):
+4 -4
View File
@@ -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>
+13 -19
View File
@@ -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:
+64 -5
View File
@@ -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!
+5 -5
View File
@@ -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','&lt;&gt;',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','&lt;&gt;',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>
+3 -3
View File
@@ -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)]}),
+3
View File
@@ -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>
+37 -7
View File
@@ -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:
+16 -7
View File
@@ -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()
+15 -170
View File
@@ -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&amp;width=300&amp;height=300&amp;header=true&amp;colorscheme=light&amp;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&amp;up_title=Note&amp;up_bgcolor=white&amp;up_textcolor=Black&amp;up_stickydata=&amp;synd=open&amp;w=320&amp;h=200&amp;title=Notes&amp;lang=all&amp;country=ALL&amp;border=%23ffffff%7C3px%2C1px+solid+%23999999&amp;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&amp;up_location=Ramillies&amp;up_largeMapMode=1&amp;up_kml=1&amp;up_traffic=&amp;up_locationCacheString=&amp;up_locationCacheLat=&amp;up_locationCacheLng=&amp;up_mapType=m&amp;up_idleZoom=11&amp;up_transitionQuery=&amp;up_rawquery=&amp;up_selectedtext=&amp;synd=open&amp;w=320&amp;h=350&amp;title=Map&amp;lang=all&amp;country=ALL&amp;border=%23ffffff%7C3px%2C1px+solid+%23999999&amp;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&amp;up_fromcur=USD&amp;up_tocur=EUR&amp;synd=open&amp;w=320&amp;h=110&amp;title=Currency+Converter&amp;lang=all&amp;country=ALL&amp;border=%23ffffff%7C3px%2C1px+solid+%23999999&amp;output=js"></script>]]></field>
</record>
<record id="openerp_favorites" model="res.widget.user">
+4 -4
View File
@@ -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>
+2 -3
View File
@@ -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" >
+1
View File
@@ -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>
+1 -1
View File
@@ -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">
+2 -1
View File
@@ -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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_res_widget_user_all res_widget_user all model_res_widget_user 1 0 1 0 1 0 1
3 access_res_widget_user_group_user res_widget_user group_user model_res_widget_user group_user 1 1 1 1
4 access_ir_attachment_all ir_attachment all model_ir_attachment 1 0 0 0
5 access_ir_attachment_group_user ir_attachment group_user model_ir_attachment group_user 1 1 1 1
20 access_ir_module_module_group_user ir_module_module group_user model_ir_module_module group_system 1 1 1 1
21 access_ir_module_module_user ir_module_module user model_ir_module_module 1 0 0 0
22 access_ir_module_module_dependency_group_system ir_module_module_dependency group_system model_ir_module_module_dependency group_system 1 1 1 1
23 access_ir_module_module_dependency_all ir_module_module_dependency all model_ir_module_module_dependency 1 0 0 0
24 access_ir_property_group_user ir_property group_user model_ir_property 1 0 0 0
25 access_ir_property_group_user_manager ir_property group_manager model_ir_property base.group_partner_manager 1 1 1 0
26 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