[MERGE] Merged with server/trunk.

bzr revid: tde@openerp.com-20120810073318-gcgnj16e02qvg0y3
bzr revid: tde@openerp.com-20120814090328-seyvug8zdagbdm0o
This commit is contained in:
Thibault Delavallée 2012-08-14 11:03:28 +02:00
commit 7c0a0a0158
28 changed files with 2306 additions and 879 deletions

View File

@ -80,6 +80,7 @@
'demo_xml': [
'base_demo.xml',
'res/res_partner_demo.xml',
'res/res_partner_demo.yml',
'res/res_widget_demo.xml',
],
'test': [

View File

@ -1061,6 +1061,13 @@
<field name="company_id" eval="None"/>
<field name="customer" eval="False"/>
<field name="is_company" eval="True"/>
<field name="street">45, Rue du Palais</field>
<field name="city">Paris</field>
<field name="zip">75016</field>
<field ref="base.fr" name="country_id"/>
<field name="phone">+33 1 49 51 23 94</field>
<field name="email">info@yourcompany.com</field>
<field name="website">www.yourcompany.com</field>
</record>
<!-- Currencies -->
@ -1082,8 +1089,9 @@
<record id="main_company" model="res.company">
<field name="name">Your Company</field>
<field name="partner_id" ref="main_partner"/>
<field name="rml_footer1">Web: www.companyname.com - Tel: +1-212-555-12345</field>
<field name="rml_footer2">IBAN: XX12 3456 7890 1234 5678 - SWIFT: SWIFTCODE - VAT: Company vat number</field>
<field name="rml_header1">Your Company Slogan</field>
<field name="rml_footer1">Web: http://www.yourcompany.com - Tel: +33 1 49 51 23 94</field>
<field name="rml_footer2">Bank Accounts... to be configured in menu Settings > Accounting/Invoicing.</field>
<field name="currency_id" ref="base.EUR"/>
</record>
@ -1624,7 +1632,7 @@
</record>
<record id="res_bank_1" model="res.bank">
<field name="name">Reserve</field>
<field name="name">International Bank</field>
</record>
<record id="CRC" model="res.currency">

View File

@ -1,19 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="demo_address" model="res.partner">
<field name="name">Fabien D'souza</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>

View File

@ -7,14 +7,15 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 00:44+0000\n"
"PO-Revision-Date: 2012-02-16 22:06+0000\n"
"Last-Translator: Davide Corio - agilebg.com <davide.corio@agilebg.com>\n"
"PO-Revision-Date: 2012-08-10 18:42+0000\n"
"Last-Translator: Leonardo Pistone - Agile BG - Domsense "
"<leonardo.pistone@domsense.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: 2012-07-19 04:40+0000\n"
"X-Generator: Launchpad (build 15637)\n"
"X-Launchpad-Export-Date: 2012-08-11 05:45+0000\n"
"X-Generator: Launchpad (build 15780)\n"
#. module: base
#: model:res.country,name:base.sh
@ -849,6 +850,10 @@ msgid ""
"Launch Manually Once: after hacing been launched manually, it sets "
"automatically to Done."
msgstr ""
"Manuale: Esegui manualmente\n"
"Automatico: Viene eseguito ogni volta che il sistema viene riconfigurato \n"
"Esegui manualmente una volta sola: una volta lanciata l'esecuzione, lo stato "
"viene impostato autmaticamente su \"Eseguito\""
#. module: base
#: selection:base.language.install,lang:0
@ -1593,7 +1598,7 @@ msgstr "Login"
#: model:ir.actions.act_window,name:base.action_wizard_update_translations
#: model:ir.ui.menu,name:base.menu_wizard_update_translations
msgid "Synchronize Terms"
msgstr ""
msgstr "Sincronizza Termini"
#. module: base
#: view:ir.actions.server:0
@ -2980,7 +2985,7 @@ msgstr "Armenia"
#: model:ir.actions.act_window,name:base.ir_property_form
#: model:ir.ui.menu,name:base.menu_ir_property_form_all
msgid "Configuration Parameters"
msgstr "Parametri Configurazione"
msgstr "Parametri di configurazione"
#. module: base
#: constraint:ir.cron:0
@ -3077,7 +3082,7 @@ msgstr ""
#. module: base
#: model:ir.module.module,shortdesc:base.module_wiki_quality_manual
msgid "Wiki: Quality Manual"
msgstr ""
msgstr "Wiki: Manuale della Qualità"
#. module: base
#: selection:ir.actions.act_window.view,view_mode:0
@ -3105,7 +3110,7 @@ msgstr "Settore Risorse Umane"
#. module: base
#: model:ir.ui.menu,name:base.menu_dashboard_admin
msgid "Administration Dashboard"
msgstr ""
msgstr "Dashboard di Amministrazione"
#. module: base
#: code:addons/orm.py:4408
@ -3748,7 +3753,7 @@ msgstr ""
#. module: base
#: model:ir.module.category,name:base.module_category_human_resources
msgid "Human Resources"
msgstr ""
msgstr "Risorse Umane"
#. module: base
#: model:ir.actions.act_window,name:base.action_country
@ -3808,7 +3813,7 @@ msgstr "Partita IVA"
#. module: base
#: field:res.users,new_password:0
msgid "Set password"
msgstr ""
msgstr "Nuova password"
#. module: base
#: view:res.lang:0
@ -4737,7 +4742,7 @@ msgstr "Kenia"
#: model:ir.actions.act_window,name:base.action_translation
#: model:ir.ui.menu,name:base.menu_action_translation
msgid "Translated Terms"
msgstr ""
msgstr "Termini Tradotti"
#. module: base
#: view:res.partner.event:0
@ -6368,7 +6373,7 @@ msgstr "Menu"
#. module: base
#: selection:ir.actions.todo,type:0
msgid "Launch Manually Once"
msgstr ""
msgstr "Esegui manualmente una volta sola"
#. module: base
#: model:ir.module.category,name:base.module_category_hidden
@ -6741,6 +6746,8 @@ msgid ""
"password, otherwise leave empty. After a change of password, the user has to "
"login again."
msgstr ""
"Per modificare la password scrivila qui, altrimenti lascia il campo vuoto. "
"Dopo aver cambiato la password, l'utente deve fare nuovamente login."
#. module: base
#: view:publisher_warranty.contract:0
@ -6929,7 +6936,7 @@ msgstr ""
#. module: base
#: view:ir.property:0
msgid "Parameters that are used by all resources."
msgstr ""
msgstr "Parametri utilizzati da tutte le risorse"
#. module: base
#: model:res.country,name:base.mz
@ -9394,7 +9401,7 @@ msgstr ""
#: model:ir.model,name:base.model_ir_model
#: model:ir.ui.menu,name:base.ir_model_model_menu
msgid "Models"
msgstr ""
msgstr "Modelli"
#. module: base
#: code:addons/base/ir/ir_cron.py:292
@ -9405,7 +9412,7 @@ msgstr ""
#. module: base
#: selection:ir.actions.todo,type:0
msgid "Launch Manually"
msgstr ""
msgstr "Esegui manualmente"
#. module: base
#: model:res.country,name:base.be
@ -10753,7 +10760,7 @@ msgstr "Nazione"
#. module: base
#: model:ir.ui.menu,name:base.next_id_5
msgid "Sequences & Identifiers"
msgstr ""
msgstr "Sequenze e Identificatori"
#. module: base
#: model:ir.module.module,description:base.module_l10n_th
@ -12636,7 +12643,7 @@ msgstr "ir.values"
#. module: base
#: model:res.groups,name:base.group_no_one
msgid "Technical Features"
msgstr ""
msgstr "Funzionalità tecniche"
#. module: base
#: selection:base.language.install,lang:0
@ -12656,7 +12663,7 @@ msgstr ""
#: view:ir.model.data:0
#: model:ir.ui.menu,name:base.ir_model_data_menu
msgid "External Identifiers"
msgstr ""
msgstr "Identificatori Esterni"
#. module: base
#: model:res.groups,name:base.group_sale_salesman
@ -12950,6 +12957,7 @@ msgid ""
"Please define at least one SMTP server, or provide the SMTP parameters "
"explicitly."
msgstr ""
"Definire almeno un server SMTP, o fornire esplicitamente i parametri SMTP"
#. module: base
#: view:ir.attachment:0
@ -12993,7 +13001,7 @@ msgstr "Gabon"
#. module: base
#: model:res.groups,name:base.group_multi_company
msgid "Multi Companies"
msgstr ""
msgstr "Multi-azienda"
#. module: base
#: view:ir.model:0
@ -13166,7 +13174,7 @@ msgstr "Varie"
#: view:ir.mail_server:0
#: model:ir.ui.menu,name:base.menu_mail_servers
msgid "Outgoing Mail Servers"
msgstr ""
msgstr "Server della Posta in Uscita"
#. module: base
#: model:res.country,name:base.cn

View File

@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 00:44+0000\n"
"PO-Revision-Date: 2012-02-19 13:01+0000\n"
"PO-Revision-Date: 2012-08-09 06:15+0000\n"
"Last-Translator: Erwin <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: 2012-07-19 04:38+0000\n"
"X-Generator: Launchpad (build 15637)\n"
"X-Launchpad-Export-Date: 2012-08-10 04:58+0000\n"
"X-Generator: Launchpad (build 15761)\n"
#. module: base
#: model:res.country,name:base.sh
@ -1443,7 +1443,7 @@ msgstr ""
"U kunt de navolgende extra data toevoegen aan een verkooporder:\n"
"* Aanvraagdatum\n"
"* Bevestigde datum\n"
"* Effectieve datum\n"
"* Boek datum\n"
#. module: base
#: model:ir.module.module,shortdesc:base.module_account_sequence
@ -8110,7 +8110,7 @@ msgstr "Kenmerk"
#. module: base
#: model:ir.module.module,shortdesc:base.module_analytic
msgid "Analytic Accounting"
msgstr "Kostenplaats boekhouding"
msgstr "Kostenplaatsen"
#. module: base
#: view:ir.actions.report.xml:0

View File

@ -223,11 +223,11 @@ class act_window(osv.osv):
help="Model name of the object to open in the view window"),
'src_model': fields.char('Source Model', size=64,
help="Optional model name of the objects on which this action should be visible"),
'target': fields.selection([('current','Current Window'),('new','New Window'),('inline','Inline')], 'Target Window'),
'view_type': fields.selection((('tree','Tree'),('form','Form')), string='View Type', required=True,
help="View type: set to 'tree' for a hierarchical tree view, or 'form' for other views"),
'target': fields.selection([('current','Current Window'),('new','New Window'),('inline','Inline Edit'),('inlineview','Inline View')], 'Target Window'),
'view_mode': fields.char('View Mode', size=250, required=True,
help="Comma-separated list of allowed view modes, such as 'form', 'tree', 'calendar', etc. (Default: tree,form)"),
'view_type': fields.selection((('tree','Tree'),('form','Form')), string='View Type', required=True,
help="View type: Tree type to use for the tree view, set to 'tree' for a hierarchical tree view, or 'form' for a regular list view"),
'usage': fields.char('Action Usage', size=32,
help="Used to filter menu and home actions from the user form."),
'view_ids': fields.one2many('ir.actions.act_window.view', 'act_window_id', 'Views'),

View File

@ -110,8 +110,8 @@
<field name="zip" class="oe_inline" placeholder="ZIP"/>
<field name="city" class="oe_inline" placeholder="City"/>
</div>
<field name="state_id" placeholder="State"/>
<field name="country_id" placeholder="Country"/>
<field name="state_id" placeholder="State" options='{"no_open": true}'/>
<field name="country_id" placeholder="Country" options='{"no_open": true}'/>
</div>
</group>
<group name="bank" string="Information About the Bank">

View File

@ -51,10 +51,10 @@
<field name="street2"/>
<div>
<field name="city" placeholder="City" style="width: 40%%"/>
<field name="state_id" class="oe_no_button" placeholder="State" style="width: 24%%"/>
<field name="state_id" class="oe_no_button" placeholder="State" style="width: 24%%" options='{"no_open": true}'/>
<field name="zip" placeholder="ZIP" style="width: 34%%"/>
</div>
<field name="country_id" placeholder="Country" class="oe_no_button"/>
<field name="country_id" placeholder="Country" class="oe_no_button" options='{"no_open": true}'/>
</div>
<field name="website" widget="url" placeholder="e.g. www.openerp.com"/>
</group>

View File

@ -71,7 +71,7 @@
<group>
<field name="name"/>
<field name="code"/>
<field name="country_id"/>
<field name="country_id" options='{"no_open": true}'/>
</group>
</form>
</field>

View File

@ -232,6 +232,8 @@ class res_partner(osv.osv):
'type': 'default',
'use_parent_address': True,
'image': lambda self, cr, uid, context: self._get_default_image(cr, uid, False, context),
'image_small': lambda self, cr, uid, context: self._get_default_image(cr, uid, False, context),
'image_medium': lambda self, cr, uid, context: self._get_default_image(cr, uid, False, context),
}
def copy(self, cr, uid, id, default=None, context=None):

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,261 @@
-
!record {model: 'res.partner', id: base.res_partner_address_1}:
name: Tang Tsui
parent_id: base.res_partner_1
use_parent_address: True
function: Service Manager
email: tang@asustek.com
-
!record {model: 'res.partner', id: base.res_partner_address_2}:
name: Joseph Walters
parent_id: base.res_partner_1
use_parent_address: True
function: Store Manager
email: joseph.walters@asustek.com
-
!record {model: 'res.partner', id: base.res_partner_address_3}:
name: Thomas Passot
parent_id: base.res_partner_2
use_parent_address: True
function: Functional Consultant
email: p.thomas@agrolait.com
-
!record {model: 'res.partner', id: base.res_partner_address_4}:
name: Michel Fletcher
parent_id: base.res_partner_2
use_parent_address: True
function: Analyst
email: m.fletcher@agrolait.com
-
!record {model: 'res.partner', id: base.res_partner_address_5}:
name: Chao Wang
parent_id: base.res_partner_3
use_parent_address: True
function: Marketing Manager
email: chao_wang@chinaexport.com
-
!record {model: 'res.partner', id: base.res_partner_address_6}:
name: Zhi Ch'ang
parent_id: base.res_partner_3
use_parent_address: True
function: Supervisor
email: zhi_chang@chinaexport.com
-
!record {model: 'res.partner', id: base.res_partner_address_7}:
name: Richard Ellis
parent_id: base.res_partner_4
use_parent_address: True
function: Production Supervisor
email:
-
!record {model: 'res.partner', id: base.res_partner_address_8}:
name: Paul Williams
parent_id: base.res_partner_4
use_parent_address: True
function: Line Mechanic
email:
-
!record {model: 'res.partner', id: base.res_partner_address_9}:
name: Brian Williams
parent_id: base.res_partner_4
use_parent_address: True
function: Computer Technician
email:
-
!record {model: 'res.partner', id: base.res_partner_address_10}:
name: David Simpson
parent_id: base.res_partner_5
use_parent_address: True
function: Senior Consultant
email: david.s@tech.info
-
!record {model: 'res.partner', id: base.res_partner_address_11}:
name: John M. Brown
parent_id: base.res_partner_5
use_parent_address: True
function: Director
email: john.b@tech.info
-
!record {model: 'res.partner', id: base.res_partner_address_12}:
name: James Miller
parent_id: base.res_partner_6
use_parent_address: True
function: Electrical Supervisor
email:
-
!record {model: 'res.partner', id: base.res_partner_address_13}:
name: Charlie Bernard
parent_id: base.res_partner_7
use_parent_address: True
function: Senior Associate
email: charlie.bernard@wealthyandsons.com
-
!record {model: 'res.partner', id: base.res_partner_address_14}:
name: Jessica Dupont
parent_id: base.res_partner_7
use_parent_address: True
function: Analyst
email: jessica.dupont@wealthyandsons.com
-
!record {model: 'res.partner', id: base.res_partner_address_15}:
name: Phillipp Miller
parent_id: base.res_partner_8
use_parent_address: True
function: Creative Director
email:
-
!record {model: 'res.partner', id: base.res_partner_address_16}:
name: Ayaan Agarwal
parent_id: base.res_partner_9
use_parent_address: True
function: Director
email:
-
!record {model: 'res.partner', id: base.res_partner_address_17}:
name: Daniel Jackson
parent_id: base.res_partner_10
use_parent_address: True
function: Managing Partner
email: daniel@jackson.com
-
!record {model: 'res.partner', id: base.res_partner_address_18}:
name: William Thomas
parent_id: base.res_partner_10
use_parent_address: True
function: Senior Consultant
email: william@jackson.com
-
!record {model: 'res.partner', id: base.res_partner_address_19}:
name: Sergio Pérez
parent_id: base.res_partner_11
use_parent_address: True
function: Accountant
email:
-
!record {model: 'res.partner', id: base.res_partner_address_20}:
name: Laura Castro
parent_id: base.res_partner_11
use_parent_address: True
function: Goods Supervisor
email:
-
!record {model: 'res.partner', id: base.res_partner_address_21}:
name: Luc Maurer
parent_id: base.res_partner_12
use_parent_address: True
function: Director
email:
-
!record {model: 'res.partner', id: base.res_partner_address_22}:
name: Laith Jubair
parent_id: base.res_partner_13
use_parent_address: True
function: Director
email:
-
!record {model: 'res.partner', id: base.res_partner_address_23}:
name: Angel Cook
parent_id: base.res_partner_14
use_parent_address: True
function: General Manager
email: angel.cook@chamberworks.com
-
!record {model: 'res.partner', id: base.res_partner_address_24}:
name: Robert Anderson
parent_id: base.res_partner_14
use_parent_address: True
function: System Analyst
email: robert.anderson@chamberworks.com
-
!record {model: 'res.partner', id: base.res_partner_address_25}:
name: Jacob Taylor
parent_id: base.res_partner_15
use_parent_address: True
function: Order Clerk
email:
-
!record {model: 'res.partner', id: base.res_partner_address_26}:
name: Arthur Gomez
parent_id: base.res_partner_16
use_parent_address: True
function: Software Developer
email:
-
!record {model: 'res.partner', id: base.res_partner_address_27}:
name: Julia Rivero
parent_id: base.res_partner_16
use_parent_address: True
function: Technical Director
email:
-
!record {model: 'res.partner', id: base.res_partner_address_28}:
name: Benjamin Flores
parent_id: base.res_partner_17
use_parent_address: True
function: Business Executive
email: ben@nebula.ar
-
!record {model: 'res.partner', id: base.res_partner_address_29}:
name: George Wilson
parent_id: base.res_partner_18
use_parent_address: True
function: Chief Information Officer (CIO)
email:
-
!record {model: 'res.partner', id: base.res_partner_address_30}:
name: Lucas Jones
parent_id: base.res_partner_18
use_parent_address: True
function: Functional Consultant
email: jones@thinkbig.com
-
!record {model: 'res.partner', id: base.res_partner_address_31}:
name: Edward Foster
parent_id: base.res_partner_19
use_parent_address: True
function: Sales Representative
email: efoster@seagate.com
-
!record {model: 'res.partner', id: base.res_partner_address_32}:
name: Robin Smith
parent_id: base.res_partner_21
use_parent_address: True
function: Sales Manager
email:
-
!record {model: 'res.partner', id: base.res_partner_address_33}:
name: Morgan Rose
parent_id: base.res_partner_21
use_parent_address: True
function: Financial Manager
email:
-
!record {model: 'res.partner', id: base.res_partner_address_34}:
name: Kevin Clarke
parent_id: base.res_partner_21
use_parent_address: True
function: Knowledge Manager
email:
-
!record {model: 'res.partner', id: base.res_partner_address_35}:
name: Peter Mitchell
parent_id: base.res_partner_22
use_parent_address: True
function: Store Manager
email:
-
!record {model: 'res.partner', id: base.res_partner_main1}:
name: Mark Davis
customer: False
parent_id: base.main_partner
use_parent_address: True
function: Chief Executive Officer (CEO)
email: mark@yourcompany.com
-
!record {model: 'res.partner', id: base.res_partner_main2}:
name: Roger Scott
customer: False
parent_id: base.main_partner
use_parent_address: True
function: Chief Operations Officer (COO)
email: roger@yourcompany.com

View File

@ -119,8 +119,8 @@
<group>
<group>
<label for="type" attrs="{'invisible': [('parent_id','=', False)]}"/>
<div attrs="{'invisible': [('parent_id','=', False)]}">
<label for="type" attrs="{'invisible': [('parent_id','=', False)]}" invisible="1"/>
<div attrs="{'invisible': [('parent_id','=', False)]}" invisible="1" name="div_type">
<field class="oe_inline"
name="type"/>
<label for="use_parent_address" class="oe_edit_only"/>
@ -134,10 +134,10 @@
<field name="street2"/>
<div class="address_format">
<field name="city" placeholder="City" style="width: 40%%"/>
<field name="state_id" options='{"no_open": true}' placeholder="State" style="width: 24%%"/>
<field name="state_id" class="oe_no_button" placeholder="State" style="width: 24%%" options='{"no_open": true}'/>
<field name="zip" placeholder="ZIP" style="width: 34%%"/>
</div>
<field name="country_id" placeholder="Country" options='{"no_open": true}'/>
<field name="country_id" placeholder="Country" class="oe_no_button" options='{"no_open": true}'/>
</div>
<field name="website" widget="url" placeholder="e.g. www.openerp.com"/>
</group>
@ -228,7 +228,7 @@
<page string="Sales &amp; Purchases" attrs="{'invisible': [('customer', '=', False), ('supplier', '=', False)]}">
<group>
<group>
<field name="user_id" />
<field name="user_id"/>
<field name="company_id" groups="base.group_multi_company" widget="selection"/>
</group>
<group>

View File

@ -325,6 +325,8 @@ class users(osv.osv):
'context_lang': lambda self, cr, uid, context: context.get('lang', 'en_US'),
'context_tz': lambda self, cr, uid, context: context.get('tz', False),
'image': _get_default_image,
'image_small': _get_default_image,
'image_medium': _get_default_image,
'active' : True,
'menu_id': _get_menu,
'company_id': _get_company,

View File

@ -7,7 +7,7 @@
-->
<assert model="res.request" id="res_partner_asustek_request" string="Reference field request returns a browsable object">
<test expr="ref_doc1.name">ASUStek</test>
<test expr="ref_doc1.name">ASUSTeK</test>
</assert>
</data>

View File

@ -9,14 +9,14 @@
Test hierarchical search in M2M with child ID1
-
!python {model: res.partner }: |
ids = self.search(cr, uid, [('category_id', 'child_of','Components Supplier')])
ids = self.search(cr, uid, [('category_id', 'child_of','Customer')])
assert len(ids) >= 1, ids
-
Test hierarchical search in M2M with child ID2
-
!python {model: res.partner }: |
ids = self.search(cr, uid, [('category_id', 'child_of','Miscellaneous Suppliers')])
assert len(ids) >= 1, ids
ids = self.search(cr, uid, [('category_id', 'child_of','Manufacturer')])
assert len(ids) == 2, ids
-
"1.0 Setup test partner categories: parent root"
@ -464,8 +464,8 @@
!python {model: res.partner }: |
all_ids = self.search(cr, uid, [('name', '=like', 'A_e_or')])
assert len(all_ids) == 1, "Must match one partner (Axelor), got %r"%all_ids
all_ids = self.search(cr, uid, [('name', '=ilike', 'm_____')])
assert len(all_ids) == 1, "Must match *only* one partner (Maxtor), got %r"%all_ids
all_ids = self.search(cr, uid, [('name', '=ilike', 'v%')])
assert len(all_ids) >= 1, "Must match one partner (Vicking Direct), got %r"%all_ids
-
Check that =like/=ilike expressions (no wildcard variants of like/ilike) are working on translated field.
-
@ -512,7 +512,7 @@
Testing for Many2Many field with category supplier and active=False
-
!python {model: res.partner }: |
vals = {'category_id': [(6, 0, [ref("base.res_partner_category_8")])],
vals = {'category_id': [(6, 0, [ref("base.res_partner_category_1")])],
'name': 'OpenERP Test',
'active': False,
'child_ids': [(0, 0, {'name': 'address of OpenERP Test', 'country_id': ref("base.be")})]

View File

@ -24,11 +24,7 @@
"""
import openerp.modules.db
import openerp.modules.graph
import openerp.modules.loading
import openerp.modules.migration
import openerp.modules.module
from . import db, graph, loading, migration, module, registry
# TODO temporarily expose those things
from openerp.modules.module import \

View File

@ -22,6 +22,7 @@
""" Models registries.
"""
from contextlib import contextmanager
import logging
import threading
@ -43,12 +44,12 @@ class Registry(object):
"""
def __init__(self, db_name):
self.models = {} # model name/model instance mapping
self.models = {} # model name/model instance mapping
self._sql_error = {}
self._store_function = {}
self._init = True
self._init_parent = {}
# modules fully loaded (maintained during init phase by `loading` module)
self._init_modules = set()
@ -119,6 +120,17 @@ class Registry(object):
for model in self.models.itervalues():
model.clear_caches()
@contextmanager
def cursor(self, auto_commit=True):
cr = self.db.cursor()
try:
yield cr
if auto_commit:
cr.commit()
finally:
cr.close()
class RegistryManager(object):
""" Model registries manager.
@ -196,7 +208,6 @@ class RegistryManager(object):
del cls.registries[db_name]
openerp.cron.cancel(db_name)
@classmethod
def delete_all(cls):
"""Delete all the registries. """

View File

@ -2442,9 +2442,9 @@ class BaseModel(object):
context=context)
result_template = dict.fromkeys(aggregated_fields, False)
result_template.update({groupby + '_count':0})
result_template[groupby + '_count'] = 0
if groupby_list and len(groupby_list) > 1:
result_template.update(__context={'group_by': groupby_list[1:]})
result_template['__context'] = {'group_by': groupby_list[1:]}
# Merge the left_side (current results as dicts) with the right_side (all
# possible values as m2o pairs). Both lists are supposed to be using the
@ -2463,10 +2463,8 @@ class BaseModel(object):
grouped_value = right_side[0]
if not grouped_value in known_values:
line = dict(result_template)
line.update({
groupby: right_side,
'__domain': [(groupby,'=',grouped_value)] + domain,
})
line[groupby] = right_side
line['__domain'] = [(groupby,'=',grouped_value)] + domain
result.append(line)
known_values[grouped_value] = line
while read_group_result or all_groups:
@ -4207,7 +4205,7 @@ class BaseModel(object):
cr.execute("SELECT nextval('"+self._sequence+"')")
except:
raise except_orm(_('UserError'),
_('You cannot perform this operation. New Record Creation is not allowed for this object as this object is for reporting purpose.'))
_('You cannot perform this operation. New Record Creation is not allowed for this object as this object is for reporting purpose.'))
id_new = cr.fetchone()[0]
for table in tocreate:

View File

@ -30,9 +30,9 @@ RELEASE_LEVELS_DISPLAY = {ALPHA: ALPHA,
# properly comparable using normal operarors, for example:
# (6,1,0,'beta',0) < (6,1,0,'candidate',1) < (6,1,0,'candidate',2)
# (6,1,0,'candidate',2) < (6,1,0,'final',0) < (6,1,2,'final',0)
version_info = (6,2,0,ALPHA,0)
version = '.'.join(map(str,version_info[:2])) + RELEASE_LEVELS_DISPLAY[version_info[3]] + str(version_info[4] or '')
major_version = '.'.join(map(str,version_info[:2]))
version_info = (7, 0, 0, ALPHA, 0)
version = '.'.join(map(str, version_info[:2])) + RELEASE_LEVELS_DISPLAY[version_info[3]] + str(version_info[4] or '')
serie = major_version = '.'.join(map(str, version_info[:2]))
description = 'OpenERP Server'
long_desc = '''OpenERP is a complete ERP and CRM. The main features are accounting (analytic

View File

@ -8,18 +8,16 @@ Tests can be explicitely added to the `fast_suite` or `checks` lists or not.
See the :ref:`test-framework` section in the :ref:`features` list.
"""
import test_expression
import test_ir_sequence
import test_orm
import test_uninstall
from . import test_expression, test_ir_sequence, test_orm,\
test_uninstall
fast_suite = [
test_ir_sequence,
]
]
checks = [
test_expression,
test_orm,
]
]
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1 @@
import models

