Обновление родственных строк в дереве в Odoo10 - PullRequest
0 голосов
/ 18 апреля 2020

У меня есть модель, которая содержит родителя и несколько дочерних элементов.

Родитель имеет вычисляемое поле «product_remaining», которое обновляется после модификации другого поля в любом из дочерних элементов («lot_qty») ).

Поле "product_remaining" отображается в дереве для всех детей с использованием поля "related" в модели детей.

Все работает нормально, за исключением того, что дерево обновляется только поле «product_remaining» в строке, для которой было выполнено изменение, и оно не обновляет никакую другую строку.

Кроме того, если я щелкну, чтобы изменить строку, которая не была обновлена ​​предыдущим изменением, и оставив без изменения, строка обновляется корректно.

Есть ли способ обновить / обновить sh все затронутые строки в древовидном представлении, а не только ту, в которой было сделано изменение?

Я использую Odoo v10.

Вот соответствующий код:

Python:

class Te2PackLotOperation(models.TransientModel):
    _name = 'te2.pack.lot.operation'
    parent_id = fields.Many2one('te2.pack.product.operation', readonly=True, ondelete='cascade')
    product_id = fields.Many2one('product.product', 'Product', related='parent_id.product_id')
    product_qty = fields.Float('Total', readonly=True, related='parent_id.product_qty')
    product_remaining = fields.Float('Remaining', readonly=True, related='parent_id.product_remaining')
    lot_id = fields.Many2one('stock.production.lot')
    lot_qty = fields.Float('Done')
    packing = fields.Char('Packing')
    @api.onchange('lot_qty')
    def onchange_lot_qty(self):
        rec = self._origin
        rec.write({'lot_qty': self.lot_qty})

class Te2PackProductOperation(models.TransientModel):
    _name = 'te2.pack.product.operation'
    product_id = fields.Many2one('product.product', 'Product', readonly=True)
    product_qty = fields.Float('Total', readonly=True)
    product_remaining = fields.Float('Remaining', readonly=True, stored=False, compute='_product_remaining_get')
    lot_ids = fields.One2many('te2.pack.lot.operation', 'parent_id')

    def _product_remaining_get(self):
        for rec in self:
            already_done = 0
            for lot in rec.lot_ids:
                already_done += lot.lot_qty
            rec.product_remaining = rec.product_qty - already_done

XML:

    <record id="te2_stock_picking_advanced_view_form" model="ir.ui.view">
        <field name="name">te2.pack.operation.form</field>
        <field name="model">te2.pack.product.operation</field>
        <field name="arch" type="xml">
            <form string="Advanced Stock Picking">
                <field name="lot_ids">
                    <tree editable="bottom" create="false" delete="false"
                          decoration-danger="product_remaining!=0" decoration-success="product_remaining==0"
                          default_order="product_id">
                        <field name="product_id"/>
                        <field name="product_qty"/>
                        <field name="product_remaining"/>
                        <field name="lot_id"
                               domain="[('product_id','=', product_id)]"
                        />
                        <field name="use_date"/>
                        <field name="lot_qty"/>
                        <field name="packing"/>
                        <button name="add_lot" string="Lot Split" type="object" icon="fa-list"/>
                    </tree>
                </field>
                <footer>
                    <button name="save" string="Save" type="object" class="oe_highlight" />
                    <button string="Cancel" class="oe_link" special="cancel"/>
                </footer>
            </form>
        </field>
    </record>

1 Ответ

0 голосов
/ 20 апреля 2020

Хорошо, после некоторых копаний мне удалось решить проблему путем расширения классов JavaScript.

Если кому-то интересно, код выглядит следующим образом:

odoo.define('te2_base', function(require) {
  "use strict";

  var core = require('web.core');

  //The ListView. This view is used by the one2many field (see below)
  var One2ManyUpdateAllListView = core.one2many_view_registry.get('list').extend({
    init: function(viewmanager) {
      var result = this._super.apply(this, arguments);
      //Register to the save event
      this.on("save:after", this, this.reload_all_records);
      return result;
    },

    //Similar to "reload_record" from "list_view.js", but supporting an array of records, and moving the
    //100ms delay to the end of the operation, instead of one delay per record.
    reload_records: function (records, options={}) {
        var self = this;
        var fields = this.fields_view.fields;

        if (!options || !options.do_not_evict) {
            //This is from "form_relational_widgets.js".
            // Evict records from cache to ensure it will be reloaded correctly
            records.each( function (record) {
                self.dataset.evict_record(record.get('id'));
            })
        }

        return this.dataset.read_ids(
            records.map(function (record) {return record.get('id')}),
            _.pluck(_(this.columns).filter(function (r) {
                    return r.tag === 'field';
                }), 'name'),
            {check_access_rule: true}
        ).then(function (upd_records) {
          records.each(function (record) {
            var values = upd_records.find(function (upd_r) {return upd_r['id'] == record.get('id')});
            if (values == undefined) {
              self.records.remove(record);
            } else {
              // _.each is broken if a field "length" is present
              for (var key in values) {
                  if (fields[key] && fields[key].type === 'many2many')
                      record.set(key + '__display', false, {silent: true});
                  record.set(key, values[key], {silent: true});
              }
              record.trigger('change', record);
            }
          });

          var def = $.Deferred();
          setTimeout(function() {
              def.resolve();
          }, 100);
          return def;
        });
    },
    reload_all_records: function () {
      return this.reload_records(this.records);
    },
  });

  //The Field. We should override the listview used by the field, so it uses our custom view.
  var FieldOne2ManyUpdateAll = core.form_widget_registry.get('one2many').extend({
    init: function() {
      var result = this._super.apply(this, arguments);
      this.x2many_views.list=One2ManyUpdateAllListView;
      return result;
    }
  });

  //Register the new field, so we can use it from our XML files
  core.form_widget_registry.add('te2_tree_update_all', FieldOne2ManyUpdateAll);

  //Make the classes available for other modules.
  return {
    One2ManyUpdateAllListView: One2ManyUpdateAllListView,
    FieldOne2ManyUpdateAll: FieldOne2ManyUpdateAll
  };
});

И его можно использовать, просто добавив атрибут виджета к тегу поля (примечание: его следует добавлять к тегу «поля», а не к тегу «дерева»):

<field name="lot_op_ids" options='{"always_reload": True}' widget="te2_tree_update_all">
...