1
votes

My purpose

I have made a widget in JavaScript which has a button. I want to modify a One2many field after clicking on this button. My widget is shown in sale.order form view and I want to modify the O2M order_line field after the click.

In fact, I am trying to emulate part of the hr_timesheet_sheet module. This module adds a widget in hr_timesheet_sheet.sheet form view and has a button too, each time the button is clicked the O2M timesheet_ids changes.

Source code

So I was copying that part step by step, but I get a weird error in the update_sheets method. This is the source code:

update_sheets: function() {
    if(this.querying) {
        return;
    }
    this.updating = true;

    var commands = [form_common.commands.delete_all()];
    _.each(this.get("sheets"), function (_data) {
        var data = _.clone(_data);
        if(data.id) {
            commands.push(form_common.commands.link_to(data.id));
            commands.push(form_common.commands.update(data.id, data));
        } else {
            commands.push(form_common.commands.create(data));
        }
    });

    var self = this;
    this.field_manager.set_values({'timesheet_ids': commands}).done(function() {
        self.updating = false;
    });
},

My code: 1st attempt

And this is mine:

update_order_line_js: function() {
    if(this.querying) {
        return;
    }
    this.updating = true;

    var commands = [form_common.commands.delete_all()];
    _.each(this.get('order_line_js'), function (_data) {
        var data = _.clone(_data);
        if(data.id) {
            commands.push(form_common.commands.link_to(data.id));
            commands.push(form_common.commands.update(data.id, data));
        } else {
            commands.push(form_common.commands.create(data));
        }
    });

    var self = this;

    this.field_manager.set_values({'order_line': commands}).done(function() {
        self.updating = false;
    });
},

The error

As you can see, I have only changed the variable names, and order_line_js contains sale.order.line data such as sheets contains account.analytic.line data.

But when update_order_line_js is called, the following line fails:

this.field_manager.set_values({'order_line': commands}).done(function() {
    self.updating = false;
});

And throws me this error:

Unknown field qty_invoiced in domain ["|",["qty_invoiced",">",0],["procurement_ids","!=",[]]]

NOTE: If I remove the line commands.push(form_common.commands.create(data));, which is in the else statement, the error disappears.

Example

For example, I have a sale order with only a sale order line. The line has ID 28. When I add manually a new line to O2M order_line, update_order_line_js is called and the content of commands just before the error is the following one:

[
    [5, false, false],
    [0, false, {
        analytic_tag_ids: [],
        customer_lead: 0,
        discount: 0,
        invoice_status: "no",
        layout_category_id: false,
        name: "[CONS_DEL03] Basic Computer Dvorak keyboard left-handed mouse",
        price_unit: 23500,
        procurement_ids: [],
        product_id: 32,
        product_uom: 1,
        product_uom_qty: 1,
        qty_delivered: 0,
        qty_delivered_updateable: true,
        sequence: 13,
        state: "draft",
        tax_id: []
    }],
    [4, 28, false],
    [1, 28, {
        analytic_tag_ids: [],
        company_id: [1, "AnubĂ­a Soluciones en la Nube, S.L."],
        create_date: "2018-10-30 09:03:34",
        create_uid: [1, "Administrator"],
        currency_id: [1, "EUR"],
        customer_lead: 0,
        discount: 0,
        display_name: "Screen X555",
        id: 28,
        invoice_lines: [],
        invoice_status: "to invoice",
        layout_category_id: false,
        layout_category_sequence: 0,
        name: "Screen X555",
        order_id: [11, "SO010"],
        order_partner_id: [8, "Agrolait"],
        price_reduce: 10,
        price_reduce_taxexcl: 10,
        price_reduce_taxinc: 12.1,
        price_subtotal: 10,
        price_tax: 2.1,
        price_total: 12.1,
        price_unit: 10,
        procurement_ids: [],
        product_id: [44, "Screen X555"],
        product_uom: [1, "Unit(s)"],
        product_uom_qty: 1,
        qty_delivered: 0,
        qty_delivered_updateable: true,
        qty_invoiced: 0,
        qty_to_invoice: 1,
        salesman_id: [1, "Administrator"],
        sequence: 12,
        state: "sale",
        tax_id: [1],
        write_date: "2018-10-30 09:03:34",
        write_uid: [1, "Administrator"]
    }]
]

I guess the problem is because the field qty_invoiced is inside the dictionary of the existing line, but why does it throw an error? I am stuck with this.

My code: 2nd attempt

I have also tried a way using Python, which is calling a Python method from the JS on_click to update the current One2many of the sale order lines:

JS on_click content

var sale_order_id = self.field_manager.datarecord.id;
var SaleOrder = new Model('sale.order');
SaleOrder.call(
    'test', [sale_order_id],
).then(function(result) {
    console.log(result);
});

Python method called

@api.model
def test(self, id):
    self = self.browse([id])
    self.update({
        'order_line': [(6, 0, [24, 27])],
    })
    return True

As you can see, I always replace the current lines with the existing ones (in my testing database) with the IDs 24 and 27, only to try the method. The problem is that the One2many field view is not automatically reloaded, so after clicking on my JS button, I still see the old records, but when I click on Save button, I see the records 24 and 27. Besides, if I click on Discard button, I get a domain error and the old records are overwritten by 24 and 27, ignoring the Discard button functionality. I guess that using update out of an onchange method does the write functionality actually (what I cannot understand is the domain error).

My code: 3rd attempt

And because of this, I have tried this too, to update O2M order_line directly in JS:

self.field_manager.fields['order_line'].viewmanager.views.list.controller.do_delete(
    self.field_manager.fields['order_line'].dataset.ids
);

That line works great, but now I need to add the old records with the new data I want. I was searching how to use do_add_record or do_edit, but I still do not know which arguments they need and I was wondering if I am making things more complex than they are.

Can anyone recommend me something to achieve what I need or does anyone know why I am getting the qty_invoiced domain error?

1

1 Answers

1
votes

Finally, I have found a solution for this problem, but I do not like it very much:

update_order_line_js: function() {
    var self = this;
    if(self.querying) {
        return;
    }
    self.updating = true;
    setTimeout(function() {
        var commands = [form_common.commands.delete_all()];
        _.each(self.get('order_line_js'), function (_data) {
            var data = _.clone(_data);
            if(data.id) {
                commands.push(form_common.commands.link_to(data.id));
                commands.push(form_common.commands.update(data.id, data));
            } else {
                data['qty_invoiced'] = 0;
                data['procurement_ids'] = [];
                commands.push(form_common.commands.create(data));
            }
        });

        self.field_manager.set_values({'order_line': commands}).done(function() {    
            self.updating = false;     
        });
    }, 500)
},

If the record does not exist yet, the data to generate it must contain the field qty_invoiced. Why? I do not know exactly. After adding that line, the problem was gone, but then I got the most incomprehensible error, which was cannot get property set of undefined... After a lot of investigation, I found out that the asynchronism of JS was a problem here, and I had to add the setTimeout. After that, everything was running OK, at least in my computer. But in some specific cases, I got the error Unknown field procurement_ids in domain ["|",["qty_invoiced",">",0],["procurement_ids","!=",[]]], which is basically similar to the one which made me ask this question, so I fixed it the same way.

None of the three solutions are OK for me, but at least I was able to continue with my work.