View File

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
{
'name': 'test-import-export',
'version': '0.1',
'category': 'Tests',
'description': """A module to test import/export.""",
'author': 'OpenERP SA',
'maintainer': 'OpenERP SA',
'website': 'http://www.openerp.com',
'depends': ['base'],
'data': [],
'installable': True,
'auto_install': False,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
from openerp.osv import orm, fields
def selection_fn(obj, cr, uid, context=None):
return list(enumerate(["Corge", "Grault", "Wheee", "Moog"]))
def function_fn(model, cr, uid, ids, field_name, arg, context):
return dict((id, 3) for id in ids)
def function_fn_write(model, cr, uid, id, field_name, field_value, fnct_inv_arg, context):
""" just so CreatorCase.export can be used
"""
pass
models = [
('boolean', fields.boolean()),
('integer', fields.integer()),
('float', fields.float()),
('decimal', fields.float(digits=(16, 3))),
('string.bounded', fields.char('unknown', size=16)),
('string', fields.char('unknown', size=None)),
('date', fields.date()),
('datetime', fields.datetime()),
('text', fields.text()),
('selection', fields.selection([(1, "Foo"), (2, "Bar"), (3, "Qux")])),
('selection.function', fields.selection(selection_fn)),
# just relate to an integer
('many2one', fields.many2one('export.integer')),
('one2many', fields.one2many('export.one2many.child', 'parent_id')),
('many2many', fields.many2many('export.many2many.other')),
('function', fields.function(function_fn, fnct_inv=function_fn_write, type="integer")),
# related: specialization of fields.function, should work the same way
# TODO: reference
]
for name, field in models:
attrs = {
'_name': 'export.%s' % name,
'_columns': {
'const': fields.integer(),
'value': field
},
'_defaults': {'const': 4},
'name_get': (lambda self, cr, uid, ids, context=None:
[(record.id, "%s:%s" % (self._name, record.value))
for record in self.browse(cr, uid, ids, context=context)]),
'name_search': (lambda self, cr, uid, name, operator, context=None:
self.name_get(cr, uid,
self.search(cr, uid, [['value', operator, int(name.split(':')[1])]])
, context=context)
if isinstance(name, basestring) and name.split(':')[0] == self._name
else [])
}
NewModel = type(
'Export%s' % ''.join(section.capitalize() for section in name.split('.')),
(orm.Model,),
attrs)
class One2ManyChild(orm.Model):
_name = 'export.one2many.child'
# FIXME: orm.py:1161, fix to name_get on m2o field
_rec_name = 'value'
_columns = {
'parent_id': fields.many2one('export.one2many'),
'str': fields.char('unknown', size=None),
'value': fields.integer()
}
def name_get(self, cr, uid, ids, context=None):
return [(record.id, "%s:%s" % (self._name, record.value))
for record in self.browse(cr, uid, ids, context=context)]
class One2ManyMultiple(orm.Model):
_name = 'export.one2many.multiple'
_columns = {
'const': fields.integer(),
'child1': fields.one2many('export.one2many.child.1', 'parent_id'),
'child2': fields.one2many('export.one2many.child.2', 'parent_id'),
}
_defaults = { 'const': 36 }
class One2ManyChildMultiple(orm.Model):
_name = 'export.one2many.multiple.child'
# FIXME: orm.py:1161, fix to name_get on m2o field
_rec_name = 'value'
_columns = {
'parent_id': fields.many2one('export.one2many.multiple'),
'str': fields.char('unknown', size=None),
'value': fields.integer()
}
def name_get(self, cr, uid, ids, context=None):
return [(record.id, "%s:%s" % (self._name, record.value))
for record in self.browse(cr, uid, ids, context=context)]
class One2ManyChild1(orm.Model):
_name = 'export.one2many.child.1'
_inherit = 'export.one2many.multiple.child'
class One2ManyChild2(orm.Model):
_name = 'export.one2many.child.2'
_inherit = 'export.one2many.multiple.child'
class Many2ManyChild(orm.Model):
_name = 'export.many2many.other'
# FIXME: orm.py:1161, fix to name_get on m2o field
_rec_name = 'value'
_columns = {
'str': fields.char('unknown', size=None),
'value': fields.integer()
}
def name_get(self, cr, uid, ids, context=None):
return [(record.id, "%s:%s" % (self._name, record.value))
for record in self.browse(cr, uid, ids, context=context)]
def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100):
return (self.name_get(cr, user,
self.search(cr, user, [['value', operator, int(name.split(':')[1])]])
, context=context)
if isinstance(name, basestring) and name.split(':')[0] == self._name
else [])

View File

