Merge lp:~camptocamp/openerp-product-attributes/6.1-backport-lot-custom-attributes-lep into lp:~product-core-editors/openerp-product-attributes/6.1

Proposed by Leonardo Pistone
Status: Merged
Merged at revision: 195
Proposed branch: lp:~camptocamp/openerp-product-attributes/6.1-backport-lot-custom-attributes-lep
Merge into: lp:~product-core-editors/openerp-product-attributes/6.1
Diff against target: 2143 lines (+2048/-0)
18 files modified
base_custom_attributes/__init__.py (+29/-0)
base_custom_attributes/__openerp__.py (+48/-0)
base_custom_attributes/custom_attributes.py (+440/-0)
base_custom_attributes/custom_attributes_view.xml (+312/-0)
base_custom_attributes/i18n/base_custom_attributes.pot (+291/-0)
base_custom_attributes/i18n/fr.po (+291/-0)
base_custom_attributes/ir_model.py (+39/-0)
base_custom_attributes/security/attribute_security.xml (+11/-0)
base_custom_attributes/security/ir.model.access.csv (+13/-0)
production_lot_custom_attributes/__init__.py (+25/-0)
production_lot_custom_attributes/__openerp__.py (+62/-0)
production_lot_custom_attributes/custom_attributes_view.xml (+58/-0)
production_lot_custom_attributes/lot.py (+207/-0)
production_lot_custom_attributes/lot_view.xml (+52/-0)
production_lot_custom_attributes/test/lot_attribute_test.yml (+48/-0)
production_lot_custom_attributes/wizard/__init__.py (+25/-0)
production_lot_custom_attributes/wizard/open_lot_by_attribute_set.py (+67/-0)
production_lot_custom_attributes/wizard/open_lot_by_attribute_set.xml (+30/-0)
To merge this branch: bzr merge lp:~camptocamp/openerp-product-attributes/6.1-backport-lot-custom-attributes-lep
Reviewer Review Type Date Requested Status
Omar (Pexego) code review, no test Approve
Review via email: mp+196538@code.launchpad.net

Commit message

[mrg] new modules: base_custom_attributes and production_lot_custom_attributes, backported from 7.0 and cleaned up

Description of the change

This is to backport the modules base_custom_attributes and production_lot_custom_attributes to v6.1.

I added some docstrings and comments that should make creating a new similar module easier.

Warning: in v7.0 the module product_custom_attributes (where all that started) has been split to use base_custom_attributes. In 6.1 is hasn't, so at the moment in 6.1 product_custom_attributes and production_lot_custom_attributes are incompatible.

Thanks to Akretion for the original modules this is based on.

To post a comment you must log in.
Revision history for this message
Omar (Pexego) (omar7r) wrote :

LGTM

review: Approve (code review, no test)
200. By Leonardo Pistone

[imp] production_lot_custom_attributes: refactor wizard

Revision history for this message
Leonardo Pistone (lepistone) wrote :

Thanks Omar.

I improved the code of the wizard in a similar fashion to the corresponding 7.0 branch.

L

201. By Leonardo Pistone

[fix] typo lenght -> length. yaml test now passes

202. By Leonardo Pistone

[add] method to search in all serialized fields

203. By Leonardo Pistone

