[ADD] base: tests for translations and duplication
[odoo/odoo.git] / openerp / addons / base / tests / test_base.py
1 import unittest2
2
3 import openerp.tests.common as common
4 from openerp.osv.orm import except_orm
5
6 class test_base(common.TransactionCase):
7
8     def setUp(self):
9         super(test_base,self).setUp()
10         self.res_partner = self.registry('res.partner')
11
12         # samples use effective TLDs from the Mozilla public suffix
13         # list at http://publicsuffix.org
14         self.samples = [
15             ('"Raoul Grosbedon" <raoul@chirurgiens-dentistes.fr> ', 'Raoul Grosbedon', 'raoul@chirurgiens-dentistes.fr'),
16             ('ryu+giga-Sushi@aizubange.fukushima.jp', '', 'ryu+giga-Sushi@aizubange.fukushima.jp'),
17             ('Raoul chirurgiens-dentistes.fr', 'Raoul chirurgiens-dentistes.fr', ''),
18             (" Raoul O'hara  <!@historicalsociety.museum>", "Raoul O'hara", '!@historicalsociety.museum')
19         ]
20
21     def test_00_res_partner_name_create(self):
22         cr, uid = self.cr, self.uid
23         parse = self.res_partner._parse_partner_name
24         for text, name, mail in self.samples:
25             self.assertEqual((name,mail), parse(text), 'Partner name parsing failed')
26             partner_id, dummy = self.res_partner.name_create(cr, uid, text)
27             partner = self.res_partner.browse(cr, uid, partner_id)
28             self.assertEqual(name or mail, partner.name, 'Partner name incorrect')
29             self.assertEqual(mail or False, partner.email, 'Partner email incorrect')
30
31     def test_10_res_partner_find_or_create(self):
32         cr,uid = self.cr, self.uid
33         email = self.samples[0][0]
34         partner_id, dummy = self.res_partner.name_create(cr, uid, email)
35         found_id = self.res_partner.find_or_create(cr, uid, email)
36         self.assertEqual(partner_id, found_id, 'find_or_create failed')
37         new_id = self.res_partner.find_or_create(cr, uid, self.samples[1][0])
38         self.assertTrue(new_id > partner_id, 'find_or_create failed - should have created new one')
39         new_id2 = self.res_partner.find_or_create(cr, uid, self.samples[2][0])
40         self.assertTrue(new_id2 > new_id, 'find_or_create failed - should have created new one again')
41
42
43     def test_20_res_partner_address_sync(self):
44         cr, uid = self.cr, self.uid
45         ghoststep = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid,
46                                                                              {'name': 'GhostStep',
47                                                                               'is_company': True,
48                                                                               'street': 'Main Street, 10',
49                                                                               'phone': '123456789',
50                                                                               'email': 'info@ghoststep.com',
51                                                                               'vat': 'BE0477472701',
52                                                                               'type': 'default'}))
53         p1 = self.res_partner.browse(cr, uid, self.res_partner.name_create(cr, uid, 'Denis Bladesmith <denis.bladesmith@ghoststep.com>')[0])
54         self.assertEqual(p1.type, 'contact', 'Default type must be "contact"')
55         p1phone = '123456789#34'
56         p1.write({'phone': p1phone,
57                   'parent_id': ghoststep.id,
58                   'use_parent_address': True})
59         p1.refresh()
60         self.assertEqual(p1.street, ghoststep.street, 'Address fields must be synced')
61         self.assertEqual(p1.phone, p1phone, 'Phone should be preserved after address sync')
62         self.assertEqual(p1.type, 'contact', 'Type should be preserved after address sync')
63         self.assertEqual(p1.email, 'denis.bladesmith@ghoststep.com', 'Email should be preserved after sync')
64
65         # turn off sync
66         p1street = 'Different street, 42'
67         p1.write({'street': p1street,
68                   'use_parent_address': False})
69         p1.refresh(), ghoststep.refresh() 
70         self.assertEqual(p1.street, p1street, 'Address fields must not be synced after turning sync off')
71         self.assertNotEqual(ghoststep.street, p1street, 'Parent address must never be touched')
72
73         # turn on sync again       
74         p1.write({'use_parent_address': True})
75         p1.refresh()
76         self.assertEqual(p1.street, ghoststep.street, 'Address fields must be synced again')
77         self.assertEqual(p1.phone, p1phone, 'Phone should be preserved after address sync')
78         self.assertEqual(p1.type, 'contact', 'Type should be preserved after address sync')
79         self.assertEqual(p1.email, 'denis.bladesmith@ghoststep.com', 'Email should be preserved after sync')
80
81         # Modify parent, sync to children
82         ghoststreet = 'South Street, 25'
83         ghoststep.write({'street': ghoststreet})
84         p1.refresh()
85         self.assertEqual(p1.street, ghoststreet, 'Address fields must be synced automatically')
86         self.assertEqual(p1.phone, p1phone, 'Phone should not be synced')
87         self.assertEqual(p1.email, 'denis.bladesmith@ghoststep.com', 'Email should be preserved after sync')
88
89         p1street = 'My Street, 11'
90         p1.write({'street': p1street})
91         ghoststep.refresh()
92         self.assertEqual(ghoststep.street, ghoststreet, 'Touching contact should never alter parent')
93
94
95     def test_30_res_partner_first_contact_sync(self):
96         """ Test initial creation of company/contact pair where contact address gets copied to
97         company """
98         cr, uid = self.cr, self.uid
99         ironshield = self.res_partner.browse(cr, uid, self.res_partner.name_create(cr, uid, 'IronShield')[0])
100         self.assertFalse(ironshield.is_company, 'Partners are not companies by default')
101         self.assertFalse(ironshield.use_parent_address, 'use_parent_address defaults to False')
102         self.assertEqual(ironshield.type, 'contact', 'Default type must be "contact"')
103         ironshield.write({'type': 'default'}) # force default type to double-check sync 
104         p1 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid,
105                                                                       {'name': 'Isen Hardearth',
106                                                                        'street': 'Strongarm Avenue, 12',
107                                                                        'parent_id': ironshield.id}))
108         self.assertEquals(p1.type, 'contact', 'Default type must be "contact", not the copied parent type')
109         ironshield.refresh()
110         self.assertEqual(ironshield.street, p1.street, 'Address fields should be copied to company')
111         self.assertTrue(ironshield.is_company, 'Company flag should be turned on after first contact creation')
112
113     def test_40_res_partner_address_getc(self):
114         """ Test address_get address resolution mechanism: it should first go down through descendants,
115         stopping when encountering another is_copmany entity, then go up, stopping again at the first
116         is_company entity or the root ancestor and if nothing matches, it should use the provided partner
117         itself """
118         cr, uid = self.cr, self.uid
119         elmtree = self.res_partner.browse(cr, uid, self.res_partner.name_create(cr, uid, 'Elmtree')[0])
120         branch1 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Branch 1',
121                                                                                      'parent_id': elmtree.id,
122                                                                                      'is_company': True}))
123         leaf10 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 10',
124                                                                                     'parent_id': branch1.id,
125                                                                                     'type': 'invoice'}))
126         branch11 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Branch 11',
127                                                                                       'parent_id': branch1.id,
128                                                                                       'type': 'other'}))
129         leaf111 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 111',
130                                                                                     'parent_id': branch11.id,
131                                                                                     'type': 'delivery'}))
132         branch11.write({'is_company': False}) # force is_company after creating 1rst child
133         branch2 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Branch 2',
134                                                                                      'parent_id': elmtree.id,
135                                                                                      'is_company': True}))
136         leaf21 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 21',
137                                                                                     'parent_id': branch2.id,
138                                                                                     'type': 'delivery'}))
139         leaf22 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 22',
140                                                                                     'parent_id': branch2.id}))
141         leaf23 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid, {'name': 'Leaf 23',
142                                                                                     'parent_id': branch2.id,
143                                                                                     'type': 'default'}))
144         # go up, stop at branch1
145         self.assertEqual(self.res_partner.address_get(cr, uid, [leaf111.id], ['delivery', 'invoice', 'contact', 'other', 'default']),
146                          {'delivery': leaf111.id,
147                           'invoice': leaf10.id,
148                           'contact': branch1.id,
149                           'other': branch11.id,
150                           'default': leaf111.id}, 'Invalid address resolution')
151         self.assertEqual(self.res_partner.address_get(cr, uid, [branch11.id], ['delivery', 'invoice', 'contact', 'other', 'default']),
152                          {'delivery': leaf111.id,
153                           'invoice': leaf10.id,
154                           'contact': branch1.id,
155                           'other': branch11.id,
156                           'default': branch11.id}, 'Invalid address resolution')
157
158         # go down, stop at at all child companies
159         self.assertEqual(self.res_partner.address_get(cr, uid, [elmtree.id], ['delivery', 'invoice', 'contact', 'other', 'default']),
160                          {'delivery': elmtree.id,
161                           'invoice': elmtree.id,
162                           'contact': elmtree.id,
163                           'other': elmtree.id,
164                           'default': elmtree.id}, 'Invalid address resolution')
165
166         # go down through children
167         self.assertEqual(self.res_partner.address_get(cr, uid, [branch1.id], ['delivery', 'invoice', 'contact', 'other', 'default']),
168                          {'delivery': leaf111.id,
169                           'invoice': leaf10.id,
170                           'contact': branch1.id,
171                           'other': branch11.id,
172                           'default': branch1.id}, 'Invalid address resolution')
173         self.assertEqual(self.res_partner.address_get(cr, uid, [branch2.id], ['delivery', 'invoice', 'contact', 'other', 'default']),
174                          {'delivery': leaf21.id,
175                           'invoice': leaf23.id,
176                           'contact': branch2.id,
177                           'other': leaf23.id,
178                           'default': leaf23.id}, 'Invalid address resolution')
179
180         # go up then down through siblings
181         self.assertEqual(self.res_partner.address_get(cr, uid, [leaf21.id], ['delivery', 'invoice', 'contact', 'other', 'default']),
182                          {'delivery': leaf21.id,
183                           'invoice': leaf23.id,
184                           'contact': branch2.id,
185                           'other': leaf23.id,
186                           'default': leaf23.id
187                           }, 'Invalid address resolution, should scan commercial entity ancestor and its descendants')
188         self.assertEqual(self.res_partner.address_get(cr, uid, [leaf22.id], ['delivery', 'invoice', 'contact', 'other', 'default']),
189                          {'delivery': leaf21.id,
190                           'invoice': leaf23.id,
191                           'contact': leaf22.id,
192                           'other': leaf23.id,
193                           'default': leaf23.id}, 'Invalid address resolution, should scan commercial entity ancestor and its descendants')
194         self.assertEqual(self.res_partner.address_get(cr, uid, [leaf23.id], ['delivery', 'invoice', 'contact', 'other', 'default']),
195                          {'delivery': leaf21.id,
196                           'invoice': leaf23.id,
197                           'contact': branch2.id,
198                           'other': leaf23.id,
199                           'default': leaf23.id}, 'Invalid address resolution, `default` should only override if no partner with specific type exists')
200
201         # empty adr_pref means only 'default'
202         self.assertEqual(self.res_partner.address_get(cr, uid, [elmtree.id], []),
203                         {'default': elmtree.id}, 'Invalid address resolution, no default means commercial entity ancestor')
204         self.assertEqual(self.res_partner.address_get(cr, uid, [leaf111.id], []),
205                         {'default': leaf111.id}, 'Invalid address resolution, no default means contact itself')
206         branch11.write({'type': 'default'})
207         self.assertEqual(self.res_partner.address_get(cr, uid, [leaf111.id], []),
208                         {'default': branch11.id}, 'Invalid address resolution, branch11 should now be default')
209
210
211     def test_50_res_partner_commercial_sync(self):    
212         cr, uid = self.cr, self.uid
213         p0 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid,
214                                                                       {'name': 'Sigurd Sunknife',
215                                                                        'email': 'ssunknife@gmail.com'}))
216         sunhelm = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid,
217                                                                            {'name': 'Sunhelm',
218                                                                             'is_company': True,
219                                                                             'street': 'Rainbow Street, 13',
220                                                                             'phone': '1122334455',
221                                                                             'email': 'info@sunhelm.com',
222                                                                             'vat': 'BE0477472701',
223                                                                             'child_ids': [(4, p0.id),
224                                                                                           (0, 0, {'name': 'Alrik Greenthorn',
225                                                                                                   'email': 'agr@sunhelm.com'})],
226                                                                             }))
227         p1 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid,
228                                                                       {'name': 'Otto Blackwood',
229                                                                        'email': 'otto.blackwood@sunhelm.com',
230                                                                        'parent_id': sunhelm.id}))
231         p11 = self.res_partner.browse(cr, uid, self.res_partner.create(cr, uid,
232                                                                       {'name': 'Gini Graywool',
233                                                                        'email': 'ggr@sunhelm.com',
234                                                                        'parent_id': p1.id}))
235         p2 = self.res_partner.browse(cr, uid, self.res_partner.search(cr, uid,
236                                                                       [('email', '=', 'agr@sunhelm.com')])[0])
237
238         for p in (p0, p1, p11, p2):
239             p.refresh()
240             self.assertEquals(p.commercial_partner_id, sunhelm, 'Incorrect commercial entity resolution')
241             self.assertEquals(p.vat, sunhelm.vat, 'Commercial fields must be automatically synced')
242         sunhelmvat = 'BE0123456789'
243         sunhelm.write({'vat': sunhelmvat})
244         for p in (p0, p1, p11, p2):
245             p.refresh()
246             self.assertEquals(p.vat, sunhelmvat, 'Commercial fields must be automatically and recursively synced')
247
248         p1vat = 'BE0987654321'
249         p1.write({'vat': p1vat})
250         for p in (sunhelm, p0, p11, p2):
251             p.refresh()
252             self.assertEquals(p.vat, sunhelmvat, 'Sync to children should only work downstream and on commercial entities')
253
254         # promote p1 to commercial entity
255         vals = p1.onchange_type(is_company=True)['value']
256         p1.write(dict(vals, parent_id=sunhelm.id,
257                       is_company=True,
258                       name='Sunhelm Subsidiary'))
259         p1.refresh()
260         self.assertEquals(p1.vat, p1vat, 'Setting is_company should stop auto-sync of commercial fields')
261         self.assertEquals(p1.commercial_partner_id, p1, 'Incorrect commercial entity resolution after setting is_company')
262
263         # writing on parent should not touch child commercial entities
264         sunhelmvat2 = 'BE0112233445'
265         sunhelm.write({'vat': sunhelmvat2})
266         p1.refresh()
267         self.assertEquals(p1.vat, p1vat, 'Setting is_company should stop auto-sync of commercial fields')
268         p0.refresh()
269         self.assertEquals(p0.vat, sunhelmvat2, 'Commercial fields must be automatically synced')
270
271 class test_partner_recursion(common.TransactionCase):
272
273     def setUp(self):
274         super(test_partner_recursion,self).setUp()
275         self.res_partner = self.registry('res.partner')
276         cr, uid = self.cr, self.uid
277         self.p1 = self.res_partner.name_create(cr, uid, 'Elmtree')[0]
278         self.p2 = self.res_partner.create(cr, uid, {'name': 'Elmtree Child 1', 'parent_id': self.p1})
279         self.p3 = self.res_partner.create(cr, uid, {'name': 'Elmtree Grand-Child 1.1', 'parent_id': self.p2})
280
281     # split 101, 102, 103 tests to force SQL rollback between them
282
283     def test_101_res_partner_recursion(self):
284         cr, uid, p1, p3 = self.cr, self.uid, self.p1, self.p3
285         self.assertRaises(except_orm, self.res_partner.write, cr, uid, [p1], {'parent_id': p3})
286
287     def test_102_res_partner_recursion(self):
288         cr, uid, p2, p3 = self.cr, self.uid, self.p2, self.p3
289         self.assertRaises(except_orm, self.res_partner.write, cr, uid, [p2], {'parent_id': p3})
290
291     def test_103_res_partner_recursion(self):
292         cr, uid, p3 = self.cr, self.uid, self.p3
293         self.assertRaises(except_orm, self.res_partner.write, cr, uid, [p3], {'parent_id': p3})
294
295     def test_104_res_partner_recursion_indirect_cycle(self):
296         """ Indirect hacky write to create cycle in children """
297         cr, uid, p2, p3 = self.cr, self.uid, self.p2, self.p3
298         p3b = self.res_partner.create(cr, uid, {'name': 'Elmtree Grand-Child 1.2', 'parent_id': self.p2})
299         self.assertRaises(except_orm, self.res_partner.write, cr, uid, [p2],
300                           {'child_ids': [(1, p3, {'parent_id': p3b}), (1, p3b, {'parent_id': p3})]})
301
302     def test_110_res_partner_recursion_multi_update(self):
303         """ multi-write on several partners in same hierarchy must not trigger a false cycle detection """
304         cr, uid, p1, p2, p3 = self.cr, self.uid, self.p1, self.p2, self.p3
305         self.assertTrue(self.res_partner.write(cr, uid, [p1,p2,p3], {'phone': '123456'}))
306
307 class test_translation(common.TransactionCase):
308
309     def setUp(self):
310         super(test_translation, self).setUp()
311         self.res_category = self.registry('res.partner.category')
312         self.ir_translation = self.registry('ir.translation')
313         cr, uid = self.cr, self.uid
314         self.registry('ir.translation').load(cr, ['base'], ['fr_BE'])
315         self.cat_id = self.res_category.create(cr, uid, {'name': 'Customers'})
316         self.ir_translation.create(cr, uid, {'name': 'res.partner.category,name', 'module':'base', 
317             'value': 'Clients', 'res_id': self.cat_id, 'lang':'fr_BE', 'state':'translated', 'type': 'model'})
318
319     def test_101_create_translated_record(self):
320         cr, uid = self.cr, self.uid
321         
322         no_context_cat = self.res_category.browse(cr, uid, self.cat_id)
323         self.assertTrue(no_context_cat.name == 'Customers', "Error in basic name_get")
324
325         fr_context_cat = self.res_category.browse(cr, uid, self.cat_id, context={'lang':'fr_BE'})
326         self.assertTrue(fr_context_cat.name == 'Clients', "Translation not found")
327
328     def test_102_duplicate_record(self):
329         cr, uid = self.cr, self.uid
330         self.new_cat_id = self.res_category.copy(cr, uid, self.cat_id, context={'lang':'fr_BE'})
331
332         no_context_cat = self.res_category.browse(cr, uid, self.new_cat_id)
333         self.assertTrue(no_context_cat.name == 'Customers', "Duplication did not set untranslated value")
334
335         fr_context_cat = self.res_category.browse(cr, uid, self.new_cat_id, context={'lang':'fr_BE'})
336         self.assertTrue(fr_context_cat.name == 'Clients', "Did not found translation for initial value")
337
338     def test_103_duplicate_record_fr(self):
339         cr, uid = self.cr, self.uid
340         self.new_fr_cat_id = self.res_category.copy(cr, uid, self.cat_id, default={'name': 'Clients (copie)'}, context={'lang':'fr_BE'})
341
342         no_context_cat = self.res_category.browse(cr, uid, self.new_fr_cat_id)
343         self.assertTrue(no_context_cat.name == 'Clients (copie)', "Duplication with default value not applied")
344
345         fr_context_cat = self.res_category.browse(cr, uid, self.new_fr_cat_id, context={'lang':'fr_BE'})
346         self.assertTrue(fr_context_cat.name == 'Clients', "Did not found translation for initial value")
347
348
349 if __name__ == '__main__':
350     unittest2.main()