@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
from . import test_export, test_import
fast_suite = [
]
checks = [
test_export,
test_import,
]
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,589 @@
# -*- coding: utf-8 -*-
import itertools
import openerp.modules.registry
import openerp
from openerp.tests import common
class CreatorCase(common.TransactionCase):
model_name = False
def __init__(self, *args, **kwargs):
super(CreatorCase, self).__init__(*args, **kwargs)
self.model = None
def setUp(self):
super(CreatorCase, self).setUp()
self.model = self.registry(self.model_name)
def make(self, value):
id = self.model.create(self.cr, openerp.SUPERUSER_ID, {'value': value})
return self.model.browse(self.cr, openerp.SUPERUSER_ID, [id])[0]
def export(self, value, fields=('value',), context=None):
record = self.make(value)
return self.model._BaseModel__export_row(
self.cr, openerp.SUPERUSER_ID, record,
[f.split('/') for f in fields],
context=context)
class test_boolean_field(CreatorCase):
model_name = 'export.boolean'
def test_true(self):
self.assertEqual(
self.export(True),
[[u'True']])
def test_false(self):
""" ``False`` value to boolean fields is unique in being exported as a
(unicode) string, not a boolean
"""
self.assertEqual(
self.export(False),
[[u'False']])
class test_integer_field(CreatorCase):
model_name = 'export.integer'
def test_empty(self):
self.assertEqual(self.model.search(self.cr, openerp.SUPERUSER_ID, []), [],
"Test model should have no records")
def test_0(self):
self.assertEqual(
self.export(0),
[[False]])
def test_basic_value(self):
self.assertEqual(
self.export(42),
[[u'42']])
def test_negative(self):
self.assertEqual(
self.export(-32),
[[u'-32']])
def test_huge(self):
self.assertEqual(
self.export(2**31-1),
[[unicode(2**31-1)]])
class test_float_field(CreatorCase):
model_name = 'export.float'
def test_0(self):
self.assertEqual(
self.export(0.0),
[[False]])
def test_epsilon(self):
self.assertEqual(
self.export(0.000000000027),
[[u'2.7e-11']])
def test_negative(self):
self.assertEqual(
self.export(-2.42),
[[u'-2.42']])
def test_positive(self):
self.assertEqual(
self.export(47.36),
[[u'47.36']])
def test_big(self):
self.assertEqual(
self.export(87654321.4678),
[[u'87654321.4678']])
class test_decimal_field(CreatorCase):
model_name = 'export.decimal'
def test_0(self):
self.assertEqual(
self.export(0.0),
[[False]])
def test_epsilon(self):
""" epsilon gets sliced to 0 due to precision
"""
self.assertEqual(
self.export(0.000000000027),
[[False]])
def test_negative(self):
self.assertEqual(
self.export(-2.42),
[[u'-2.42']])
def test_positive(self):
self.assertEqual(
self.export(47.36),
[[u'47.36']])
def test_big(self):
self.assertEqual(
self.export(87654321.4678), [[u'87654321.468']])
class test_string_field(CreatorCase):
model_name = 'export.string.bounded'
def test_empty(self):
self.assertEqual(
self.export(""),
[[False]])
def test_within_bounds(self):
self.assertEqual(
self.export("foobar"),
[[u"foobar"]])
def test_out_of_bounds(self):
self.assertEqual(
self.export("C for Sinking, "
"Java for Drinking, "
"Smalltalk for Thinking. "
"...and Power to the Penguin!"),
[[u"C for Sinking, J"]])
class test_unbound_string_field(CreatorCase):
model_name = 'export.string'
def test_empty(self):
self.assertEqual(
self.export(""),
[[False]])
def test_small(self):
self.assertEqual(
self.export("foobar"),
[[u"foobar"]])
def test_big(self):
self.assertEqual(
self.export("We flew down weekly to meet with IBM, but they "
"thought the way to measure software was the amount "
"of code we wrote, when really the better the "
"software, the fewer lines of code."),
[[u"We flew down weekly to meet with IBM, but they thought the "
u"way to measure software was the amount of code we wrote, "
u"when really the better the software, the fewer lines of "
u"code."]])
class test_text(CreatorCase):
model_name = 'export.text'
def test_empty(self):
self.assertEqual(
self.export(""),
[[False]])
def test_small(self):
self.assertEqual(
self.export("foobar"),
[[u"foobar"]])
def test_big(self):
self.assertEqual(
self.export("So, `bind' is `let' and monadic programming is"
" equivalent to programming in the A-normal form. That"
" is indeed all there is to monads"),
[[u"So, `bind' is `let' and monadic programming is equivalent to"
u" programming in the A-normal form. That is indeed all there"
u" is to monads"]])
class test_date(CreatorCase):
model_name = 'export.date'
def test_empty(self):
self.assertEqual(
self.export(False),
[[False]])
def test_basic(self):
self.assertEqual(
self.export('2011-11-07'),
[[u'2011-11-07']])
class test_datetime(CreatorCase):
model_name = 'export.datetime'
def test_empty(self):
self.assertEqual(
self.export(False),
[[False]])
def test_basic(self):
self.assertEqual(
self.export('2011-11-07 21:05:48'),
[[u'2011-11-07 21:05:48']])
def test_tz(self):
""" Export ignores the timezone and always exports to UTC
.. note:: on the other hand, export uses user lang for name_get
"""
# NOTE: ignores user timezone, always exports to UTC
self.assertEqual(
self.export('2011-11-07 21:05:48', context={'tz': 'Pacific/Norfolk'}),
[[u'2011-11-07 21:05:48']])
class test_selection(CreatorCase):
model_name = 'export.selection'
translations_fr = [
("Qux", "toto"),
("Bar", "titi"),
("Foo", "tete"),
]
def test_empty(self):
self.assertEqual(
self.export(False),
[[False]])
def test_value(self):
""" selections export the *label* for their value
"""
self.assertEqual(
self.export(2),
[[u"Bar"]])
def test_localized_export(self):
self.registry('res.lang').create(self.cr, openerp.SUPERUSER_ID, {
'name': u'Français',
'code': 'fr_FR',
'translatable': True,
'date_format': '%d.%m.%Y',
'decimal_point': ',',
'thousand_sep': ' ',
})
Translations = self.registry('ir.translation')
for source, value in self.translations_fr:
Translations.create(self.cr, openerp.SUPERUSER_ID, {
'name': 'export.selection,value',
'lang': 'fr_FR',
'type': 'selection',
'src': source,
'value': value
})
self.assertEqual(
self.export(2, context={'lang': 'fr_FR'}),
[[u'Bar']])
class test_selection_function(CreatorCase):
model_name = 'export.selection.function'
def test_empty(self):
self.assertEqual(
self.export(False),
[[False]])
def test_value(self):
# FIXME: selection functions export the *value* itself
self.assertEqual(
self.export(1),
[[u'1']])
self.assertEqual(
self.export(3),
[[u'3']])
# fucking hell
self.assertEqual(
self.export(0),
[[False]])
class test_m2o(CreatorCase):
model_name = 'export.many2one'
def test_empty(self):
self.assertEqual(
self.export(False),
[[False]])
def test_basic(self):
""" Exported value is the name_get of the related object
"""
integer_id = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 42})
name = dict(self.registry('export.integer').name_get(
self.cr, openerp.SUPERUSER_ID,[integer_id]))[integer_id]
self.assertEqual(
self.export(integer_id),
[[name]])
def test_path(self):
""" Can recursively export fields of m2o via path
"""
integer_id = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 42})
self.assertEqual(
self.export(integer_id, fields=['value/.id', 'value/value']),
[[unicode(integer_id), u'42']])
def test_external_id(self):
integer_id = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 42})
# __export__.$class.$id
external_id = u'__export__.export_many2one_%d' % integer_id
self.assertEqual(
self.export(integer_id, fields=['value/id']),
[[external_id]])
class test_o2m(CreatorCase):
model_name = 'export.one2many'
commands = [
(0, False, {'value': 4, 'str': 'record1'}),
(0, False, {'value': 42, 'str': 'record2'}),
(0, False, {'value': 36, 'str': 'record3'}),
(0, False, {'value': 4, 'str': 'record4'}),
(0, False, {'value': 13, 'str': 'record5'}),
]
names = [
u'export.one2many.child:%d' % d['value']
for c, _, d in commands
]
def test_empty(self):
self.assertEqual(
self.export(False),
[[False]])
def test_single(self):
self.assertEqual(
self.export([(0, False, {'value': 42})]),
# name_get result
[[u'export.one2many.child:42']])
def test_single_subfield(self):
self.assertEqual(
self.export([(0, False, {'value': 42})],
fields=['value', 'value/value']),
[[u'export.one2many.child:42', u'42']])
def test_integrate_one_in_parent(self):
self.assertEqual(
self.export([(0, False, {'value': 42})],
fields=['const', 'value/value']),
[[u'4', u'42']])
def test_multiple_records(self):
self.assertEqual(
self.export(self.commands, fields=['const', 'value/value']),
[
[u'4', u'4'],
[u'', u'42'],
[u'', u'36'],
[u'', u'4'],
[u'', u'13'],
])
def test_multiple_records_name(self):
self.assertEqual(
self.export(self.commands, fields=['const', 'value']),
[[
u'4', u','.join(self.names)
]])
def test_multiple_records_id(self):
export = self.export(self.commands, fields=['const', 'value/.id'])
O2M_c = self.registry('export.one2many.child')
ids = O2M_c.browse(self.cr, openerp.SUPERUSER_ID,
O2M_c.search(self.cr, openerp.SUPERUSER_ID, []))
self.assertEqual(
export,
[
['4', str(ids[0].id)],
['', str(ids[1].id)],
['', str(ids[2].id)],
['', str(ids[3].id)],
['', str(ids[4].id)],
])
def test_multiple_records_with_name_before(self):
self.assertEqual(
self.export(self.commands, fields=['const', 'value', 'value/value']),
[[ # exports sub-fields of very first o2m
u'4', u','.join(self.names), u'4'
]])
def test_multiple_records_with_name_after(self):
self.assertEqual(
self.export(self.commands, fields=['const', 'value/value', 'value']),
[ # completely ignores name_get request
[u'4', u'4', ''],
['', u'42', ''],
['', u'36', ''],
['', u'4', ''],
['', u'13', ''],
])
def test_multiple_subfields_neighbour(self):
self.assertEqual(
self.export(self.commands, fields=['const', 'value/str','value/value']),
[
[u'4', u'record1', u'4'],
['', u'record2', u'42'],
['', u'record3', u'36'],
['', u'record4', u'4'],
['', u'record5', u'13'],
])
def test_multiple_subfields_separated(self):
self.assertEqual(
self.export(self.commands, fields=['value/str', 'const', 'value/value']),
[
[u'record1', u'4', u'4'],
[u'record2', '', u'42'],
[u'record3', '', u'36'],
[u'record4', '', u'4'],
[u'record5', '', u'13'],
])
class test_o2m_multiple(CreatorCase):
model_name = 'export.one2many.multiple'
def make(self, value=None, **values):
if value is not None: values['value'] = value
id = self.model.create(self.cr, openerp.SUPERUSER_ID, values)
return self.model.browse(self.cr, openerp.SUPERUSER_ID, [id])[0]
def export(self, value=None, fields=('child1', 'child2',), context=None, **values):
record = self.make(value, **values)
return self.model._BaseModel__export_row(
self.cr, openerp.SUPERUSER_ID, record,
[f.split('/') for f in fields],
context=context)
def test_empty(self):
self.assertEqual(
self.export(child1=False, child2=False),
[[False, False]])
def test_single_per_side(self):
self.assertEqual(
self.export(child1=False, child2=[(0, False, {'value': 42})]),
[[False, u'export.one2many.child.2:42']])
self.assertEqual(
self.export(child1=[(0, False, {'value': 43})], child2=False),
[[u'export.one2many.child.1:43', False]])
self.assertEqual(
self.export(child1=[(0, False, {'value': 43})],
child2=[(0, False, {'value': 42})]),
[[u'export.one2many.child.1:43', u'export.one2many.child.2:42']])
def test_single_integrate_subfield(self):
fields = ['const', 'child1/value', 'child2/value']
self.assertEqual(
self.export(child1=False, child2=[(0, False, {'value': 42})],
fields=fields),
[[u'36', False, u'42']])
self.assertEqual(
self.export(child1=[(0, False, {'value': 43})], child2=False,
fields=fields),
[[u'36', u'43', False]])
self.assertEqual(
self.export(child1=[(0, False, {'value': 43})],
child2=[(0, False, {'value': 42})],
fields=fields),
[[u'36', u'43', u'42']])
def test_multiple(self):
""" With two "concurrent" o2ms, exports the first line combined, then
exports the rows for the first o2m, then the rows for the second o2m.
"""
fields = ['const', 'child1/value', 'child2/value']
child1 = [(0, False, {'value': v, 'str': 'record%.02d' % index})
for index, v in zip(itertools.count(), [4, 42, 36, 4, 13])]
child2 = [(0, False, {'value': v, 'str': 'record%.02d' % index})
for index, v in zip(itertools.count(10), [8, 12, 8, 55, 33, 13])]
self.assertEqual(
self.export(child1=child1, child2=False, fields=fields),
[
[u'36', u'4', False],
['', u'42', ''],
['', u'36', ''],
['', u'4', ''],
['', u'13', ''],
])
self.assertEqual(
self.export(child1=False, child2=child2, fields=fields),
[
[u'36', False, u'8'],
['', '', u'12'],
['', '', u'8'],
['', '', u'55'],
['', '', u'33'],
['', '', u'13'],
])
self.assertEqual(
self.export(child1=child1, child2=child2, fields=fields),
[
[u'36', u'4', u'8'],
['', u'42', ''],
['', u'36', ''],
['', u'4', ''],
['', u'13', ''],
['', '', u'12'],
['', '', u'8'],
['', '', u'55'],
['', '', u'33'],
['', '', u'13'],
])
class test_m2m(CreatorCase):
model_name = 'export.many2many'
commands = [
(0, False, {'value': 4, 'str': 'record000'}),
(0, False, {'value': 42, 'str': 'record001'}),
(0, False, {'value': 36, 'str': 'record010'}),
(0, False, {'value': 4, 'str': 'record011'}),
(0, False, {'value': 13, 'str': 'record100'}),
]
names = [
u'export.many2many.other:%d' % d['value']
for c, _, d in commands
]
def test_empty(self):
self.assertEqual(
self.export(False),
[[False]])
def test_single(self):
self.assertEqual(
self.export([(0, False, {'value': 42})]),
# name_get result
[[u'export.many2many.other:42']])
def test_single_subfield(self):
self.assertEqual(
self.export([(0, False, {'value': 42})],
fields=['value', 'value/value']),
[[u'export.many2many.other:42', u'42']])
def test_integrate_one_in_parent(self):
self.assertEqual(
self.export([(0, False, {'value': 42})],
fields=['const', 'value/value']),
[[u'4', u'42']])
def test_multiple_records(self):
self.assertEqual(
self.export(self.commands, fields=['const', 'value/value']),
[
[u'4', u'4'],
[u'', u'42'],
[u'', u'36'],
[u'', u'4'],
[u'', u'13'],
])
def test_multiple_records_name(self):
self.assertEqual(
self.export(self.commands, fields=['const', 'value']),
[[ # FIXME: hardcoded comma, import uses config.csv_internal_sep
# resolution: remove configurable csv_internal_sep
u'4', u','.join(self.names)
]])
# essentially same as o2m, so boring
class test_function(CreatorCase):
model_name = 'export.function'
def test_value(self):
""" Exports value normally returned by accessing the function field
"""
self.assertEqual(
self.export(42),
[[u'3']])

View File

@ -0,0 +1,906 @@
# -*- coding: utf-8 -*-
import openerp.modules.registry
import openerp
from openerp.tests import common
def ok(n):
""" Successful import of ``n`` records
:param int n: number of records which should have been imported
"""
return n, 0, 0, 0
def error(row, message, record=None, **kwargs):
""" Failed import of the record ``record`` at line ``row``, with the error
message ``message``
:param str message:
:param dict record:
"""
return (
-1, dict(record or {}, **kwargs),
"Line %d : %s" % (row, message),
'')
def values(seq, field='value'):
return [item[field] for item in seq]
class ImporterCase(common.TransactionCase):
model_name = False
def __init__(self, *args, **kwargs):
super(ImporterCase, self).__init__(*args, **kwargs)
self.model = None
def setUp(self):
super(ImporterCase, self).setUp()
self.model = self.registry(self.model_name)
def import_(self, fields, rows, context=None):
return self.model.import_data(
self.cr, openerp.SUPERUSER_ID, fields, rows, context=context)
def read(self, fields=('value',), domain=(), context=None):
return self.model.read(
self.cr, openerp.SUPERUSER_ID,
self.model.search(self.cr, openerp.SUPERUSER_ID, domain, context=context),
fields=fields, context=context)
def browse(self, domain=(), context=None):
return self.model.browse(
self.cr, openerp.SUPERUSER_ID,
self.model.search(self.cr, openerp.SUPERUSER_ID, domain, context=context),
context=context)
def xid(self, record):
ModelData = self.registry('ir.model.data')
ids = ModelData.search(
self.cr, openerp.SUPERUSER_ID,
[('model', '=', record._table_name), ('res_id', '=', record.id)])
if ids:
d = ModelData.read(
self.cr, openerp.SUPERUSER_ID, ids, ['name', 'module'])[0]
if d['module']:
return '%s.%s' % (d['module'], d['name'])
return d['name']
name = dict(record.name_get())[record.id]
# fix dotted name_get results, otherwise xid lookups blow up
name = name.replace('.', '-')
ModelData.create(self.cr, openerp.SUPERUSER_ID, {
'name': name,
'model': record._table_name,
'res_id': record.id,
'module': '__test__'
})
return '__test__.' + name
class test_ids_stuff(ImporterCase):
model_name = 'export.integer'
def test_create_with_id(self):
self.assertRaises(
Exception, # dammit
self.import_, ['.id', 'value'], [['42', '36']])
def test_create_with_xid(self):
self.assertEqual(
self.import_(['id', 'value'], [['somexmlid', '42']]),
ok(1))
self.assertEqual(
'somexmlid',
self.xid(self.browse()[0]))
def test_update_with_id(self):
id = self.model.create(self.cr, openerp.SUPERUSER_ID, {'value': 36})
self.assertEqual(
36,
self.model.browse(self.cr, openerp.SUPERUSER_ID, id).value)
self.assertEqual(
self.import_(['.id', 'value'], [[str(id), '42']]),
ok(1))
self.assertEqual(
[42], # updated value to imported
values(self.read()))
def test_update_with_xid(self):
self.import_(['id', 'value'], [['somexmlid', '36']])
self.assertEqual([36], values(self.read()))
self.import_(['id', 'value'], [['somexmlid', '1234567']])
self.assertEqual([1234567], values(self.read()))
class test_boolean_field(ImporterCase):
model_name = 'export.boolean'
def test_empty(self):
self.assertEqual(
self.import_(['value'], []),
ok(0))
def test_exported(self):
self.assertEqual(
self.import_(['value'], [
['False'],
['True'],
]),
ok(2))
records = self.read()
self.assertEqual([
False,
True,
], values(records))
def test_falses(self):
self.assertEqual(
self.import_(['value'], [
[u'0'],
[u'off'],
[u'false'],
[u'FALSE'],
[u'OFF'],
[u''],
]),
ok(6))
self.assertEqual([
False,
False,
False,
False,
False,
False,
],
values(self.read()))
def test_trues(self):
self.assertEqual(
self.import_(['value'], [
['no'],
['None'],
['nil'],
['()'],
['f'],
['#f'],
# Problem: OpenOffice (and probably excel) output localized booleans
['VRAI'],
]),
ok(7))
self.assertEqual(
[True] * 7,
values(self.read()))
class test_integer_field(ImporterCase):
model_name = 'export.integer'
def test_none(self):
self.assertEqual(
self.import_(['value'], []),
ok(0))
def test_empty(self):
self.assertEqual(
self.import_(['value'], [['']]),
ok(1))
self.assertEqual(
[False],
values(self.read()))
def test_zero(self):
self.assertEqual(
self.import_(['value'], [['0']]),
ok(1))
self.assertEqual(
self.import_(['value'], [['-0']]),
ok(1))
self.assertEqual([False, False], values(self.read()))
def test_positives(self):
self.assertEqual(
self.import_(['value'], [
['1'],
['42'],
[str(2**31-1)],
['12345678']
]),
ok(4))
self.assertEqual([
1, 42, 2**31-1, 12345678
], values(self.read()))
def test_negatives(self):
self.assertEqual(
self.import_(['value'], [
['-1'],
['-42'],
[str(-(2**31 - 1))],
[str(-(2**31))],
['-12345678']
]),
ok(5))
self.assertEqual([
-1, -42, -(2**31 - 1), -(2**31), -12345678
], values(self.read()))
def test_out_of_range(self):
self.assertEqual(
self.import_(['value'], [[str(2**31)]]),
error(1, "integer out of range\n", value=2**31))
# auto-rollbacks if error is in process_liness, but not during
# ir.model.data write. Can differentiate because former ends lines
# error lines with "!"
self.cr.rollback()
self.assertEqual(
self.import_(['value'], [[str(-2**32)]]),
error(1, "integer out of range\n", value=-2**32))
def test_nonsense(self):
# FIXME: shit error reporting, exceptions half the time, messages the other half
self.assertRaises(
ValueError,
self.import_, ['value'], [['zorglub']])
class test_float_field(ImporterCase):
model_name = 'export.float'
def test_none(self):
self.assertEqual(
self.import_(['value'], []),
ok(0))
def test_empty(self):
self.assertEqual(
self.import_(['value'], [['']]),
ok(1))
self.assertEqual(
[False],
values(self.read()))
def test_zero(self):
self.assertEqual(
self.import_(['value'], [['0']]),
ok(1))
self.assertEqual(
self.import_(['value'], [['-0']]),
ok(1))
self.assertEqual([False, False], values(self.read()))
def test_positives(self):
self.assertEqual(
self.import_(['value'], [
['1'],
['42'],
[str(2**31-1)],
['12345678'],
[str(2**33)],
['0.000001'],
]),
ok(6))
self.assertEqual([
1, 42, 2**31-1, 12345678, 2.0**33, .000001
], values(self.read()))
def test_negatives(self):
self.assertEqual(
self.import_(['value'], [
['-1'],
['-42'],
[str(-2**31 + 1)],
[str(-2**31)],
['-12345678'],
[str(-2**33)],
['-0.000001'],
]),
ok(7))
self.assertEqual([
-1, -42, -(2**31 - 1), -(2**31), -12345678, -2.0**33, -.000001
], values(self.read()))
def test_nonsense(self):
self.assertRaises(
ValueError,
self.import_, ['value'], [['foobar']])
class test_string_field(ImporterCase):
model_name = 'export.string.bounded'
def test_empty(self):
self.assertEqual(
self.import_(['value'], [['']]),
ok(1))
self.assertEqual([False], values(self.read()))
def test_imported(self):
self.assertEqual(
self.import_(['value'], [
[u'foobar'],
[u'foobarbaz'],
[u'Með suð í eyrum við spilum endalaust'],
[u"People 'get' types. They use them all the time. Telling "
u"someone he can't pound a nail with a banana doesn't much "
u"surprise him."]
]),
ok(4))
self.assertEqual([
u"foobar",
u"foobarbaz",
u"Með suð í eyrum ",
u"People 'get' typ",
], values(self.read()))
class test_unbound_string_field(ImporterCase):
model_name = 'export.string'
def test_imported(self):
self.assertEqual(
self.import_(['value'], [
[u'í dag viðrar vel til loftárása'],
# ackbar.jpg
[u"If they ask you about fun, you tell them fun is a filthy"
u" parasite"]
]),
ok(2))
self.assertEqual([
u"í dag viðrar vel til loftárása",
u"If they ask you about fun, you tell them fun is a filthy parasite"
], values(self.read()))
class test_text(ImporterCase):
model_name = 'export.text'
def test_empty(self):
self.assertEqual(
self.import_(['value'], [['']]),
ok(1))
self.assertEqual([False], values(self.read()))
def test_imported(self):
s = (u"Breiðskífa er notað um útgefna hljómplötu sem inniheldur "
u"stúdíóupptökur frá einum flytjanda. Breiðskífur eru oftast "
u"milli 25-80 mínútur og er lengd þeirra oft miðuð við 33⅓ "
u"snúninga 12 tommu vínylplötur (sem geta verið allt að 30 mín "
u"hvor hlið).\n\nBreiðskífur eru stundum tvöfaldar og eru þær þá"
u" gefnar út á tveimur geisladiskum eða tveimur vínylplötum.")
self.assertEqual(
self.import_(['value'], [[s]]),
ok(1))
self.assertEqual([s], values(self.read()))
class test_selection(ImporterCase):
model_name = 'export.selection'
translations_fr = [
("Qux", "toto"),
("Bar", "titi"),
("Foo", "tete"),
]
def test_imported(self):
self.assertEqual(
self.import_(['value'], [
['Qux'],
['Bar'],
['Foo'],
['2'],
]),
ok(4))
self.assertEqual([3, 2, 1, 2], values(self.read()))
def test_imported_translated(self):
self.registry('res.lang').create(self.cr, openerp.SUPERUSER_ID, {
'name': u'Français',
'code': 'fr_FR',
'translatable': True,
'date_format': '%d.%m.%Y',
'decimal_point': ',',
'thousand_sep': ' ',
})
Translations = self.registry('ir.translation')
for source, value in self.translations_fr:
Translations.create(self.cr, openerp.SUPERUSER_ID, {
'name': 'export.selection,value',
'lang': 'fr_FR',
'type': 'selection',
'src': source,
'value': value
})
# FIXME: can't import an exported selection field label if lang != en_US
# (see test_export.test_selection.test_localized_export)
self.assertEqual(
self.import_(['value'], [
['toto'],
['tete'],
['titi'],
], context={'lang': 'fr_FR'}),
ok(3))
self.assertEqual([3, 1, 2], values(self.read()))
self.assertEqual(
self.import_(['value'], [['Foo']], context={'lang': 'fr_FR'}),
error(1, "Key/value 'Foo' not found in selection field 'value'",
value=False))
def test_invalid(self):
self.assertEqual(
self.import_(['value'], [['Baz']]),
error(1, "Key/value 'Baz' not found in selection field 'value'",
# what the fuck?
value=False))
self.cr.rollback()
self.assertEqual(
self.import_(['value'], [[42]]),
error(1, "Key/value '42' not found in selection field 'value'",
value=False))
class test_selection_function(ImporterCase):
model_name = 'export.selection.function'
translations_fr = [
("Corge", "toto"),
("Grault", "titi"),
("Whee", "tete"),
("Moog", "tutu"),
]
def test_imported(self):
""" import uses fields_get, so translates import label (may or may not
be good news) *and* serializes the selection function to reverse it:
import does not actually know that the selection field uses a function
"""
# NOTE: conflict between a value and a label => ?
self.assertEqual(
self.import_(['value'], [
['3'],
["Grault"],
]),
ok(2))
self.assertEqual(
['3', '1'],
values(self.read()))
def test_translated(self):
""" Expects output of selection function returns translated labels
"""
self.registry('res.lang').create(self.cr, openerp.SUPERUSER_ID, {
'name': u'Français',
'code': 'fr_FR',
'translatable': True,
'date_format': '%d.%m.%Y',
'decimal_point': ',',
'thousand_sep': ' ',
})
Translations = self.registry('ir.translation')
for source, value in self.translations_fr:
Translations.create(self.cr, openerp.SUPERUSER_ID, {
'name': 'export.selection,value',
'lang': 'fr_FR',
'type': 'selection',
'src': source,
'value': value
})
self.assertEqual(
self.import_(['value'], [
['toto'],
['tete'],
], context={'lang': 'fr_FR'}),
error(1, "Key/value 'toto' not found in selection field 'value'",
value=False))
self.assertEqual(
self.import_(['value'], [['Wheee']], context={'lang': 'fr_FR'}),
ok(1))
class test_m2o(ImporterCase):
model_name = 'export.many2one'
def test_by_name(self):
# create integer objects
integer_id1 = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 42})
integer_id2 = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 36})
# get its name
name1 = dict(self.registry('export.integer').name_get(
self.cr, openerp.SUPERUSER_ID,[integer_id1]))[integer_id1]
name2 = dict(self.registry('export.integer').name_get(
self.cr, openerp.SUPERUSER_ID,[integer_id2]))[integer_id2]
self.assertEqual(
self.import_(['value'], [
# import by name_get
[name1],
[name1],
[name2],
]),
ok(3))
# correct ids assigned to corresponding records
self.assertEqual([
(integer_id1, name1),
(integer_id1, name1),
(integer_id2, name2),],
values(self.read()))
def test_by_xid(self):
ExportInteger = self.registry('export.integer')
integer_id = ExportInteger.create(
self.cr, openerp.SUPERUSER_ID, {'value': 42})
xid = self.xid(ExportInteger.browse(
self.cr, openerp.SUPERUSER_ID, [integer_id])[0])
self.assertEqual(
self.import_(['value/id'], [[xid]]),
ok(1))
b = self.browse()
self.assertEqual(42, b[0].value.value)
def test_by_id(self):
integer_id = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 42})
self.assertEqual(
self.import_(['value/.id'], [[integer_id]]),
ok(1))
b = self.browse()
self.assertEqual(42, b[0].value.value)
def test_by_names(self):
integer_id1 = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 42})
integer_id2 = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 42})
name1 = dict(self.registry('export.integer').name_get(
self.cr, openerp.SUPERUSER_ID,[integer_id1]))[integer_id1]
name2 = dict(self.registry('export.integer').name_get(
self.cr, openerp.SUPERUSER_ID,[integer_id2]))[integer_id2]
# names should be the same
self.assertEqual(name1, name2)
self.assertEqual(
self.import_(['value'], [[name2]]),
ok(1))
# FIXME: is it really normal import does not care for name_search collisions?
self.assertEqual([
(integer_id1, name1)
], values(self.read()))
def test_fail_by_implicit_id(self):
""" Can't implicitly import records by id
"""
# create integer objects
integer_id1 = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 42})
integer_id2 = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 36})
self.assertRaises(
ValueError, # Because name_search all the things. Fallback schmallback
self.import_, ['value'], [
# import by id, without specifying it
[integer_id1],
[integer_id2],
[integer_id1],
])
def test_sub_field(self):
""" Does not implicitly create the record, does not warn that you can't
import m2o subfields (at all)...
"""
self.assertRaises(
ValueError, # No record found for 42, name_searches the bloody thing
self.import_, ['value/value'], [['42']])
def test_fail_noids(self):
self.assertRaises(
ValueError,
self.import_, ['value'], [['nameisnoexist:3']])
self.cr.rollback()
self.assertRaises(
ValueError,
self.import_, ['value/id'], [['noxidhere']]),
self.cr.rollback()
self.assertRaises(
Exception, # FIXME: Why can't you be a ValueError like everybody else?
self.import_, ['value/.id'], [[66]])
class test_m2m(ImporterCase):
model_name = 'export.many2many'
# apparently, one and only thing which works is a
# csv_internal_sep-separated list of ids, xids, or names (depending if
# m2m/.id, m2m/id or m2m[/anythingelse]
def test_ids(self):
id1 = self.registry('export.many2many.other').create(
self.cr, openerp.SUPERUSER_ID, {'value': 3, 'str': 'record0'})
id2 = self.registry('export.many2many.other').create(
self.cr, openerp.SUPERUSER_ID, {'value': 44, 'str': 'record1'})
id3 = self.registry('export.many2many.other').create(
self.cr, openerp.SUPERUSER_ID, {'value': 84, 'str': 'record2'})
id4 = self.registry('export.many2many.other').create(
self.cr, openerp.SUPERUSER_ID, {'value': 9, 'str': 'record3'})
id5 = self.registry('export.many2many.other').create(
self.cr, openerp.SUPERUSER_ID, {'value': 99, 'str': 'record4'})
self.assertEqual(
self.import_(['value/.id'], [
['%d,%d' % (id1, id2)],
['%d,%d,%d' % (id1, id3, id4)],
['%d,%d,%d' % (id1, id2, id3)],
['%d' % id5]
]),
ok(4))
ids = lambda records: [record.id for record in records]
b = self.browse()
self.assertEqual(ids(b[0].value), [id1, id2])
self.assertEqual(values(b[0].value), [3, 44])
self.assertEqual(ids(b[2].value), [id1, id2, id3])
self.assertEqual(values(b[2].value), [3, 44, 84])
def test_noids(self):
try:
self.import_(['value/.id'], [['42']])
self.fail("Should have raised an exception")
except Exception, e:
self.assertIs(type(e), Exception,
"test should be fixed on exception subclass")
def test_xids(self):
M2O_o = self.registry('export.many2many.other')
id1 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 3, 'str': 'record0'})
id2 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 44, 'str': 'record1'})
id3 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 84, 'str': 'record2'})
id4 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 9, 'str': 'record3'})
records = M2O_o.browse(self.cr, openerp.SUPERUSER_ID, [id1, id2, id3, id4])
self.assertEqual(
self.import_(['value/id'], [
['%s,%s' % (self.xid(records[0]), self.xid(records[1]))],
['%s' % self.xid(records[3])],
['%s,%s' % (self.xid(records[2]), self.xid(records[1]))],
]),
ok(3))
b = self.browse()
self.assertEqual(values(b[0].value), [3, 44])
self.assertEqual(values(b[2].value), [44, 84])
def test_noxids(self):
self.assertRaises(
ValueError,
self.import_, ['value/id'], [['noxidforthat']])
def test_names(self):
M2O_o = self.registry('export.many2many.other')
id1 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 3, 'str': 'record0'})
id2 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 44, 'str': 'record1'})
id3 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 84, 'str': 'record2'})
id4 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 9, 'str': 'record3'})
records = M2O_o.browse(self.cr, openerp.SUPERUSER_ID, [id1, id2, id3, id4])
name = lambda record: dict(record.name_get())[record.id]
self.assertEqual(
self.import_(['value'], [
['%s,%s' % (name(records[1]), name(records[2]))],
['%s,%s,%s' % (name(records[0]), name(records[1]), name(records[2]))],
['%s,%s' % (name(records[0]), name(records[3]))],
]),
ok(3))
b = self.browse()
self.assertEqual(values(b[1].value), [3, 44, 84])
self.assertEqual(values(b[2].value), [3, 9])
def test_nonames(self):
self.assertRaises(
ValueError,
self.import_, ['value'], [['wherethem2mhavenonames']])
def test_import_to_existing(self):
M2O_o = self.registry('export.many2many.other')
id1 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 3, 'str': 'record0'})
id2 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 44, 'str': 'record1'})
id3 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 84, 'str': 'record2'})
id4 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 9, 'str': 'record3'})
xid = 'myxid'
self.assertEqual(
self.import_(['id', 'value/.id'], [[xid, '%d,%d' % (id1, id2)]]),
ok(1))
self.assertEqual(
self.import_(['id', 'value/.id'], [[xid, '%d,%d' % (id3, id4)]]),
ok(1))
b = self.browse()
self.assertEqual(len(b), 1)
# TODO: replacement of existing m2m values is correct?
self.assertEqual(values(b[0].value), [84, 9])
class test_o2m(ImporterCase):
model_name = 'export.one2many'
def test_single(self):
self.assertEqual(
self.import_(['const', 'value/value'], [
['5', '63']
]),
ok(1))
(b,) = self.browse()
self.assertEqual(b.const, 5)
self.assertEqual(values(b.value), [63])
def test_multicore(self):
self.assertEqual(
self.import_(['const', 'value/value'], [
['5', '63'],
['6', '64'],
]),
ok(2))
b1, b2 = self.browse()
self.assertEqual(b1.const, 5)
self.assertEqual(values(b1.value), [63])
self.assertEqual(b2.const, 6)
self.assertEqual(values(b2.value), [64])
def test_multisub(self):
self.assertEqual(
self.import_(['const', 'value/value'], [
['5', '63'],
['', '64'],
['', '65'],
['', '66'],
]),
ok(4))
(b,) = self.browse()
self.assertEqual(values(b.value), [63, 64, 65, 66])
def test_multi_subfields(self):
self.assertEqual(
self.import_(['value/str', 'const', 'value/value'], [
['this', '5', '63'],
['is', '', '64'],
['the', '', '65'],
['rhythm', '', '66'],
]),
ok(4))
(b,) = self.browse()
self.assertEqual(values(b.value), [63, 64, 65, 66])
self.assertEqual(
values(b.value, 'str'),
'this is the rhythm'.split())
def test_link_inline(self):
id1 = self.registry('export.one2many.child').create(self.cr, openerp.SUPERUSER_ID, {
'str': 'Bf', 'value': 109
})
id2 = self.registry('export.one2many.child').create(self.cr, openerp.SUPERUSER_ID, {
'str': 'Me', 'value': 262
})
try:
self.import_(['const', 'value/.id'], [
['42', '%d,%d' % (id1, id2)]
])
except ValueError, e:
# should be Exception(Database ID doesn't exist: export.one2many.child : $id1,$id2)
self.assertIs(type(e), ValueError)
self.assertEqual(
e.args[0],
"invalid literal for int() with base 10: '%d,%d'" % (id1, id2))
def test_link(self):
id1 = self.registry('export.one2many.child').create(self.cr, openerp.SUPERUSER_ID, {
'str': 'Bf', 'value': 109
})
id2 = self.registry('export.one2many.child').create(self.cr, openerp.SUPERUSER_ID, {
'str': 'Me', 'value': 262
})
self.assertEqual(
self.import_(['const', 'value/.id'], [
['42', str(id1)],
['', str(id2)],
]),
ok(2))
# No record values alongside id => o2m resolution skipped altogether,
# creates 2 records => remove/don't import columns sideshow columns,
# get completely different semantics
b, b1 = self.browse()
self.assertEqual(b.const, 42)
self.assertEqual(values(b.value), [])
self.assertEqual(b1.const, 4)
self.assertEqual(values(b1.value), [])
def test_link_2(self):
O2M_c = self.registry('export.one2many.child')
id1 = O2M_c.create(self.cr, openerp.SUPERUSER_ID, {
'str': 'Bf', 'value': 109
})
id2 = O2M_c.create(self.cr, openerp.SUPERUSER_ID, {
'str': 'Me', 'value': 262
})
self.assertEqual(
self.import_(['const', 'value/.id', 'value/value'], [
['42', str(id1), '1'],
['', str(id2), '2'],
]),
ok(2))
(b,) = self.browse()
# if an id (db or xid) is provided, expectations that objects are
# *already* linked and emits UPDATE (1, id, {}).
# Noid => CREATE (0, ?, {})
# TODO: xid ignored aside from getting corresponding db id?
self.assertEqual(b.const, 42)
self.assertEqual(values(b.value), [])
# FIXME: updates somebody else's records?
self.assertEqual(
O2M_c.read(self.cr, openerp.SUPERUSER_ID, id1),
{'id': id1, 'str': 'Bf', 'value': 1, 'parent_id': False})
self.assertEqual(
O2M_c.read(self.cr, openerp.SUPERUSER_ID, id2),
{'id': id2, 'str': 'Me', 'value': 2, 'parent_id': False})
class test_o2m_multiple(ImporterCase):
model_name = 'export.one2many.multiple'
def test_multi_mixed(self):
self.assertEqual(
self.import_(['const', 'child1/value', 'child2/value'], [
['5', '11', '21'],
['', '12', '22'],
['', '13', '23'],
['', '14', ''],
]),
ok(4))
# Oh yeah, that's the stuff
(b, b1, b2) = self.browse()
self.assertEqual(values(b.child1), [11])
self.assertEqual(values(b.child2), [21])
self.assertEqual(values(b1.child1), [12])
self.assertEqual(values(b1.child2), [22])
self.assertEqual(values(b2.child1), [13, 14])
self.assertEqual(values(b2.child2), [23])
def test_multi(self):
self.assertEqual(
self.import_(['const', 'child1/value', 'child2/value'], [
['5', '11', '21'],
['', '12', ''],
['', '13', ''],
['', '14', ''],
['', '', '22'],
['', '', '23'],
]),
ok(6))
# What the actual fuck?
(b, b1) = self.browse()
self.assertEqual(values(b.child1), [11, 12, 13, 14])
self.assertEqual(values(b.child2), [21])
self.assertEqual(values(b1.child2), [22, 23])
def test_multi_fullsplit(self):
self.assertEqual(
self.import_(['const', 'child1/value', 'child2/value'], [
['5', '11', ''],
['', '12', ''],
['', '13', ''],
['', '14', ''],
['', '', '21'],
['', '', '22'],
['', '', '23'],
]),
ok(7))
# oh wow
(b, b1) = self.browse()
self.assertEqual(b.const, 5)
self.assertEqual(values(b.child1), [11, 12, 13, 14])
self.assertEqual(b1.const, 36)
self.assertEqual(values(b1.child2), [21, 22, 23])
# function, related, reference: written to db as-is...
# => function uses @type for value coercion/conversion

View File

@ -39,13 +39,16 @@ class TransactionCase(unittest2.TestCase):
"""
def setUp(self):
self.cr = openerp.modules.registry.RegistryManager.get(DB).db.cursor()
self.cr = self.cursor()
self.uid = openerp.SUPERUSER_ID
def tearDown(self):
self.cr.rollback()
self.cr.close()
def cursor(self):
return openerp.modules.registry.RegistryManager.get(DB).db.cursor()
def registry(self, model):
return openerp.modules.registry.RegistryManager.get(DB)[model]