[FIX] prevent KeyError if no 'attribute_ids' is present in 'vals'

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'base_custom_attributes'
2=== added file 'base_custom_attributes/__init__.py'
3--- base_custom_attributes/__init__.py 1970-01-01 00:00:00 +0000
4+++ base_custom_attributes/__init__.py 2013-12-11 14:54:36 +0000
5@@ -0,0 +1,29 @@
6+# -*- encoding: utf-8 -*-
7+###############################################################################
8+# #
9+# product_custom_attributes for OpenERP #
10+# Copyright (C) 2011 Akretion Benoît GUILLOT <benoit.guillot@akretion.com> #
11+# #
12+# This program is free software: you can redistribute it and/or modify #
13+# it under the terms of the GNU Affero General Public License as #
14+# published by the Free Software Foundation, either version 3 of the #
15+# License, or (at your option) any later version. #
16+# #
17+# This program is distributed in the hope that it will be useful, #
18+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
19+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
20+# GNU Affero General Public License for more details. #
21+# #
22+# You should have received a copy of the GNU Affero General Public License #
23+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
24+# #
25+###############################################################################
26+
27+
28+
29+import ir_model
30+import custom_attributes
31+
32+
33+
34+
35
36=== added file 'base_custom_attributes/__openerp__.py'
37--- base_custom_attributes/__openerp__.py 1970-01-01 00:00:00 +0000
38+++ base_custom_attributes/__openerp__.py 2013-12-11 14:54:36 +0000
39@@ -0,0 +1,48 @@
40+# -*- encoding: utf-8 -*-
41+###############################################################################
42+# #
43+# base_custom_attributes for OpenERP #
44+# Copyright (C) 2011 Akretion Benoît GUILLOT <benoit.guillot@akretion.com> #
45+# #
46+# This program is free software: you can redistribute it and/or modify #
47+# it under the terms of the GNU Affero General Public License as #
48+# published by the Free Software Foundation, either version 3 of the #
49+# License, or (at your option) any later version. #
50+# #
51+# This program is distributed in the hope that it will be useful, #
52+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
53+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
54+# GNU Affero General Public License for more details. #
55+# #
56+# You should have received a copy of the GNU Affero General Public License #
57+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
58+# #
59+###############################################################################
60+
61+
62+
63+{
64+ 'name': 'base_custom_attributes',
65+ 'version': '0.1',
66+ 'category': 'Generic Modules/Others',
67+ 'license': 'AGPL-3',
68+ 'description': """This module adds the possibility to easily create custom attributes in any OpenERP business object. See the product_custom_attributes module for instance.
69+ """,
70+ 'author': 'Akretion',
71+ 'website': 'http://www.akretion.com/',
72+ 'depends': ['base'],
73+ 'init_xml': [],
74+ 'update_xml': [
75+ 'security/ir.model.access.csv',
76+ 'security/attribute_security.xml',
77+ 'custom_attributes_view.xml',
78+ ],
79+ 'demo_xml': [],
80+ 'installable': True,
81+ 'active': False,
82+ 'external_dependencies' : {
83+ 'python' : ['unidecode'],
84+ }
85+
86+}
87+
88
89=== added file 'base_custom_attributes/custom_attributes.py'
90--- base_custom_attributes/custom_attributes.py 1970-01-01 00:00:00 +0000
91+++ base_custom_attributes/custom_attributes.py 2013-12-11 14:54:36 +0000
92@@ -0,0 +1,440 @@
93+# -*- encoding: utf-8 -*-
94+###############################################################################
95+# #
96+# base_attribute.attributes for OpenERP #
97+# Copyright (C) 2011 Akretion Benoît GUILLOT <benoit.guillot@akretion.com>
98+# Copyright (C) 2013 Akretion Raphaël VALYI <raphael.valyi@akretion.com>
99+# #
100+# This program is free software: you can redistribute it and/or modify #
101+# it under the terms of the GNU Affero General Public License as #
102+# published by the Free Software Foundation, either version 3 of the #
103+# License, or (at your option) any later version. #
104+# #
105+# This program is distributed in the hope that it will be useful, #
106+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
107+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
108+# GNU Affero General Public License for more details. #
109+# #
110+# You should have received a copy of the GNU Affero General Public License #
111+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
112+# #
113+###############################################################################
114+
115+import ast
116+from openerp.osv import orm, fields
117+from openerp.osv.osv import except_osv
118+from openerp.tools.translate import _
119+from lxml import etree
120+from unidecode import unidecode # Debian package python-unidecode
121+import re
122+
123+
124+def safe_column_name(string):
125+ """This function prevent portability problem in database column name
126+ with other DBMS system
127+ Use case : if you synchronise attributes with other applications """
128+ string = unidecode(string.replace(' ', '_').lower())
129+ return re.sub(r'[^0-9a-z_]','', string)
130+
131+
132+class attribute_option(orm.Model):
133+ _name = "attribute.option"
134+ _description = "Attribute Option"
135+ _order="sequence"
136+
137+ def _get_model_list(self, cr, uid, context=None):
138+ model_pool = self.pool.get('ir.model')
139+ ids = model_pool.search(cr, uid, [], context=context)
140+ res = model_pool.read(cr, uid, ids, ['model', 'name'], context=context)
141+ return [(r['model'], r['name']) for r in res]
142+
143+ _columns = {
144+ 'name': fields.char(
145+ 'Name',
146+ size=128,
147+ translate=True,
148+ required=True),
149+ 'value_ref': fields.reference(
150+ 'Reference',
151+ selection=_get_model_list,
152+ size=128),
153+ 'attribute_id': fields.many2one(
154+ 'attribute.attribute',
155+ 'Product Attribute',
156+ required=True),
157+ 'sequence': fields.integer('Sequence'),
158+ }
159+
160+ def name_change(self, cr, uid, ids, name, relation_model_id, context=None):
161+ if relation_model_id:
162+ warning = {'title': _('Error!'),
163+ 'message': _("Use the 'Load Options' button "
164+ "instead to select appropriate "
165+ "model references'")}
166+ return {"value": {"name": False}, "warning": warning}
167+ else:
168+ return True
169+
170+
171+class attribute_option_wizard(orm.TransientModel):
172+ _name = "attribute.option.wizard"
173+ _rec_name = 'attribute_id'
174+
175+ _columns = {
176+ 'attribute_id': fields.many2one(
177+ 'attribute.attribute',
178+ 'Product Attribute',
179+ required=True),
180+ }
181+
182+ _defaults = {
183+ 'attribute_id': lambda self, cr, uid, context:
184+ context.get('attribute_id',False)
185+ }
186+
187+ def validate(self, cr, uid, ids, context=None):
188+ return True
189+
190+ def create(self, cr, uid, vals, context=None):
191+ attr_obj = self.pool.get("attribute.attribute")
192+ attr = attr_obj.browse(cr, uid, vals['attribute_id'])
193+ op_ids = [op.id for op in attr.option_ids]
194+ opt_obj = self.pool.get("attribute.option")
195+ opt_obj.unlink(cr, uid, op_ids)
196+ for op_id in (vals.get("option_ids") and vals['option_ids'][0][2] or []):
197+ model = attr.relation_model_id.model
198+ name = self.pool.get(model).name_get(cr, uid, [op_id], context)[0][1]
199+ opt_obj.create(cr, uid, {
200+ 'attribute_id': vals['attribute_id'],
201+ 'name': name,
202+ 'value_ref': "%s,%s" % (attr.relation_model_id.model, op_id)
203+ })
204+ res = super(attribute_option_wizard, self).create(cr, uid, vals, context)
205+ return res
206+
207+ def fields_view_get(self, cr, uid, view_id=None, view_type='form',
208+ context=None, toolbar=False, submenu=False):
209+ res = super(attribute_option_wizard, self).fields_view_get(
210+ cr, uid, view_id, view_type, context, toolbar, submenu)
211+ if view_type == 'form' and context and context.get("attribute_id"):
212+ attr_obj = self.pool.get("attribute.attribute")
213+ model_id = attr_obj.read(cr, uid, [context.get("attribute_id")],
214+ ['relation_model_id'])[0]['relation_model_id'][0]
215+ relation = self.pool.get("ir.model").read(cr, uid, [model_id],
216+ ["model"])[0]["model"]
217+ res['fields'].update({'option_ids': {
218+ 'domain': [],
219+ 'string': "Options",
220+ 'type': 'many2many',
221+ 'relation': relation,
222+ 'required': True,
223+ }
224+ })
225+ eview = etree.fromstring(res['arch'])
226+ options = etree.Element('field', name='option_ids', colspan='6')
227+ placeholder = eview.xpath("//separator[@string='options_placeholder']")[0]
228+ placeholder.getparent().replace(placeholder, options)
229+ res['arch'] = etree.tostring(eview, pretty_print=True)
230+ return res
231+
232+
233+class attribute_attribute(orm.Model):
234+ _name = "attribute.attribute"
235+ _description = "Attribute"
236+ _inherits = {'ir.model.fields': 'field_id'}
237+
238+ def _build_attribute_field(self, cr, uid, page, attribute, context=None):
239+ parent = etree.SubElement(page, 'group', colspan="2", col="4")
240+ kwargs = {'name': "%s" % attribute.name}
241+ if attribute.ttype in ['many2many', 'text']:
242+ parent = etree.SubElement(parent, 'group', colspan="2", col="4")
243+ etree.SubElement(parent,
244+ 'separator',
245+ string="%s" % attribute.field_description,
246+ colspan="4")
247+ kwargs['nolabel'] = "1"
248+ if attribute.ttype in ['many2one', 'many2many']:
249+ if attribute.relation_model_id:
250+ # attribute.domain is a string, it may be an empty list
251+ try:
252+ domain = ast.literal_eval(attribute.domain)
253+ except ValueError:
254+ domain = None
255+ if domain:
256+ kwargs['domain'] = attribute.domain
257+ else:
258+ ids = [op.value_ref.id for op in attribute.option_ids]
259+ kwargs['domain'] = "[('id', 'in', %s)]" % ids
260+ else:
261+ kwargs['domain'] = "[('attribute_id', '=', %s)]" % attribute.attribute_id.id
262+ kwargs['context'] = "{'default_attribute_id': %s}" % attribute.attribute_id.id
263+ kwargs['required'] = str(attribute.required or
264+ attribute.required_on_views)
265+ field = etree.SubElement(parent, 'field', **kwargs)
266+ orm.setup_modifiers(field, self.fields_get(cr, uid, attribute.name,
267+ context))
268+ return parent
269+
270+ def _build_attributes_notebook(self, cr, uid, attribute_group_ids,
271+ context=None):
272+ notebook = etree.Element('notebook', name="attributes_notebook",
273+ colspan="4")
274+ toupdate_fields = []
275+ grp_obj = self.pool.get('attribute.group')
276+ for group in grp_obj.browse(cr, uid, attribute_group_ids,
277+ context=context):
278+ page = etree.SubElement(notebook, 'page',
279+ string=group.name.capitalize())
280+ for attribute in group.attribute_ids:
281+ if attribute.name not in toupdate_fields:
282+ toupdate_fields.append(attribute.name)
283+ self._build_attribute_field(cr, uid, page, attribute,
284+ context=context)
285+ return notebook, toupdate_fields
286+
287+ def relation_model_id_change(self, cr, uid, ids, relation_model_id,
288+ option_ids, context=None):
289+ "removed selected options as they would be inconsistent"
290+ return {'value': {'option_ids': [(2, i[1]) for i in option_ids]}}
291+
292+ def button_add_options(self, cr, uid, ids, context=None):
293+ return {
294+ 'context': "{'attribute_id': %s}" % (ids[0]),
295+ 'name': _('Options Wizard'),
296+ 'view_type': 'form',
297+ 'view_mode': 'form',
298+ 'res_model': 'attribute.option.wizard',
299+ 'type': 'ir.actions.act_window',
300+ 'target': 'new',
301+ }
302+
303+ _columns = {
304+ 'field_id': fields.many2one(
305+ 'ir.model.fields',
306+ 'Ir Model Fields',
307+ required=True,
308+ ondelete="cascade"),
309+ 'attribute_type': fields.selection([
310+ ('char', 'Char'),
311+ ('text', 'Text'),
312+ ('select', 'Select'),
313+ ('multiselect', 'Multiselect'),
314+ ('boolean', 'Boolean'),
315+ ('integer', 'Integer'),
316+ ('date', 'Date'),
317+ ('datetime', 'Datetime'),
318+ ('binary', 'Binary'),
319+ ('float', 'Float')],
320+ 'Type', required=True),
321+ 'serialized': fields.boolean(
322+ 'Field serialized',
323+ help="If serialized, the field will be stocked in the serialized "
324+ "field: attribute_custom_tmpl or attribute_custom_variant "
325+ "depending on the field based_on"),
326+ 'option_ids': fields.one2many(
327+ 'attribute.option',
328+ 'attribute_id',
329+ 'Attribute Options'),
330+ 'create_date': fields.datetime('Created date', readonly=True),
331+ 'relation_model_id': fields.many2one(
332+ 'ir.model',
333+ 'Model'),
334+ 'required_on_views': fields.boolean(
335+ 'Required (on views)',
336+ help="If activated, the attribute will be mandatory on the views, "
337+ "but not in the database"),
338+ }
339+
340+ def create(self, cr, uid, vals, context=None):
341+ if vals.get('relation_model_id'):
342+ relation = self.pool.get('ir.model').read(
343+ cr, uid, [vals.get('relation_model_id')], ['model'])[0]['model']
344+ else:
345+ relation = 'attribute.option'
346+ if vals['attribute_type'] == 'select':
347+ vals['ttype'] = 'many2one'
348+ vals['relation'] = relation
349+ elif vals['attribute_type'] == 'multiselect':
350+ vals['ttype'] = 'many2many'
351+ vals['relation'] = relation
352+ vals['serialized'] = True
353+ else:
354+ vals['ttype'] = vals['attribute_type']
355+
356+ if vals.get('serialized'):
357+ field_obj = self.pool.get('ir.model.fields')
358+ serialized_ids = field_obj.search(cr, uid, [
359+ ('ttype', '=', 'serialized'),
360+ ('model_id', '=', vals['model_id']),
361+ ('name', '=', 'x_custom_json_attrs')],
362+ context=context)
363+ if serialized_ids:
364+ vals['serialization_field_id'] = serialized_ids[0]
365+ else:
366+ f_vals = {
367+ 'name': u'x_custom_json_attrs',
368+ 'field_description': u'Serialized JSON Attributes',
369+ 'ttype': 'serialized',
370+ 'model_id': vals['model_id'],
371+ }
372+ vals['serialization_field_id'] = field_obj.create(
373+ cr, uid, f_vals, {'manual': True})
374+ vals['state'] = 'manual'
375+ return super(attribute_attribute, self).create(cr, uid, vals, context)
376+
377+ def onchange_field_description(self, cr, uid, ids, field_description,
378+ name, create_date, context=None):
379+ name = name or u'x_'
380+ if field_description and not create_date:
381+ name = unicode('x_' + safe_column_name(field_description))
382+ return {'value': {'name': name}}
383+
384+ def onchange_name(self, cr, uid, ids, name, context=None):
385+ res = {}
386+ if not name.startswith('x_'):
387+ name = u'x_%s' % name
388+ else:
389+ name = u'%s' % name
390+ res = {'value': {'name': unidecode(name)}}
391+
392+ #FILTER ON MODEL
393+ model_name = context.get('force_model')
394+ if not model_name:
395+ model_id = context.get('default_model_id')
396+ if model_id:
397+ model = self.pool['ir.model'].browse(cr, uid, model_id,
398+ context=context)
399+ model_name = model.model
400+ if model_name:
401+ model_obj = self.pool[model_name]
402+ allowed_model = [x for x in model_obj._inherits] + [model_name]
403+ res['domain'] = {'model_id': [['model', 'in', allowed_model]]}
404+
405+ return res
406+
407+ def _get_default_model(self, cr, uid, context=None):
408+ if context and context.get('force_model'):
409+ model_id = self.pool['ir.model'].search(cr, uid, [
410+ ('model', '=', context['force_model'])
411+ ], context=context)
412+ if model_id:
413+ return model_id[0]
414+ return None
415+
416+ _defaults = {
417+ 'model_id': _get_default_model
418+ }
419+
420+
421+class attribute_group(orm.Model):
422+ _name = "attribute.group"
423+ _description = "Attribute Group"
424+ _order ="sequence"
425+
426+ _columns = {
427+ 'name': fields.char(
428+ 'Name',
429+ size=128,
430+ required=True,
431+ translate=True),
432+ 'sequence': fields.integer('Sequence'),
433+ 'attribute_set_id': fields.many2one(
434+ 'attribute.set',
435+ 'Attribute Set'),
436+ 'attribute_ids': fields.one2many(
437+ 'attribute.location',
438+ 'attribute_group_id',
439+ 'Attributes'),
440+ 'model_id': fields.many2one(
441+ 'ir.model',
442+ 'Model',
443+ required=True),
444+ }
445+
446+ def create(self, cr, uid, vals, context=None):
447+ for attribute in vals.get('attribute_ids', []):
448+ if (vals.get('attribute_set_id') and attribute[2] and
449+ not attribute[2].get('attribute_set_id')):
450+ attribute[2]['attribute_set_id'] = vals['attribute_set_id']
451+ return super(attribute_group, self).create(cr, uid, vals, context)
452+
453+ def _get_default_model(self, cr, uid, context=None):
454+ if context and context.get('force_model'):
455+ model_id = self.pool['ir.model'].search(
456+ cr, uid, [['model', '=', context['force_model']]],
457+ context=context)
458+ if model_id:
459+ return model_id[0]
460+ return None
461+
462+ _defaults = {
463+ 'model_id': _get_default_model
464+ }
465+
466+
467+class attribute_set(orm.Model):
468+ _name = "attribute.set"
469+ _description = "Attribute Set"
470+ _columns = {
471+ 'name': fields.char(
472+ 'Name',
473+ size=128,
474+ required=True,
475+ translate=True),
476+ 'attribute_group_ids': fields.one2many(
477+ 'attribute.group',
478+ 'attribute_set_id',
479+ 'Attribute Groups'),
480+ 'model_id': fields.many2one(
481+ 'ir.model',
482+ 'Model',
483+ required=True),
484+ }
485+
486+ def _get_default_model(self, cr, uid, context=None):
487+ if context and context.get('force_model'):
488+ model_id = self.pool['ir.model'].search(
489+ cr, uid, [['model', '=', context['force_model']]],
490+ context=context)
491+ if model_id:
492+ return model_id[0]
493+ return None
494+
495+ _defaults = {
496+ 'model_id': _get_default_model
497+ }
498+
499+
500+class attribute_location(orm.Model):
501+ _name = "attribute.location"
502+ _description = "Attribute Location"
503+ _order="sequence"
504+ _inherits = {'attribute.attribute': 'attribute_id'}
505+
506+ def _get_attribute_loc_from_group(self, cr, uid, ids, context=None):
507+ return self.pool.get('attribute.location').search(
508+ cr, uid, [('attribute_group_id', 'in', ids)], context=context)
509+
510+ _columns = {
511+ 'attribute_id': fields.many2one(
512+ 'attribute.attribute',
513+ 'Product Attribute',
514+ required=True,
515+ ondelete="cascade"),
516+ 'attribute_set_id': fields.related(
517+ 'attribute_group_id',
518+ 'attribute_set_id',
519+ type='many2one',
520+ relation='attribute.set',
521+ string='Attribute Set',
522+ readonly=True,
523+ store={
524+ 'attribute.group': (_get_attribute_loc_from_group,
525+ ['attribute_set_id'], 10),
526+ }),
527+ 'attribute_group_id': fields.many2one(
528+ 'attribute.group',
529+ 'Attribute Group',
530+ required=True),
531+ 'sequence': fields.integer('Sequence'),
532+ }
533
534=== added file 'base_custom_attributes/custom_attributes_view.xml'
535--- base_custom_attributes/custom_attributes_view.xml 1970-01-01 00:00:00 +0000
536+++ base_custom_attributes/custom_attributes_view.xml 2013-12-11 14:54:36 +0000
537@@ -0,0 +1,312 @@
538+<?xml version="1.0" encoding="utf-8"?>
539+<!--
540+ base_custom_attributes for OpenERP
541+ Copyright (C) 2011-2013 Akretion (http://www.akretion.com/)
542+ @author: Benoît GUILLOT <benoit.guillot@akretion.com>
543+ The licence is in the file __openerp__.py
544+-->
545+
546+<openerp>
547+ <data>
548+
549+ <menuitem
550+ id="menu_attribute_in_admin" name="Attributes"
551+ parent="base.next_id_9" sequence="1"/>
552+
553+ <!-- ATTRIBUTE SET VIEW -->
554+
555+ <record id="attribute_set_form_view" model="ir.ui.view">
556+ <field name="name">attribute.set.form</field>
557+ <field name="model">attribute.set</field>
558+ <field name="type">form</field>
559+ <field name="arch" type="xml">
560+ <form string="Attribute Set">
561+ <field name="name"/>
562+ <field name="model_id" invisible="context.get('force_model')"/>
563+ <field name="attribute_group_ids" colspan="4"
564+ context="{'default_model_id': model_id, 'from_attribute_set':True}">
565+ </field>
566+ </form>
567+ </field>
568+ </record>
569+
570+ <record id="attribute_set_tree_view" model="ir.ui.view">
571+ <field name="name">attribute.set.tree</field>
572+ <field name="model">attribute.set</field>
573+ <field name="type">tree</field>
574+ <field name="arch" type="xml">
575+ <tree string="Attribute Set" >
576+ <field name="name" />
577+ <field name="model_id" />
578+ </tree>
579+ </field>
580+ </record>
581+
582+ <record id="view_attribute_set_search" model="ir.ui.view">
583+ <field name="name">attribute.set.list</field>
584+ <field name="model">attribute.set</field>
585+ <field name="type">search</field>
586+ <field name="arch" type="xml">
587+ <search string="Search Attribute Sets">
588+ <field name="name"/>
589+ <field name="model_id" />
590+ </search>
591+ </field>
592+ </record>
593+
594+ <record id="attribute_set_form_action" model="ir.actions.act_window">
595+ <field name="name">Attribute Sets</field>
596+ <field name="res_model">attribute.set</field>
597+ <field name="view_type">form</field>
598+ <field name="view_mode">tree,form</field>
599+ <field name="search_view_id" ref="view_attribute_set_search"/>
600+ <field name="context">{"search_default_user_id":uid}</field>
601+ <field name="help"></field>
602+ </record>
603+
604+ <menuitem
605+ action="attribute_set_form_action" id="menu_attribute_set_action"
606+ parent="menu_attribute_in_admin" sequence="10"/>
607+
608+
609+
610+ <!-- ATTRIBUTE GROUP VIEW -->
611+
612+ <record id="attribute_group_form_view" model="ir.ui.view">
613+ <field name="name">attribute.group.form</field>
614+ <field name="model">attribute.group</field>
615+ <field name="type">form</field>
616+ <field name="arch" type="xml">
617+ <form string="Attribute Group">
618+ <field name="name" />
619+ <field name="sequence" />
620+ <field name="model_id" invisible="context.get('from_attribute_set') or context.get('force_model')"/>
621+ <field name="attribute_set_id" invisible="context.get('from_attribute_set')"/>
622+ <field name="attribute_ids" colspan="4" nolabel="1">
623+ <form string="Attribute Location">
624+ <field name="attribute_id" context="{'default_model_id': parent.model_id}"/>
625+ <field name="sequence" />
626+ </form>
627+ <tree string="Attribute Location" editable="top">
628+ <field name="attribute_id" context="{'default_model_id': parent.model_id}"/>
629+ <field name="sequence" />
630+ </tree>
631+ </field>
632+ </form>
633+ </field>
634+ </record>
635+
636+ <record id="attribute_group_tree_view" model="ir.ui.view">
637+ <field name="name">attribute.group.tree</field>
638+ <field name="model">attribute.group</field>
639+ <field name="type">tree</field>
640+ <field name="arch" type="xml">
641+ <tree string="Attribute Group">
642+ <field name="name" />
643+ <field name="sequence" />
644+ <field name="attribute_set_id" invisible="context.get('from_attribute_set')"/>
645+ <field name="model_id" invisible="context.get('from_attribute_set')"/>
646+ </tree>
647+ </field>
648+ </record>
649+
650+ <record id="view_attribute_group_search" model="ir.ui.view">
651+ <field name="name">attribute.group.list</field>
652+ <field name="model">attribute.group</field>
653+ <field name="type">search</field>
654+ <field name="arch" type="xml">
655+ <search string="Search Attribute Groups">
656+ <field name="name"/>
657+ <field name="attribute_set_id"/>
658+ <field name="model_id" />
659+ </search>
660+ </field>
661+ </record>
662+
663+
664+ <record id="attribute_group_form_action" model="ir.actions.act_window">
665+ <field name="name">Attribute Groups</field>
666+ <field name="res_model">attribute.group</field>
667+ <field name="view_type">form</field>
668+ <field name="view_mode">tree,form</field>
669+ <field name="context">{"search_default_user_id":uid}</field>
670+ <field name="help"></field>
671+ </record>
672+
673+ <menuitem
674+ action="attribute_group_form_action" id="menu_attribute_group_action"
675+ parent="menu_attribute_in_admin" sequence="20"/>
676+
677+ <!-- ATTRIBUTE VIEW -->
678+
679+ <record id="attribute_attribute_form_view" model="ir.ui.view">
680+ <field name="name">attribute.attribute.form</field>
681+ <field name="model">attribute.attribute</field>
682+ <field name="type">form</field>
683+ <field name="arch" type="xml">
684+ <form string="Attribute">
685+ <field name="field_description" on_change="onchange_field_description(field_description, name, create_date, context)"/>
686+ <field name="name" attrs="{'readonly':[('create_date', '!=', False)]}" on_change="onchange_name(name, context)"/>
687+ <field name="attribute_type" />
688+ <field name="model_id" />
689+ <field name="serialized" attrs="{'invisible':[('attribute_type', '=', 'multiselect')]}"/>
690+ <field name="size" attrs="{'invisible':[('attribute_type', '!=', 'char')]}"/>
691+ <field name="required_on_views"/>
692+ <field name="translate" attrs="{'invisible':[('attribute_type', 'not in', ('char', 'text'))]}"/>
693+ <newline />
694+ <group colspan="4" attrs="{'invisible':[('attribute_type', 'not in', ['select', 'multiselect'])]}">
695+ <group groups="base.group_advanced_attribute">
696+ <field name="relation_model_id" on_change="relation_model_id_change(relation_model_id, option_ids, context)"/>
697+ <field name="domain" attrs="{'invisible':[('relation_model_id', '=', False)]}"/>
698+ <button name="button_add_options" attrs="{'invisible':[('relation_model_id', '=', False), ('domain', '!=', False)]}" type="object" string="Load Options"/>
699+ </group>
700+ <field name="option_ids" colspan="4" nolabel="1">
701+ <tree string="Attribute Options" editable="top">
702+ <field name="sequence" invisible="1"/>
703+ <field name="name" on_change="name_change(name, parent.relation_model_id, context)"/>
704+ </tree>
705+ </field>
706+ </group>
707+ <field name="create_date" invisible="1"/>
708+ </form>
709+ </field>
710+ </record>
711+
712+ <record id="attribute_attribute_tree_view" model="ir.ui.view">
713+ <field name="name">attribute.attribute.tree</field>
714+ <field name="model">attribute.attribute</field>
715+ <field name="type">tree</field>
716+ <field name="arch" type="xml">
717+ <tree string="Attribute">
718+ <field name="name" />
719+ <field name="attribute_type" />
720+ </tree>
721+ </field>
722+ </record>
723+
724+ <record id="view_attribute_attribute_search" model="ir.ui.view">
725+ <field name="name">attribute.attribute.list</field>
726+ <field name="model">attribute.attribute</field>
727+ <field name="type">search</field>
728+ <field name="arch" type="xml">
729+ <search string="Search Attributes">
730+ <field name="name"/>
731+ </search>
732+ </field>
733+ </record>
734+
735+ <record id="attribute_attribute_form_action" model="ir.actions.act_window">
736+ <field name="name">Attributes</field>
737+ <field name="res_model">attribute.attribute</field>
738+ <field name="view_type">form</field>
739+ <field name="view_mode">tree,form</field>
740+ <field name="search_view_id" ref="view_attribute_attribute_search"/>
741+ <field name="context">{"search_default_user_id":uid}</field>
742+ <field name="help"></field>
743+ </record>
744+ <menuitem
745+ action="attribute_attribute_form_action" id="menu_attribute_attribute_action"
746+ parent="menu_attribute_in_admin" sequence="30"/>
747+
748+ <!-- ATTRIBUTE OPTION VIEW -->
749+ <record id="attribute_option_form_popup_view" model="ir.ui.view">
750+ <field name="name">attribute.option.form.popup</field>
751+ <field name="model">attribute.option</field>
752+ <field name="priority" eval="6"/>
753+ <field name="type">form</field>
754+ <field name="arch" type="xml">
755+ <form string="Attribute Option">
756+ <field name="name" colspan="2"/>
757+ <field name="value_ref" colspan="2" groups="base.group_advanced_attribute"/>
758+ <field name="sequence" colspan="2"/>
759+ </form>
760+ </field>
761+ </record>
762+
763+ <record id="attribute_option_form_view" model="ir.ui.view">
764+ <field name="name">attribute.option.form</field>
765+ <field name="model">attribute.option</field>
766+ <field name="type">form</field>
767+ <field name="arch" type="xml">
768+ <form string="Attribute Option">
769+ <field name="name" colspan="2"/>
770+ <field name="value_ref" colspan="2" groups="base.group_advanced_attribute"/>
771+ <field name="sequence" colspan="2"/>
772+ <field name="attribute_id" colspan="2"/>
773+ </form>
774+ </field>
775+ </record>
776+
777+ <record id="attribute_option_tree_view" model="ir.ui.view">
778+ <field name="name">attribute.option.tree</field>
779+ <field name="model">attribute.option</field>
780+ <field eval="20" name="priority"/>
781+ <field name="type">tree</field>
782+ <field name="arch" type="xml">
783+ <tree string="Attribute Option">
784+ <field name="name" />
785+ <field name="sequence" />
786+ <field name="value_ref" groups="base.group_advanced_attribute"/>
787+ <field name="attribute_id" />
788+ </tree>
789+ </field>
790+ </record>
791+
792+ <record id="view_attribute_option_search" model="ir.ui.view">
793+ <field name="name">attribute.option.list</field>
794+ <field name="model">attribute.option</field>
795+ <field name="type">search</field>
796+ <field name="arch" type="xml">
797+ <search string="Search Attribute Options">
798+ <field name="name" />
799+ <field name="attribute_id"/>
800+ </search>
801+ </field>
802+ </record>
803+
804+ <record id="attribute_option_form_action" model="ir.actions.act_window">
805+ <field name="name">Attribute Options</field>
806+ <field name="res_model">attribute.option</field>
807+ <field name="view_type">form</field>
808+ <field name="view_mode">tree,form</field>
809+ <field name="view_id" ref="attribute_option_tree_view"/>
810+ <field name="search_view_id" ref="view_attribute_option_search"/>
811+ <field name="context">{"search_default_user_id":uid}</field>
812+ <field name="help"></field>
813+ </record>
814+
815+ <record id="attribute_option_form_action_tree" model="ir.actions.act_window.view">
816+ <field name="sequence" eval="1"/>
817+ <field name="act_window_id" ref="attribute_option_form_action"/>
818+ <field name="view_id" ref="attribute_option_tree_view"/>
819+ <field name="view_mode">tree</field>
820+ </record>
821+
822+ <record id="attribute_option_form_action_form" model="ir.actions.act_window.view">
823+ <field name="sequence" eval="2"/>
824+ <field name="act_window_id" ref="attribute_option_form_action"/>
825+ <field name="view_id" ref="attribute_option_form_view"/>
826+ <field name="view_mode">form</field>
827+ </record>
828+
829+ <menuitem
830+ action="attribute_option_form_action" id="menu_attribute_option_action"
831+ parent="menu_attribute_in_admin" sequence="40"/>
832+
833+ <!-- ATTRIBUTE OPTION WIZARD -->
834+ <record id="attribute_option_wizard_form_view" model="ir.ui.view">
835+ <field name="name">attribute.option.wizard</field>
836+ <field name="model">attribute.option.wizard</field>
837+ <field name="type">form</field>
838+ <field name="arch" type="xml">
839+ <form string="Options Wizard" col="6">
840+ <field name="attribute_id" invisible="1" colspan="2"/>
841+ <separator string="options_placeholder"/>
842+ <button special="cancel" string="Cancel" icon="gtk-cancel"/>
843+ <button name="validate" string="Validate" type="object" icon="gtk-convert"/>
844+ </form>
845+ </field>
846+ </record>
847+
848+ </data>
849+</openerp>
850
851=== added directory 'base_custom_attributes/i18n'
852=== added file 'base_custom_attributes/i18n/base_custom_attributes.pot'
853--- base_custom_attributes/i18n/base_custom_attributes.pot 1970-01-01 00:00:00 +0000
854+++ base_custom_attributes/i18n/base_custom_attributes.pot 2013-12-11 14:54:36 +0000
855@@ -0,0 +1,291 @@
856+# Translation of OpenERP Server.
857+# This file contains the translation of the following modules:
858+# * base_custom_attributes
859+#
860+msgid ""
861+msgstr ""
862+"Project-Id-Version: OpenERP Server 7.0\n"
863+"Report-Msgid-Bugs-To: \n"
864+"POT-Creation-Date: 2013-10-16 10:39+0000\n"
865+"PO-Revision-Date: 2013-10-16 10:39+0000\n"
866+"Last-Translator: <>\n"
867+"Language-Team: \n"
868+"MIME-Version: 1.0\n"
869+"Content-Type: text/plain; charset=UTF-8\n"
870+"Content-Transfer-Encoding: \n"
871+"Plural-Forms: \n"
872+
873+#. module: base_custom_attributes
874+#: code:addons/base_custom_attributes/custom_attributes.py:44
875+#, python-format
876+msgid "Use the 'Load Options' button instead to select appropriate model references."
877+msgstr ""
878+
879+#. module: base_custom_attributes
880+#: selection:attribute.attribute,attribute_type:0
881+msgid "Binary"
882+msgstr ""
883+
884+#. module: base_custom_attributes
885+#: view:attribute.attribute:0
886+msgid "Search Attributes"
887+msgstr ""
888+
889+#. module: base_custom_attributes
890+#: view:attribute.group:0
891+#: field:attribute.location,attribute_group_id:0
892+#: model:ir.model,name:base_custom_attributes.model_attribute_group
893+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_location_attribute_group_id
894+msgid "Attribute Group"
895+msgstr ""
896+
897+#. module: base_custom_attributes
898+#: view:attribute.group:0
899+#: model:ir.model,name:base_custom_attributes.model_attribute_location
900+msgid "Attribute Location"
901+msgstr ""
902+
903+#. module: base_custom_attributes
904+#: code:addons/base_custom_attributes/custom_attributes.py:154
905+#: view:attribute.option.wizard:0
906+#, python-format
907+msgid "Options Wizard"
908+msgstr ""
909+
910+#. module: base_custom_attributes
911+#: view:attribute.group:0
912+msgid "Search Attribute Groups"
913+msgstr ""
914+
915+#. module: base_custom_attributes
916+#: field:attribute.attribute,attribute_type:0
917+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_attribute_attribute_type
918+msgid "Type"
919+msgstr ""
920+
921+#. module: base_custom_attributes
922+#: field:attribute.set,attribute_group_ids:0
923+#: model:ir.actions.act_window,name:base_custom_attributes.attribute_group_form_action
924+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_set_attribute_group_ids
925+#: model:ir.ui.menu,name:base_custom_attributes.menu_attribute_group_action
926+msgid "Attribute Groups"
927+msgstr ""
928+
929+#. module: base_custom_attributes
930+#: field:attribute.attribute,create_date:0
931+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_attribute_create_date
932+msgid "Created date"
933+msgstr ""
934+
935+#. module: base_custom_attributes
936+#: view:attribute.set:0
937+msgid "Search Attribute Sets"
938+msgstr ""
939+
940+#. module: base_custom_attributes
941+#: view:attribute.option:0
942+#: model:ir.model,name:base_custom_attributes.model_attribute_option
943+msgid "Attribute Option"
944+msgstr ""
945+
946+#. module: base_custom_attributes
947+#: selection:attribute.attribute,attribute_type:0
948+msgid "Date"
949+msgstr ""
950+
951+#. module: base_custom_attributes
952+#: help:attribute.attribute,required_on_views:0
953+msgid "If activated, the attribute will be mandatory on the views, but not in the database"
954+msgstr ""
955+
956+#. module: base_custom_attributes
957+#: field:attribute.attribute,field_id:0
958+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_attribute_field_id
959+msgid "Ir Model Fields"
960+msgstr ""
961+
962+#. module: base_custom_attributes
963+#: view:attribute.option.wizard:0
964+msgid "options_placeholder"
965+msgstr ""
966+
967+#. module: base_custom_attributes
968+#: field:attribute.group,name:0
969+#: field:attribute.option,name:0
970+#: field:attribute.set,name:0
971+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_group_name
972+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_option_name
973+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_set_name
974+msgid "Name"
975+msgstr ""
976+
977+#. module: base_custom_attributes
978+#: help:attribute.attribute,serialized:0
979+msgid "If serialized, the field will be stocked in the serialized field: attribute_custom_tmpl or attribute_custom_variant depending on the field based_on"
980+msgstr ""
981+
982+#. module: base_custom_attributes
983+#: field:attribute.attribute,required_on_views:0
984+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_attribute_required_on_views
985+msgid "Required (on views)"
986+msgstr ""
987+
988+#. module: base_custom_attributes
989+#: model:ir.model,name:base_custom_attributes.model_ir_model_fields
990+msgid "Fields"
991+msgstr ""
992+
993+#. module: base_custom_attributes
994+#: view:attribute.attribute:0
995+#: field:attribute.attribute,option_ids:0
996+#: model:ir.actions.act_window,name:base_custom_attributes.attribute_option_form_action
997+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_attribute_option_ids
998+#: model:ir.ui.menu,name:base_custom_attributes.menu_attribute_option_action
999+msgid "Attribute Options"
1000+msgstr ""
1001+
1002+#. module: base_custom_attributes
1003+#: field:attribute.attribute,serialized:0
1004+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_attribute_serialized
1005+msgid "Field serialized"
1006+msgstr ""
1007+
1008+#. module: base_custom_attributes
1009+#: code:addons/base_custom_attributes/custom_attributes.py:44
1010+#, python-format
1011+msgid "Error!"
1012+msgstr ""
1013+
1014+#. module: base_custom_attributes
1015+#: view:attribute.option.wizard:0
1016+msgid "Validate"
1017+msgstr ""
1018+
1019+#. module: base_custom_attributes
1020+#: selection:attribute.attribute,attribute_type:0
1021+msgid "Multiselect"
1022+msgstr ""
1023+
1024+#. module: base_custom_attributes
1025+#: view:attribute.option:0
1026+msgid "Search Attribute Options"
1027+msgstr ""
1028+
1029+#. module: base_custom_attributes
1030+#: selection:attribute.attribute,attribute_type:0
1031+msgid "Integer"
1032+msgstr ""
1033+
1034+#. module: base_custom_attributes
1035+#: field:attribute.group,attribute_ids:0
1036+#: model:ir.actions.act_window,name:base_custom_attributes.attribute_attribute_form_action
1037+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_group_attribute_ids
1038+#: model:ir.ui.menu,name:base_custom_attributes.menu_attribute_attribute_action
1039+#: model:ir.ui.menu,name:base_custom_attributes.menu_attribute_in_admin
1040+msgid "Attributes"
1041+msgstr ""
1042+
1043+#. module: base_custom_attributes
1044+#: field:attribute.attribute,relation_model_id:0
1045+#: field:attribute.group,model_id:0
1046+#: field:attribute.set,model_id:0
1047+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_attribute_relation_model_id
1048+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_group_model_id
1049+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_set_model_id
1050+msgid "Model"
1051+msgstr ""
1052+
1053+#. module: base_custom_attributes
1054+#: model:ir.actions.act_window,name:base_custom_attributes.attribute_set_form_action
1055+#: model:ir.ui.menu,name:base_custom_attributes.menu_attribute_set_action
1056+msgid "Attribute Sets"
1057+msgstr ""
1058+
1059+#. module: base_custom_attributes
1060+#: view:attribute.attribute:0
1061+msgid "Load Options"
1062+msgstr ""
1063+
1064+#. module: base_custom_attributes
1065+#: field:attribute.option,value_ref:0
1066+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_option_value_ref
1067+msgid "Reference"
1068+msgstr ""
1069+
1070+#. module: base_custom_attributes
1071+#: field:attribute.group,sequence:0
1072+#: field:attribute.location,sequence:0
1073+#: field:attribute.option,sequence:0
1074+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_group_sequence
1075+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_location_sequence
1076+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_option_sequence
1077+msgid "Sequence"
1078+msgstr ""
1079+
1080+#. module: base_custom_attributes
1081+#: view:attribute.attribute:0
1082+#: field:attribute.location,attribute_id:0
1083+#: field:attribute.option,attribute_id:0
1084+#: field:attribute.option.wizard,attribute_id:0
1085+#: model:ir.model,name:base_custom_attributes.model_attribute_attribute
1086+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_location_attribute_id
1087+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_option_attribute_id
1088+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_option_wizard_attribute_id
1089+msgid "Attribute"
1090+msgstr ""
1091+
1092+#. module: base_custom_attributes
1093+#: selection:attribute.attribute,attribute_type:0
1094+msgid "Float"
1095+msgstr ""
1096+
1097+#. module: base_custom_attributes
1098+#: field:attribute.group,attribute_set_id:0
1099+#: field:attribute.location,attribute_set_id:0
1100+#: view:attribute.set:0
1101+#: model:ir.model,name:base_custom_attributes.model_attribute_set
1102+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_group_attribute_set_id
1103+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_location_attribute_set_id
1104+msgid "Attribute Set"
1105+msgstr ""
1106+
1107+#. module: base_custom_attributes
1108+#: selection:attribute.attribute,attribute_type:0
1109+msgid "Datetime"
1110+msgstr ""
1111+
1112+#. module: base_custom_attributes
1113+#: selection:attribute.attribute,attribute_type:0
1114+msgid "Char"
1115+msgstr ""
1116+
1117+#. module: base_custom_attributes
1118+#: selection:attribute.attribute,attribute_type:0
1119+msgid "Boolean"
1120+msgstr ""
1121+
1122+#. module: base_custom_attributes
1123+#: selection:attribute.attribute,attribute_type:0
1124+msgid "Text"
1125+msgstr ""
1126+
1127+#. module: base_custom_attributes
1128+#: view:attribute.option.wizard:0
1129+msgid "Cancel"
1130+msgstr ""
1131+
1132+#. module: base_custom_attributes
1133+#: model:ir.model,name:base_custom_attributes.model_attribute_option_wizard
1134+msgid "attribute.option.wizard"
1135+msgstr ""
1136+
1137+#. module: base_custom_attributes
1138+#: sql_constraint:ir.model.fields:0
1139+msgid "The name of the field has to be uniq for a given model !"
1140+msgstr ""
1141+
1142+#. module: base_custom_attributes
1143+#: selection:attribute.attribute,attribute_type:0
1144+msgid "Select"
1145+msgstr ""
1146+
1147
1148=== added file 'base_custom_attributes/i18n/fr.po'
1149--- base_custom_attributes/i18n/fr.po 1970-01-01 00:00:00 +0000
1150+++ base_custom_attributes/i18n/fr.po 2013-12-11 14:54:36 +0000
1151@@ -0,0 +1,291 @@
1152+# Translation of OpenERP Server.
1153+# This file contains the translation of the following modules:
1154+# * base_custom_attributes
1155+#
1156+msgid ""
1157+msgstr ""
1158+"Project-Id-Version: OpenERP Server 7.0\n"
1159+"Report-Msgid-Bugs-To: \n"
1160+"POT-Creation-Date: 2013-10-16 09:03+0000\n"
1161+"PO-Revision-Date: 2013-10-16 09:03+0000\n"
1162+"Last-Translator: <>\n"
1163+"Language-Team: \n"
1164+"MIME-Version: 1.0\n"
1165+"Content-Type: text/plain; charset=UTF-8\n"
1166+"Content-Transfer-Encoding: \n"
1167+"Plural-Forms: \n"
1168+
1169+#. module: base_custom_attributes
1170+#: code:addons/base_custom_attributes/custom_attributes.py:44
1171+#, python-format
1172+msgid "Use the 'Load Options' button instead to select appropriate model references."
1173+msgstr "Utiliser le bouton 'Charger les options' pour sélectionner le modèle de référence approprié."
1174+
1175+#. module: base_custom_attributes
1176+#: selection:attribute.attribute,attribute_type:0
1177+msgid "Binary"
1178+msgstr "Binary"
1179+
1180+#. module: base_custom_attributes
1181+#: view:attribute.attribute:0
1182+msgid "Search Attributes"
1183+msgstr "Rechercher des attributs"
1184+
1185+#. module: base_custom_attributes
1186+#: view:attribute.group:0
1187+#: field:attribute.location,attribute_group_id:0
1188+#: model:ir.model,name:base_custom_attributes.model_attribute_group
1189+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_location_attribute_group_id
1190+msgid "Attribute Group"
1191+msgstr "Groupe d'attributs"
1192+
1193+#. module: base_custom_attributes
1194+#: view:attribute.group:0
1195+#: model:ir.model,name:base_custom_attributes.model_attribute_location
1196+msgid "Attribute Location"
1197+msgstr "Attribute Location"
1198+
1199+#. module: base_custom_attributes
1200+#: code:addons/base_custom_attributes/custom_attributes.py:154
1201+#: view:attribute.option.wizard:0
1202+#, python-format
1203+msgid "Options Wizard"
1204+msgstr "Options Wizard"
1205+
1206+#. module: base_custom_attributes
1207+#: view:attribute.group:0
1208+msgid "Search Attribute Groups"
1209+msgstr "Rechercher des groupes d'attributs"
1210+
1211+#. module: base_custom_attributes
1212+#: field:attribute.attribute,attribute_type:0
1213+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_attribute_attribute_type
1214+msgid "Type"
1215+msgstr "Type"
1216+
1217+#. module: base_custom_attributes
1218+#: field:attribute.set,attribute_group_ids:0
1219+#: model:ir.actions.act_window,name:base_custom_attributes.attribute_group_form_action
1220+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_set_attribute_group_ids
1221+#: model:ir.ui.menu,name:base_custom_attributes.menu_attribute_group_action
1222+msgid "Attribute Groups"
1223+msgstr "Groupes d'attributs"
1224+
1225+#. module: base_custom_attributes
1226+#: field:attribute.attribute,create_date:0
1227+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_attribute_create_date
1228+msgid "Created date"
1229+msgstr "Date de création"
1230+
1231+#. module: base_custom_attributes
1232+#: view:attribute.set:0
1233+msgid "Search Attribute Sets"
1234+msgstr "Rechercher des jeux d'attributs"
1235+
1236+#. module: base_custom_attributes
1237+#: view:attribute.option:0
1238+#: model:ir.model,name:base_custom_attributes.model_attribute_option
1239+msgid "Attribute Option"
1240+msgstr "Option d'attribut"
1241+
1242+#. module: base_custom_attributes
1243+#: selection:attribute.attribute,attribute_type:0
1244+msgid "Date"
1245+msgstr "Date"
1246+
1247+#. module: base_custom_attributes
1248+#: help:attribute.attribute,required_on_views:0
1249+msgid "If activated, the attribute will be mandatory on the views, but not in the database"
1250+msgstr "Si activé, l'attribut sera obligatoire dans les vues, mais pas dans la base de données."
1251+
1252+#. module: base_custom_attributes
1253+#: field:attribute.attribute,field_id:0
1254+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_attribute_field_id
1255+msgid "Ir Model Fields"
1256+msgstr "Ir Model Fields"
1257+
1258+#. module: base_custom_attributes
1259+#: view:attribute.option.wizard:0
1260+msgid "options_placeholder"
1261+msgstr "options_placeholder"
1262+
1263+#. module: base_custom_attributes
1264+#: field:attribute.group,name:0
1265+#: field:attribute.option,name:0
1266+#: field:attribute.set,name:0
1267+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_group_name
1268+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_option_name
1269+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_set_name
1270+msgid "Name"
1271+msgstr "Nom"
1272+
1273+#. module: base_custom_attributes
1274+#: help:attribute.attribute,serialized:0
1275+msgid "If serialized, the field will be stocked in the serialized field: attribute_custom_tmpl or attribute_custom_variant depending on the field based_on"
1276+msgstr "Si serialisé, le champ sera stocké dans un champ serialisé : attribute_custom_tmpl ou attribut_custom_variant selon la valeur du champ based_on"
1277+
1278+#. module: base_custom_attributes
1279+#: field:attribute.attribute,required_on_views:0
1280+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_attribute_required_on_views
1281+msgid "Required (on views)"
1282+msgstr "Obligatoire (dans les vues)"
1283+
1284+#. module: base_custom_attributes
1285+#: model:ir.model,name:base_custom_attributes.model_ir_model_fields
1286+msgid "Fields"
1287+msgstr "Champs"
1288+
1289+#. module: base_custom_attributes
1290+#: view:attribute.attribute:0
1291+#: field:attribute.attribute,option_ids:0
1292+#: model:ir.actions.act_window,name:base_custom_attributes.attribute_option_form_action
1293+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_attribute_option_ids
1294+#: model:ir.ui.menu,name:base_custom_attributes.menu_attribute_option_action
1295+msgid "Attribute Options"
1296+msgstr "Options d'attribut"
1297+
1298+#. module: base_custom_attributes
1299+#: field:attribute.attribute,serialized:0
1300+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_attribute_serialized
1301+msgid "Field serialized"
1302+msgstr "Champ serialisé"
1303+
1304+#. module: base_custom_attributes
1305+#: code:addons/base_custom_attributes/custom_attributes.py:44
1306+#, python-format
1307+msgid "Error!"
1308+msgstr "Erreur !"
1309+
1310+#. module: base_custom_attributes
1311+#: view:attribute.option.wizard:0
1312+msgid "Validate"
1313+msgstr "Valider"
1314+
1315+#. module: base_custom_attributes
1316+#: selection:attribute.attribute,attribute_type:0
1317+msgid "Multiselect"
1318+msgstr "Multiselect"
1319+
1320+#. module: base_custom_attributes
1321+#: view:attribute.option:0
1322+msgid "Search Attribute Options"
1323+msgstr "Rechercher des options d'attribut"
1324+
1325+#. module: base_custom_attributes
1326+#: selection:attribute.attribute,attribute_type:0
1327+msgid "Integer"
1328+msgstr "Integer"
1329+
1330+#. module: base_custom_attributes
1331+#: field:attribute.group,attribute_ids:0
1332+#: model:ir.actions.act_window,name:base_custom_attributes.attribute_attribute_form_action
1333+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_group_attribute_ids
1334+#: model:ir.ui.menu,name:base_custom_attributes.menu_attribute_attribute_action
1335+#: model:ir.ui.menu,name:base_custom_attributes.menu_attribute_in_admin
1336+msgid "Attributes"
1337+msgstr "Attributs"
1338+
1339+#. module: base_custom_attributes
1340+#: field:attribute.attribute,relation_model_id:0
1341+#: field:attribute.group,model_id:0
1342+#: field:attribute.set,model_id:0
1343+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_attribute_relation_model_id
1344+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_group_model_id
1345+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_set_model_id
1346+msgid "Model"
1347+msgstr "Modèle"
1348+
1349+#. module: base_custom_attributes
1350+#: model:ir.actions.act_window,name:base_custom_attributes.attribute_set_form_action
1351+#: model:ir.ui.menu,name:base_custom_attributes.menu_attribute_set_action
1352+msgid "Attribute Sets"
1353+msgstr "Jeux d'attributs"
1354+
1355+#. module: base_custom_attributes
1356+#: view:attribute.attribute:0
1357+msgid "Load Options"
1358+msgstr "Charger les options"
1359+
1360+#. module: base_custom_attributes
1361+#: field:attribute.option,value_ref:0
1362+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_option_value_ref
1363+msgid "Reference"
1364+msgstr "Référence"
1365+
1366+#. module: base_custom_attributes
1367+#: field:attribute.group,sequence:0
1368+#: field:attribute.location,sequence:0
1369+#: field:attribute.option,sequence:0
1370+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_group_sequence
1371+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_location_sequence
1372+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_option_sequence
1373+msgid "Sequence"
1374+msgstr "Séquence"
1375+
1376+#. module: base_custom_attributes
1377+#: view:attribute.attribute:0
1378+#: field:attribute.location,attribute_id:0
1379+#: field:attribute.option,attribute_id:0
1380+#: field:attribute.option.wizard,attribute_id:0
1381+#: model:ir.model,name:base_custom_attributes.model_attribute_attribute
1382+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_location_attribute_id
1383+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_option_attribute_id
1384+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_option_wizard_attribute_id
1385+msgid "Attribute"
1386+msgstr "Attribut"
1387+
1388+#. module: base_custom_attributes
1389+#: selection:attribute.attribute,attribute_type:0
1390+msgid "Float"
1391+msgstr "Float"
1392+
1393+#. module: base_custom_attributes
1394+#: field:attribute.group,attribute_set_id:0
1395+#: field:attribute.location,attribute_set_id:0
1396+#: view:attribute.set:0
1397+#: model:ir.model,name:base_custom_attributes.model_attribute_set
1398+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_group_attribute_set_id
1399+#: model:ir.model.fields,field_description:base_custom_attributes.field_attribute_location_attribute_set_id
1400+msgid "Attribute Set"
1401+msgstr "Jeux d'attributs"
1402+
1403+#. module: base_custom_attributes
1404+#: selection:attribute.attribute,attribute_type:0
1405+msgid "Datetime"
1406+msgstr "Datetime"
1407+
1408+#. module: base_custom_attributes
1409+#: selection:attribute.attribute,attribute_type:0
1410+msgid "Char"
1411+msgstr "Char"
1412+
1413+#. module: base_custom_attributes
1414+#: selection:attribute.attribute,attribute_type:0
1415+msgid "Boolean"
1416+msgstr "Boolean"
1417+
1418+#. module: base_custom_attributes
1419+#: selection:attribute.attribute,attribute_type:0
1420+msgid "Text"
1421+msgstr "Text"
1422+
1423+#. module: base_custom_attributes
1424+#: view:attribute.option.wizard:0
1425+msgid "Cancel"
1426+msgstr "Annuler"
1427+
1428+#. module: base_custom_attributes
1429+#: model:ir.model,name:base_custom_attributes.model_attribute_option_wizard
1430+msgid "attribute.option.wizard"
1431+msgstr "attribute.option.wizard"
1432+
1433+#. module: base_custom_attributes
1434+#: sql_constraint:ir.model.fields:0
1435+msgid "The name of the field has to be uniq for a given model !"
1436+msgstr "Le nom du champ doit être unique pour un modèle donné !"
1437+
1438+#. module: base_custom_attributes
1439+#: selection:attribute.attribute,attribute_type:0
1440+msgid "Select"
1441+msgstr "Select"
1442+
1443
1444=== added file 'base_custom_attributes/ir_model.py'
1445--- base_custom_attributes/ir_model.py 1970-01-01 00:00:00 +0000
1446+++ base_custom_attributes/ir_model.py 2013-12-11 14:54:36 +0000
1447@@ -0,0 +1,39 @@
1448+# -*- encoding: utf-8 -*-
1449+###############################################################################
1450+# #
1451+# product_custom_attributes for OpenERP
1452+# Copyright (C) 2011 Akretion Benoît GUILLOT <benoit.guillot@akretion.com>
1453+# #
1454+# This program is free software: you can redistribute it and/or modify #
1455+# it under the terms of the GNU Affero General Public License as #
1456+# published by the Free Software Foundation, either version 3 of the #
1457+# License, or (at your option) any later version. #
1458+# #
1459+# This program is distributed in the hope that it will be useful, #
1460+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
1461+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
1462+# GNU Affero General Public License for more details. #
1463+# #
1464+# You should have received a copy of the GNU Affero General Public License #
1465+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
1466+# #
1467+###############################################################################
1468+
1469+from openerp.osv.orm import Model
1470+from openerp.osv import fields
1471+
1472+
1473+class ir_model_fields(Model):
1474+
1475+ _inherit = "ir.model.fields"
1476+ _columns = {
1477+ 'field_description': fields.char(
1478+ 'Field Label',
1479+ required=True,
1480+ size=256,
1481+ translate=True),
1482+ }
1483+ _sql_constraints = [
1484+ ('name_model_uniq', 'unique (name, model_id)',
1485+ 'The name of the field has to be uniq for a given model !'),
1486+ ]
1487
1488=== added directory 'base_custom_attributes/security'
1489=== added file 'base_custom_attributes/security/attribute_security.xml'
1490--- base_custom_attributes/security/attribute_security.xml 1970-01-01 00:00:00 +0000
1491+++ base_custom_attributes/security/attribute_security.xml 2013-12-11 14:54:36 +0000
1492@@ -0,0 +1,11 @@
1493+<?xml version="1.0" encoding="utf-8"?>
1494+<openerp>
1495+<data noupdate="0">
1496+
1497+ <record id="base.group_advanced_attribute" model="res.groups">
1498+ <field name="name">Advanced Attribute Option</field>
1499+ <field name="category_id" ref="base.module_category_hidden"/>
1500+ </record>
1501+
1502+</data>
1503+</openerp>
1504
1505=== added file 'base_custom_attributes/security/ir.model.access.csv'
1506--- base_custom_attributes/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
1507+++ base_custom_attributes/security/ir.model.access.csv 2013-12-11 14:54:36 +0000
1508@@ -0,0 +1,13 @@
1509+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
1510+access_base_custom_attributes_attribute_group_salemanager,base_custom_attributes_attribute_group,base_custom_attributes.model_attribute_group,base.group_sale_manager,1,1,1,1
1511+access_base_custom_attributes_attribute_attribute_salemanager,base_custom_attributes_product_attribute,base_custom_attributes.model_attribute_attribute,base.group_sale_manager,1,1,1,1
1512+access_base_custom_attributes_attribute_option_salemanager,base_custom_attributes_attribute_option,base_custom_attributes.model_attribute_option,base.group_sale_manager,1,1,1,1
1513+access_base_custom_attributes_attribute_location_salemanager,base_custom_attributes_attribute_location,base_custom_attributes.model_attribute_location,base.group_sale_manager,1,1,1,1
1514+access_base_custom_attributes_attribute_group_manager,base_custom_attributes_attribute_group,base_custom_attributes.model_attribute_group,base.group_no_one,1,1,1,1
1515+access_base_custom_attributes_attribute_attribute_manager,base_custom_attributes_attribute_attribute,base_custom_attributes.model_attribute_attribute,base.group_no_one,1,1,1,1
1516+access_base_custom_attributes_attribute_option_manager,base_custom_attributes_attribute_option,base_custom_attributes.model_attribute_option,base.group_no_one,1,1,1,1
1517+access_base_custom_attributes_attribute_location_manager,base_custom_attributes_attribute_location,base_custom_attributes.model_attribute_location,base.group_no_one,1,1,1,1
1518+access_base_custom_attributes_attribute_group_user,base_custom_attributes_attribute_group,base_custom_attributes.model_attribute_group,base.group_user,1,0,0,0
1519+access_base_custom_attributes_attribute_attribute_user,base_custom_attributes_attribute_attribute,base_custom_attributes.model_attribute_attribute,base.group_user,1,0,0,0
1520+access_base_custom_attributes_attribute_option_user,base_custom_attributes_attribute_option,base_custom_attributes.model_attribute_option,base.group_user,1,0,0,0
1521+access_base_custom_attributes_attribute_location_user,base_custom_attributes_attribute_location,base_custom_attributes.model_attribute_location,base.group_user,1,1,1,0
1522
1523=== added directory 'production_lot_custom_attributes'
1524=== added file 'production_lot_custom_attributes/__init__.py'
1525--- production_lot_custom_attributes/__init__.py 1970-01-01 00:00:00 +0000
1526+++ production_lot_custom_attributes/__init__.py 2013-12-11 14:54:36 +0000
1527@@ -0,0 +1,25 @@
1528+# -*- coding: utf-8 -*-
1529+###############################################################################
1530+# #
1531+# Author: Leonardo Pistone <leonardo.pistone@camptocamp.com> #
1532+# Copyright 2013 Camptocamp SA #
1533+# #
1534+# Inspired by the module product_custom_attributes #
1535+# by Benoît GUILLOT <benoit.guillot@akretion.com>, Akretion #
1536+# #
1537+# This program is free software: you can redistribute it and/or modify #
1538+# it under the terms of the GNU Affero General Public License as #
1539+# published by the Free Software Foundation, either version 3 of the #
1540+# License, or (at your option) any later version. #
1541+# #
1542+# This program is distributed in the hope that it will be useful, #
1543+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
1544+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
1545+# GNU Affero General Public License for more details. #
1546+# #
1547+# You should have received a copy of the GNU Affero General Public License #
1548+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
1549+# #
1550+###############################################################################
1551+from . import lot
1552+from . import wizard
1553
1554=== added file 'production_lot_custom_attributes/__openerp__.py'
1555--- production_lot_custom_attributes/__openerp__.py 1970-01-01 00:00:00 +0000
1556+++ production_lot_custom_attributes/__openerp__.py 2013-12-11 14:54:36 +0000
1557@@ -0,0 +1,62 @@
1558+# -*- coding: utf-8 -*-
1559+###############################################################################
1560+# #
1561+# Author: Leonardo Pistone <leonardo.pistone@camptocamp.com> #
1562+# Copyright 2013 Camptocamp SA #
1563+# #
1564+# Inspired by the module product_custom_attributes #
1565+# by Benoît GUILLOT <benoit.guillot@akretion.com>, Akretion #
1566+# #
1567+# This program is free software: you can redistribute it and/or modify #
1568+# it under the terms of the GNU Affero General Public License as #
1569+# published by the Free Software Foundation, either version 3 of the #
1570+# License, or (at your option) any later version. #
1571+# #
1572+# This program is distributed in the hope that it will be useful, #
1573+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
1574+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
1575+# GNU Affero General Public License for more details. #
1576+# #
1577+# You should have received a copy of the GNU Affero General Public License #
1578+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
1579+# #
1580+###############################################################################
1581+
1582+{'name': 'production_lot_custom_attributes',
1583+ 'version': '0.1',
1584+ 'category': 'Generic Modules/Others',
1585+ 'license': 'AGPL-3',
1586+ 'description': """
1587+Production lot custom attributes
1588+================================
1589+
1590+This module adds the possibility to easily create custom fields on stock
1591+production lots. Each lot can be linked to an attribute set.
1592+Each attribute has custom fields (for example, you don't need the same field
1593+for a frigde and a camera).
1594+In particular it's used by the Magento Magentoerpconnect module to match the
1595+EAV flexibility of Magento.
1596+
1597+Warning: This module is not compatible with product_custom_attributes from 6.1.
1598+To make the two compatible, product_custom_attributes should be split to depend
1599+from base_custom_attributes, like it is already in 7.0.
1600+
1601+This module is inspired by the module product_custom_attributes by
1602+Benoît GUILLOT, Akretion
1603+
1604+""",
1605+ 'complexity': 'normal',
1606+ 'author': 'Camptocamp',
1607+ 'website': 'http://www.camptocamp.com/',
1608+ 'depends': ['stock', 'base_custom_attributes'],
1609+ 'init_xml': [],
1610+ 'update_xml': ['lot_view.xml',
1611+ 'custom_attributes_view.xml',
1612+ 'wizard/open_lot_by_attribute_set.xml'
1613+ ],
1614+ 'test': ['test/lot_attribute_test.yml',
1615+ ],
1616+ 'demo_xml': [],
1617+ 'installable': True,
1618+ 'active': False,
1619+ }
1620
1621=== added file 'production_lot_custom_attributes/custom_attributes_view.xml'
1622--- production_lot_custom_attributes/custom_attributes_view.xml 1970-01-01 00:00:00 +0000
1623+++ production_lot_custom_attributes/custom_attributes_view.xml 2013-12-11 14:54:36 +0000
1624@@ -0,0 +1,58 @@
1625+<?xml version="1.0" encoding="utf-8"?>
1626+<openerp>
1627+ <data>
1628+
1629+ <menuitem
1630+ id="menu_lot_attribute_in_warehouse_config"
1631+ name="Serial Number Attributes"
1632+ parent="stock.menu_warehouse_config"
1633+ sequence="20"/>
1634+
1635+ <record id="lot_attribute_set_form_action" model="ir.actions.act_window">
1636+ <field name="name">Lot Attribute Sets</field>
1637+ <field name="res_model">attribute.set</field>
1638+ <field name="view_type">form</field>
1639+ <field name="view_mode">tree,form</field>
1640+ <field name="search_view_id" ref="base_custom_attributes.view_attribute_set_search"/>
1641+ <field name="context">{"force_model": 'stock.production.lot'}</field>
1642+ <field name="help"></field>
1643+ </record>
1644+
1645+ <record id="lot_attribute_group_form_action" model="ir.actions.act_window">
1646+ <field name="name">Attribute Groups</field>
1647+ <field name="res_model">attribute.group</field>
1648+ <field name="view_type">form</field>
1649+ <field name="view_mode">tree,form</field>
1650+ <field name="search_view_id" ref="base_custom_attributes.view_attribute_attribute_search"/>
1651+ <field name="context">{"force_model": 'stock.production.lot'}</field>
1652+ <field name="help"></field>
1653+ </record>
1654+
1655+ <record id="lot_attribute_attribute_form_action" model="ir.actions.act_window">
1656+ <field name="name">Lot Attributes</field>
1657+ <field name="res_model">attribute.attribute</field>
1658+ <field name="view_type">form</field>
1659+ <field name="view_mode">tree,form</field>
1660+ <field name="search_view_id" ref="base_custom_attributes.view_attribute_attribute_search"/>
1661+ <field name="context">{"force_model": 'stock.production.lot'}</field>
1662+ <field name="help"></field>
1663+ </record>
1664+
1665+ <menuitem
1666+ action="lot_attribute_set_form_action"
1667+ id="menu_lot_attribute_set_action"
1668+ parent="menu_lot_attribute_in_warehouse_config"
1669+ sequence="1"/>
1670+ <menuitem
1671+ action="lot_attribute_group_form_action"
1672+ id="menu_lot_attribute_group_action"
1673+ parent="menu_lot_attribute_in_warehouse_config"
1674+ sequence="2"/>
1675+ <menuitem
1676+ action="lot_attribute_attribute_form_action"
1677+ id="menu_lot_attribute_attribute_action"
1678+ parent="menu_lot_attribute_in_warehouse_config"
1679+ sequence="4"/>
1680+
1681+ </data>
1682+</openerp>
1683
1684=== added file 'production_lot_custom_attributes/lot.py'
1685--- production_lot_custom_attributes/lot.py 1970-01-01 00:00:00 +0000
1686+++ production_lot_custom_attributes/lot.py 2013-12-11 14:54:36 +0000
1687@@ -0,0 +1,207 @@
1688+# -*- coding: utf-8 -*-
1689+###############################################################################
1690+# #
1691+# Author: Leonardo Pistone <leonardo.pistone@camptocamp.com> #
1692+# Copyright 2013 Camptocamp SA #
1693+# #
1694+# Inspired by the module product_custom_attributes #
1695+# by Benoît GUILLOT <benoit.guillot@akretion.com>, Akretion #
1696+# #
1697+# This program is free software: you can redistribute it and/or modify #
1698+# it under the terms of the GNU Affero General Public License as #
1699+# published by the Free Software Foundation, either version 3 of the #
1700+# License, or (at your option) any later version. #
1701+# #
1702+# This program is distributed in the hope that it will be useful, #
1703+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
1704+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
1705+# GNU Affero General Public License for more details. #
1706+# #
1707+# You should have received a copy of the GNU Affero General Public License #
1708+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
1709+# #
1710+###############################################################################
1711+
1712+from openerp.osv import fields, osv
1713+from tools.translate import _
1714+from lxml import etree
1715+import re
1716+
1717+
1718+class stock_production_lot(osv.Model):
1719+ _inherit = "stock.production.lot"
1720+
1721+ def _search_all_attributes(self, cr, uid, obj, name, args, context):
1722+ """Search in all serialized attributes
1723+
1724+ Receives a domain in args, and expands all relevant terms into ids
1725+ to search into all attributes. The ORM will take care of security
1726+ afterwards, so it' OK to use SQL here.
1727+
1728+ In the future, we could consider storing attributes as native PostgreSQL
1729+ hstore or JSON instead of strings, and substitute this rough regexp
1730+ search with native PostgreSQL goodness.
1731+
1732+ """
1733+
1734+ def expand_arg(arg):
1735+ """Takes a single argument of the domain, and when possible expands
1736+ it to a trivial domain ('in', 'in', list)
1737+
1738+ """
1739+ if isinstance(arg, tuple) and arg[0] == name:
1740+ if arg[1] == 'like':
1741+ operator = '~'
1742+ elif arg[1] == 'ilike':
1743+ operator = '~*'
1744+ else:
1745+ raise osv.except_osv(
1746+ _('Not Implemented!'),
1747+ _('Search not supported for this field'))
1748+
1749+ cr.execute(
1750+ """
1751+ select id
1752+ from {0}
1753+ where x_custom_json_attrs {1} %s;
1754+ """.format(
1755+ self._table,
1756+ operator
1757+ ),
1758+ (ur'.*: "[^"]*%s' % re.escape(arg[2]) ,)
1759+ )
1760+ sql_ids = [line[0] for line in cr.fetchall()]
1761+ return ('id', 'in', sql_ids)
1762+ else:
1763+ return arg
1764+
1765+ return [expand_arg(arg) for arg in args]
1766+
1767+ _columns = {
1768+ 'attribute_set_id': fields.many2one('attribute.set', 'Attribute Set'),
1769+ 'attribute_group_ids': fields.related(
1770+ 'attribute_set_id',
1771+ 'attribute_group_ids',
1772+ type='many2many',
1773+ relation='attribute.group'
1774+ ),
1775+ 'search_all_attributes': fields.function(
1776+ lambda self, cr, uid, ids, field, args, context: u'',
1777+ type="char",
1778+ fnct_search=_search_all_attributes,
1779+ method=True,
1780+ string="Search all Attributes"),
1781+ }
1782+
1783+ def _fix_size_bug(self, cr, uid, result, context=None):
1784+ """When created a field text dynamicaly, its size is limited to 64 in
1785+ the view. The bug is fixed but not merged
1786+ https://code.launchpad.net/~openerp-dev/openerp-web/6.1-opw-579462-cpa
1787+ To remove when the fix will be merged
1788+
1789+ """
1790+ for field in result['fields']:
1791+ if result['fields'][field]['type'] == 'text':
1792+ if 'size' in result['fields'][field]:
1793+ del result['fields'][field]['size']
1794+ return result
1795+
1796+ def open_attributes(self, cr, uid, ids, context=None):
1797+ """Open the attributes of an object
1798+
1799+ This method is called when the user presses the Open Attributes button
1800+ in the form view of the object. It opens a dinamically-built form view.
1801+
1802+ :param ids: this is normally a singleton. If a longer list is passed,
1803+ we consider only the first item.
1804+
1805+ """
1806+
1807+ if context is None:
1808+ context = {}
1809+
1810+ model_data_pool = self.pool.get('ir.model.data')
1811+
1812+ for lot in self.browse(cr, uid, ids, context=context):
1813+ view_id = model_data_pool.get_object_reference(
1814+ cr, uid,
1815+ 'production_lot_custom_attributes',
1816+ 'lot_attributes_form_view')[1]
1817+ ctx = {
1818+ 'open_attributes': True,
1819+ 'attribute_group_ids': [
1820+ group.id for group in lot.attribute_group_ids
1821+ ]
1822+ }
1823+
1824+ return {
1825+ 'name': 'Lot Attributes',
1826+ 'view_type': 'form',
1827+ 'view_mode': 'form',
1828+ 'view_id': [view_id],
1829+ 'res_model': self._name,
1830+ 'context': ctx,
1831+ 'type': 'ir.actions.act_window',
1832+ 'nodestroy': True,
1833+ 'target': 'new',
1834+ 'res_id': lot.id,
1835+ }
1836+
1837+ def save_and_close_lot_attributes(self, cr, uid, ids, context=None):
1838+ return {'type': 'ir.actions.act_window_close'}
1839+
1840+ def fields_view_get(self, cr, uid, view_id=None, view_type='form',
1841+ context=None, toolbar=False, submenu=False):
1842+ """Dinamically adds attributes to the view
1843+
1844+ Modifies dinamically the view to show the attributes. If the users
1845+ presses the Open Attributes button, the attributes are shown in a
1846+ new form field. Otherwise, if the attribute set is known beforehand,
1847+ attributes are added to a new tab in the main form view.
1848+
1849+ """
1850+ if context is None:
1851+ context = {}
1852+ attr_pool = self.pool.get('attribute.attribute')
1853+ result = super(stock_production_lot, self).fields_view_get(
1854+ cr, uid, view_id, view_type, context, toolbar=toolbar,
1855+ submenu=submenu
1856+ )
1857+ if view_type == 'form' and context.get('attribute_group_ids'):
1858+ eview = etree.fromstring(result['arch'])
1859+ #hide button under the name
1860+ button = eview.xpath("//button[@name='open_attributes']")
1861+ if button:
1862+ button = button[0]
1863+ button.getparent().remove(button)
1864+ attributes_notebook, toupdate_fields = (
1865+ attr_pool._build_attributes_notebook(
1866+ cr, uid, context['attribute_group_ids'], context=context
1867+ )
1868+ )
1869+ result['fields'].update(
1870+ self.fields_get(cr, uid, toupdate_fields, context)
1871+ )
1872+ if context.get('open_attributes'):
1873+ # i.e. the user pressed the open attributes button on the
1874+ # form view. We put the attributes in a separate form view
1875+ placeholder = eview.xpath(
1876+ "//separator[@string='attributes_placeholder']"
1877+ )[0]
1878+ placeholder.getparent().replace(
1879+ placeholder, attributes_notebook
1880+ )
1881+ elif context.get('open_lot_by_attribute_set'):
1882+ # in this case, we know the attribute set beforehand, and we
1883+ # add the attributes to the current view
1884+ main_page = etree.Element(
1885+ 'page', string=_('Custom Attributes')
1886+ )
1887+ main_page.append(attributes_notebook)
1888+ info_page = eview.xpath(
1889+ "//page[@string='%s']" % (_('Stock Moves'),)
1890+ )[0]
1891+ info_page.addnext(main_page)
1892+ result['arch'] = etree.tostring(eview, pretty_print=True)
1893+ result = self._fix_size_bug(cr, uid, result, context=context)
1894+ return result
1895
1896=== added file 'production_lot_custom_attributes/lot_view.xml'
1897--- production_lot_custom_attributes/lot_view.xml 1970-01-01 00:00:00 +0000
1898+++ production_lot_custom_attributes/lot_view.xml 2013-12-11 14:54:36 +0000
1899@@ -0,0 +1,52 @@
1900+<?xml version="1.0" encoding="utf-8"?>
1901+
1902+<openerp>
1903+ <data>
1904+
1905+ <record model="ir.ui.view" id="lot_form_view_set_button">
1906+ <field name="name">attributes.lot.normal.form</field>
1907+ <field name="model">stock.production.lot</field>
1908+ <field name="inherit_id" ref="stock.view_production_lot_form"/>
1909+ <field name="arch" type="xml">
1910+ <notebook position="inside">
1911+ <page string="Attributes">
1912+ <group name="attribute_fields">
1913+ <field name="attribute_set_id" />
1914+ <button name="open_attributes" string="Open Attributes" type="object" icon="gtk-ok" attrs="{'invisible':[('attribute_set_id', '=', False)]}"/>
1915+ </group>
1916+ </page>
1917+ </notebook>
1918+ </field>
1919+ </record>
1920+
1921+ <record model="ir.ui.view" id="search_product_lot_filter">
1922+ <field name="model">stock.production.lot</field>
1923+ <field name="inherit_id" ref="stock.search_product_lot_filter"/>
1924+ <field name="arch" type="xml">
1925+ <field name="date" position="after">
1926+ <field name="search_all_attributes"/>
1927+ </field>
1928+ </field>
1929+ </record>
1930+
1931+ <record model="ir.ui.view" id="lot_attributes_form_view">
1932+ <field name="name">lot.attributes.normal.wizard</field>
1933+ <field name="model">stock.production.lot</field>
1934+ <field name="priority">20</field>
1935+ <field name="arch" type="xml">
1936+ <form string="Lot">
1937+ <group name="name_set" colspan='4' col='8'>
1938+ <field name="name"/>
1939+ <field name="attribute_set_id" />
1940+ </group>
1941+ <separator string="attributes_placeholder" colspan="4"/>
1942+ <group colspan='4' col='4'>
1943+ <button icon="gtk-cancel" special="cancel" string="Cancel"/>
1944+ <button icon="gtk-ok" name="save_and_close_lot_attributes" string="Save and Close" type="object"/>
1945+ </group>
1946+ </form>
1947+ </field>
1948+ </record>
1949+
1950+ </data>
1951+</openerp>
1952
1953=== added directory 'production_lot_custom_attributes/test'
1954=== added file 'production_lot_custom_attributes/test/lot_attribute_test.yml'
1955--- production_lot_custom_attributes/test/lot_attribute_test.yml 1970-01-01 00:00:00 +0000
1956+++ production_lot_custom_attributes/test/lot_attribute_test.yml 2013-12-11 14:54:36 +0000
1957@@ -0,0 +1,48 @@
1958+-
1959+ In order to test Production Lot Custom Fields
1960+-
1961+ First I create an Attribute Set
1962+-
1963+ !record {model: attribute.set, id: lot_attribute_set_A}:
1964+ name: Serial Number Attribute Set A
1965+ model_id: stock.model_stock_production_lot
1966+ attribute_group_ids:
1967+ - name: Components
1968+ model_id: stock.model_stock_production_lot
1969+ sequence: 1
1970+ attribute_ids:
1971+ - name: x_ram_amount
1972+ model_id: stock.model_stock_production_lot
1973+ field_description: Amount of RAM
1974+ attribute_type: float
1975+ - name: x_has_display
1976+ model_id: stock.model_stock_production_lot
1977+ field_description: Has Display
1978+ attribute_type: boolean
1979+ - name: Characteristics
1980+ model_id: stock.model_stock_production_lot
1981+ sequence: 2
1982+ attribute_ids:
1983+ - name: x_color
1984+ model_id: stock.model_stock_production_lot
1985+ field_description: Color
1986+ attribute_type: char
1987+ - name: x_length
1988+ model_id: stock.model_stock_production_lot
1989+ field_description: Length
1990+ attribute_type: float
1991+-
1992+ Then I create a Serial Number and set some Attributes
1993+-
1994+ !record {model: stock.production.lot, id: lot_A}:
1995+ product_id: product.product_product_pc2
1996+ name: 0005
1997+ attribute_set_id: lot_attribute_set_A
1998+ x_color: green
1999+ x_length: 12.5
2000+-
2001+ Now I check that my attributes are there
2002+-
2003+ !assert {model: stock.production.lot, id: lot_A, string: Lot Attributes do not work}:
2004+ - x_color == 'green'
2005+ - x_length == 12.5
2006
2007=== added directory 'production_lot_custom_attributes/wizard'
2008=== added file 'production_lot_custom_attributes/wizard/__init__.py'
2009--- production_lot_custom_attributes/wizard/__init__.py 1970-01-01 00:00:00 +0000
2010+++ production_lot_custom_attributes/wizard/__init__.py 2013-12-11 14:54:36 +0000
2011@@ -0,0 +1,25 @@
2012+# -*- coding: utf-8 -*-
2013+###############################################################################
2014+# #
2015+# Author: Leonardo Pistone <leonardo.pistone@camptocamp.com> #
2016+# Copyright 2013 Camptocamp SA #
2017+# #
2018+# Inspired by the module product_custom_attributes #
2019+# by Benoît GUILLOT <benoit.guillot@akretion.com>, Akretion #
2020+# #
2021+# This program is free software: you can redistribute it and/or modify #
2022+# it under the terms of the GNU Affero General Public License as #
2023+# published by the Free Software Foundation, either version 3 of the #
2024+# License, or (at your option) any later version. #
2025+# #
2026+# This program is distributed in the hope that it will be useful, #
2027+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
2028+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
2029+# GNU Affero General Public License for more details. #
2030+# #
2031+# You should have received a copy of the GNU Affero General Public License #
2032+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
2033+# #
2034+###############################################################################
2035+
2036+from . import open_lot_by_attribute_set
2037
2038=== added file 'production_lot_custom_attributes/wizard/open_lot_by_attribute_set.py'
2039--- production_lot_custom_attributes/wizard/open_lot_by_attribute_set.py 1970-01-01 00:00:00 +0000
2040+++ production_lot_custom_attributes/wizard/open_lot_by_attribute_set.py 2013-12-11 14:54:36 +0000
2041@@ -0,0 +1,67 @@
2042+# -*- coding: utf-8 -*-
2043+###############################################################################
2044+# #
2045+# Author: Leonardo Pistone <leonardo.pistone@camptocamp.com> #
2046+# Copyright 2013 Camptocamp SA #
2047+# #
2048+# This program is free software: you can redistribute it and/or modify #
2049+# it under the terms of the GNU Affero General Public License as #
2050+# published by the Free Software Foundation, either version 3 of the #
2051+# License, or (at your option) any later version. #
2052+# #
2053+# This program is distributed in the hope that it will be useful, #
2054+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
2055+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
2056+# GNU Affero General Public License for more details. #
2057+# #
2058+# You should have received a copy of the GNU Affero General Public License #
2059+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
2060+# #
2061+###############################################################################
2062+
2063+from openerp.osv.orm import TransientModel
2064+from osv import fields
2065+
2066+
2067+class open_lot_by_attribute_set(TransientModel):
2068+ _name = 'open.lot.by.attribute.set'
2069+ _description = 'Wizard to open lots by attributes set'
2070+
2071+ _columns = {
2072+ 'attribute_set_id': fields.many2one('attribute.set', 'Attribute Set'),
2073+ }
2074+
2075+ def open_lot_by_attribute(self, cr, uid, ids, context=None):
2076+ """Opens a lot by attributes
2077+
2078+ Returns a custom action built modifying the original one.
2079+ """
2080+
2081+ mod_obj = self.pool.get('ir.model.data')
2082+ act_obj = self.pool.get('ir.actions.act_window')
2083+
2084+ if context is None:
2085+ context = {}
2086+
2087+ # we expect one wizard instance at a time
2088+ for wiz in self.browse(cr, uid, ids, context=context):
2089+ action_id = mod_obj.get_object_reference(
2090+ cr, uid, 'stock', 'action_production_lot_form')[1]
2091+ action = act_obj.read(cr, uid, [action_id], context=context)[0]
2092+
2093+ ctx = (
2094+ "{'open_lot_by_attribute_set': True, "
2095+ "'attribute_group_ids': %s}"
2096+ % [
2097+ group.id
2098+ for group in wiz.attribute_set_id.attribute_group_ids
2099+ ]
2100+ )
2101+
2102+ action['context'] = ctx
2103+ action['domain'] = (
2104+ "[('attribute_set_id', '=', %s)]"
2105+ % wiz.attribute_set_id.id
2106+ )
2107+ action['name'] = wiz.attribute_set_id.name
2108+ return action
2109
2110=== added file 'production_lot_custom_attributes/wizard/open_lot_by_attribute_set.xml'
2111--- production_lot_custom_attributes/wizard/open_lot_by_attribute_set.xml 1970-01-01 00:00:00 +0000
2112+++ production_lot_custom_attributes/wizard/open_lot_by_attribute_set.xml 2013-12-11 14:54:36 +0000
2113@@ -0,0 +1,30 @@
2114+<?xml version="1.0" encoding="utf-8"?>
2115+
2116+<openerp>
2117+ <data>
2118+
2119+ <record id="open_lot_by_attribute_set_view" model="ir.ui.view">
2120+ <field name="name">open.lot.by.attribute.set.view</field>
2121+ <field name="model">open.lot.by.attribute.set</field>
2122+ <field name="arch" type="xml">
2123+ <form string="Open lot by attributes set">
2124+ <field name="attribute_set_id" colspan="4"/>
2125+ <button icon="gtk-cancel" special="cancel" string="Cancel"/>
2126+ <button icon="gtk-ok" name="open_lot_by_attribute" string="Open Product By attribute" type="object"/>
2127+ </form>
2128+ </field>
2129+ </record>
2130+
2131+ <record id="open_lot_by_attribute_set" model="ir.actions.act_window">
2132+ <field name="name">Open lot By Attribute Set</field>
2133+ <field name="res_model">open.lot.by.attribute.set</field>
2134+ <field name="view_type">form</field>
2135+ <field name="target">new</field>
2136+ <field name="view_id" ref="open_lot_by_attribute_set_view"/>
2137+ <field name="help"></field>
2138+ </record>
2139+
2140+ <menuitem action="open_lot_by_attribute_set" id="open_lot_wizard" parent="stock.menu_traceability"/>
2141+
2142+ </data>
2143+</openerp>

Subscribers

People subscribed via source and target branches