I have added a new state to a Selection field, using the parameter selection_add
:
state = fields.Selection(
selection_add=[
('draft_ok', 'Validated Quotation'),
],
)
Now I want to show it in the XML view, where currently state
is shown this way:
<field name="state" widget="statusbar" statusbar_visible="draft,sent,sale"/>
If I inherit from that view, to add the new state:
<xpath expr="//header/field[@name='state']" position="attributes">
<attribute name="statusbar_visible">draft,draft_ok,sent,sale</attribute>
</xpath>
The new state is shown at the end of the status bar. I want to show it between draft
and sent
states.
The only way I know to do that is redefining the states in Python:
state = fields.Selection(
selection=[
('draft', 'Quotation'),
('draft_ok', 'Validated Quotation'),
('sent', 'Quotation Sent'),
('sale', 'Sales Order'),
('done', 'Locked'),
('cancel', 'Cancelled'),
],
)
But this solution is not very consistent, because if other module also adds a state to this field and my module code is executed after it, I would destroy the state added by this other module.
So I am looking for other way to show the statusbar with a customised order. Any ideas?
From the code responsible of this witch located in fields.Selection
class
There is no way to do it
without using special tricks:
# frame code
def _setup_attrs(self, model, name):
super(Selection, self)._setup_attrs(model, name)
# determine selection (applying 'selection_add' extensions)
for field in reversed(resolve_mro(model, name, self._can_setup_from)):
# We cannot use field.selection or field.selection_add here
# because those attributes are overridden by ``_setup_attrs``.
if 'selection' in field.args:
self.selection = field.args['selection']
if 'selection_add' in field.args:
# use an OrderedDict to update existing values
selection_add = field.args['selection_add']
self.selection = OrderedDict(self.selection + selection_add).items()
Like for example monkey patching I tried normal inheritance
It didn't work I think It needs a lot of work.
This what I tried and it worked just fine in Odoo 9. I created a new key is selection_add_after
witch is a dictionary
1. key is the value of selection that you want to add item after it
2. value is the list of selection items that you want to add
def _setup_attrs(self, model, name):
super(fields.Selection, self)._setup_attrs(model, name)
# determine selection (applying 'selection_add' extensions)
for field in reversed(fields.resolve_mro(model, name, self._can_setup_from)):
# We cannot use field.selection or field.selection_add here
# because those attributes are overridden by ``_setup_attrs``.
if 'selection' in field.args:
self.selection = field.args['selection']
if 'selection_add' in field.args:
# use an OrderedDict to update existing values
selection_add = field.args['selection_add']
self.selection = OrderedDict(self.selection + selection_add).items()
if 'selection_add_after' in field.args:
selection_add_atfer = field.args['selection_add_after']
new_selection = []
for item in self.selection:
new_selection.append(item) # add the element firs
items_to_add = selection_add_atfer.get(item[0], [])
for item_to_add in items_to_add: # then add the element if there is
new_selection.append(item_to_add)
# I don't know why they used OrderdedDict ???!! do you have any idea why?!!
self.selection = OrderedDict(new_selection).items()
# mucky patch the method in selection field
fields.Selection._setup_attrs = _setup_attrs
Make sure you patch before defining the field
# add element after draft
state = fields.Selection(selection_add_after={'draft': [('hello', 'Hello')]})
# add element after draft and other emelent after confirmed
state = fields.Selection(selection_add_after={'draft': [('hello', 'Hello')], 'confirmed': [('test','Test')]})
You can add new key like removing or anything you want.
But monkey patching Framework method is also a bad idea because if there is any updates in the _setup_attrs
is always
removed by this.
EDIT
For Odoo 11, this is the code:
def _setup_attrs(self, model, name):
super(fields.Selection, self)._setup_attrs(model, name)
# determine selection (applying 'selection_add' extensions)
for field in reversed(fields.resolve_mro(model, name, self._can_setup_from)):
# We cannot use field.selection or field.selection_add here
# because those attributes are overridden by ``_setup_attrs``.
if 'selection' in field.args:
self.selection = field.args['selection']
if 'selection_add' in field.args:
# use an OrderedDict to update existing values
selection_add = field.args['selection_add']
self.selection = list(OrderedDict(self.selection + selection_add).items())
if 'selection_add_after' in field.args:
selection_add_atfer = field.args['selection_add_after']
new_selection = []
for item in self.selection:
new_selection.append(item) # add the element firs
items_to_add = selection_add_atfer.get(item[0], [])
for item_to_add in items_to_add: # then add the element if there is
new_selection.append(item_to_add)
# I don't know why they used OrderdedDict ???!! do you have any idea why?!!
self.selection = list(OrderedDict(new_selection).items())
fields.Selection._setup_attrs = _setup_attrs