Search code examples
javascriptodooodoo-15odoo-16

Console error models.load_fields is not a function while I try to load custom field into POS odoo16


This console error faced me when I try to use models.load_fields to load custom field to POS orderline:

Console: 'TypeError: models.load_fields is not a function'

My code as follow:

odoo.define('serial_attributes.pos_attributes', function (require) {
    "use strict";
    console.log("Iam HEreeeeeeeeeeeeeee!!!!!!!!!!!!!!!")

    var models = require("point_of_sale.models");
    var _super_orderline = models.Orderline.prototype;
    console.log("models", models);
    models.load_fields("product.product", "test")
    models.Orderline = models.Orderline.extend({
        initialize: function (attr, options) {
            var line = _super_orderline.initialize.apply(this, session, arguments);
            this.test = this.product.test;
            console.log("test", this.test)
        }
    })


})

I try to load custom field to porduct.product to show it with POS order.


Solution

  • Odoo should raise:

    ReferenceError: session is not defined
    

    The session parameters passed to apply is not defined in this context, you should remove it

    You don't need to assign the result to the line variable

    You can find an example in pos_restaurant module that extends the OrderLine to add a note field

    Original code:

    odoo.define('pos_restaurant.notes', function (require) {
    "use strict";
    
    var models = require('point_of_sale.models');
    
    var _super_orderline = models.Orderline.prototype;
    models.Orderline = models.Orderline.extend({
        initialize: function(attr, options) {
            _super_orderline.initialize.call(this,attr,options);
            this.note = this.note || "";
        },
        set_note: function(note){
            this.note = note;
            this.trigger('change',this);
        },
        get_note: function(note){
            return this.note;
        },
        can_be_merged_with: function(orderline) {
            if (orderline.get_note() !== this.get_note()) {
                return false;
            } else {
                return _super_orderline.can_be_merged_with.apply(this,arguments);
            }
        },
        clone: function(){
            var orderline = _super_orderline.clone.call(this);
            orderline.note = this.note;
            return orderline;
        },
        export_as_JSON: function(){
            var json = _super_orderline.export_as_JSON.call(this);
            json.note = this.note;
            return json;
        },
        init_from_JSON: function(json){
            _super_orderline.init_from_JSON.apply(this,arguments);
            this.note = json.note;
        },
    });
    
    

    For Odoo 16

    The Javascript framework has changed.

    As you can read in the [REF] point_of_sale,pos: remove Backbone.js, single loading request commit:

    It is possible to make customizations in the loading but is done in several steps:

    1. Override _pos_ui_models_to_load to include the new model to load.
    2. Define _loader_params_<model_name> to define the search_params and optional context.
    3. Define _get_pos_ui_<model_name> to return the data that will be included in the full loaded_data. Perform the organization in this method whenever necessary.
    4. Override _pos_data_process for further post processing. The final form of loaded_data in this method will be sent to the frontend. To make customization To load a model, you need to use _loader_params_MODEL_MODEL in the pos.session model. You can find an example used to load res_country model. The point_of_sale already loads the product model so you need to override that function and extend the list of fields

    Example:

    class PosSession(models.Model):
        _inherit = 'pos.session'
    
        def _loader_params_product_product(self):
            result = super()._loader_params_product_product()
            result['search_params']['fields'].extend(['test'])
            return result
    

    To override Orderline use the following code

    odoo.define('serial_attributes.pos_attributes', function (require) {
        "use strict";
    
        const { Orderline } = require('point_of_sale.models');
        const Registries = require('point_of_sale.Registries');
    
        const PosAttributesOrderline = (Orderline) => class PosAttributesOrderline extends Orderline {
            constructor() {
                super(...arguments);
                this.test = this.product.test;
            }
        };
    
        Registries.Model.extend(Orderline, PosAttributesOrderline);
    });
    

    Edit: Load a new model

    As an example, we can use the pos_hr module that overrides the POS session functions mentioned above and extends the POS widget to define the employee list

    1/ Inherit pos.session model

    class PosSession(models.Model):
        _inherit = 'pos.session'
    
        def _pos_ui_models_to_load(self):
            result = super()._pos_ui_models_to_load()
            new_model = 'hr.employee'
            if new_model not in result:
                result.append(new_model)
            return result
    
        def _loader_params_hr_employee(self):
            return {'search_params': {'domain': [], 'fields': ['name', 'id', 'user_id'], 'load': False}}
    
        def _get_pos_ui_hr_employee(self, params):
            employees = self.env['hr.employee'].search_read(**params['search_params'])
            return employees
    
        def _pos_data_process(self, loaded_data):
            super()._pos_data_process(loaded_data)
            loaded_data['employee_by_id'] = {employee['id']: employee for employee in loaded_data['hr.employee']}
    
    

    2/ Extend The POS widget to set the employees list

    const { PosGlobalState } = require('point_of_sale.models');
    
    const PosAttributesPosGlobalState = (PosGlobalState) => class PosAttributesPosGlobalState extends PosGlobalState {
        async _processData(loadedData) {
            await super._processData(...arguments);
            this.employee_by_id = loadedData['employee_by_id'];
        }
    }
    
    Registries.Model.extend(PosGlobalState, PosAttributesPosGlobalState);
    

    To access the list of employees from the order line use: this.pos.employee_by_id