Merged with main trunk
bzr revid: hda@tinyerp.com-20100505131038-k4or5j9x5zkxl5ac
This commit is contained in:
commit
15171f62d1
|
@ -640,10 +640,20 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs):
|
|||
|
||||
def load_test(cr, module_name, id_map, mode):
|
||||
cr.commit()
|
||||
try:
|
||||
_load_data(cr, module_name, id_map, mode, 'test')
|
||||
finally:
|
||||
cr.rollback()
|
||||
if not tools.config.options['test-disable']:
|
||||
try:
|
||||
_load_data(cr, module_name, id_map, mode, 'test')
|
||||
except Exception, e:
|
||||
if tools.config.options['test-continue']:
|
||||
logger.notifyChannel('ERROR', netsvc.LOG_TEST, e)
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
finally:
|
||||
if tools.config.options['test-rollback']:
|
||||
cr.rollback()
|
||||
else:
|
||||
cr.commit()
|
||||
|
||||
def _load_data(cr, module_name, id_map, mode, kind):
|
||||
noupdate = (kind == 'demo')
|
||||
|
@ -757,6 +767,15 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs):
|
|||
return has_updates
|
||||
|
||||
def load_modules(db, force_demo=False, status=None, update_module=False):
|
||||
|
||||
def check_module_name(cr, mods, state):
|
||||
for mod in mods:
|
||||
id = modobj.search(cr, 1, ['&', ('state', '=', state), ('name', '=', mod)])
|
||||
if id:
|
||||
getattr(modobj, states[state])(cr, 1, id)
|
||||
elif mod != 'all':
|
||||
logger.notifyChannel('init', netsvc.LOG_WARNING, 'module %s: invalid module name!' % (mod))
|
||||
|
||||
if not status:
|
||||
status = {}
|
||||
cr = db.cursor()
|
||||
|
@ -787,21 +806,16 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
|||
return
|
||||
if update_module:
|
||||
modobj = pool.get('ir.module.module')
|
||||
states = {'installed': 'button_upgrade', 'uninstalled': 'button_install'}
|
||||
logger.notifyChannel('init', netsvc.LOG_INFO, 'updating modules list')
|
||||
if ('base' in tools.config['init']) or ('base' in tools.config['update']):
|
||||
modobj.update_list(cr, 1)
|
||||
|
||||
mods = [k for k in tools.config['init'] if tools.config['init'][k]]
|
||||
if mods:
|
||||
ids = modobj.search(cr, 1, ['&', ('state', '=', 'uninstalled'), ('name', 'in', mods)])
|
||||
if ids:
|
||||
modobj.button_install(cr, 1, ids)
|
||||
check_module_name(cr, mods, 'uninstalled')
|
||||
|
||||
mods = [k for k in tools.config['update'] if tools.config['update'][k]]
|
||||
if mods:
|
||||
ids = modobj.search(cr, 1, ['&', ('state', '=', 'installed'), ('name', 'in', mods)])
|
||||
if ids:
|
||||
modobj.button_upgrade(cr, 1, ids)
|
||||
check_module_name(cr, mods, 'installed')
|
||||
|
||||
cr.execute("update ir_module_module set state=%s where name=%s", ('installed', 'base'))
|
||||
|
||||
|
|
|
@ -7,14 +7,14 @@ msgstr ""
|
|||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-02-07 05:09+0000\n"
|
||||
"PO-Revision-Date: 2010-05-02 05:54+0000\n"
|
||||
"Last-Translator: Jordi Esteve - http://www.zikzakmedia.com "
|
||||
"<jesteve@zikzakmedia.com>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-04-17 03:49+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-05-03 04:02+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
|
@ -109,7 +109,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Escolliu entre la \"Interfície simplificada\" o \"Interfície estesa\".\n"
|
||||
"Si esteu examinant o utilitzant OpenERP per la primera vegada,\n"
|
||||
"us suggerim per utilitzar la interfície simplificada, que té menys\n"
|
||||
"us suggerim que utilitzeu la interfície simplificada, que té menys\n"
|
||||
"opcions i camps però és més fàcil d'entendre. Més tard podreu\n"
|
||||
"canviar a la vista estesa.\n"
|
||||
" "
|
||||
|
@ -388,8 +388,8 @@ msgid ""
|
|||
"If you check this, then the second time the user prints with same attachment "
|
||||
"name, it returns the previous report."
|
||||
msgstr ""
|
||||
"Si marca aquesta opció, quan l'usuari imprimeixi el mateix nom d'adjunt per "
|
||||
"segona vegada, tornarà l'informe anterior."
|
||||
"Si marqueu aquesta opció, quan l'usuari imprimeixi el mateix nom d'adjunt "
|
||||
"per segona vegada, obtindrá l'informe anterior."
|
||||
|
||||
#. module: base
|
||||
#: help:res.lang,iso_code:0
|
||||
|
@ -433,7 +433,7 @@ msgid ""
|
|||
"The ISO country code in two chars.\n"
|
||||
"You can use this field for quick search."
|
||||
msgstr ""
|
||||
"EL codi ISO del país en dos caràcters.\n"
|
||||
"EL codi ISO del país de dos caràcters.\n"
|
||||
"Podeu utilitzar aquest camp per la cerca ràpida."
|
||||
|
||||
#. module: base
|
||||
|
@ -474,7 +474,7 @@ msgstr "Interfície estesa"
|
|||
#: code:addons/base/ir/ir_model.py:0
|
||||
#, python-format
|
||||
msgid "Custom fields must have a name that starts with 'x_' !"
|
||||
msgstr "Els camps personalitzats han de tenir un nom que comença con 'x_'!"
|
||||
msgstr "Els camps personalitzats han de tenir un nom que comenci amb 'x_'!"
|
||||
|
||||
#. module: base
|
||||
#: help:ir.actions.server,action_id:0
|
||||
|
@ -913,7 +913,7 @@ msgstr "STOCK_MISSING_IMAGE"
|
|||
#. module: base
|
||||
#: view:res.users:0
|
||||
msgid "Define New Users"
|
||||
msgstr "Defineix nous usuaris"
|
||||
msgstr "Definiu nous usuaris"
|
||||
|
||||
#. module: base
|
||||
#: selection:ir.ui.menu,icon:0
|
||||
|
@ -1489,7 +1489,7 @@ msgstr "Menú"
|
|||
#. module: base
|
||||
#: field:res.currency,rate:0
|
||||
msgid "Current Rate"
|
||||
msgstr "Tasa"
|
||||
msgstr "Taxa"
|
||||
|
||||
#. module: base
|
||||
#: selection:module.lang.install,init,lang:0
|
||||
|
@ -3124,7 +3124,7 @@ msgid ""
|
|||
"any."
|
||||
msgstr ""
|
||||
"L'usuari intern que s'encarrega de comunicar-se amb aquesta empresa, si "
|
||||
"n'hi ha."
|
||||
"n'hi hagués."
|
||||
|
||||
#. module: base
|
||||
#: field:res.partner,parent_id:0
|
||||
|
@ -5073,8 +5073,8 @@ msgstr "Islàndia"
|
|||
#: view:res.users:0
|
||||
msgid "Roles are used to defined available actions, provided by workflows."
|
||||
msgstr ""
|
||||
"Els rols s'utilitzen per definir les accions disponibles, de les que "
|
||||
"proveeixen els fluxos."
|
||||
"Els rols s'utilitzen per definir les accions disponibles dins d'un flux de "
|
||||
"treball."
|
||||
|
||||
#. module: base
|
||||
#: model:res.country,name:base.de
|
||||
|
@ -5437,7 +5437,7 @@ msgstr "Dia de l'any: %(doy)s"
|
|||
#. module: base
|
||||
#: model:res.country,name:base.nt
|
||||
msgid "Neutral Zone"
|
||||
msgstr "Zona Neutral"
|
||||
msgstr "Zona neutral"
|
||||
|
||||
#. module: base
|
||||
#: view:ir.model:0
|
||||
|
@ -5828,7 +5828,7 @@ msgstr "Companyia per defecte per objecte"
|
|||
#. module: base
|
||||
#: view:ir.actions.configuration.wizard:0
|
||||
msgid "Next Configuration Step"
|
||||
msgstr "Següent pas configuració"
|
||||
msgstr "Següent pas de la configuració"
|
||||
|
||||
#. module: base
|
||||
#: field:res.groups,comment:0
|
||||
|
@ -6645,8 +6645,8 @@ msgid ""
|
|||
"Access all the fields related to the current object using expression in "
|
||||
"double brackets, i.e. [[ object.partner_id.name ]]"
|
||||
msgstr ""
|
||||
"Accedeix a tots els camps relacionats amb l'objecte actual mitjançant una "
|
||||
"expressió en claudàtors dobles, per exemple [[ object.partner_id.name ]]"
|
||||
"Podeu accedir a tots els camps relacionats amb l'objecte actual mitjançant "
|
||||
"una expressió en claudàtors dobles, per exemple [[ object.partner_id.name ]]"
|
||||
|
||||
#. module: base
|
||||
#: field:res.request.history,body:0
|
||||
|
@ -8088,7 +8088,7 @@ msgstr ""
|
|||
#. module: base
|
||||
#: wizard_view:module.lang.install,init:0
|
||||
msgid "Choose a language to install:"
|
||||
msgstr "Selecciona un idioma per instal·lar:"
|
||||
msgstr "Seleccioneu un idioma a instal·lar:"
|
||||
|
||||
#. module: base
|
||||
#: model:res.country,name:base.lk
|
||||
|
|
|
@ -7,14 +7,14 @@ msgstr ""
|
|||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-02-07 05:11+0000\n"
|
||||
"PO-Revision-Date: 2010-05-02 05:52+0000\n"
|
||||
"Last-Translator: Jordi Esteve - http://www.zikzakmedia.com "
|
||||
"<jesteve@zikzakmedia.com>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-04-17 03:52+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-05-03 04:03+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
|
@ -389,7 +389,7 @@ msgid ""
|
|||
"name, it returns the previous report."
|
||||
msgstr ""
|
||||
"Si marca esta opción, cuando el usuario imprima el mismo nombre de adjunto "
|
||||
"por segunda vez, devolverá el informe anterior."
|
||||
"por segunda vez, obtendrá el informe anterior."
|
||||
|
||||
#. module: base
|
||||
#: help:res.lang,iso_code:0
|
||||
|
@ -434,8 +434,8 @@ msgid ""
|
|||
"The ISO country code in two chars.\n"
|
||||
"You can use this field for quick search."
|
||||
msgstr ""
|
||||
"EL código ISO del país en dos caracteres.\n"
|
||||
"Puede usar este campo para la búsqueda rápida."
|
||||
"EL código ISO del país de dos caracteres.\n"
|
||||
"Puede utilizar este campo para la búsqueda rápida."
|
||||
|
||||
#. module: base
|
||||
#: selection:workflow.activity,join_mode:0
|
||||
|
@ -3127,7 +3127,8 @@ msgid ""
|
|||
"The internal user that is in charge of communicating with this partner if "
|
||||
"any."
|
||||
msgstr ""
|
||||
"El usuario interno que se encarga de comunicarse con esta empresa si hay."
|
||||
"El usuario interno que se encarga de comunicarse con esta empresa, si los "
|
||||
"hubiera."
|
||||
|
||||
#. module: base
|
||||
#: field:res.partner,parent_id:0
|
||||
|
@ -5076,8 +5077,8 @@ msgstr "Islandia"
|
|||
#: view:res.users:0
|
||||
msgid "Roles are used to defined available actions, provided by workflows."
|
||||
msgstr ""
|
||||
"Los roles se utilizan para definir las acciones disponibles, que son "
|
||||
"proporcionadas por los flujos."
|
||||
"Los roles se utilizan para definir las acciones disponibles dentro de un "
|
||||
"flujo de trabajo."
|
||||
|
||||
#. module: base
|
||||
#: model:res.country,name:base.de
|
||||
|
@ -5830,7 +5831,7 @@ msgstr "Compañía por defecto por objeto"
|
|||
#. module: base
|
||||
#: view:ir.actions.configuration.wizard:0
|
||||
msgid "Next Configuration Step"
|
||||
msgstr "Siguiente paso configuración"
|
||||
msgstr "Siguiente paso de la configuración"
|
||||
|
||||
#. module: base
|
||||
#: field:res.groups,comment:0
|
||||
|
|
|
@ -7,13 +7,13 @@ msgstr ""
|
|||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-04-26 04:29+0000\n"
|
||||
"PO-Revision-Date: 2010-05-03 14:18+0000\n"
|
||||
"Last-Translator: goranc <goranc@gmail.com>\n"
|
||||
"Language-Team: openerp-translators\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-04-27 03:37+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-05-05 03:47+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
"Language: hr\n"
|
||||
|
||||
|
|
|
@ -7,13 +7,13 @@ msgstr ""
|
|||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-03-31 05:14+0000\n"
|
||||
"Last-Translator: OpenERP Administrators <Unknown>\n"
|
||||
"PO-Revision-Date: 2010-04-29 04:41+0000\n"
|
||||
"Last-Translator: eLBati - albatos.com <lorenzo.battistini@albatos.com>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-04-17 03:51+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-04-30 03:50+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
|
@ -422,7 +422,7 @@ msgstr "Colombia"
|
|||
#. module: base
|
||||
#: view:ir.module.module:0
|
||||
msgid "Schedule Upgrade"
|
||||
msgstr "Aggiornamento Programmazione"
|
||||
msgstr "Pianifica l'aggiornamento"
|
||||
|
||||
#. module: base
|
||||
#: field:ir.actions.report.custom,report_id:0
|
||||
|
|
|
@ -8,13 +8,13 @@ msgstr ""
|
|||
"Project-Id-Version: openobject-server\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-04-26 04:24+0000\n"
|
||||
"PO-Revision-Date: 2010-05-03 14:46+0000\n"
|
||||
"Last-Translator: Harry (Open ERP) <hmo@tinyerp.com>\n"
|
||||
"Language-Team: Japanese <ja@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-04-27 03:37+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-05-05 03:47+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
|
|
|
@ -7,13 +7,13 @@ msgstr ""
|
|||
"Project-Id-Version: OpenERP Server 5.0.0\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-04-26 04:22+0000\n"
|
||||
"PO-Revision-Date: 2010-05-03 14:48+0000\n"
|
||||
"Last-Translator: Anders Wallenquist <anders.wallenquist@vertel.se>\n"
|
||||
"Language-Team: <>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-04-27 03:37+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-05-05 03:47+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
|
|
|
@ -7,13 +7,13 @@ msgstr ""
|
|||
"Project-Id-Version: OpenERP Server 5.0.0\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-04-26 04:19+0000\n"
|
||||
"PO-Revision-Date: 2010-05-03 14:29+0000\n"
|
||||
"Last-Translator: Fabien (Open ERP) <fp@tinyerp.com>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-04-27 03:37+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-05-05 03:47+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
|
|
|
@ -7,13 +7,13 @@ msgstr ""
|
|||
"Project-Id-Version: OpenERP Server 5.0.4\n"
|
||||
"Report-Msgid-Bugs-To: support@openerp.com\n"
|
||||
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
|
||||
"PO-Revision-Date: 2010-04-26 04:28+0000\n"
|
||||
"PO-Revision-Date: 2010-05-03 14:47+0000\n"
|
||||
"Last-Translator: OpenERP Administrators <Unknown>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2010-04-27 03:37+0000\n"
|
||||
"X-Launchpad-Export-Date: 2010-05-05 03:47+0000\n"
|
||||
"X-Generator: Launchpad (build Unknown)\n"
|
||||
|
||||
#. module: base
|
||||
|
|
|
@ -1147,67 +1147,51 @@
|
|||
|
||||
<!-- Rules -->
|
||||
|
||||
<record id="view_rule_group_form" model="ir.ui.view">
|
||||
<record id="view_rule_form" model="ir.ui.view">
|
||||
<field name="name">Record rules</field>
|
||||
<field name="model">ir.rule.group</field>
|
||||
<field name="model">ir.rule</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Record rules">
|
||||
<field name="model_id" select="1"/>
|
||||
<field name="global" select="1"/>
|
||||
<field colspan="4" name="name"/>
|
||||
<group col="6" colspan="4" expand="1">
|
||||
<field colspan="6" name="rules" nolabel="1"/>
|
||||
<label align="0.0" colspan="6" string="The rule is satisfied if all test are True (AND)"/>
|
||||
<label align="0.0" colspan="6" string="Multiple rules on same objects are joined using operator OR"/>
|
||||
<separator colspan="4" string="Combination of rules"/>
|
||||
<label align="0.0" angle="2" colspan="4" string="1. Global rules are combined together with a logical AND operator, and with the result of the following steps"/>
|
||||
<label align="0.0" angle="2" colspan="4" string="2. Group-specific rules are combined together with a logical AND operator"/>
|
||||
<label align="0.0" angle="2" colspan="4" string="3. If user belongs to several groups, the results from step 2 are combined with logical OR operator"/>
|
||||
<label align="0.0" angle="2" colspan="4" string="Example: GLOBAL_RULE_1 AND GLOBAL_RULE_2 AND ( (GROUP_A_RULE_1 AND GROUP_A_RULE_2) OR (GROUP_B_RULE_1 AND GROUP_B_RULE_2) )"/>
|
||||
<group col="2" colspan="2">
|
||||
<separator colspan="2" string="General"/>
|
||||
<field colspan="4" name="name"/>
|
||||
<field name="model_id" select="1"/>
|
||||
</group>
|
||||
<group col="4" colspan="2">
|
||||
<separator colspan="4" string="Access Rights"/>
|
||||
<field name="perm_read"/>
|
||||
<field name="perm_write"/>
|
||||
<field name="perm_create"/>
|
||||
<field name="perm_unlink"/>
|
||||
</group>
|
||||
<separator colspan="4" string="Domain Setup"/>
|
||||
<group colspan="4">
|
||||
<field name="domain_force" colspan="4"/>
|
||||
</group>
|
||||
<separator colspan="4" string="Groups (no group = global)"/>
|
||||
<group colspan="4" expand="1">
|
||||
<field name="global" select="1"/>
|
||||
<field name="groups" select="1" nolabel="1" colspan="4"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_rule_group_tree" model="ir.ui.view">
|
||||
<record id="view_rule_tree" model="ir.ui.view">
|
||||
<field name="name">Record rules</field>
|
||||
<field name="model">ir.rule.group</field>
|
||||
<field name="model">ir.rule</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Record rules">
|
||||
<field name="model_id"/>
|
||||
<field name="name"/>
|
||||
<field name="global"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_rule_form" model="ir.ui.view">
|
||||
<field name="name">Rule Definition</field>
|
||||
<field name="model">ir.rule</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Test">
|
||||
<separator colspan="4" string="Simple domain setup"/>
|
||||
<group col="6" colspan="4">
|
||||
<field name="field_id"/>
|
||||
<field name="operator"/>
|
||||
<field name="operand"/>
|
||||
</group>
|
||||
<separator colspan="4" string="Manual domain setup"/>
|
||||
<field name="domain_force"/>
|
||||
<label colspan="4" string="If you don't force the domain, it will use the simple domain setup"/>
|
||||
<newline/>
|
||||
<field name="perm_read"/>
|
||||
<field name="perm_write"/>
|
||||
<field name="perm_create"/>
|
||||
<field name="perm_unlink"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_rule_tree" model="ir.ui.view">
|
||||
<field name="name">Rules</field>
|
||||
<field name="model">ir.rule</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Test">
|
||||
<field name="domain"/>
|
||||
<field name="perm_read"/>
|
||||
<field name="perm_write"/>
|
||||
<field name="perm_create"/>
|
||||
|
@ -1215,22 +1199,20 @@
|
|||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_rule" model="ir.actions.act_window">
|
||||
<field name="name">Record Rules</field>
|
||||
<field name="res_model">ir.rule.group</field>
|
||||
<field name="res_model">ir.rule</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="view_rule_group_tree"/>
|
||||
<field name="view_id" ref="view_rule_tree"/>
|
||||
</record>
|
||||
<menuitem action="action_rule" id="menu_action_rule" parent="base.menu_security"/>
|
||||
|
||||
<record id="property_rule_group" model="ir.rule.group">
|
||||
<record id="property_rule" model="ir.rule">
|
||||
<field name="name">Property multi-company</field>
|
||||
<field model="ir.model" name="model_id" ref="model_ir_property"/>
|
||||
<field eval="True" name="global"/>
|
||||
</record>
|
||||
<record id="property_rule" model="ir.rule">
|
||||
<field name="domain_force">['|',('company_id','child_of',user.company_id.id),('company_id','=',False)]</field>
|
||||
<field name="rule_group" ref="property_rule_group"/>
|
||||
</record>
|
||||
|
||||
<!--server action view-->
|
||||
|
|
|
@ -191,7 +191,7 @@ class act_window(osv.osv):
|
|||
return s.encode('utf8')
|
||||
return s
|
||||
for act in self.browse(cr, uid, ids):
|
||||
fields_from_fields_get = self.pool.get(act.res_model).fields_get(cr, uid)
|
||||
fields_from_fields_get = self.pool.get(act.res_model).fields_get(cr, uid, context=context)
|
||||
search_view_id = False
|
||||
if act.search_view_id:
|
||||
search_view_id = act.search_view_id.id
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
|
@ -15,7 +15,7 @@
|
|||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
import logging
|
||||
|
@ -80,7 +80,7 @@ class ir_model(osv.osv):
|
|||
if context:
|
||||
context.pop('__last_update', None)
|
||||
return super(ir_model,self).write(cr, user, ids, vals, context)
|
||||
|
||||
|
||||
def create(self, cr, user, vals, context=None):
|
||||
if context and context.get('manual',False):
|
||||
vals['state']='manual'
|
||||
|
@ -226,7 +226,7 @@ class ir_model_fields(osv.osv):
|
|||
'domain': fields.char('Domain', size=256),
|
||||
'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'),
|
||||
'selectable': fields.boolean('Selectable'),
|
||||
}
|
||||
_rec_name='field_description'
|
||||
_defaults = {
|
||||
|
@ -278,7 +278,7 @@ class ir_model_fields(osv.osv):
|
|||
self.pool.get(vals['model'])._auto_init(cr, ctx)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
ir_model_fields()
|
||||
|
||||
class ir_model_access(osv.osv):
|
||||
|
@ -378,6 +378,7 @@ class ir_model_access(osv.osv):
|
|||
'create': _('You can not create this kind of document! (%s)'),
|
||||
'unlink': _('You can not delete this document! (%s)'),
|
||||
}
|
||||
|
||||
raise except_orm(_('AccessError'), msgs[mode] % model_name )
|
||||
return r
|
||||
|
||||
|
|
|
@ -23,154 +23,121 @@ from osv import fields,osv
|
|||
import time
|
||||
import tools
|
||||
|
||||
|
||||
class ir_rule_group(osv.osv):
|
||||
_name = 'ir.rule.group'
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=128, select=1),
|
||||
'model_id': fields.many2one('ir.model', 'Object',select=1, required=True),
|
||||
'global': fields.boolean('Global', select=1, help="Make the rule global, otherwise it needs to be put on a group"),
|
||||
'rules': fields.one2many('ir.rule', 'rule_group', 'Tests', help="The rule is satisfied if at least one test is True"),
|
||||
'groups': fields.many2many('res.groups', 'group_rule_group_rel', 'rule_group_id', 'group_id', 'Groups'),
|
||||
'users': fields.many2many('res.users', 'user_rule_group_rel', 'rule_group_id', 'user_id', 'Users'),
|
||||
}
|
||||
|
||||
_order = 'model_id, global DESC'
|
||||
|
||||
_defaults={
|
||||
'global': lambda *a: True,
|
||||
}
|
||||
|
||||
ir_rule_group()
|
||||
|
||||
|
||||
class ir_rule(osv.osv):
|
||||
_name = 'ir.rule'
|
||||
_rec_name = 'field_id'
|
||||
|
||||
def _operand(self,cr,uid,context):
|
||||
|
||||
def get(object, level=3, recur=None, root_tech='', root=''):
|
||||
res = []
|
||||
if not recur:
|
||||
recur = []
|
||||
fields = self.pool.get(object).fields_get(cr,uid)
|
||||
key = fields.keys()
|
||||
key.sort()
|
||||
for k in key:
|
||||
|
||||
if fields[k]['type'] in ('many2one'):
|
||||
res.append((root_tech+'.'+k+'.id',
|
||||
root+'/'+fields[k]['string']))
|
||||
|
||||
elif fields[k]['type'] in ('many2many', 'one2many'):
|
||||
res.append(('\',\'.join(map(lambda x: str(x.id), '+root_tech+'.'+k+'))',
|
||||
root+'/'+fields[k]['string']))
|
||||
|
||||
else:
|
||||
res.append((root_tech+'.'+k,
|
||||
root+'/'+fields[k]['string']))
|
||||
|
||||
if (fields[k]['type'] in recur) and (level>0):
|
||||
res.extend(get(fields[k]['relation'], level-1,
|
||||
recur, root_tech+'.'+k, root+'/'+fields[k]['string']))
|
||||
|
||||
return res
|
||||
|
||||
res = [("False", "False"), ("True", "True"), ("user.id", "User")]
|
||||
res += get('res.users', level=1,
|
||||
recur=['many2one'], root_tech='user', root='User')
|
||||
return res
|
||||
|
||||
def _domain_force_get(self, cr, uid, ids, field_name, arg, context={}):
|
||||
res = {}
|
||||
for rule in self.browse(cr, uid, ids, context):
|
||||
eval_user_data = {'user': self.pool.get('res.users').browse(cr, 1, uid),
|
||||
'time':time}
|
||||
|
||||
if rule.domain_force:
|
||||
res[rule.id] = eval(rule.domain_force, eval_user_data)
|
||||
else:
|
||||
if rule.operand and rule.operand.startswith('user.') and rule.operand.count('.') > 1:
|
||||
#Need to check user.field.field1.field2(if field is False,it will break the chain)
|
||||
op = rule.operand[5:]
|
||||
rule.operand = rule.operand[:5+len(op[:op.find('.')])] +' and '+ rule.operand + ' or False'
|
||||
if rule.operator in ('in', 'child_of'):
|
||||
dom = eval("[('%s', '%s', [%s])]" % (rule.field_id.name, rule.operator,
|
||||
eval(rule.operand,eval_user_data)), eval_user_data)
|
||||
else:
|
||||
dom = eval("[('%s', '%s', %s)]" % (rule.field_id.name, rule.operator,
|
||||
rule.operand), eval_user_data)
|
||||
res[rule.id] = dom
|
||||
res[rule.id] = eval(rule.domain_force, eval_user_data)
|
||||
return res
|
||||
|
||||
def _get_value(self, cr, uid, ids, field_name, arg, context={}):
|
||||
res = {}
|
||||
for rule in self.browse(cr, uid, ids, context):
|
||||
if not rule.groups:
|
||||
res[rule.id] = True
|
||||
else:
|
||||
res[rule.id] = False
|
||||
return res
|
||||
|
||||
def _check_model_obj(self, cr, uid, ids, context={}):
|
||||
model_obj = self.pool.get('ir.model')
|
||||
for rule in self.browse(cr, uid, ids, context):
|
||||
model = model_obj.browse(cr, uid, rule.model_id.id, context).model
|
||||
obj = self.pool.get(model)
|
||||
if isinstance(obj, osv.osv_memory):
|
||||
return False
|
||||
return True
|
||||
|
||||
_columns = {
|
||||
'field_id': fields.many2one('ir.model.fields', 'Field',domain= "[('model_id','=', parent.model_id)]", select=1),
|
||||
'operator':fields.selection((('=', '='), ('<>', '<>'), ('<=', '<='), ('>=', '>='), ('in', 'in'), ('child_of', 'child_of')), 'Operator'),
|
||||
'operand':fields.selection(_operand,'Operand', size=64),
|
||||
'rule_group': fields.many2one('ir.rule.group', 'Group', select=2, required=True, ondelete="cascade"),
|
||||
'domain_force': fields.char('Force Domain', size=250),
|
||||
'name': fields.char('Name', size=128, select=1),
|
||||
'model_id': fields.many2one('ir.model', 'Object',select=1, required=True),
|
||||
'global': fields.function(_get_value, method=True, string='Global', type='boolean', store=True, help="If no group is specified the rule is global and applied to everyone"),
|
||||
'groups': fields.many2many('res.groups', 'rule_group_rel', 'rule_group_id', 'group_id', 'Groups'),
|
||||
'domain_force': fields.char('Domain', size=250),
|
||||
'domain': fields.function(_domain_force_get, method=True, string='Domain', type='char', size=250),
|
||||
'perm_read': fields.boolean('Read Access'),
|
||||
'perm_write': fields.boolean('Write Access'),
|
||||
'perm_create': fields.boolean('Create Access'),
|
||||
'perm_unlink': fields.boolean('Delete Access')
|
||||
'perm_read': fields.boolean('Apply For Read'),
|
||||
'perm_write': fields.boolean('Apply For Write'),
|
||||
'perm_create': fields.boolean('Apply For Create'),
|
||||
'perm_unlink': fields.boolean('Apply For Delete')
|
||||
}
|
||||
|
||||
_order = 'model_id DESC'
|
||||
|
||||
_defaults = {
|
||||
'perm_read': lambda *a: True,
|
||||
'perm_write': lambda *a: True,
|
||||
'perm_create': lambda *a: True,
|
||||
'perm_unlink': lambda *a: True,
|
||||
'perm_read': True,
|
||||
'perm_write': True,
|
||||
'perm_create': True,
|
||||
'perm_unlink': True,
|
||||
'global': True,
|
||||
}
|
||||
_sql_constraints = [
|
||||
('no_access_rights', 'CHECK (perm_read!=False or perm_write!=False or perm_create!=False or perm_unlink!=False)', 'Rule must have atleast one checked access right'),
|
||||
('no_access_rights', 'CHECK (perm_read!=False or perm_write!=False or perm_create!=False or perm_unlink!=False)', 'Rule must have at least one checked access right'),
|
||||
]
|
||||
_constraints = [
|
||||
(_check_model_obj, 'Rules are not supported for osv_memory objects !', ['model_id'])
|
||||
]
|
||||
|
||||
def onchange_all(self, cr, uid, ids, field_id, operator, operand):
|
||||
if not (field_id or operator or operand):
|
||||
return {}
|
||||
def domain_create(self, cr, uid, rule_ids):
|
||||
dom = ['&'] * (len(rule_ids)-1)
|
||||
for rule in self.browse(cr, uid, rule_ids):
|
||||
dom += rule.domain
|
||||
return dom
|
||||
|
||||
@tools.cache()
|
||||
def _compute_domain(self, cr, uid, model_name, mode="read"):
|
||||
group_rule = {}
|
||||
global_rules = []
|
||||
|
||||
def domain_get(self, cr, uid, model_name, mode='read', context={}):
|
||||
if uid == 1:
|
||||
return [], [], ['"'+self.pool.get(model_name)._table+'"']
|
||||
|
||||
return None
|
||||
cr.execute("""SELECT r.id
|
||||
FROM ir_rule r
|
||||
JOIN (ir_rule_group g
|
||||
JOIN ir_model m ON (g.model_id = m.id))
|
||||
ON (g.id = r.rule_group)
|
||||
JOIN ir_model m ON (r.model_id = m.id)
|
||||
WHERE m.model = %s
|
||||
AND r.perm_""" + mode + """
|
||||
AND (g.id IN (SELECT rule_group_id FROM group_rule_group_rel g_rel
|
||||
AND (r.id IN (SELECT rule_group_id FROM rule_group_rel g_rel
|
||||
JOIN res_groups_users_rel u_rel ON (g_rel.group_id = u_rel.gid)
|
||||
WHERE u_rel.uid = %s) OR g.global)""", (model_name, uid))
|
||||
WHERE u_rel.uid = %s) OR r.global)""", (model_name, uid))
|
||||
ids = map(lambda x: x[0], cr.fetchall())
|
||||
dom = []
|
||||
for rule in self.browse(cr, uid, ids):
|
||||
dom += rule.domain
|
||||
d1,d2,tables = self.pool.get(model_name)._where_calc(cr, uid, dom, active_test=False)
|
||||
return d1, d2, tables
|
||||
domain_get = tools.cache()(domain_get)
|
||||
for group in rule.groups:
|
||||
group_rule.setdefault(group.id, []).append(rule.id)
|
||||
if not rule.groups:
|
||||
global_rules.append(rule.id)
|
||||
dom = self.domain_create(cr, uid, global_rules)
|
||||
dom += ['|'] * (len(group_rule)-1)
|
||||
for value in group_rule.values():
|
||||
dom += self.domain_create(cr, uid, value)
|
||||
return dom
|
||||
|
||||
def domain_get(self, cr, uid, model_name, mode='read', context={}):
|
||||
dom = self._compute_domain(cr, uid, model_name, mode=mode)
|
||||
if dom:
|
||||
return self.pool.get(model_name)._where_calc(cr, uid, dom, active_test=False)
|
||||
return [], [], ['"'+self.pool.get(model_name)._table+'"']
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
res = super(ir_rule, self).unlink(cr, uid, ids, context=context)
|
||||
# Restart the cache on the domain_get method of ir.rule
|
||||
self.domain_get.clear_cache(cr.dbname)
|
||||
# Restart the cache on the _compute_domain method of ir.rule
|
||||
self._compute_domain.clear_cache(cr.dbname)
|
||||
return res
|
||||
|
||||
def create(self, cr, user, vals, context=None):
|
||||
res = super(ir_rule, self).create(cr, user, vals, context=context)
|
||||
# Restart the cache on the domain_get method of ir.rule
|
||||
self.domain_get.clear_cache(cr.dbname)
|
||||
# Restart the cache on the _compute_domain method of ir.rule
|
||||
self._compute_domain.clear_cache(cr.dbname)
|
||||
return res
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
if not context:
|
||||
context={}
|
||||
res = super(ir_rule, self).write(cr, uid, ids, vals, context=context)
|
||||
# Restart the cache on the domain_get method
|
||||
self.domain_get.clear_cache(cr.dbname)
|
||||
# Restart the cache on the _compute_domain method
|
||||
self._compute_domain.clear_cache(cr.dbname)
|
||||
return res
|
||||
|
||||
ir_rule()
|
||||
|
|
|
@ -86,7 +86,7 @@ class CountryState(osv.osv):
|
|||
args = []
|
||||
if not context:
|
||||
context = {}
|
||||
ids = self.search(cr, user, [('code', '=', name)] + args, limit=limit,
|
||||
ids = self.search(cr, user, [('code', 'ilike', name)] + args, limit=limit,
|
||||
context=context)
|
||||
if not ids:
|
||||
ids = self.search(cr, user, [('name', operator, name)] + args,
|
||||
|
|
|
@ -34,7 +34,7 @@ class groups(osv.osv):
|
|||
_columns = {
|
||||
'name': fields.char('Group Name', size=64, required=True),
|
||||
'model_access': fields.one2many('ir.model.access', 'group_id', 'Access Controls'),
|
||||
'rule_groups': fields.many2many('ir.rule.group', 'group_rule_group_rel',
|
||||
'rule_groups': fields.many2many('ir.rule', 'rule_group_rel',
|
||||
'group_id', 'rule_group_id', 'Rules', domain="[('global', '<>', True)]"),
|
||||
'menu_access': fields.many2many('ir.ui.menu', 'ir_ui_menu_group_rel', 'gid', 'menu_id', 'Access Menu'),
|
||||
'comment' : fields.text('Comment',size=250),
|
||||
|
@ -47,7 +47,7 @@ class groups(osv.osv):
|
|||
group_name = self.read(cr, uid, [id], ['name'])[0]['name']
|
||||
default.update({'name': group_name +' (copy)'})
|
||||
return super(groups, self).copy(cr, uid, id, default, context)
|
||||
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
if 'name' in vals:
|
||||
if vals['name'].startswith('-'):
|
||||
|
@ -185,7 +185,6 @@ class users(osv.osv):
|
|||
'menu_id': fields.many2one('ir.actions.actions', 'Menu Action'),
|
||||
'groups_id': fields.many2many('res.groups', 'res_groups_users_rel', 'uid', 'gid', 'Groups'),
|
||||
'roles_id': fields.many2many('res.roles', 'res_roles_users_rel', 'uid', 'rid', 'Roles'),
|
||||
'rules_id': fields.many2many('ir.rule.group', 'user_rule_group_rel', 'user_id', 'rule_group_id', 'Rules'),
|
||||
'company_id': fields.many2one('res.company', 'Company', required=True,
|
||||
help="The company this user is currently working for."),
|
||||
'company_ids':fields.many2many('res.company','res_company_users_rel','user_id','cid','Companies'),
|
||||
|
|
|
@ -72,37 +72,24 @@
|
|||
</record>
|
||||
|
||||
|
||||
<record model="ir.rule.group" id="res_partner_address_rule_group">
|
||||
<record model="ir.rule" id="res_partner_address_rule">
|
||||
<field name="name">res.partner.address company</field>
|
||||
<field name="model_id" ref="model_res_partner_address"/>
|
||||
<field name="global" eval="True"/>
|
||||
</record>
|
||||
<record model="ir.rule" id="res_partner_address_comp_rule">
|
||||
<field name="field_id" search="[('model','=','res.partner.address'),('name','=','company_id')]" model="ir.model.fields"/>
|
||||
<field name="rule_group" ref="res_partner_address_rule_group"/>
|
||||
<field name="domain_force">[('company_id','child_of',[user.company_id.id])]</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule.group" id="res_partner_rule_group">
|
||||
<record model="ir.rule" id="res_partner_rule">
|
||||
<field name="name">res.partner company</field>
|
||||
<field name="model_id" ref="model_res_partner"/>
|
||||
<field name="global" eval="True"/>
|
||||
</record>
|
||||
<record model="ir.rule" id="res_partner_comp_rule">
|
||||
<field name="field_id" search="[('model','=','res.partner'),('name','=','company_id')]" model="ir.model.fields"/>
|
||||
<field name="rule_group" ref="res_partner_rule_group"/>
|
||||
<field name="domain_force">[('company_id','child_of',[user.company_id.id])]</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record model="ir.rule.group" id="multi_company_default_rule_group">
|
||||
<record model="ir.rule" id="multi_company_default_rule">
|
||||
<field name="name">Multi_company_default company</field>
|
||||
<field name="model_id" ref="model_multi_company_default"/>
|
||||
<field name="global" eval="True"/>
|
||||
</record>
|
||||
<record model="ir.rule" id="multi_company_default_comp_rule">
|
||||
<field name="field_id" search="[('model','=','multi_company.default'),('name','=','company_id')]" model="ir.model.fields"/>
|
||||
<field name="rule_group" ref="multi_company_default_rule_group"/>
|
||||
<field name="domain_force">[('company_id','child_of',[user.company_id.id])]</field>
|
||||
</record>
|
||||
|
||||
|
|
|
@ -23,9 +23,7 @@
|
|||
"access_ir_report_custom_group_system","ir_report_custom group_system","model_ir_report_custom",,1,0,0,0
|
||||
"access_ir_report_custom_fields_group_system","ir_report_custom_fields group_system","model_ir_report_custom_fields",,1,0,0,0
|
||||
"access_ir_rule_group_user","ir_rule group_user","model_ir_rule",,1,0,0,0
|
||||
"access_ir_rule_group_group_user","ir_rule_group group_user","model_ir_rule_group",,1,0,0,0
|
||||
"access_ir_rule_group_erp_manager","ir_rule group_erp_manager","model_ir_rule","group_erp_manager",1,1,1,1
|
||||
"access_ir_rule_group_group_erp_manager","ir_rule_group group_erp_manager","model_ir_rule_group","group_erp_manager",1,1,1,1
|
||||
"access_ir_sequence_group_user","ir_sequence group_user","model_ir_sequence",,1,1,1,1
|
||||
"access_ir_sequence_type_group_user","ir_sequence_type group_user","model_ir_sequence_type",,1,0,0,0
|
||||
"access_ir_translation_group_system","ir_translation group_system","model_ir_translation",,1,1,1,1
|
||||
|
|
|
|
@ -26,6 +26,17 @@ import os
|
|||
import sys
|
||||
import glob
|
||||
|
||||
def load_information_from_description_file(module):
|
||||
"""
|
||||
:param module: The name of the module (sale, purchase, ...)
|
||||
"""
|
||||
for filename in ['__openerp__.py', '__terp__.py']:
|
||||
description_file = os.path.join(module, filename)
|
||||
if os.path.isfile(description_file):
|
||||
return eval(file(description_file).read())
|
||||
|
||||
return {}
|
||||
|
||||
if len(sys.argv) == 2 and (sys.argv[1] in ['-h', '--help']):
|
||||
print >>sys.stderr, 'Usage: module_graph.py [module1 module2 module3]\n\tWhen no module is specified, all modules in current directory are used'
|
||||
sys.exit(1)
|
||||
|
@ -41,7 +52,7 @@ print 'digraph G {'
|
|||
while len(modules):
|
||||
f = modules.pop(0)
|
||||
done.append(f)
|
||||
info = addons.load_information_from_description_file(f)
|
||||
info = load_information_from_description_file(f)
|
||||
if info.get('installable', True):
|
||||
for name in info['depends']:
|
||||
if name not in done+modules:
|
||||
|
|
|
@ -656,6 +656,11 @@ class function(_column):
|
|||
self._symbol_f = float._symbol_f
|
||||
self._symbol_set = float._symbol_set
|
||||
|
||||
if type == 'boolean':
|
||||
self._symbol_c = boolean._symbol_c
|
||||
self._symbol_f = boolean._symbol_f
|
||||
self._symbol_set = boolean._symbol_set
|
||||
|
||||
def digits_change(self, cr):
|
||||
if self.digits_compute:
|
||||
t = self.digits_compute(cr)
|
||||
|
|
|
@ -1139,6 +1139,25 @@ class orm_template(object):
|
|||
return s.encode('utf8')
|
||||
return s
|
||||
|
||||
# return True if node can be displayed to current user
|
||||
def check_group(node):
|
||||
if node.get('groups'):
|
||||
groups = node.get('groups').split(',')
|
||||
can_see = False
|
||||
access_pool = self.pool.get('ir.model.access')
|
||||
for group in groups:
|
||||
can_see = can_see or access_pool.check_groups(cr, user, group)
|
||||
if can_see:
|
||||
break
|
||||
if not can_see:
|
||||
node.set('invisible', '1')
|
||||
if 'attrs' in node.attrib:
|
||||
del(node.attrib['attrs']) #avoid making field visible later
|
||||
del(node.attrib['groups'])
|
||||
return can_see
|
||||
else:
|
||||
return True
|
||||
|
||||
if node.tag in ('field', 'node', 'arrow'):
|
||||
if node.get('object'):
|
||||
attrs = {}
|
||||
|
@ -1185,15 +1204,18 @@ class orm_template(object):
|
|||
}
|
||||
attrs = {'views': views}
|
||||
if node.get('widget') and node.get('widget') == 'selection':
|
||||
if not check_group(node):
|
||||
attrs['selection'] = []
|
||||
# We can not use the 'string' domain has it is defined according to the record !
|
||||
dom = []
|
||||
if column._domain and not isinstance(column._domain, (str, unicode)):
|
||||
dom = column._domain
|
||||
dom += eval(node.get('domain','[]'), {'uid':user, 'time':time})
|
||||
context.update(eval(node.get('context','{}')))
|
||||
attrs['selection'] = self.pool.get(relation).name_search(cr, user, '', dom, context=context,limit=None)
|
||||
if (node.get('required') and not int(node.get('required'))) or not column.required:
|
||||
attrs['selection'].append((False,''))
|
||||
else:
|
||||
dom = []
|
||||
if column._domain and not isinstance(column._domain, (str, unicode)):
|
||||
dom = column._domain
|
||||
dom += eval(node.get('domain','[]'), {'uid':user, 'time':time})
|
||||
context.update(eval(node.get('context','{}')))
|
||||
attrs['selection'] = self.pool.get(relation)._name_search(cr, user, '', dom, context=context, limit=None, name_get_uid=1)
|
||||
if (node.get('required') and not int(node.get('required'))) or not column.required:
|
||||
attrs['selection'].append((False,''))
|
||||
fields[node.get('name')] = attrs
|
||||
|
||||
elif node.tag in ('form', 'tree'):
|
||||
|
@ -1207,15 +1229,7 @@ class orm_template(object):
|
|||
fields[node.get(additional_field)] = {}
|
||||
|
||||
if 'groups' in node.attrib:
|
||||
if node.get('groups'):
|
||||
groups = node.get('groups').split(',')
|
||||
readonly = False
|
||||
access_pool = self.pool.get('ir.model.access')
|
||||
for group in groups:
|
||||
readonly = readonly or access_pool.check_groups(cr, user, group)
|
||||
if not readonly:
|
||||
node.set('invisible', '1')
|
||||
del(node.attrib['groups'])
|
||||
check_group(node)
|
||||
|
||||
# translate view
|
||||
if ('lang' in context) and not result:
|
||||
|
@ -1725,6 +1739,7 @@ class orm_memory(orm_template):
|
|||
def read(self, cr, user, ids, fields_to_read=None, context=None, load='_classic_read'):
|
||||
if not context:
|
||||
context = {}
|
||||
self.pool.get('ir.model.access').check(cr, user, self._name, 'read', context=context)
|
||||
if not fields_to_read:
|
||||
fields_to_read = self._columns.keys()
|
||||
result = []
|
||||
|
@ -1754,6 +1769,7 @@ class orm_memory(orm_template):
|
|||
def write(self, cr, user, ids, vals, context=None):
|
||||
if not ids:
|
||||
return True
|
||||
self.pool.get('ir.model.access').check(cr, user, self._name, 'write', context=context)
|
||||
vals2 = {}
|
||||
upd_todo = []
|
||||
for field in vals:
|
||||
|
@ -1772,6 +1788,7 @@ class orm_memory(orm_template):
|
|||
return id_new
|
||||
|
||||
def create(self, cr, user, vals, context=None):
|
||||
self.pool.get('ir.model.access').check(cr, user, self._name, 'create', context=context)
|
||||
self.vaccum(cr, user)
|
||||
self.next_id += 1
|
||||
id_new = self.next_id
|
||||
|
@ -1923,6 +1940,7 @@ class orm_memory(orm_template):
|
|||
return res or []
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
self.pool.get('ir.model.access').check(cr, uid, self._name, 'unlink', context=context)
|
||||
for id in ids:
|
||||
if id in self.datas:
|
||||
del self.datas[id]
|
||||
|
@ -3225,7 +3243,7 @@ class orm(orm_template):
|
|||
"""
|
||||
if not context:
|
||||
context = {}
|
||||
self.pool.get('ir.model.access').check(cr, user, self._name, 'create')
|
||||
self.pool.get('ir.model.access').check(cr, user, self._name, 'create', context=context)
|
||||
|
||||
default = []
|
||||
|
||||
|
@ -3282,7 +3300,7 @@ class orm(orm_template):
|
|||
|
||||
record_id = tocreate[table].pop('id', None)
|
||||
|
||||
if record_id is None:
|
||||
if record_id is None or not record_id:
|
||||
record_id = self.pool.get(table).create(cr, user, tocreate[table], context=context)
|
||||
else:
|
||||
self.pool.get(table).write(cr, user, [record_id], tocreate[table], context=context)
|
||||
|
@ -3649,6 +3667,20 @@ class orm(orm_template):
|
|||
return [(r['id'], tools.ustr(r[self._rec_name])) for r in self.read(cr, user, ids,
|
||||
[self._rec_name], context, load='_classic_write')]
|
||||
|
||||
# private implementation of name_search, allows passing a dedicated user for the name_get part to
|
||||
# solve some access rights issues
|
||||
def _name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100, name_get_uid=None):
|
||||
if not args:
|
||||
args = []
|
||||
if not context:
|
||||
context = {}
|
||||
args = args[:]
|
||||
if name:
|
||||
args += [(self._rec_name, operator, name)]
|
||||
ids = self.search(cr, user, args, limit=limit, context=context)
|
||||
res = self.name_get(cr, name_get_uid or user, ids, context)
|
||||
return res
|
||||
|
||||
def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100):
|
||||
"""
|
||||
|
||||
|
@ -3664,16 +3696,7 @@ class orm(orm_template):
|
|||
This method is equivalent of search() on name + name_get()
|
||||
|
||||
"""
|
||||
if not args:
|
||||
args = []
|
||||
if not context:
|
||||
context = {}
|
||||
args = args[:]
|
||||
if name:
|
||||
args += [(self._rec_name, operator, name)]
|
||||
ids = self.search(cr, user, args, limit=limit, context=context)
|
||||
res = self.name_get(cr, user, ids, context)
|
||||
return res
|
||||
return self._name_search(cr, user, name, args, operator, context, limit)
|
||||
|
||||
def copy_data(self, cr, uid, id, default=None, context=None):
|
||||
"""
|
||||
|
|
|
@ -82,6 +82,9 @@ class configmanager(object):
|
|||
'login_message': False,
|
||||
'list_db' : True,
|
||||
'timezone' : False, # to override the default TZ
|
||||
'test-disable' : False,
|
||||
'test-rollback' : True,
|
||||
'test-continue' : False
|
||||
}
|
||||
|
||||
self.misc = {}
|
||||
|
@ -134,7 +137,17 @@ class configmanager(object):
|
|||
default="server.pkey",
|
||||
help="specify the private key file for the SSL connection")
|
||||
parser.add_option_group(group)
|
||||
|
||||
|
||||
# Testing Group
|
||||
group = optparse.OptionGroup(parser, "Testing Configuration")
|
||||
group.add_option("--test-disable", action="store_true", dest="test_disable",
|
||||
default=False, help="Disable loading test files.")
|
||||
group.add_option("--test-no-rollback", action="store_false", dest="test_rollback",
|
||||
default=True, help="Don't rollback after running test.")
|
||||
group.add_option("--test-continue", action="store_true", dest="test_continue",
|
||||
default=False, help="Display exception but then test should continue.")
|
||||
parser.add_option_group(group)
|
||||
|
||||
# Logging Group
|
||||
group = optparse.OptionGroup(parser, "Logging Configuration")
|
||||
group.add_option("--logfile", dest="logfile", help="file where the server log will be stored")
|
||||
|
@ -274,6 +287,9 @@ class configmanager(object):
|
|||
|
||||
self.options['init'] = opt.init and dict.fromkeys(opt.init.split(','), 1) or {}
|
||||
self.options["demo"] = not opt.without_demo and self.options['init'] or {}
|
||||
self.options["test-disable"] = opt.test_disable
|
||||
self.options["test-rollback"] = opt.test_rollback
|
||||
self.options["test-continue"] = opt.test_continue
|
||||
self.options['update'] = opt.update and dict.fromkeys(opt.update.split(','), 1) or {}
|
||||
|
||||
self.options['translate_modules'] = opt.translate_modules and map(lambda m: m.strip(), opt.translate_modules.split(',')) or ['all']
|
||||
|
|
|
@ -254,38 +254,48 @@ class YamlInterpreter(object):
|
|||
b = bool(value)
|
||||
else:
|
||||
b = default
|
||||
return b
|
||||
|
||||
def process_record(self, node):
|
||||
record, fields = node.items()[0]
|
||||
|
||||
self.validate_xml_id(record.id)
|
||||
if self.isnoupdate(record) and self.mode != 'init':
|
||||
id = self.pool.get('ir.model.data')._update_dummy(self.cr, self.uid, record.model, self.module, record.id)
|
||||
# check if the resource already existed at the last update
|
||||
if id:
|
||||
self.id_map[record] = int(id)
|
||||
return None
|
||||
else:
|
||||
if not self._coerce_bool(record.forcecreate):
|
||||
return None
|
||||
return b
|
||||
|
||||
def create_osv_memory_record(self, record, fields):
|
||||
model = self.get_model(record.model)
|
||||
record_dict = self._create_record(model, fields)
|
||||
self.logger.debug("RECORD_DICT %s" % record_dict)
|
||||
id = self.pool.get('ir.model.data')._update(self.cr, self.uid, record.model, \
|
||||
self.module, record_dict, record.id, noupdate=self.isnoupdate(record), mode=self.mode)
|
||||
self.id_map[record.id] = int(id)
|
||||
if config.get('import_partial', False):
|
||||
self.cr.commit()
|
||||
|
||||
id_new=model.create(self.cr, self.uid, record_dict, context=self.context)
|
||||
self.id_map[record.id] = int(id_new)
|
||||
return record_dict
|
||||
|
||||
def process_record(self, node):
|
||||
import osv
|
||||
record, fields = node.items()[0]
|
||||
model = self.get_model(record.model)
|
||||
if isinstance(model, osv.osv.osv_memory):
|
||||
record_dict=self.create_osv_memory_record(record, fields)
|
||||
else:
|
||||
self.validate_xml_id(record.id)
|
||||
if self.isnoupdate(record) and self.mode != 'init':
|
||||
id = self.pool.get('ir.model.data')._update_dummy(self.cr, self.uid, record.model, self.module, record.id)
|
||||
# check if the resource already existed at the last update
|
||||
if id:
|
||||
self.id_map[record] = int(id)
|
||||
return None
|
||||
else:
|
||||
if not self._coerce_bool(record.forcecreate):
|
||||
return None
|
||||
|
||||
record_dict = self._create_record(model, fields)
|
||||
self.logger.debug("RECORD_DICT %s" % record_dict)
|
||||
id = self.pool.get('ir.model.data')._update(self.cr, self.uid, record.model, \
|
||||
self.module, record_dict, record.id, noupdate=self.isnoupdate(record), mode=self.mode)
|
||||
self.id_map[record.id] = int(id)
|
||||
if config.get('import_partial'):
|
||||
self.cr.commit()
|
||||
|
||||
def _create_record(self, model, fields):
|
||||
record_dict = {}
|
||||
for field_name, expression in fields.items():
|
||||
field_value = self._eval_field(model, field_name, expression)
|
||||
record_dict[field_name] = field_value
|
||||
return record_dict
|
||||
|
||||
return record_dict
|
||||
|
||||
def process_ref(self, node, column=None):
|
||||
if node.search:
|
||||
if node.model:
|
||||
|
@ -307,10 +317,10 @@ class YamlInterpreter(object):
|
|||
else:
|
||||
value = None
|
||||
return value
|
||||
|
||||
|
||||
def process_eval(self, node):
|
||||
return eval(node.expression, self.eval_context)
|
||||
|
||||
|
||||
def _eval_field(self, model, field_name, expression):
|
||||
# TODO this should be refactored as something like model.get_field() in bin/osv
|
||||
if field_name in model._columns:
|
||||
|
@ -390,6 +400,10 @@ class YamlInterpreter(object):
|
|||
uid = workflow.uid
|
||||
else:
|
||||
uid = self.uid
|
||||
self.cr.execute('select distinct signal from wkf_transition')
|
||||
signals=[x['signal'] for x in self.cr.dictfetchall()]
|
||||
if workflow.action not in signals:
|
||||
raise YamlImportException('Incorrect action %s. No such action defined' % workflow.action)
|
||||
wf_service = netsvc.LocalService("workflow")
|
||||
wf_service.trg_validate(uid, workflow.model, id, workflow.action, self.cr)
|
||||
|
||||
|
@ -528,15 +542,19 @@ class YamlInterpreter(object):
|
|||
'tree_but_open', 'Menuitem', [('ir.ui.menu', int(parent_id))], action, True, True, xml_id=node.id)
|
||||
|
||||
def process_act_window(self, node):
|
||||
assert getattr(node, 'id'), "Attribute %s of act_window is empty !" % ('id',)
|
||||
assert getattr(node, 'name'), "Attribute %s of act_window is empty !" % ('name',)
|
||||
assert getattr(node, 'res_model'), "Attribute %s of act_window is empty !" % ('res_model',)
|
||||
self.validate_xml_id(node.id)
|
||||
view_id = False
|
||||
if node.view:
|
||||
view_id = self.get_id(node.view)
|
||||
context = eval(node.context, self.eval_context)
|
||||
|
||||
if not node.context:
|
||||
node.context={}
|
||||
context = eval(str(node.context), self.eval_context)
|
||||
values = {
|
||||
'name': node.name,
|
||||
'type': type or 'ir.actions.act_window',
|
||||
'type': node.type or 'ir.actions.act_window',
|
||||
'view_id': view_id,
|
||||
'domain': node.domain,
|
||||
'context': context,
|
||||
|
@ -566,13 +584,17 @@ class YamlInterpreter(object):
|
|||
# TODO add remove ir.model.data
|
||||
|
||||
def process_delete(self, node):
|
||||
if len(node.search):
|
||||
ids = self.pool.get(node.model).search(self.cr, self.uid, eval(node.search, self.eval_context))
|
||||
assert getattr(node, 'model'), "Attribute %s of delete tag is empty !" % ('model',)
|
||||
if self.pool.get(node.model):
|
||||
if len(node.search):
|
||||
ids = self.pool.get(node.model).search(self.cr, self.uid, eval(node.search, self.eval_context))
|
||||
else:
|
||||
ids = [self.get_id(node.id)]
|
||||
if len(ids):
|
||||
self.pool.get(node.model).unlink(self.cr, self.uid, ids)
|
||||
self.pool.get('ir.model.data')._unlink(self.cr, self.uid, node.model, ids)
|
||||
else:
|
||||
ids = [self.get_id(node.id)]
|
||||
if len(ids):
|
||||
self.pool.get(node.model).unlink(self.cr, self.uid, ids)
|
||||
self.pool.get('ir.model.data')._unlink(self.cr, self.uid, node.model, ids)
|
||||
self.logger.log(logging.TEST, "Record not deleted.")
|
||||
|
||||
def process_url(self, node):
|
||||
self.validate_xml_id(node.id)
|
||||
|
@ -649,6 +671,8 @@ class YamlInterpreter(object):
|
|||
"""
|
||||
Processes a Yaml string. Custom tags are interpreted by 'process_' instance methods.
|
||||
"""
|
||||
yaml_tag.add_constructors()
|
||||
|
||||
is_preceded_by_comment = False
|
||||
for node in yaml.load(yaml_string):
|
||||
is_preceded_by_comment = self._log(node, is_preceded_by_comment)
|
||||
|
|
|
@ -48,9 +48,7 @@ class Workflow(YamlTag):
|
|||
super(Workflow, self).__init__(**kwargs)
|
||||
|
||||
class ActWindow(YamlTag):
|
||||
def __init__(self, model, action, **kwargs):
|
||||
self.model = model
|
||||
self.action = action
|
||||
def __init__(self, **kwargs):
|
||||
super(ActWindow, self).__init__(**kwargs)
|
||||
|
||||
class Function(YamlTag):
|
||||
|
@ -67,10 +65,7 @@ class Report(YamlTag):
|
|||
super(Report, self).__init__(**kwargs)
|
||||
|
||||
class Delete(YamlTag):
|
||||
def __init__(self, model, id, search, **kwargs):
|
||||
self.model = model
|
||||
self.id = id
|
||||
self.search = search
|
||||
def __init__(self, **kwargs):
|
||||
super(Delete, self).__init__(**kwargs)
|
||||
|
||||
class Context(YamlTag):
|
||||
|
@ -156,17 +151,19 @@ def ir_set_constructor(loader, node):
|
|||
# Registers constructors for custom tags.
|
||||
# Constructors are actually defined globally: do not redefined them in another
|
||||
# class/file/package. This means that module recorder need import this file.
|
||||
yaml.add_constructor(u"!assert", assert_constructor)
|
||||
yaml.add_constructor(u"!record", record_constructor)
|
||||
yaml.add_constructor(u"!python", python_constructor)
|
||||
yaml.add_constructor(u"!menuitem", menuitem_constructor)
|
||||
yaml.add_constructor(u"!workflow", workflow_constructor)
|
||||
yaml.add_constructor(u"!act_window", act_window_constructor)
|
||||
yaml.add_constructor(u"!function", function_constructor)
|
||||
yaml.add_constructor(u"!report", report_constructor)
|
||||
yaml.add_constructor(u"!context", context_constructor)
|
||||
yaml.add_constructor(u"!delete", delete_constructor)
|
||||
yaml.add_constructor(u"!url", url_constructor)
|
||||
yaml.add_constructor(u"!eval", eval_constructor)
|
||||
yaml.add_multi_constructor(u"!ref", ref_constructor)
|
||||
yaml.add_constructor(u"!ir_set", ir_set_constructor)
|
||||
def add_constructors():
|
||||
yaml.add_constructor(u"!assert", assert_constructor)
|
||||
yaml.add_constructor(u"!record", record_constructor)
|
||||
yaml.add_constructor(u"!python", python_constructor)
|
||||
yaml.add_constructor(u"!menuitem", menuitem_constructor)
|
||||
yaml.add_constructor(u"!workflow", workflow_constructor)
|
||||
yaml.add_constructor(u"!act_window", act_window_constructor)
|
||||
yaml.add_constructor(u"!function", function_constructor)
|
||||
yaml.add_constructor(u"!report", report_constructor)
|
||||
yaml.add_constructor(u"!context", context_constructor)
|
||||
yaml.add_constructor(u"!delete", delete_constructor)
|
||||
yaml.add_constructor(u"!url", url_constructor)
|
||||
yaml.add_constructor(u"!eval", eval_constructor)
|
||||
yaml.add_multi_constructor(u"!ref", ref_constructor)
|
||||
yaml.add_constructor(u"!ir_set", ir_set_constructor)
|
||||
add_constructors()
|
Loading…
Reference in New Issue