Search code examples
pythonxmlpython-3.xodooodoo-11

How to add a state to a Selection field and show it ordered in the statusbar in Odoo 11?


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?


Solution

  • 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