Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to change modules config settings remotely with erppeek #85

Closed
esciara opened this issue May 5, 2016 · 19 comments
Closed

How to change modules config settings remotely with erppeek #85

esciara opened this issue May 5, 2016 · 19 comments

Comments

@esciara
Copy link

esciara commented May 5, 2016

Hi,

I am trying to use erppeek to change remotely config settings of modules. But I cannot manage to make it work. For the time being I am trying to do it on base.config.settings, account.config.settings, stock.config.settings and sale.config.settings (which seem to have a different behavior than the other two, in that it does not create a new record when the config is updated on the user interface, which is what the others do.)

I try to do it by creating a new config setting record, then I run the equivalent of the following code.

model_name = 'sale.config.settings'
records = erppeek_client.model(model_name).browse([], order='id DESC', limit=1)
if len(records) > 0:
    record = records[0]
    erppeek_client.execute_kw(model_name, 'execute', [[record.id]])
else:
    logging.warning('Config Settings for %r could not be created => cannot execute settings',
                    self._model_name)

As a result, on the odoo interface, the change is recorded (here the sale price setting has been changed to allow pricelists) but it has not been taken into account/executed. See screenshot below.
image
But when I hit "Apply" on the user interface, then the configuration is taken into account, as you can see on the screenshot below.
image

Any clues about what I am doing wrong?

@dreispt
Copy link

dreispt commented May 6, 2016

The sale.config.settings is a TransientModel (aka a wizard).
Try using create() on it to get a new instance, and then perform the write() operations on the fields for the setting you want.

@yvaucher
Copy link
Contributor

yvaucher commented May 6, 2016

@esciara This config is a special case.
I faced it using oerpscenario https://github.com/camptocamp/oerpscenario (which use erppeek in background)
To set the formula I had to use

    Given I enable "Use pricelists to adapt your price per customers" in "Sales" settings menu
    Given I enable "Show pricelists to customers" in "Sales" settings menu

Because Sale Price option is a selection field sale_pricelist_settings that control 3 other boolean fields with an onchange.
And erppeek doesn't play onchanges for you. Thus you have multiple choices.

  1. You do a create() setting the field sale_pricelist_settings to formula and thus you call the method onchange_sale_price and you might do another write.
  2. You directly do a create() settings the 3 fields group_product_pricelist, group_sale_pricelist and group_pricelist_item
  3. You can directly assign the groups to the employee security group. As it is what those field do.

See what the onchange does:

    def onchange_sale_price(self, cr, uid, ids, sale_pricelist_setting, context=None):
        if sale_pricelist_setting == 'percentage':
            return {'value': {'group_product_pricelist': True, 'group_sale_pricelist': True, 'group_pricelist_item': False}}
        if sale_pricelist_setting == 'formula':
            return {'value': {'group_pricelist_item': True, 'group_sale_pricelist': True, 'group_product_pricelist': False}}
        return {'value': {'group_pricelist_item': False, 'group_sale_pricelist': False, 'group_product_pricelist': False}}

@yvaucher
Copy link
Contributor

yvaucher commented May 6, 2016

Plus see @dreispt comment, you need to do a create, not a browse as it is a transient model.

[...]
Wizard = erppeek_client.model(config_model_name)
config = Wizard.create(values)
config.execute()

@esciara
Copy link
Author

esciara commented May 8, 2016

Thanks for the tips! Will apply and share results.

@esciara
Copy link
Author

esciara commented May 11, 2016

Thanks for your help! Here is the code I ended up writing, and which works fine:

elif self._model_name == 'sale.config.settings':
    for row in rows:
        config_values = self._extract_data_from_row(row, fieldnames)
        config = self._model.create(config_values)
        if 'sale_pricelist_setting' in config_values.keys():
            value_to_change = config.onchange_sale_price(config_values['sale_pricelist_setting'])
            config.write(value_to_change['value'])
        config.execute()

Is that the way to do it or is there a more elegant way?

Anybody could give a bit more insight on config.execute() and what it does?

For info rows are initially coming from a csv file, so the self._extract_data_from_row method makes surethe fields are translated the right type, for instance integers for selection fields such as module_delivery.

One last question: are pretty much all configs transient objects and should be treated the same why as above? Some of them are osv.TransientModel and others are osv.osv_memory. For instance:

class sale_configuration(osv.TransientModel):
class stock_config_settings(osv.osv_memory):

[EDIT] Never mind, I just found info in the code about what execute does:

class res_config_settings(osv.osv_memory, res_config_module_installation_mixin):
    """ Base configuration wizard for application settings.  It provides support for setting
        default values, assigning groups to employee users, and installing modules.
        To make such a 'settings' wizard, define a model like::

            class my_config_wizard(osv.osv_memory):
                _name = 'my.settings'
                _inherit = 'res.config.settings'
                _columns = {
                    'default_foo': fields.type(..., default_model='my.model'),
                    'group_bar': fields.boolean(..., group='base.group_user', implied_group='my.group'),
                    'module_baz': fields.boolean(...),
                    'other_field': fields.type(...),
                }

        The method ``execute`` provides some support based on a naming convention:
[..]

Also found https://www.odoo.com/documentation/9.0/howtos/backend.html#wizards

Still curious about eventual differences between osv.TransientModel and osv.osv_memory classes.

@dreispt
Copy link

dreispt commented May 11, 2016

Still curious about eventual differences between osv.TransientModel and osv.osv_memory classes.

They are the same thing. osv_memory was renamed to TransientModel in a later OpenERP version.

@esciara
Copy link
Author

esciara commented May 31, 2016

On last question before I close this issue.

I want to be able to test that my config settings have been correctly configured after I did it. But when I do a model.browse([]) on the config settings (account.config.settings for instance), I get back as many records as I did updates. When I take the last one created, it does not contains the correct settings, only the last one I changed.

How do I get to retrieve the configs from my Odoo instance?

@dreispt
Copy link

dreispt commented May 31, 2016

The Settings is just a transient Wizard used to collect selections from the user.
Depending on the option you chose, you need to check if it's activation was done: some install a module, other enable a security Group, other set a config value...
No straight answer for that.

@yvaucher
Copy link
Contributor

yvaucher commented Jun 1, 2016

An other option which might not be simpler than @dreispt one. You could create a new wizard and read it, you have to ensure default_get is called as it is where it populates the wizard values in version 9.0. (in version 8.0 it was also done in company_id onchange)
https://github.com/OCA/OCB/blob/9.0/openerp/addons/base/res/res_config.py#L509

Also ensure if there are no other onchanges to calls as they aren't called by the create.

@esciara
Copy link
Author

esciara commented Jun 1, 2016

@dreispt @yvaucher thanks.

@yvaucher I looked at the account/views/res_config_view.xml file in Odoo, which displays the form that appears populated with the settings. Is what you suggest the way the data is populated there? (using <field name="model">account.config.settings</field> to define what config to use). @dreispt I was thinking that would provide some kind of straight, standard way of getting the settings from the config wizards...

@yvaucher
Copy link
Contributor

yvaucher commented Jun 1, 2016

@esciara No the xml file is only the view definition. You will have the values you are looking for in the records. But as transient model is not persistent in database, the value you are looking for are setted on the wizard in the web client when opening the settings. This is done by calling default_get method.

Thus, to check through erppeek the settings on the server you have to call default_get which will return you a list of values. In case of sale settings it might be all you have to do. However, for account settings there are some options that are stored on the company model (like currency and paypal account). In that case you probably want to do a create providing the company_id. That way you should get the value for related fields.

@esciara
Copy link
Author

esciara commented Jun 1, 2016

Thanks for the explanations @yvaucher :). That should give me what I need for my current tests.

Out of curiosity, if you happen to know where the piece of code that handles populating the config views is, I will gladly take that info to look at how Odoo handles the special case like the one you mention on account settings and companies. My goal would be to build a testing code that handles as many options as possible so I can get access to the data I want to test.

Cheers!

@yvaucher
Copy link
Contributor

yvaucher commented Jun 1, 2016

@esciara I already gave it to you in my previous comment 😉

https://github.com/OCA/OCB/blob/9.0/openerp/addons/base/res/res_config.py#L509

All config settings inherit from res.config.settings

@esciara
Copy link
Author

esciara commented Jun 1, 2016

😄 @yvaucher understood that part.

I was talking about the code that handles all the special cases that are not handled by default_get. The one you mention with the account settings for instance.

If the default_get is not enough for that, then it is not enough to load the data to populate account/views/res_config_view.xml (the account_config_settings form). Since the data is definitely there when you browse on the config form, it means that is must be handled by some code somewhere. That is what I would like to look at.

@yvaucher
Copy link
Contributor

yvaucher commented Jun 2, 2016

@esciara This might be defined in the specific config settings for example: onchange_company_id for account.config.settings

This is an onchange that the view will calls automatically but with erppeek you need to call it manually.

And you may cascade the change to the onchange by calling the following methods: onchange_chart_template_id and onchange_tax_rate

@esciara
Copy link
Author

esciara commented Jun 2, 2016

@yvaucher thanks. You are confirming what I found in the book "Odoo Developement Cookbook" (thanks @dreispt 😉 ) page 104:

On the other hand, onchange methods are not called by create(), because they are called by the web client during the initial edition of the record. Some of these methods compute default values for fields related to a given field. When creating records by hand you have to do the work yourself, either by providing explicit values or by calling the onchange methods.

So the likely solution is:

  • create a new config object/record (which is a wizard or transient model)
  • call the default_get on the config
  • call all onchange methods on the config

Thank you all for your help. I will close this. Don't hesitate to correct if this is wrong.

@esciara esciara closed this as completed Jun 2, 2016
@esciara
Copy link
Author

esciara commented Jun 8, 2016

Right, errr... struggling a bit on how to find programatically the onchange methods of a model that can be called through XMLRPC...

Still on "Odoo Developement Cookbook", it is mentioned that the _onchange_spec() can be used on the Odoo server... but since it starts with _, it cannot be called through XMLRPC.

Could not find any other way of finding out... Any pointers to how this could be done?

@esciara esciara reopened this Jun 8, 2016
@yvaucher
Copy link
Contributor

yvaucher commented Jun 9, 2016

@esciara Sorry for "private" methods, like onchanges the only way to do it is to do a "public" wrapper (without _) for those and call them that way.

@esciara
Copy link
Author

esciara commented Jun 9, 2016

Yep @yvaucher ...

And in any case, I saw that sometimes onchange methods have to be called in a certain order. For instance, on account.config.settings, the onchange_company_id method seems to have to be called before the onchange_chart_template_id method, as self.chart_template_id is set in the first one and used in the second.

I would need to have a look at how the config view is populated with the data, since my understanding is that it is populated through calls to an XMLRPC method and we saw here that a default_get and a create does not do the trick, meaning that you need to call onchange methods in a required order, or call another exposed method that would do.

I will keep this issue open until I find this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants