Merge lp:~akretion-team/openerp-product-attributes/mixin-extraction into lp:~product-core-editors/openerp-product-attributes/7.0

Proposed by Raphaël Valyi - http://www.akretion.com
Status: Merged
Merged at revision: 206
Proposed branch: lp:~akretion-team/openerp-product-attributes/mixin-extraction
Merge into: lp:~product-core-editors/openerp-product-attributes/7.0
Prerequisite: lp:~akretion-team/openerp-product-attributes/polymorphic-relations
Diff against target: 1225 lines (+560/-341)
14 files modified
base_custom_attributes/__init__.py (+1/-3)
base_custom_attributes/__openerp__.py (+6/-9)
base_custom_attributes/custom_attributes.py (+148/-52)
base_custom_attributes/custom_attributes_view.xml (+171/-226)
base_custom_attributes/security/attribute_security.xml (+11/-0)
base_custom_attributes/security/ir.model.access.csv (+9/-15)
product_categ_attributes/__init__.py (+1/-0)
product_categ_attributes/__openerp__.py (+42/-0)
product_categ_attributes/product.py (+25/-0)
product_categ_attributes/product_view.xml (+52/-0)
product_custom_attributes/__init__.py (+2/-0)
product_custom_attributes/__openerp__.py (+47/-0)
product_custom_attributes/custom_attributes_view.xml (+44/-0)
product_custom_attributes/product.py (+1/-36)
To merge this branch: bzr merge lp:~akretion-team/openerp-product-attributes/mixin-extraction
Reviewer Review Type Date Requested Status
Benoit Guillot - http://www.akretion.com (community) test Approve
Guewen Baconnier @ Camptocamp code review, no test Approve
Raphaël Valyi - http://www.akretion.com Approve
Review via email: mp+151333@code.launchpad.net

Description of the change

See commit messages:
no more code but but code is now split in two modules: product_custom_attributes and base_custom_attributes that can be reused in any OpenERP object (partner, project, production order etc...). That last module may be moved to another branch later if it makes more sense.

To post a comment you must log in.
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

When you build a view yourself, you should call
`openerp.osv.orm.setup_modifiers` on the nodes. (example in
`account.wizard.account_report_common.account_common_report.fields_view_get`).

In your case, I don't think it will change anything, because it setup
the modifiers for `attrs`, `states`, `invisible`, `readonly`, `required`
and you don't use them. But I still think it would be proper to call it.

What do you think?

Nitpickings on the style:
* The indentation of l.170,183,184 is a bit weird.
* l.213,215 spaces around '='

review: Needs Information
Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

Raphael, Guewen, what is the status of this MP ?

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

I'm fine to merge this proposal without changing the nitpickings.
But `openerp.osv.orm.setup_modifiers` has to be called on the fields.
Raphaël, can you just change this please? The merge proposal can then be merged.

By the way, that's really nice to have extracted this behavior from the product models to a generic module.

review: Needs Fixing
Revision history for this message
Raphaël Valyi - http://www.akretion.com (rvalyi) wrote :

Hello will do that as soon as possible (hopefully today), sorry for the
delay.

On Tue, Mar 19, 2013 at 4:49 AM, Guewen Baconnier @ Camptocamp <
<email address hidden>> wrote:

> Review: Needs Fixing
>
> I'm fine to merge this proposal without changing the nitpickings.
> But `openerp.osv.orm.setup_modifiers` has to be called on the fields.
> Raphaël, can you just change this please? The merge proposal can then be
> merged.
>
> By the way, that's really nice to have extracted this behavior from the
> product models to a generic module.
> --
>
> https://code.launchpad.net/~akretion-team/openerp-product-attributes/mixin-extraction/+merge/151333
> Your team OpenERP Community is subscribed to branch
> lp:openerp-product-attributes.
>
> _______________________________________________
> Mailing list: https://launchpad.net/~openerp-community
> Post to : <email address hidden>
> Unsubscribe : https://launchpad.net/~openerp-community
> More help : https://help.launchpad.net/ListHelp
>

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Thanks for the change

review: Approve (code review, no test)
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

I tried to merge lp:~akretion-team/openerp-product-attributes/polymorphic-relations, then this branch, but when I merge this one I have a conflict. Can you check why please?

205. By Raphaël Valyi - http://www.akretion.com

[IMP] Generalization of product_custom_attributes for OpenERP v7. See detailed logs for more information

206. By Sébastien BEAU - http://www.akretion.com

[MERGE] update with stable branch

207. By Sébastien BEAU - http://www.akretion.com

[MERGE] merge view improvement from benoit branch

208. By Sébastien BEAU - http://www.akretion.com

[MERGE] merge Benoit branch for improving view, do some refactor due to the change done in mixing branch

209. By Sébastien BEAU - http://www.akretion.com

[TYPO] no change juste reorganise the code

210. By Sébastien BEAU - http://www.akretion.com

[REF] Continue refactor, move attribut set to abstract module

211. By Sébastien BEAU - http://www.akretion.com

[REF] base_custom_attributes : refcator view and add model on set and group. Now the model of the attrbitue is filtred according to the model selected on the set or the group

212. By Sébastien BEAU - http://www.akretion.com

[REF] continue refactor, now the abstract model base_custom_attributs have some special option like force model, take a look in product_custom_attribut, just add {'force_model': 'our_model'} in the context and the model will be hide and automatically filled

213. By Sébastien BEAU - http://www.akretion.com

[REF] rename custom.attribute into attribute.attribute

214. By Sébastien BEAU - http://www.akretion.com

[IMP] add a special group for advanced option

215. By Sébastien BEAU - http://www.akretion.com

[IMP] base_custom_attribute: if the field have the type multiselect the option serialized is hide as we have no choice and the option have to be selected

216. By Sébastien BEAU - http://www.akretion.com

[FIX] fix error due to previous merge

217. By Sébastien BEAU - http://www.akretion.com

[REF] Remove useless file

Revision history for this message
Sébastien BEAU - http://www.akretion.com (sebastien.beau) wrote :

Hi all
I merge the improvement done by Benoit
https://code.launchpad.net/~akretion-team/openerp-product-attributes/openerp-product-attributes-fix-view/+merge/168461
https://code.launchpad.net/~akretion-team/openerp-product-attributes/openerp-product-attributes-fix-view/+merge/168461

I extract the attribut.set from the product custom module
I added the model on the group and the attibut set and it's propagated.
The model is also correctly filtred on the attributs

And I also did some other view improvement.

Let's merge it ;)

Revision history for this message
Raphaël Valyi - http://www.akretion.com (rvalyi) wrote :

You rock Seb, this is really a pleasure to have this result now. Now we have both the killer ergnomy of product_custom_attributes but enough genericity to use base_custom_attributes as a basis for things like product configurators. I'm really proud of these 2 modules now!

review: Approve
Revision history for this message
Raphaël Valyi - http://www.akretion.com (rvalyi) wrote :

(Just to mention: I both tested and looked at the code)

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

l.78 the import from `tools.translate` should be from `openerp.tools.translate`

once that fixed, I'll be ok for the merge

218. By Sébastien BEAU - http://www.akretion.com

[FIX] fix incorrect importing of translate tools _ Thanks to Guewen

Revision history for this message
Sébastien BEAU - http://www.akretion.com (sebastien.beau) wrote :

Thanks Guewen for your remark. It's fix now.

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Thanks for the change

LGTM

review: Approve (code review, no test)
219. By Benoit Guillot - http://www.akretion.com

[FIX] remove 'product' in base_custom_atributeviews

220. By Benoit Guillot - http://www.akretion.com

[FIX] clean imports, and fix encoding of strings

Revision history for this message
Benoit Guillot - http://www.akretion.com (benoit-guillot-z) wrote :

I made fiew fixes.

review: Approve (test)
Revision history for this message
debaetsr (rubendebaets) wrote :

Hey,

I've read a lovely book recently, the author is admired by everyone, you should read the book too, that's for sure, here is the link <http://score.strtgk.com/e4trfvt>

Sincerely, ruben

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== renamed directory 'product_custom_attributes' => 'base_custom_attributes'
2=== modified file 'base_custom_attributes/__init__.py'
3--- product_custom_attributes/__init__.py 2012-08-03 14:33:51 +0000
4+++ base_custom_attributes/__init__.py 2013-06-18 16:21:29 +0000
5@@ -22,9 +22,7 @@
6
7
8 import ir_model
9-import product_attribute
10-import product
11-import wizard
12+import custom_attributes
13
14
15
16
17=== modified file 'base_custom_attributes/__openerp__.py'
18--- product_custom_attributes/__openerp__.py 2013-02-11 22:58:10 +0000
19+++ base_custom_attributes/__openerp__.py 2013-06-18 16:21:29 +0000
20@@ -1,7 +1,7 @@
21 # -*- encoding: utf-8 -*-
22 ###############################################################################
23 # #
24-# product_custom_attributes for OpenERP #
25+# base_custom_attributes for OpenERP #
26 # Copyright (C) 2011 Akretion Benoît GUILLOT <benoit.guillot@akretion.com> #
27 # #
28 # This program is free software: you can redistribute it and/or modify #
29@@ -22,23 +22,20 @@
30
31
32 {
33- 'name': 'product_custom_attributes',
34+ 'name': 'base_custom_attributes',
35 'version': '0.1',
36 'category': 'Generic Modules/Others',
37 'license': 'AGPL-3',
38- 'description': """This module adds the possibility to easily create custom fields on products.
39-Each product can be linked to an attribute set (like camera, fridge...).
40-Each attribute has custom fields (for example, you don't need the same field for a frigde and a camera).
41+ 'description': """This module adds the possibility to easily create custom attributes in any OpenERP business object. See the product_custom_attributes module for instance.
42 """,
43 'author': 'Akretion',
44 'website': 'http://www.akretion.com/',
45- 'depends': ['product'],
46+ 'depends': ['base'],
47 'init_xml': [],
48 'update_xml': [
49 'security/ir.model.access.csv',
50- 'product_attribute_view.xml',
51- 'product_view.xml',
52- 'wizard/open_product_by_attribute_set.xml',
53+ 'security/attribute_security.xml',
54+ 'custom_attributes_view.xml',
55 ],
56 'demo_xml': [],
57 'installable': True,
58
59=== renamed file 'product_custom_attributes/product_attribute.py' => 'base_custom_attributes/custom_attributes.py'
60--- product_custom_attributes/product_attribute.py 2013-06-13 16:55:06 +0000
61+++ base_custom_attributes/custom_attributes.py 2013-06-18 16:21:29 +0000
62@@ -1,8 +1,9 @@
63 # -*- encoding: utf-8 -*-
64 ###############################################################################
65 # #
66-# product_custom_attributes for OpenERP #
67+# base_attribute.attributes for OpenERP #
68 # Copyright (C) 2011 Akretion Benoît GUILLOT <benoit.guillot@akretion.com> #
69+# Copyright (C) 2013 Akretion Raphaël VALYI <raphael.valyi@akretion.com> #
70 # #
71 # This program is free software: you can redistribute it and/or modify #
72 # it under the terms of the GNU Affero General Public License as #
73@@ -19,13 +20,13 @@
74 # #
75 ###############################################################################
76
77-from openerp.osv import orm
78-from openerp.osv import fields
79+from openerp.osv import orm, fields
80 from openerp.osv.osv import except_osv
81+from openerp.tools.translate import _
82 from lxml import etree
83-from openerp.tools.translate import _
84 from unidecode import unidecode # Debian package python-unidecode
85
86+
87 class attribute_option(orm.Model):
88 _name = "attribute.option"
89 _description = "Attribute Option"
90@@ -34,7 +35,7 @@
91 _columns = {
92 'name': fields.char('Name', size=128, translate=True, required=True),
93 'value_ref': fields.reference('Reference', selection=[], size=128),
94- 'attribute_id': fields.many2one('product.attribute', 'Product Attribute', required=True),
95+ 'attribute_id': fields.many2one('attribute.attribute', 'Product Attribute', required=True),
96 'sequence': fields.integer('Sequence'),
97 }
98
99@@ -45,12 +46,13 @@
100 else:
101 return True
102
103+
104 class attribute_option_wizard(orm.TransientModel):
105 _name = "attribute.option.wizard"
106 _rec_name = 'attribute_id'
107
108 _columns = {
109- 'attribute_id': fields.many2one('product.attribute', 'Product Attribute', required=True),
110+ 'attribute_id': fields.many2one('attribute.attribute', 'Product Attribute', required=True),
111 }
112
113 _defaults = {
114@@ -61,7 +63,7 @@
115 return True
116
117 def create(self, cr, uid, vals, context=None):
118- attr_obj = self.pool.get("product.attribute")
119+ attr_obj = self.pool.get("attribute.attribute")
120 attr = attr_obj.browse(cr, uid, vals['attribute_id'])
121 op_ids = [op.id for op in attr.option_ids]
122 opt_obj = self.pool.get("attribute.option")
123@@ -80,7 +82,7 @@
124 def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
125 res = super(attribute_option_wizard, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar, submenu)
126 if view_type == 'form' and context and context.get("attribute_id"):
127- attr_obj = self.pool.get("product.attribute")
128+ attr_obj = self.pool.get("attribute.attribute")
129 model_id = attr_obj.read(cr, uid, [context.get("attribute_id")], ['relation_model_id'])[0]['relation_model_id'][0]
130 relation = self.pool.get("ir.model").read(cr, uid, [model_id], ["model"])[0]["model"]
131 res['fields'].update({'option_ids': {
132@@ -99,11 +101,47 @@
133 return res
134
135
136-class product_attribute(orm.Model):
137- _name = "product.attribute"
138- _description = "Product Attribute"
139+class attribute_attribute(orm.Model):
140+ _name = "attribute.attribute"
141+ _description = "Attribute"
142 _inherits = {'ir.model.fields': 'field_id'}
143
144+ def _build_attribute_field(self, cr, uid, page, attribute, context=None):
145+ parent = etree.SubElement(page, 'group', colspan="2", col="4")
146+ kwargs = {'name': "%s" % attribute.name}
147+ if attribute.ttype in ['many2many', 'text']:
148+ parent = etree.SubElement(parent, 'group', colspan="2", col="4")
149+ sep = etree.SubElement(parent,
150+ 'separator',
151+ string="%s" % attribute.field_description,
152+ colspan="4")
153+
154+ kwargs['nolabel'] = "1"
155+ if attribute.ttype in ['many2one', 'many2many']:
156+ if attribute.relation_model_id:
157+ if attribute.domain:
158+ kwargs['domain'] = attribute.domain
159+ else:
160+ ids = [op.value_ref.id for op in attribute.option_ids]
161+ kwargs['domain'] = "[('id', 'in', %s)]" % ids
162+ else:
163+ kwargs['domain'] = "[('attribute_id', '=', %s)]" % attribute.attribute_id.id
164+ field = etree.SubElement(parent, 'field', **kwargs)
165+ orm.setup_modifiers(field, self.fields_get(cr, uid, attribute.name, context))
166+ return parent
167+
168+ def _build_attributes_notebook(self, cr, uid, attribute_group_ids, context=None):
169+ notebook = etree.Element('notebook', name="attributes_notebook", colspan="4")
170+ toupdate_fields = []
171+ grp_obj = self.pool.get('attribute.group')
172+ for group in grp_obj.browse(cr, uid, attribute_group_ids, context=context):
173+ page = etree.SubElement(notebook, 'page', string=group.name.capitalize())
174+ for attribute in group.attribute_ids:
175+ if attribute.name not in toupdate_fields:
176+ toupdate_fields.append(attribute.name)
177+ self._build_attribute_field(cr, uid, page, attribute, context=context)
178+ return notebook, toupdate_fields
179+
180 def relation_model_id_change(self, cr, uid, ids, relation_model_id, option_ids, context=None):
181 "removed selected options as they would be inconsistent"
182 return {'value': {'option_ids': [(2, i[1]) for i in option_ids]}}
183@@ -147,6 +185,17 @@
184 [vals.get('relation_model_id')], ['model'])[0]['model']
185 else:
186 relation = 'attribute.option'
187+
188+ if vals['attribute_type'] == 'select':
189+ vals['ttype'] = 'many2one'
190+ vals['relation'] = relation
191+ elif vals['attribute_type'] == 'multiselect':
192+ vals['ttype'] = 'many2many'
193+ vals['relation'] = relation
194+ vals['serialized'] = True
195+ else:
196+ vals['ttype'] = vals['attribute_type']
197+
198 if vals.get('serialized'):
199 field_obj = self.pool.get('ir.model.fields')
200 serialized_ids = field_obj.search(cr, uid,
201@@ -156,56 +205,56 @@
202 vals['serialization_field_id'] = serialized_ids[0]
203 else:
204 f_vals = {
205- 'name': 'x_custom_json_attrs',
206- 'field_description': 'Serialized JSON Attributes',
207+ 'name': u'x_custom_json_attrs',
208+ 'field_description': u'Serialized JSON Attributes',
209 'ttype': 'serialized',
210 'model_id': vals['model_id'],
211 }
212 vals['serialization_field_id'] = field_obj.create(cr, uid, f_vals, {'manual': True})
213- if vals['attribute_type'] == 'select':
214- vals['ttype'] = 'many2one'
215- vals['relation'] = relation
216- elif vals['attribute_type'] == 'multiselect':
217- vals['ttype'] = 'many2many'
218- vals['relation'] = relation
219- if not vals.get('serialized'):
220- raise except_osv(_('Create Error'), _("The field serialized should be ticked for a multiselect field !"))
221- else:
222- vals['ttype'] = vals['attribute_type']
223 vals['state'] = 'manual'
224- return super(product_attribute, self).create(cr, uid, vals, context)
225+ return super(attribute_attribute, self).create(cr, uid, vals, context)
226
227 def onchange_field_description(self, cr, uid, ids, field_description, context=None):
228- name = 'x_'
229+ name = u'x_'
230 if field_description:
231- name = unidecode('x_%s' % field_description.replace(' ', '_').lower())
232+ name = unidecode(u'x_%s' % field_description.replace(' ', '_').lower())
233 return {'value' : {'name' : name}}
234
235 def onchange_name(self, cr, uid, ids, name, context=None):
236+ res = {}
237 if not name.startswith('x_'):
238- name = 'x_%s' % name
239- return {'value' : {'name' : unidecode(name)}}
240-
241-
242-class attribute_location(orm.Model):
243- _name = "attribute.location"
244- _description = "Attribute Location"
245- _order="sequence"
246- _inherits = {'product.attribute': 'attribute_id'}
247-
248-
249- def _get_attribute_loc_from_group(self, cr, uid, ids, context=None):
250- return self.pool.get('attribute.location').search(cr, uid, [('attribute_group_id', 'in', ids)], context=context)
251-
252- _columns = {
253- 'attribute_id': fields.many2one('product.attribute', 'Product Attribute', required=True, ondelete="cascade"),
254- 'attribute_set_id': fields.related('attribute_group_id', 'attribute_set_id', type='many2one', relation='attribute.set', string='Attribute Set', readonly=True,
255-store={
256- 'attribute.group': (_get_attribute_loc_from_group, ['attribute_set_id'], 10),
257- }),
258- 'attribute_group_id': fields.many2one('attribute.group', 'Attribute Group', required=True),
259- 'sequence': fields.integer('Sequence'),
260- }
261+ name = u'x_%s' % name
262+ else:
263+ name = u'%s' % name
264+ res = {'value' : {'name' : unidecode(name)}}
265+
266+ #FILTER ON MODEL
267+ model_domain = []
268+ model_name = context.get('force_model')
269+ if not model_name:
270+ model_id = context.get('default_model_id')
271+ if model_id:
272+ model = self.pool['ir.model'].browse(cr, uid, model_id, context=context)
273+ model_name = model.model
274+ if model_name:
275+ model_obj = self.pool[model_name]
276+ allowed_model = [x for x in model_obj._inherits] + [model_name]
277+ res['domain'] = {'model_id': [['model', 'in', allowed_model]]}
278+
279+ return res
280+
281+ def _get_default_model(self, cr, uid, context=None):
282+ if context and context.get('force_model'):
283+ model_id = self.pool['ir.model'].search(cr, uid, [
284+ ['model', '=', context['force_model']]
285+ ], context=context)
286+ if model_id:
287+ return model_id[0]
288+ return None
289+
290+ _defaults = {
291+ 'model_id': _get_default_model
292+ }
293
294
295 class attribute_group(orm.Model):
296@@ -215,9 +264,10 @@
297
298 _columns = {
299 'name': fields.char('Name', size=128, required=True),
300+ 'sequence': fields.integer('Sequence'),
301 'attribute_set_id': fields.many2one('attribute.set', 'Attribute Set'),
302 'attribute_ids': fields.one2many('attribute.location', 'attribute_group_id', 'Attributes'),
303- 'sequence': fields.integer('Sequence'),
304+ 'model_id': fields.many2one('ir.model', 'Model', required=True),
305 }
306
307 def create(self, cr, uid, vals, context=None):
308@@ -226,6 +276,19 @@
309 attribute[2]['attribute_set_id'] = vals['attribute_set_id']
310 return super(attribute_group, self).create(cr, uid, vals, context)
311
312+ def _get_default_model(self, cr, uid, context=None):
313+ if context and context.get('force_model'):
314+ model_id = self.pool['ir.model'].search(cr, uid, [
315+ ['model', '=', context['force_model']]
316+ ], context=context)
317+ if model_id:
318+ return model_id[0]
319+ return None
320+
321+ _defaults = {
322+ 'model_id': _get_default_model
323+ }
324+
325
326 class attribute_set(orm.Model):
327 _name = "attribute.set"
328@@ -233,5 +296,38 @@
329 _columns = {
330 'name': fields.char('Name', size=128, required=True),
331 'attribute_group_ids': fields.one2many('attribute.group', 'attribute_set_id', 'Attribute Groups'),
332- }
333-
334+ 'model_id': fields.many2one('ir.model', 'Model', required=True),
335+ }
336+
337+ def _get_default_model(self, cr, uid, context=None):
338+ if context and context.get('force_model'):
339+ model_id = self.pool['ir.model'].search(cr, uid, [
340+ ['model', '=', context['force_model']]
341+ ], context=context)
342+ if model_id:
343+ return model_id[0]
344+ return None
345+
346+ _defaults = {
347+ 'model_id': _get_default_model
348+ }
349+
350+class attribute_location(orm.Model):
351+ _name = "attribute.location"
352+ _description = "Attribute Location"
353+ _order="sequence"
354+ _inherits = {'attribute.attribute': 'attribute_id'}
355+
356+
357+ def _get_attribute_loc_from_group(self, cr, uid, ids, context=None):
358+ return self.pool.get('attribute.location').search(cr, uid, [('attribute_group_id', 'in', ids)], context=context)
359+
360+ _columns = {
361+ 'attribute_id': fields.many2one('attribute.attribute', 'Product Attribute', required=True, ondelete="cascade"),
362+ 'attribute_set_id': fields.related('attribute_group_id', 'attribute_set_id', type='many2one', relation='attribute.set', string='Attribute Set', readonly=True,
363+store={
364+ 'attribute.group': (_get_attribute_loc_from_group, ['attribute_set_id'], 10),
365+ }),
366+ 'attribute_group_id': fields.many2one('attribute.group', 'Attribute Group', required=True),
367+ 'sequence': fields.integer('Sequence'),
368+ }
369
370=== renamed file 'product_custom_attributes/product_attribute_view.xml' => 'base_custom_attributes/custom_attributes_view.xml'
371--- product_custom_attributes/product_attribute_view.xml 2013-02-28 20:39:39 +0000
372+++ base_custom_attributes/custom_attributes_view.xml 2013-06-18 16:21:29 +0000
373@@ -1,6 +1,6 @@
374 <?xml version="1.0" encoding="utf-8"?>
375 <!--
376- product_custom_attributes for OpenERP
377+ base_custom_attributes for OpenERP
378 Copyright (C) 2011-2013 Akretion (http://www.akretion.com/)
379 @author: Benoît GUILLOT <benoit.guillot@akretion.com>
380 The licence is in the file __openerp__.py
381@@ -10,37 +10,65 @@
382 <data>
383
384 <menuitem
385- id="menu_attribute_in_config_product" name="Attributes"
386- parent="product.prod_config_main" sequence="20"/>
387+ id="menu_attribute_in_admin" name="Attributes"
388+ parent="base.next_id_9" sequence="1"/>
389+
390+ <!-- ATTRIBUTE SET VIEW -->
391
392 <record id="attribute_set_form_view" model="ir.ui.view">
393 <field name="name">attribute.set.form</field>
394 <field name="model">attribute.set</field>
395 <field name="arch" type="xml">
396 <form string="Attribute Set">
397- <field name="name" colspan="4"/>
398- <field name="attribute_group_ids" colspan="4" >
399- <form string="Attribute Groups">
400- <field name="name" />
401- <field name="sequence" />
402- <field name="attribute_ids" colspan="4">
403- <form string="Attribute Location">
404- <field name="attribute_id" />
405- <field name="sequence" />
406- </form>
407- <tree string="Attribute Location">
408- <field name="attribute_id" />
409- </tree>
410- </field>
411- </form>
412- <tree string="Attribute Groups">
413- <field name="name" />
414- </tree>
415+ <field name="name"/>
416+ <field name="model_id" invisible="context.get('force_model')"/>
417+ <field name="attribute_group_ids" colspan="4"
418+ context="{'default_model_id': model_id, 'from_attribute_set':True}">
419 </field>
420 </form>
421 </field>
422 </record>
423
424+ <record id="attribute_set_tree_view" model="ir.ui.view">
425+ <field name="name">attribute.set.tree</field>
426+ <field name="model">attribute.set</field>
427+ <field name="arch" type="xml">
428+ <tree string="Attribute Set" >
429+ <field name="name" />
430+ <field name="model_id" />
431+ </tree>
432+ </field>
433+ </record>
434+
435+ <record id="view_attribute_set_search" model="ir.ui.view">
436+ <field name="name">attribute.set.list</field>
437+ <field name="model">attribute.set</field>
438+ <field name="arch" type="xml">
439+ <search string="Search Attribute Sets">
440+ <field name="name"/>
441+ <field name="model_id" />
442+ </search>
443+ </field>
444+ </record>
445+
446+ <record id="attribute_set_form_action" model="ir.actions.act_window">
447+ <field name="name">Attribute Sets</field>
448+ <field name="res_model">attribute.set</field>
449+ <field name="view_type">form</field>
450+ <field name="view_mode">tree,form</field>
451+ <field name="search_view_id" ref="view_attribute_set_search"/>
452+ <field name="context">{"search_default_user_id":uid}</field>
453+ <field name="help"></field>
454+ </record>
455+
456+ <menuitem
457+ action="attribute_set_form_action" id="menu_attribute_set_action"
458+ parent="menu_attribute_in_admin" sequence="10"/>
459+
460+
461+
462+ <!-- ATTRIBUTE GROUP VIEW -->
463+
464 <record id="attribute_group_form_view" model="ir.ui.view">
465 <field name="name">attribute.group.form</field>
466 <field name="model">attribute.group</field>
467@@ -48,253 +76,168 @@
468 <form string="Attribute Group">
469 <field name="name" />
470 <field name="sequence" />
471- <field name="attribute_set_id" />
472+ <field name="model_id" invisible="context.get('from_attribute_set') or context.get('force_model')"/>
473+ <field name="attribute_set_id" invisible="context.get('from_attribute_set')"/>
474 <field name="attribute_ids" colspan="4" nolabel="1">
475 <form string="Attribute Location">
476- <field name="attribute_id" />
477+ <field name="attribute_id" context="{'default_model_id': parent.model_id}"/>
478 <field name="sequence" />
479 </form>
480- <tree string="Attribute Location">
481- <field name="attribute_id" />
482+ <tree string="Attribute Location" editable="top">
483+ <field name="attribute_id" context="{'default_model_id': parent.model_id}"/>
484+ <field name="sequence" />
485 </tree>
486 </field>
487 </form>
488 </field>
489 </record>
490
491- <record id="attribute_location_form_view" model="ir.ui.view">
492- <field name="name">attribute.location.form</field>
493- <field name="model">attribute.location</field>
494+ <record id="attribute_group_tree_view" model="ir.ui.view">
495+ <field name="name">attribute.group.tree</field>
496+ <field name="model">attribute.group</field>
497 <field name="arch" type="xml">
498- <form string="Attribute Location">
499- <field name="attribute_id" />
500+ <tree string="Attribute Group">
501+ <field name="name" />
502 <field name="sequence" />
503- <field name="attribute_group_id" />
504- <field name="attribute_set_id" />
505- </form>
506- </field>
507- </record>
508-
509- <record id="product_attribute_form_view" model="ir.ui.view">
510- <field name="name">product.attribute.form</field>
511- <field name="model">product.attribute</field>
512- <field name="arch" type="xml">
513- <form string="Product Attribute">
514+ <field name="attribute_set_id" invisible="context.get('from_attribute_set')"/>
515+ <field name="model_id" invisible="context.get('from_attribute_set')"/>
516+ </tree>
517+ </field>
518+ </record>
519+
520+ <record id="view_attribute_group_search" model="ir.ui.view">
521+ <field name="name">attribute.group.list</field>
522+ <field name="model">attribute.group</field>
523+ <field name="arch" type="xml">
524+ <search string="Search Attribute Groups">
525+ <field name="name"/>
526+ <field name="attribute_set_id"/>
527+ <field name="model_id" />
528+ </search>
529+ </field>
530+ </record>
531+
532+
533+ <record id="attribute_group_form_action" model="ir.actions.act_window">
534+ <field name="name">Attribute Groups</field>
535+ <field name="res_model">attribute.group</field>
536+ <field name="view_type">form</field>
537+ <field name="view_mode">tree,form</field>
538+ <field name="context">{"search_default_user_id":uid}</field>
539+ <field name="help"></field>
540+ </record>
541+
542+ <menuitem
543+ action="attribute_group_form_action" id="menu_attribute_group_action"
544+ parent="menu_attribute_in_admin" sequence="20"/>
545+
546+ <!-- ATTRIBUTE VIEW -->
547+
548+ <record id="attribute_attribute_form_view" model="ir.ui.view">
549+ <field name="name">attribute.attribute.form</field>
550+ <field name="model">attribute.attribute</field>
551+ <field name="arch" type="xml">
552+ <form string="Attribute">
553 <field name="field_description" on_change="onchange_field_description(field_description, context)"/>
554 <field name="name" attrs="{'readonly':[('create_date', '!=', False)]}" on_change="onchange_name(name, context)"/>
555 <field name="attribute_type" />
556 <field name="model_id" />
557- <field name="serialized" />
558+ <field name="serialized" attrs="{'invisible':[('attribute_type', '=', 'multiselect')]}"/>
559 <field name="size" attrs="{'invisible':[('attribute_type', '!=', 'char')]}"/>
560 <field name="translate" attrs="{'invisible':[('attribute_type', 'not in', ('char', 'text'))]}"/>
561 <newline />
562 <group colspan="4" attrs="{'invisible':[('attribute_type', 'not in', ['select', 'multiselect'])]}">
563- <field name="relation_model_id" on_change="relation_model_id_change(relation_model_id, option_ids, context)"/>
564- <field name="domain" attrs="{'invisible':[('relation_model_id', '=', False)]}"/>
565- <group colspan="4" attrs="{'invisible':[('domain', '!=', False)]}">
566- <button name="button_add_options" attrs="{'invisible':[('relation_model_id', '=', False)]}" type="object" string="Change Options"/>
567- <field name="option_ids" colspan="4" nolabel="1">
568- <tree string="Attribute Options" editable="top">
569- <field name="sequence" invisible="1"/>
570- <field name="name" on_change="name_change(name, parent.relation_model_id, context)"/>
571- </tree>
572- </field>
573- </group>
574+ <group groups="base.group_advanced_attribute">
575+ <field name="relation_model_id" on_change="relation_model_id_change(relation_model_id, option_ids, context)"/>
576+ <field name="domain" attrs="{'invisible':[('relation_model_id', '=', False)]}"/>
577+ <button name="button_add_options" attrs="{'invisible':[('relation_model_id', '=', False), ('domain', '!=', False)]}" type="object" string="Load Options"/>
578+ </group>
579+ <field name="option_ids" colspan="4" nolabel="1">
580+ <tree string="Attribute Options" editable="top">
581+ <field name="sequence" invisible="1"/>
582+ <field name="name" on_change="name_change(name, parent.relation_model_id, context)"/>
583+ </tree>
584+ </field>
585 </group>
586 <field name="create_date" invisible="1"/>
587 </form>
588 </field>
589 </record>
590-
591- <record id="attribute_option_wizard_form_view" model="ir.ui.view">
592- <field name="name">attribute.option.wizard</field>
593- <field name="model">attribute.option.wizard</field>
594- <field name="arch" type="xml">
595- <form string="Options Wizard" col="6">
596- <field name="attribute_id" invisible="1" colspan="2"/>
597- <separator string="options_placeholder"/>
598- <button special="cancel" string="Cancel" icon="gtk-cancel"/>
599- <button name="validate" string="Validate" type="object" icon="gtk-convert"/>
600- </form>
601- </field>
602- </record>
603-
604+
605+ <record id="attribute_attribute_tree_view" model="ir.ui.view">
606+ <field name="name">attribute.attribute.tree</field>
607+ <field name="model">attribute.attribute</field>
608+ <field name="arch" type="xml">
609+ <tree string="Attribute">
610+ <field name="name" />
611+ <field name="attribute_type" />
612+ </tree>
613+ </field>
614+ </record>
615+
616+ <record id="view_attribute_attribute_search" model="ir.ui.view">
617+ <field name="name">attribute.attribute.list</field>
618+ <field name="model">attribute.attribute</field>
619+ <field name="arch" type="xml">
620+ <search string="Search Attributes">
621+ <field name="name"/>
622+ </search>
623+ </field>
624+ </record>
625+
626+ <record id="attribute_attribute_form_action" model="ir.actions.act_window">
627+ <field name="name">Attributes</field>
628+ <field name="res_model">attribute.attribute</field>
629+ <field name="view_type">form</field>
630+ <field name="view_mode">tree,form</field>
631+ <field name="search_view_id" ref="view_attribute_attribute_search"/>
632+ <field name="context">{"search_default_user_id":uid}</field>
633+ <field name="help"></field>
634+ </record>
635+ <menuitem
636+ action="attribute_attribute_form_action" id="menu_attribute_attribute_action"
637+ parent="menu_attribute_in_admin" sequence="30"/>
638+
639+ <!-- ATTRIBUTE OPTION VIEW -->
640 <record id="attribute_option_form_view" model="ir.ui.view">
641 <field name="name">attribute.option.form</field>
642 <field name="model">attribute.option</field>
643 <field name="arch" type="xml">
644 <form string="Attribute Option" col="6">
645- <field name="value_ref" colspan="2"/>
646+ <field name="name" colspan="2"/>
647+ <field name="value_ref" colspan="2" groups="base.group_advanced_attribute"/>
648 <field name="sequence" colspan="2"/>
649 <field name="attribute_id" colspan="2"/>
650 </form>
651 </field>
652 </record>
653-
654- <record id="attribute_set_tree_view" model="ir.ui.view">
655- <field name="name">attribute.set.tree</field>
656- <field name="model">attribute.set</field>
657- <field name="arch" type="xml">
658- <tree string="Attribute Set" >
659- <field name="name" />
660- </tree>
661- </field>
662- </record>
663-
664- <record id="attribute_group_tree_view" model="ir.ui.view">
665- <field name="name">attribute.group.tree</field>
666- <field name="model">attribute.group</field>
667- <field name="arch" type="xml">
668- <tree string="Attribute Group">
669- <field name="name" />
670- <field name="sequence" />
671- <field name="attribute_set_id" />
672- </tree>
673- </field>
674- </record>
675-
676- <record id="attribute_location_tree_view" model="ir.ui.view">
677- <field name="name">attribute.location.tree</field>
678- <field name="model">attribute.location</field>
679- <field name="arch" type="xml">
680- <tree string="Attribute Location">
681- <field name="attribute_id" />
682- <field name="sequence" />
683- <field name="attribute_set_id" />
684- <field name="attribute_group_id" />
685- </tree>
686- </field>
687- </record>
688-
689- <record id="product_attribute_tree_view" model="ir.ui.view">
690- <field name="name">product.attribute.tree</field>
691- <field name="model">product.attribute</field>
692- <field name="arch" type="xml">
693- <tree string="Product Attribute">
694- <field name="name" />
695- <field name="attribute_type" />
696- </tree>
697- </field>
698- </record>
699-
700- <record id="prio_attribute_option_tree_view" model="ir.ui.view">
701- <field name="name">attribute.option.tree.prio</field>
702- <field name="model">attribute.option</field>
703- <field eval="1" name="priority"/>
704- <field name="arch" type="xml">
705- <tree string="Attribute Option">
706- <field name="value_ref" />
707- </tree>
708- </field>
709- </record>
710-
711+
712 <record id="attribute_option_tree_view" model="ir.ui.view">
713 <field name="name">attribute.option.tree</field>
714 <field name="model">attribute.option</field>
715 <field eval="20" name="priority"/>
716 <field name="arch" type="xml">
717 <tree string="Attribute Option">
718+ <field name="name" />
719 <field name="sequence" />
720- <field name="value_ref" />
721+ <field name="value_ref" groups="base.group_advanced_attribute"/>
722 <field name="attribute_id" />
723 </tree>
724 </field>
725 </record>
726
727- <record id="view_attribute_set_search" model="ir.ui.view">
728- <field name="name">attribute.set.list</field>
729- <field name="model">attribute.set</field>
730- <field name="arch" type="xml">
731- <search string="Search Attribute Sets">
732- <field name="name"/>
733- </search>
734- </field>
735- </record>
736-
737- <record id="view_attribute_group_search" model="ir.ui.view">
738- <field name="name">attribute.group.list</field>
739- <field name="model">attribute.group</field>
740- <field name="arch" type="xml">
741- <search string="Search Attribute Groups">
742- <field name="name"/>
743- <field name="attribute_set_id"/>
744- </search>
745- </field>
746- </record>
747-
748- <record id="view_attribute_location_search" model="ir.ui.view">
749- <field name="name">attribute.location.list</field>
750- <field name="model">attribute.location</field>
751- <field name="arch" type="xml">
752- <search string="Search Attribute Locations">
753- <field name="name"/>
754- <field name="attribute_set_id"/>
755- <field name="attribute_group_id"/>
756- </search>
757- </field>
758- </record>
759-
760- <record id="view_product_attribute_search" model="ir.ui.view">
761- <field name="name">product.attribute.list</field>
762- <field name="model">product.attribute</field>
763- <field name="arch" type="xml">
764- <search string="Search Product Attributes">
765- <field name="name"/>
766- </search>
767- </field>
768- </record>
769-
770 <record id="view_attribute_option_search" model="ir.ui.view">
771 <field name="name">attribute.option.list</field>
772 <field name="model">attribute.option</field>
773 <field name="arch" type="xml">
774 <search string="Search Attribute Options">
775- <field name="value_ref" />
776+ <field name="name" />
777+ <field name="value_ref" groups="base.group_advanced_attribute"/>
778 <field name="attribute_id"/>
779 </search>
780 </field>
781 </record>
782
783- <record id="attribute_set_form_action" model="ir.actions.act_window">
784- <field name="name">Attribute Sets</field>
785- <field name="res_model">attribute.set</field>
786- <field name="view_type">form</field>
787- <field name="view_mode">tree,form</field>
788- <field name="search_view_id" ref="view_attribute_set_search"/>
789- <field name="context">{"search_default_user_id":uid}</field>
790- <field name="help"></field>
791- </record>
792-
793- <record id="attribute_group_form_action" model="ir.actions.act_window">
794- <field name="name">Attribute Groups</field>
795- <field name="res_model">attribute.group</field>
796- <field name="view_type">form</field>
797- <field name="view_mode">tree,form</field>
798- <field name="search_view_id" ref="view_attribute_group_search"/>
799- <field name="context">{"search_default_user_id":uid}</field>
800- <field name="help"></field>
801- </record>
802-
803- <record id="attribute_location_form_action" model="ir.actions.act_window">
804- <field name="name">Attribute Locations</field>
805- <field name="res_model">attribute.location</field>
806- <field name="view_type">form</field>
807- <field name="view_mode">tree,form</field>
808- <field name="search_view_id" ref="view_attribute_location_search"/>
809- <field name="context">{"search_default_user_id":uid}</field>
810- <field name="help"></field>
811- </record>
812-
813- <record id="product_attribute_form_action" model="ir.actions.act_window">
814- <field name="name">Product Attributes</field>
815- <field name="res_model">product.attribute</field>
816- <field name="view_type">form</field>
817- <field name="view_mode">tree,form</field>
818- <field name="search_view_id" ref="view_product_attribute_search"/>
819- <field name="context">{"search_default_user_id":uid}</field>
820- <field name="help"></field>
821- </record>
822-
823 <record id="attribute_option_form_action" model="ir.actions.act_window">
824 <field name="name">Attribute Options</field>
825 <field name="res_model">attribute.option</field>
826@@ -306,21 +249,23 @@
827 <field name="help"></field>
828 </record>
829
830- <menuitem
831- action="attribute_set_form_action" id="menu_attribute_set_action"
832- parent="product_custom_attributes.menu_attribute_in_config_product" sequence="1"/>
833- <menuitem
834- action="attribute_group_form_action" id="menu_attribute_group_action"
835- parent="product_custom_attributes.menu_attribute_in_config_product" sequence="2"/>
836- <menuitem
837- action="attribute_location_form_action" id="menu_attribute_location_action"
838- parent="product_custom_attributes.menu_attribute_in_config_product" sequence="3"/>
839- <menuitem
840- action="product_attribute_form_action" id="menu_product_attribute_action"
841- parent="product_custom_attributes.menu_attribute_in_config_product" sequence="4"/>
842- <menuitem
843- action="attribute_option_form_action" id="menu_attribute_option_action"
844- parent="product_custom_attributes.menu_attribute_in_config_product" sequence="5"/>
845+ <menuitem
846+ action="attribute_option_form_action" id="menu_attribute_option_action"
847+ parent="menu_attribute_in_admin" sequence="40"/>
848+
849+ <!-- ATTRIBUTE OPTION WIZARD -->
850+ <record id="attribute_option_wizard_form_view" model="ir.ui.view">
851+ <field name="name">attribute.option.wizard</field>
852+ <field name="model">attribute.option.wizard</field>
853+ <field name="arch" type="xml">
854+ <form string="Options Wizard" col="6">
855+ <field name="attribute_id" invisible="1" colspan="2"/>
856+ <separator string="options_placeholder"/>
857+ <button special="cancel" string="Cancel" icon="gtk-cancel"/>
858+ <button name="validate" string="Validate" type="object" icon="gtk-convert"/>
859+ </form>
860+ </field>
861+ </record>
862
863 </data>
864 </openerp>
865
866=== added file 'base_custom_attributes/security/attribute_security.xml'
867--- base_custom_attributes/security/attribute_security.xml 1970-01-01 00:00:00 +0000
868+++ base_custom_attributes/security/attribute_security.xml 2013-06-18 16:21:29 +0000
869@@ -0,0 +1,11 @@
870+<?xml version="1.0" encoding="utf-8"?>
871+<openerp>
872+<data noupdate="0">
873+
874+ <record id="base.group_advanced_attribute" model="res.groups">
875+ <field name="name">Advanced Attribute Option</field>
876+ <field name="category_id" ref="base.module_category_hidden"/>
877+ </record>
878+
879+</data>
880+</openerp>
881
882=== modified file 'base_custom_attributes/security/ir.model.access.csv'
883--- product_custom_attributes/security/ir.model.access.csv 2013-02-11 22:58:10 +0000
884+++ base_custom_attributes/security/ir.model.access.csv 2013-06-18 16:21:29 +0000
885@@ -1,16 +1,10 @@
886 "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
887-"access_product_custom_attributes_attribute_set_salemanager","product_custom_attributes_attribute_set","product_custom_attributes.model_attribute_set","base.group_sale_manager",1,1,1,1
888-"access_product_custom_attributes_attribute_group_salemanager","product_custom_attributes_attribute_group","product_custom_attributes.model_attribute_group","base.group_sale_manager",1,1,1,1
889-"access_product_custom_attributes_attribute_location_salemanager","product_custom_attributes_attribute_location","product_custom_attributes.model_attribute_location","base.group_sale_manager",1,1,1,1
890-"access_product_custom_attributes_product_attribute_salemanager","product_custom_attributes_product_attribute","product_custom_attributes.model_product_attribute","base.group_sale_manager",1,1,1,1
891-"access_product_custom_attributes_attribute_option_salemanager","product_custom_attributes_attribute_option","product_custom_attributes.model_attribute_option","base.group_sale_manager",1,1,1,1
892-"access_product_custom_attributes_attribute_set_manager","product_custom_attributes_attribute_set","product_custom_attributes.model_attribute_set","product.group_product_variant",1,1,1,1
893-"access_product_custom_attributes_attribute_group_manager","product_custom_attributes_attribute_group","product_custom_attributes.model_attribute_group","product.group_product_variant",1,1,1,1
894-"access_product_custom_attributes_attribute_location_manager","product_custom_attributes_attribute_location","product_custom_attributes.model_attribute_location","product.group_product_variant",1,1,1,1
895-"access_product_custom_attributes_product_attribute_manager","product_custom_attributes_product_attribute","product_custom_attributes.model_product_attribute","product.group_product_variant",1,1,1,1
896-"access_product_custom_attributes_attribute_option_manager","product_custom_attributes_attribute_option","product_custom_attributes.model_attribute_option","product.group_product_variant",1,1,1,1
897-"access_product_custom_attributes_attribute_set_user","product_custom_attributes_attribute_set","product_custom_attributes.model_attribute_set","base.group_user",1,0,0,0
898-"access_product_custom_attributes_attribute_group_user","product_custom_attributes_attribute_group","product_custom_attributes.model_attribute_group","base.group_user",1,0,0,0
899-"access_product_custom_attributes_attribute_location_user","product_custom_attributes_attribute_location","product_custom_attributes.model_attribute_location","base.group_user",1,0,0,0
900-"access_product_custom_attributes_product_attribute_user","product_custom_attributes_product_attribute","product_custom_attributes.model_product_attribute","base.group_user",1,0,0,0
901-"access_product_custom_attributes_attribute_option_user","product_custom_attributes_attribute_option","product_custom_attributes.model_attribute_option","base.group_user",1,0,0,0
902+"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
903+"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
904+"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
905+"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
906+"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
907+"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
908+"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
909+"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
910+"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
911
912=== added directory 'product_categ_attributes'
913=== added file 'product_categ_attributes/__init__.py'
914--- product_categ_attributes/__init__.py 1970-01-01 00:00:00 +0000
915+++ product_categ_attributes/__init__.py 2013-06-18 16:21:29 +0000
916@@ -0,0 +1,1 @@
917+import product
918
919=== added file 'product_categ_attributes/__openerp__.py'
920--- product_categ_attributes/__openerp__.py 1970-01-01 00:00:00 +0000
921+++ product_categ_attributes/__openerp__.py 2013-06-18 16:21:29 +0000
922@@ -0,0 +1,42 @@
923+# -*- encoding: utf-8 -*-
924+###############################################################################
925+# #
926+# product_custom_attributes for OpenERP #
927+# Copyright (C) 2013 Akretion Raphaël Valyi <raphael.valyi@akretion.com> #
928+# #
929+# This program is free software: you can redistribute it and/or modify #
930+# it under the terms of the GNU Affero General Public License as #
931+# published by the Free Software Foundation, either version 3 of the #
932+# License, or (at your option) any later version. #
933+# #
934+# This program is distributed in the hope that it will be useful, #
935+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
936+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
937+# GNU Affero General Public License for more details. #
938+# #
939+# You should have received a copy of the GNU Affero General Public License #
940+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
941+# #
942+###############################################################################
943+
944+
945+
946+{
947+ 'name': 'product_categ_attributes',
948+ 'version': '0.1',
949+ 'category': 'Generic Modules/Others',
950+ 'license': 'AGPL-3',
951+ 'description': """Makes it possible to inherit product attributes from its categories
952+ """,
953+ 'author': 'Akretion',
954+ 'website': 'http://www.akretion.com/',
955+ 'depends': ['product_custom_attributes', 'product_m2mcategories'],
956+ 'init_xml': [],
957+ 'update_xml': [
958+ "product_view.xml"
959+ ],
960+ 'demo_xml': [],
961+ 'installable': True,
962+ 'active': False,
963+}
964+
965
966=== added file 'product_categ_attributes/product.py'
967--- product_categ_attributes/product.py 1970-01-01 00:00:00 +0000
968+++ product_categ_attributes/product.py 2013-06-18 16:21:29 +0000
969@@ -0,0 +1,25 @@
970+from openerp.osv.orm import Model
971+from openerp.osv import fields
972+from openerp.osv.osv import except_osv
973+from openerp.tools.translate import _
974+
975+
976+class product_category(Model):
977+ _inherit = "product.category"
978+ _columns = {
979+ 'attribute_group_ids': fields.many2many('attribute.group', 'categ_attr_grp_rel', 'categ_id', 'grp_id', 'Attribute Groups'),
980+ }
981+
982+
983+class product_product(Model):
984+ _inherit = "product.product"
985+
986+ def _attr_grp_ids(self, cr, uid, ids, field_names, arg=None, context=None):
987+ res = {}
988+ for product in self.browse(cr, uid, ids, context=context):
989+ grp_ids = [grp.id for grp in product.categ_id.attribute_group_ids]
990+ for categ in product.categ_ids:
991+ grp_ids += [grp.id for grp in categ.attribute_group_ids]
992+ res[product.id] = list(set(grp_ids))
993+ return res
994+
995
996=== added file 'product_categ_attributes/product_view.xml'
997--- product_categ_attributes/product_view.xml 1970-01-01 00:00:00 +0000
998+++ product_categ_attributes/product_view.xml 2013-06-18 16:21:29 +0000
999@@ -0,0 +1,52 @@
1000+<?xml version="1.0" encoding="utf-8"?>
1001+
1002+<openerp>
1003+ <data>
1004+
1005+ <record model="ir.ui.view" id="product_categ_form_view">
1006+ <field name="name">product_categ_form_view</field>
1007+ <field name="model">product.category</field>
1008+ <field name="inherit_id" ref="product.product_category_form_view" />
1009+ <field name="arch" type="xml">
1010+ <field name="type" position="after">
1011+ <field name="attribute_group_ids"/>
1012+ </field>
1013+ </field>
1014+ </record>
1015+
1016+ <record model="ir.ui.view" id="product_product_form_view_set_button">
1017+ <field name="name">attributes.product.normal.form</field>
1018+ <field name="model">product.product</field>
1019+ <field name="inherit_id" ref="product_custom_attributes.product_product_form_view_set_button" />
1020+ <field name="arch" type="xml">
1021+ <field name="attribute_set_id" position="replace">
1022+ </field>
1023+ <button name="open_attributes" position="replace">
1024+ <button name="open_attributes" string="Open Attributes" type="object" icon="gtk-ok"/>
1025+ </button>
1026+ </field>
1027+ </record>
1028+
1029+ <record id="attribute_group_form_view" model="ir.ui.view">
1030+ <field name="name">attribute.group.form</field>
1031+ <field name="model">attribute.group</field>
1032+ <field name="inherit_id" ref="product_custom_attributes.attribute_group_form_view" />
1033+ <field name="arch" type="xml">
1034+ <field name="attribute_set_id" position="replace">
1035+ </field>
1036+ </field>
1037+ </record>
1038+
1039+ <record id="product_attributes_form_view" model="ir.ui.view">
1040+ <field name="name">product_attributes_form_view</field>
1041+ <field name="model">product.product</field>
1042+ <field name="inherit_id" ref="product_custom_attributes.product_attributes_form_view" />
1043+ <field name="arch" type="xml">
1044+ <field name="attribute_set_id" position="replace">
1045+ </field>
1046+ </field>
1047+ </record>
1048+
1049+ </data>
1050+</openerp>
1051+
1052
1053=== added directory 'product_custom_attributes'
1054=== added file 'product_custom_attributes/__init__.py'
1055--- product_custom_attributes/__init__.py 1970-01-01 00:00:00 +0000
1056+++ product_custom_attributes/__init__.py 2013-06-18 16:21:29 +0000
1057@@ -0,0 +1,2 @@
1058+import product
1059+import wizard
1060
1061=== added file 'product_custom_attributes/__openerp__.py'
1062--- product_custom_attributes/__openerp__.py 1970-01-01 00:00:00 +0000
1063+++ product_custom_attributes/__openerp__.py 2013-06-18 16:21:29 +0000
1064@@ -0,0 +1,47 @@
1065+# -*- encoding: utf-8 -*-
1066+###############################################################################
1067+# #
1068+# product_custom_attributes for OpenERP #
1069+# Copyright (C) 2011 Akretion Benoît GUILLOT <benoit.guillot@akretion.com> #
1070+# #
1071+# This program is free software: you can redistribute it and/or modify #
1072+# it under the terms of the GNU Affero General Public License as #
1073+# published by the Free Software Foundation, either version 3 of the #
1074+# License, or (at your option) any later version. #
1075+# #
1076+# This program is distributed in the hope that it will be useful, #
1077+# but WITHOUT ANY WARRANTY; without even the implied warranty of #
1078+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
1079+# GNU Affero General Public License for more details. #
1080+# #
1081+# You should have received a copy of the GNU Affero General Public License #
1082+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
1083+# #
1084+###############################################################################
1085+
1086+
1087+
1088+{
1089+ 'name': 'product_custom_attributes',
1090+ 'version': '0.1',
1091+ 'category': 'Generic Modules/Others',
1092+ 'license': 'AGPL-3',
1093+ 'description': """This module adds the possibility to easily create custom fields on products.
1094+Each product can be linked to an attribute set (like camera, fridge...).
1095+Each attribute has custom fields (for example, you don't need the same field for a frigde and a camera).
1096+In particular it's used by the Magento Magentoerpconnect module to match the EAV flexibility of Magento.
1097+ """,
1098+ 'author': 'Akretion',
1099+ 'website': 'http://www.akretion.com/',
1100+ 'depends': ['product', 'base_custom_attributes'],
1101+ 'init_xml': [],
1102+ 'update_xml': [
1103+ 'product_view.xml',
1104+ 'custom_attributes_view.xml',
1105+ 'wizard/open_product_by_attribute_set.xml',
1106+ ],
1107+ 'demo_xml': [],
1108+ 'installable': True,
1109+ 'active': False,
1110+}
1111+
1112
1113=== added file 'product_custom_attributes/custom_attributes_view.xml'
1114--- product_custom_attributes/custom_attributes_view.xml 1970-01-01 00:00:00 +0000
1115+++ product_custom_attributes/custom_attributes_view.xml 2013-06-18 16:21:29 +0000
1116@@ -0,0 +1,44 @@
1117+<?xml version="1.0" encoding="utf-8"?>
1118+<!--
1119+ base_custom_attributes for OpenERP
1120+ Copyright (C) 2011-2013 Akretion (http://www.akretion.com/)
1121+ @author: Benoît GUILLOT <benoit.guillot@akretion.com>
1122+ The licence is in the file __openerp__.py
1123+-->
1124+
1125+<openerp>
1126+ <data>
1127+
1128+ <menuitem
1129+ id="menu_attribute_in_config_product" name="Attributes"
1130+ parent="product.prod_config_main" sequence="20"/>
1131+
1132+ <record id="attribute_set_form_action" model="ir.actions.act_window">
1133+ <field name="name">Product Attribute Sets</field>
1134+ <field name="res_model">attribute.set</field>
1135+ <field name="view_type">form</field>
1136+ <field name="view_mode">tree,form</field>
1137+ <field name="search_view_id" ref="base_custom_attributes.view_attribute_set_search"/>
1138+ <field name="context">{"force_model": 'product.product'}</field>
1139+ <field name="help"></field>
1140+ </record>
1141+
1142+ <record id="attribute_attribute_form_action" model="ir.actions.act_window">
1143+ <field name="name">Product Attribute</field>
1144+ <field name="res_model">attribute.attribute</field>
1145+ <field name="view_type">form</field>
1146+ <field name="view_mode">tree,form</field>
1147+ <field name="search_view_id" ref="base_custom_attributes.view_attribute_attribute_search"/>
1148+ <field name="context">{"force_model": 'product.product'}</field>
1149+ <field name="help"></field>
1150+ </record>
1151+
1152+ <menuitem
1153+ action="attribute_set_form_action" id="menu_attribute_set_action"
1154+ parent="product_custom_attributes.menu_attribute_in_config_product" sequence="1"/>
1155+ <menuitem
1156+ action="attribute_attribute_form_action" id="menu_attribute_attribute_action"
1157+ parent="product_custom_attributes.menu_attribute_in_config_product" sequence="4"/>
1158+
1159+ </data>
1160+</openerp>
1161
1162=== renamed file 'product_custom_attributes/product.py' => 'product_custom_attributes/product.py'
1163--- product_custom_attributes/product.py 2013-04-22 06:20:25 +0000
1164+++ product_custom_attributes/product.py 2013-06-18 16:21:29 +0000
1165@@ -28,7 +28,6 @@
1166
1167
1168 class product_product(Model):
1169-
1170 _inherit = "product.product"
1171
1172 def _attr_grp_ids(self, cr, uid, ids, field_names, arg=None, context=None):
1173@@ -83,40 +82,6 @@
1174 def save_and_close_product_attributes(self, cr, uid, ids, context=None):
1175 return {'type': 'ir.actions.act_window_close'}
1176
1177- def _build_attribute_field(self, cr, uid, page, attribute, context=None):
1178- parent = page
1179- kwargs = {'name': "%s" % attribute.name}
1180- if attribute.ttype == 'many2many':
1181- parent = etree.SubElement(page, 'group', colspan="2", col="4")
1182- #FIXME the following isn't displayed in v7:
1183- sep = etree.SubElement(parent, 'separator',
1184- string="%s" % attribute.field_description, colspan="4")
1185- kwargs['nolabel'] = "1"
1186- if attribute.ttype in ['many2one', 'many2many']:
1187- if attribute.relation_model_id:
1188- if attribute.domain:
1189- kwargs['domain'] = attribute.domain
1190- else:
1191- ids = [op.value_ref.id for op in attribute.option_ids]
1192- kwargs['domain'] = "[('id', 'in', %s)]" % ids
1193- else:
1194- kwargs['domain'] = "[('attribute_id', '=', %s)]" % attribute.attribute_id.id
1195- field = etree.SubElement(parent, 'field', **kwargs)
1196- setup_modifiers(field, self.fields_get(cr, uid, attribute.name, context))
1197- return parent
1198-
1199- def _build_attributes_notebook(self, cr, uid, attribute_group_ids, context=None):
1200- notebook = etree.Element('notebook', name="attributes_notebook", colspan="4")
1201- toupdate_fields = []
1202- grp_obj = self.pool.get('attribute.group')
1203- for group in grp_obj.browse(cr, uid, attribute_group_ids, context=context):
1204- page = etree.SubElement(notebook, 'page', string=group.name.capitalize())
1205- for attribute in group.attribute_ids:
1206- if attribute.name not in toupdate_fields:
1207- toupdate_fields.append(attribute.name)
1208- self._build_attribute_field(cr, uid, page, attribute, context=context)
1209- return notebook, toupdate_fields
1210-
1211 def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
1212 if context is None:
1213 context = {}
1214@@ -128,7 +93,7 @@
1215 if button:
1216 button = button[0]
1217 button.getparent().remove(button)
1218- attributes_notebook, toupdate_fields = self._build_attributes_notebook(cr, uid, context['attribute_group_ids'], context=context)
1219+ attributes_notebook, toupdate_fields = self.pool.get('attribute.attribute')._build_attributes_notebook(cr, uid, context['attribute_group_ids'], context=context)
1220 result['fields'].update(self.fields_get(cr, uid, toupdate_fields, context))
1221 if context.get('open_attributes'):
1222 placeholder = eview.xpath("//separator[@string='attributes_placeholder']")[0]
1223
1224=== renamed file 'product_custom_attributes/product_view.xml' => 'product_custom_attributes/product_view.xml'
1225=== renamed directory 'product_custom_attributes/wizard' => 'product_custom_attributes/wizard'

Subscribers

People subscribed via source and target branches