profile
viewpoint
Yannick Vaucher yvaucher @camptocamp Lausanne, CH

camptocamp/cubiscan 1

Cubiscan library

guewen/odoo 1

Odoo (formerly OpenERP). Open Source Business Apps.

camptocamp/docker-odoo-project-lasso 0

docker-odoo-project built with lasso lib

damdam-s/bank-statement-reconcile 0

Odoo Bank Statements Tasks (reconciliation, completion,...)

damdam-s/pyews 0

Open Sourced Python Wrapper for Microsoft Exchange Web Services (EWS)

PR opened OCA/account-payment

FIX: use field supplier_rank instead of supplier

field supplier not exits any more on V13

+1 -1

0 comment

1 changed file

pr created time in 32 minutes

Pull request review commentodoo/odoo

[FIX] portal,website_sale: translatable and responsive help text

             <t t-if="mode == ('new', 'billing') or (mode == ('edit', 'billing') and (can_edit_vat or 'vat' in checkout and checkout['vat']))">                 <div t-attf-class="form-group #{error.get('company_name') and 'o_has_error' or ''} col-lg-6">                     <label class="col-form-label font-weight-normal label-optional" for="company_name">Company Name</label>-                    <input type="text" name="company_name" t-attf-class="form-control #{error.get('company_name') and 'is-invalid' or ''}" t-att-value="'commercial_company_name' in checkout and checkout['commercial_company_name'] or 'company_name' in checkout and checkout['company_name']" t-att-readonly="'1' if 'vat' in checkout and checkout['vat'] and not can_edit_vat else None" t-att-title="'Changing company name is not allowed once document(s) have been issued for your account. Please contact us directly for this operation.' if 'vat' in checkout and checkout['vat'] and not can_edit_vat else None" />+                    <input type="text" name="company_name" t-attf-class="form-control #{error.get('company_name') and 'is-invalid' or ''}" t-att-value="'commercial_company_name' in checkout and checkout['commercial_company_name'] or 'company_name' in checkout and checkout['company_name']" t-att-readonly="'1' if 'vat' in checkout and checkout['vat'] and not can_edit_vat else None" />+                    <t t-if="'vat' in checkout and checkout['vat'] and not can_edit_vat" >+                        <small class="form-text text-muted">Changing company name is not allowed once document(s) have been issued for your account. Please contact us directly for this operation.</small>+                    </t>                 </div>                 <div t-attf-class="form-group #{error.get('vat') and 'o_has_error' or ''} col-lg-6 div_vat">                     <label class="col-form-label font-weight-normal label-optional" for="vat">TIN / VAT </label>-                    <input type="text" name="vat" t-attf-class="form-control #{error.get('vat') and 'is-invalid' or ''}" t-att-value="'vat' in checkout and checkout['vat']" t-att-readonly="'1' if 'vat' in checkout and checkout['vat'] and not can_edit_vat else None" t-att-title="'Changing VAT number is not allowed once document(s) have been issued for your account. Please contact us directly for this operation.' if 'vat' in checkout and checkout['vat'] and not can_edit_vat else None" />+                    <input type="text" name="vat" t-attf-class="form-control #{error.get('vat') and 'is-invalid' or ''}" t-att-value="'vat' in checkout and checkout['vat']" t-att-readonly="'1' if 'vat' in checkout and checkout['vat'] and not can_edit_vat else None"/>+                    <t t-if="checkout['vat'] and not can_edit_vat">

It is true that not clean but i don’t see thé bug in controlleur... While you do browserecord[] and dict[] ... maybe a read will be better... to avoid confusion

But i mean in you pr you didnt check if vat is present in checkout :) What will crash e.g. In checkout with a new shipping address

Just an idea in my head :) a good tool too ! 🤔

Yajo

comment created time in an hour

issue commentOCA/helpdesk

Wrong spelling of 'Helpdesk' (helpdesk 13.0)

Duplicate anyway of #40 for v12

Ramil-Mukhametzyanov

comment created time in 2 hours

pull request commentOCA/helpdesk

Backport to v10

@mileo This is targeting the wrong branch

mileo

comment created time in 2 hours

delete branch OCA/helpdesk

delete branch : gdgellatly-patch-1

delete time in 2 hours

PR closed OCA/helpdesk

Update helpdesk_demo.xml needs review

Solves #181 for v12

+1 -1

2 comments

1 changed file

gdgellatly

pr closed time in 2 hours

pull request commentOCA/helpdesk

Update helpdesk_demo.xml

Closing this, accidentally created branch on OCA repo

gdgellatly

comment created time in 2 hours

issue closedOCA/helpdesk

From mail ticket creation, computed partner_id is not always the best choice

Minor bug.

When creating a ticket by sending a mail (fetchmail), the partner_id is the first one found with matching mail address.

However it could be nicer to try to match a partner_id which is an helpdesk user if many matching mails are found.

See in code helpdesk_mgmt / models / helpdesk_ticket.py, def message_new ()

closed time in 2 hours

luffah

issue commentOCA/helpdesk

From mail ticket creation, computed partner_id is not always the best choice

@luffah This is as resolved as it is going to get after 1 year. The behaviour is pretty standard Odoo, however if you feel it needs documentation, please feel free to make a PR.

I think there is also a requirement for an option, potentially at team level or globally to autosubscribe partners to helpdesk tickets, this question comes up quite a bit, there is a duplicate issue #159 for your sub issue so I close this one. I will probably write the change anyway as I want autosubscribe.

Thanks for raising.

luffah

comment created time in 2 hours

issue closedOCA/helpdesk

OCA PSC team helpdesk has no projects

I think here https://odoo-community.org/psc-teams/helpdesk-164 should be listed https://github.com/OCA/helpdesk

closed time in 2 hours

emagdalenaC2i

issue closedOCA/helpdesk

[11.0] Issue on create new ticket in kanban view

When new ticket is created in kanban view the log shows the follow error:

2019-09-30 07:40:15,797 34 ERROR project odoo.sql_db: bad query: b'INSERT INTO "helpdesk_ticket" ("id", "stage_id", "company_id", "rating_status", "positive_rate_percentage", "last_stage_update", "priority", "number", "create_uid", "write_uid", "create_date", "write_date") VALUES(nextval('helpdesk_ticket_id_seq'), 6, 1, 'stage_change', -1, '2019-09-30 07:40:15', '1', 'dfd', 1, 1, (now() at time zone 'UTC'), (now() at time zone 'UTC')) RETURNING id' ERROR: null value in column "name" violates not-null constraint DETAIL: Failing row contains (17, dfd, null, null, null, 6, null, null, null, 2019-09-30 07:40:15, null, null, 1, null, null, null, 1, null, null, null, null, 1, 2019-09-30 07:40:15.794557, 1, 2019-09-30 07:40:15.794557, null, -1, stage_change).

Sequence: Tickets -> kanban view -> in any state press create -> put the title -> press button create.

closed time in 2 hours

yevbes

pull request commentOCA/helpdesk

Update helpdesk_demo.xml

I don't know how we forward port etc. Is it just manual or we bot that?

gdgellatly

comment created time in 2 hours

PR opened OCA/helpdesk

Update helpdesk_demo.xml

Solves #181 for v12

+1 -1

0 comment

1 changed file

pr created time in 2 hours

create barnchOCA/helpdesk

branch : gdgellatly-patch-1

created branch time in 2 hours

issue commentOCA/helpdesk

Wrong spelling of 'Helpdesk' (helpdesk 13.0)

@Ramil-Mukhametzyanov thanks for reporting, it is just in the demo data, not the main module but we will fix nonetheless

Ramil-Mukhametzyanov

comment created time in 2 hours

Pull request review commentOCA/helpdesk

13.0 helpdesk time control

+# Copyright 2020 Graeme Gellatly+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).++from odoo import api, models+++class HelpdeskTicket(models.Model):+    _name = "helpdesk.ticket"+    _inherit = ["helpdesk.ticket", "hr.timesheet.time_control.mixin"]++    @api.model+    def _relation_with_timesheet_line(self):+        return "ticket_id"++    @api.depends(+        "team_id.allow_timesheet",+        "project_id.allow_timesheets",+        "timesheet_ids.employee_id",+        "timesheet_ids.unit_amount",+    )+    def _compute_show_time_control(self):+        result = super()._compute_show_time_control()+        for ticket in self:+            # Never show button if timesheets are not allowed in project+            if not (+                ticket.project_id.allow_timesheets and ticket.team_id.allow_timesheet+            ):+                ticket.show_time_control = False

@Yajo this field is not a Boolean so we can't do this.

gdgellatly

comment created time in 3 hours

Pull request review commentOCA/web

[13.0][MIG] web_pivot_computed_measure: Migration to 13.0

+/* Copyright 2020 Tecnativa - Alexandre Díaz+ * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */++odoo.define("web_pivot_computed_measure.PivotModel", function(require) {+    "use strict";++    const core = require("web.core");+    const PivotModel = require("web.PivotModel");++    const _t = core._t;++    PivotModel.include({+        _computed_measures: [],++        /**+         * Create a new computed measure+         *+         * @param {String} id+         * @param {String} field1+         * @param {String} field2+         * @param {String} operation+         * @param {String} name+         * @param {String} format+         * @returns a promise+         */+        createComputedMeasure: function(id, field1, field2, operation, name, format) {+            const measure = _.find(this._computed_measures, function(item) {+                return (+                    item.field1 === field1 &&+                    item.field2 === field2 &&+                    item.operation === operation+                );+            });+            if (measure) {+                return Promise.resolve();+            }+            const fieldM1 = this.fields[field1];+            const fieldM2 = this.fields[field2];+            const cmId = "__computed_" + id;+            const oper = operation.replace(/m1/g, field1).replace(/m2/g, field2);+            const oper_human = operation+                .replace(+                    /m1/g,+                    fieldM1.__computed_id ? "(" + fieldM1.string + ")" : fieldM1.string+                )+                .replace(+                    /m2/g,+                    fieldM2.__computed_id ? "(" + fieldM2.string + ")" : fieldM2.string+                );+            const cmTotal = this._computed_measures.push({+                field1: field1,+                field2: field2,+                operation: oper,+                name: name || oper_human,+                id: cmId,+                format: format,+            });++            return this._createVirtualMeasure(this._computed_measures[cmTotal - 1]);+        },++        /**+         * Create and enable a measure based on a 'fake' field+         *+         * @private+         * @param {Object} cmDef+         * @param {List} fields *Optional*+         * @returns a promise+         */+        _createVirtualMeasure: function(cmDef, fields) {+            const arrFields = fields || this.fields;+            // This is a minimal 'fake' field info+            arrFields[cmDef.id] = {+                // Used to format the value+                type: cmDef.format,+                // Used to print the header name+                string: cmDef.name,+                // Used to know if is a computed measure field+                __computed_id: cmDef.id,+            };+            this.trigger_up("add_measure", {+                id: cmDef.id,+                def: arrFields[cmDef.id],+            });+            return this._activeMeasures([cmDef.field1, cmDef.field2, cmDef.id]);+        },++        /*+         * @private+         * @param {List of Strings} fields+         */+        _activeMeasures: function(fields) {+            var needLoad = false;+            for (const field of fields) {+                if (!this._isMeasureEnabled(field)) {+                    this.data.measures.push(field);+                    needLoad = true;+                }+            }+            if (needLoad) {+                return this._loadData();+            }+            return Promise.resolve();+        },++        /*+         * @private+         * @param {String} field+         */+        _isMeasureEnabled: function(field) {+            return _.contains(this.data.measures, field);+        },++        /**+         * Helper function to add computed measure fields data into a 'subGroupData'+         *+         * @private+         * @param {Object} subGroupData+         */+        _fillComputedMeasuresData: function(subGroupData) {+            const self = this;+            _.each(this._computed_measures, function(cm) {+                if (!self._isMeasureEnabled(cm.id)) return;+                if (subGroupData.__count === 0) {+                    subGroupData[cm.id] = false;+                } else {+                    // eslint-disable-next-line no-undef+                    subGroupData[cm.id] = py.eval(cm.operation, subGroupData);+                }+            });+        },++        /**+         * Fill the groupSubdivisions with the computed measures and their values+         *+         * @override+         */+        _prepareData: function(group, groupSubdivisions) {+            for (const groupSubdivision of groupSubdivisions) {+                for (const subGroup of groupSubdivision.subGroups) {+                    this._fillComputedMeasuresData(subGroup);+                }+            }+            this._super.apply(this, arguments);+        },++        /**+         * _getGroupSubdivision method invokes the read_group method of the+         * model via rpc and the passed 'fields' argument is the list of+         * measure names that is in this.data.measures, so we remove the+         * computed measures form this.data.measures before calling _super+         * to prevent an exception+         *+         * @override+         */+        _getGroupSubdivision: function() {+            const computed_measures = [];+            for (var i = 0; i < this.data.measures.length; i++)+                if (this.data.measures[i].startsWith("__computed_")) {+                    computed_measures.push(this.data.measures[i]);+                    this.data.measures.splice(i, 1);+                    i--;+                }+            const res = this._super.apply(this, arguments);+            $.merge(this.data.measures, computed_measures);+            return res;+        },++        /**+         * Load the computed measures in context. This is used by filters.+         *+         * @override+         */+        load: function(params) {+            const self = this;
ernestotejeda

comment created time in 3 hours

Pull request review commentOCA/web

[13.0][MIG] web_pivot_computed_measure: Migration to 13.0

+/* Copyright 2020 Tecnativa - Alexandre Díaz+ * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */++odoo.define("web_pivot_computed_measure.PivotModel", function(require) {+    "use strict";++    const core = require("web.core");+    const PivotModel = require("web.PivotModel");++    const _t = core._t;++    PivotModel.include({+        _computed_measures: [],++        /**+         * Create a new computed measure+         *+         * @param {String} id+         * @param {String} field1+         * @param {String} field2+         * @param {String} operation+         * @param {String} name+         * @param {String} format+         * @returns a promise+         */+        createComputedMeasure: function(id, field1, field2, operation, name, format) {+            const measure = _.find(this._computed_measures, function(item) {+                return (+                    item.field1 === field1 &&+                    item.field2 === field2 &&+                    item.operation === operation+                );+            });+            if (measure) {+                return Promise.resolve();+            }+            const fieldM1 = this.fields[field1];+            const fieldM2 = this.fields[field2];+            const cmId = "__computed_" + id;+            const oper = operation.replace(/m1/g, field1).replace(/m2/g, field2);+            const oper_human = operation+                .replace(+                    /m1/g,+                    fieldM1.__computed_id ? "(" + fieldM1.string + ")" : fieldM1.string+                )+                .replace(+                    /m2/g,+                    fieldM2.__computed_id ? "(" + fieldM2.string + ")" : fieldM2.string+                );+            const cmTotal = this._computed_measures.push({+                field1: field1,+                field2: field2,+                operation: oper,+                name: name || oper_human,+                id: cmId,+                format: format,+            });++            return this._createVirtualMeasure(this._computed_measures[cmTotal - 1]);+        },++        /**+         * Create and enable a measure based on a 'fake' field+         *+         * @private+         * @param {Object} cmDef+         * @param {List} fields *Optional*+         * @returns a promise+         */+        _createVirtualMeasure: function(cmDef, fields) {+            const arrFields = fields || this.fields;+            // This is a minimal 'fake' field info+            arrFields[cmDef.id] = {+                // Used to format the value+                type: cmDef.format,+                // Used to print the header name+                string: cmDef.name,+                // Used to know if is a computed measure field+                __computed_id: cmDef.id,+            };+            this.trigger_up("add_measure", {+                id: cmDef.id,+                def: arrFields[cmDef.id],+            });+            return this._activeMeasures([cmDef.field1, cmDef.field2, cmDef.id]);+        },++        /*+         * @private+         * @param {List of Strings} fields+         */+        _activeMeasures: function(fields) {+            var needLoad = false;+            for (const field of fields) {+                if (!this._isMeasureEnabled(field)) {+                    this.data.measures.push(field);+                    needLoad = true;+                }+            }+            if (needLoad) {+                return this._loadData();+            }+            return Promise.resolve();+        },++        /*+         * @private+         * @param {String} field+         */+        _isMeasureEnabled: function(field) {+            return _.contains(this.data.measures, field);+        },++        /**+         * Helper function to add computed measure fields data into a 'subGroupData'+         *+         * @private+         * @param {Object} subGroupData+         */+        _fillComputedMeasuresData: function(subGroupData) {+            const self = this;+            _.each(this._computed_measures, function(cm) {+                if (!self._isMeasureEnabled(cm.id)) return;+                if (subGroupData.__count === 0) {+                    subGroupData[cm.id] = false;+                } else {+                    // eslint-disable-next-line no-undef+                    subGroupData[cm.id] = py.eval(cm.operation, subGroupData);+                }+            });+        },++        /**+         * Fill the groupSubdivisions with the computed measures and their values+         *+         * @override+         */+        _prepareData: function(group, groupSubdivisions) {+            for (const groupSubdivision of groupSubdivisions) {+                for (const subGroup of groupSubdivision.subGroups) {+                    this._fillComputedMeasuresData(subGroup);+                }+            }+            this._super.apply(this, arguments);+        },++        /**+         * _getGroupSubdivision method invokes the read_group method of the+         * model via rpc and the passed 'fields' argument is the list of+         * measure names that is in this.data.measures, so we remove the+         * computed measures form this.data.measures before calling _super+         * to prevent an exception+         *+         * @override+         */+        _getGroupSubdivision: function() {+            const computed_measures = [];+            for (var i = 0; i < this.data.measures.length; i++)+                if (this.data.measures[i].startsWith("__computed_")) {+                    computed_measures.push(this.data.measures[i]);+                    this.data.measures.splice(i, 1);+                    i--;+                }+            const res = this._super.apply(this, arguments);+            $.merge(this.data.measures, computed_measures);+            return res;+        },++        /**+         * Load the computed measures in context. This is used by filters.+         *+         * @override+         */+        load: function(params) {+            const self = this;+            this._computed_measures =+                params.context.pivot_computed_measures ||+                params.computed_measures ||+                [];+            var toActive = [];+            for (const cmDef of this._computed_measures) {+                params.fields[cmDef.id] = {+                    type: cmDef.format,+                    string: cmDef.name,+                    __computed_id: cmDef.id,+                };+                toActive.push(cmDef.field1, cmDef.field2, cmDef.id);+            }+            return this._super(params).then(function() {+                _.defer(function() {+                    for (const cmDef of self._computed_measures) {+                        self.trigger_up("add_measure", {+                            id: cmDef.id,+                            def: self.fields[cmDef.id],+                        });+                    }+                });+                self._activeMeasures(toActive);+            });+        },++        /**+         * Load the computed measures in context. This is used by filters.+         *+         * @override+         */+        reload: function(handle, params) {+            if ("context" in params) {+                this._computed_measures =+                    params.context.pivot_computed_measures ||+                    params.computed_measures ||+                    [];+            }+            for (const cmDef of this._computed_measures) {+                this._createVirtualMeasure(cmDef);+            }+            const fieldNames = Object.keys(this.fields);+            for (const fieldName of fieldNames) {+                const field = this.fields[fieldName];+                if (field.__computed_id) {+                    const cm = _.find(this._computed_measures, {+                        id: field.__computed_id,+                    });+                    if (!cm) {+                        delete this.fields[fieldName];+                        this.data.measures = _.without(this.data.measures, fieldName);+                        this.trigger_up("remove_measure", {+                            id: fieldName,+                        });+                    }+                }+            }+            return this._super.apply(this, arguments);+        },++        /**+         * Add the computed measures to the state. This is used by filters.+         *+         * @override+         */+        get: function() {+            const res = this._super.apply(this, arguments);+            res.computed_measures = this._computed_measures;+            return res;+        },++        /**+         * Adds a rule to deny that measures can be disabled if are being used by a computed measure.+         * In the other hand, when enables a measure analyzes it to active all involved measures.+         *+         * @override+         */+        toggleMeasure: function(field) {+            if (this._isMeasureEnabled(field)) {+                // Measure is disabled+                var umeasures = _.filter(this._computed_measures, function(item) {
                var umeasures = _.filter(this._computed_measures, (item) => {
ernestotejeda

comment created time in 3 hours

Pull request review commentOCA/web

[13.0][MIG] web_pivot_computed_measure: Migration to 13.0

+/* Copyright 2020 Tecnativa - Alexandre Díaz+ * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */++odoo.define("web_pivot_computed_measure.PivotModel", function(require) {+    "use strict";++    const core = require("web.core");+    const PivotModel = require("web.PivotModel");++    const _t = core._t;++    PivotModel.include({+        _computed_measures: [],++        /**+         * Create a new computed measure+         *+         * @param {String} id+         * @param {String} field1+         * @param {String} field2+         * @param {String} operation+         * @param {String} name+         * @param {String} format+         * @returns a promise+         */+        createComputedMeasure: function(id, field1, field2, operation, name, format) {+            const measure = _.find(this._computed_measures, function(item) {+                return (+                    item.field1 === field1 &&+                    item.field2 === field2 &&+                    item.operation === operation+                );+            });+            if (measure) {+                return Promise.resolve();+            }+            const fieldM1 = this.fields[field1];+            const fieldM2 = this.fields[field2];+            const cmId = "__computed_" + id;+            const oper = operation.replace(/m1/g, field1).replace(/m2/g, field2);+            const oper_human = operation+                .replace(+                    /m1/g,+                    fieldM1.__computed_id ? "(" + fieldM1.string + ")" : fieldM1.string+                )+                .replace(+                    /m2/g,+                    fieldM2.__computed_id ? "(" + fieldM2.string + ")" : fieldM2.string+                );+            const cmTotal = this._computed_measures.push({+                field1: field1,+                field2: field2,+                operation: oper,+                name: name || oper_human,+                id: cmId,+                format: format,+            });++            return this._createVirtualMeasure(this._computed_measures[cmTotal - 1]);+        },++        /**+         * Create and enable a measure based on a 'fake' field+         *+         * @private+         * @param {Object} cmDef+         * @param {List} fields *Optional*+         * @returns a promise+         */+        _createVirtualMeasure: function(cmDef, fields) {+            const arrFields = fields || this.fields;+            // This is a minimal 'fake' field info+            arrFields[cmDef.id] = {+                // Used to format the value+                type: cmDef.format,+                // Used to print the header name+                string: cmDef.name,+                // Used to know if is a computed measure field+                __computed_id: cmDef.id,+            };+            this.trigger_up("add_measure", {+                id: cmDef.id,+                def: arrFields[cmDef.id],+            });+            return this._activeMeasures([cmDef.field1, cmDef.field2, cmDef.id]);+        },++        /*+         * @private+         * @param {List of Strings} fields+         */+        _activeMeasures: function(fields) {+            var needLoad = false;+            for (const field of fields) {+                if (!this._isMeasureEnabled(field)) {+                    this.data.measures.push(field);+                    needLoad = true;+                }+            }+            if (needLoad) {+                return this._loadData();+            }+            return Promise.resolve();+        },++        /*+         * @private+         * @param {String} field+         */+        _isMeasureEnabled: function(field) {+            return _.contains(this.data.measures, field);+        },++        /**+         * Helper function to add computed measure fields data into a 'subGroupData'+         *+         * @private+         * @param {Object} subGroupData+         */+        _fillComputedMeasuresData: function(subGroupData) {+            const self = this;+            _.each(this._computed_measures, function(cm) {+                if (!self._isMeasureEnabled(cm.id)) return;+                if (subGroupData.__count === 0) {+                    subGroupData[cm.id] = false;+                } else {+                    // eslint-disable-next-line no-undef+                    subGroupData[cm.id] = py.eval(cm.operation, subGroupData);+                }+            });+        },++        /**+         * Fill the groupSubdivisions with the computed measures and their values+         *+         * @override+         */+        _prepareData: function(group, groupSubdivisions) {+            for (const groupSubdivision of groupSubdivisions) {+                for (const subGroup of groupSubdivision.subGroups) {+                    this._fillComputedMeasuresData(subGroup);+                }+            }+            this._super.apply(this, arguments);+        },++        /**+         * _getGroupSubdivision method invokes the read_group method of the+         * model via rpc and the passed 'fields' argument is the list of+         * measure names that is in this.data.measures, so we remove the+         * computed measures form this.data.measures before calling _super+         * to prevent an exception+         *+         * @override+         */+        _getGroupSubdivision: function() {+            const computed_measures = [];+            for (var i = 0; i < this.data.measures.length; i++)+                if (this.data.measures[i].startsWith("__computed_")) {+                    computed_measures.push(this.data.measures[i]);+                    this.data.measures.splice(i, 1);+                    i--;+                }+            const res = this._super.apply(this, arguments);+            $.merge(this.data.measures, computed_measures);+            return res;+        },++        /**+         * Load the computed measures in context. This is used by filters.+         *+         * @override+         */+        load: function(params) {+            const self = this;+            this._computed_measures =+                params.context.pivot_computed_measures ||+                params.computed_measures ||+                [];+            var toActive = [];+            for (const cmDef of this._computed_measures) {+                params.fields[cmDef.id] = {+                    type: cmDef.format,+                    string: cmDef.name,+                    __computed_id: cmDef.id,+                };+                toActive.push(cmDef.field1, cmDef.field2, cmDef.id);+            }+            return this._super(params).then(function() {+                _.defer(function() {+                    for (const cmDef of self._computed_measures) {+                        self.trigger_up("add_measure", {+                            id: cmDef.id,+                            def: self.fields[cmDef.id],+                        });+                    }+                });+                self._activeMeasures(toActive);+            });
            return this._super(params).then(() => {
                _.defer(() => {
                    for (const cmDef of this._computed_measures) {
                        this.trigger_up("add_measure", {
                            id: cmDef.id,
                            def: this.fields[cmDef.id],
                        });
                    }
                });
                this._activeMeasures(toActive);
            });
ernestotejeda

comment created time in 3 hours

Pull request review commentOCA/web

[13.0][MIG] web_pivot_computed_measure: Migration to 13.0

+/* Copyright 2020 Tecnativa - Alexandre Díaz+ * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */++odoo.define("web_pivot_computed_measure.PivotController", function(require) {+    "use strict";++    const core = require("web.core");+    const config = require("web.config");+    const PivotController = require("web.PivotController");++    const QWeb = core.qweb;++    PivotController.include({+        custom_events: _.extend({}, PivotController.prototype.custom_events, {+            add_measure: "_onAddMeasure",+            remove_measure: "_onRemoveMeasure",+        }),++        computed_measures_open: false,++        /**+         * Add the computed measures to the context. This+         * will be used when save a filter.+         *+         * @override+         */+        getOwnedQueryParams: function() {+            const res = this._super.apply(this, arguments);+            const state = this.model.get({raw: true});+            res.context.pivot_computed_measures = state.computed_measures;+            return res;+        },++        /**+         * @override+         */+        renderButtons: function($node) {+            this._super.apply(this, arguments);+            if ($node) {+                this._renderComputedMeasures();+            }+        },++        /**+         * Handle click event on measures menu to support computed measures sub-menu+         *+         * @override+         */+        _onButtonClick: function(event) {+            const $target = $(event.target);+            if ($target.parents("div[data-id='__computed__']").length) {+                let hideMenu = false;+                event.preventDefault();++                if (+                    $target.hasClass("dropdown-item") ||+                    $target.hasClass("o_submenu_switcher")+                ) {+                    this.computed_measures_open = !this.computed_measures_open;+                    this._renderComputedMeasures();+                } else if ($target.hasClass("o_add_computed_measure")) {+                    hideMenu = true;+                    const field1 = this.$buttons_measures_ex+                        .find("#computed_measure_field_1")+                        .val();+                    const field2 = this.$buttons_measures_ex+                        .find("#computed_measure_field_2")+                        .val();+                    var oper = this.$buttons_measures_ex+                        .find("#computed_measure_operation")+                        .val();+                    if (oper === "custom") {+                        oper = this.$buttons_measures_ex+                            .find("#computed_measure_operation_custom")+                            .val();+                    }+                    const name = this.$buttons_measures_ex+                        .find("#computed_measure_name")+                        .val();+                    const format = this.$buttons_measures_ex+                        .find("#computed_measure_format")+                        .val();+                    const uniqueId = new Date().getTime();+                    this.model+                        .createComputedMeasure(+                            uniqueId,+                            field1,+                            field2,+                            oper,+                            name,+                            format+                        )+                        .then(this.update.bind(this, {}, {reload: false}));+                }++                if (!hideMenu) {+                    event.stopPropagation();+                }++                return;+            }++            this._super.apply(this, arguments);+        },++        /**+         * Render computed measures menu+         *+         * @private+         */+        _renderComputedMeasures: function() {+            if (this.$buttons_measures_ex && this.$buttons_measures_ex.length) {+                this.$buttons_measures_ex.remove();+            }+            const self = this;+            const measures = _.sortBy(+                _.pairs(_.omit(this.measures, "__count")),+                function(x) {+                    return x[1].string.toLowerCase();+                }+            );+            this.$buttons_measures_ex = $(+                QWeb.render("web_pivot_computed_measure.ExtendedMenu", {+                    isOpen: this.computed_measures_open,+                    debug: config.isDebug(),+                    measures: measures,+                    computed_measures: _.map(+                        _.reject(measures, function(item) {+                            return !item[1].__computed_id;+                        }),+                        function(item) {+                            item[1].active = _.contains(+                                self.model.data.measures,
                                this.model.data.measures,
ernestotejeda

comment created time in 3 hours

Pull request review commentOCA/web

[13.0][MIG] web_pivot_computed_measure: Migration to 13.0

+/* Copyright 2020 Tecnativa - Alexandre Díaz+ * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */++odoo.define("web_pivot_computed_measure.PivotModel", function(require) {+    "use strict";++    const core = require("web.core");+    const PivotModel = require("web.PivotModel");++    const _t = core._t;++    PivotModel.include({+        _computed_measures: [],++        /**+         * Create a new computed measure+         *+         * @param {String} id+         * @param {String} field1+         * @param {String} field2+         * @param {String} operation+         * @param {String} name+         * @param {String} format+         * @returns a promise+         */+        createComputedMeasure: function(id, field1, field2, operation, name, format) {+            const measure = _.find(this._computed_measures, function(item) {
            const measure = _.find(this._computed_measures, (item) => {
ernestotejeda

comment created time in 3 hours

Pull request review commentOCA/web

[13.0][MIG] web_pivot_computed_measure: Migration to 13.0

+/* Copyright 2020 Tecnativa - Alexandre Díaz+ * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */++odoo.define("web_pivot_computed_measure.PivotController", function(require) {+    "use strict";++    const core = require("web.core");+    const config = require("web.config");+    const PivotController = require("web.PivotController");++    const QWeb = core.qweb;++    PivotController.include({+        custom_events: _.extend({}, PivotController.prototype.custom_events, {+            add_measure: "_onAddMeasure",+            remove_measure: "_onRemoveMeasure",+        }),++        computed_measures_open: false,++        /**+         * Add the computed measures to the context. This+         * will be used when save a filter.+         *+         * @override+         */+        getOwnedQueryParams: function() {+            const res = this._super.apply(this, arguments);+            const state = this.model.get({raw: true});+            res.context.pivot_computed_measures = state.computed_measures;+            return res;+        },++        /**+         * @override+         */+        renderButtons: function($node) {+            this._super.apply(this, arguments);+            if ($node) {+                this._renderComputedMeasures();+            }+        },++        /**+         * Handle click event on measures menu to support computed measures sub-menu+         *+         * @override+         */+        _onButtonClick: function(event) {+            const $target = $(event.target);+            if ($target.parents("div[data-id='__computed__']").length) {+                let hideMenu = false;+                event.preventDefault();++                if (+                    $target.hasClass("dropdown-item") ||+                    $target.hasClass("o_submenu_switcher")+                ) {+                    this.computed_measures_open = !this.computed_measures_open;+                    this._renderComputedMeasures();+                } else if ($target.hasClass("o_add_computed_measure")) {+                    hideMenu = true;+                    const field1 = this.$buttons_measures_ex+                        .find("#computed_measure_field_1")+                        .val();+                    const field2 = this.$buttons_measures_ex+                        .find("#computed_measure_field_2")+                        .val();+                    var oper = this.$buttons_measures_ex+                        .find("#computed_measure_operation")+                        .val();+                    if (oper === "custom") {+                        oper = this.$buttons_measures_ex+                            .find("#computed_measure_operation_custom")+                            .val();+                    }+                    const name = this.$buttons_measures_ex+                        .find("#computed_measure_name")+                        .val();+                    const format = this.$buttons_measures_ex+                        .find("#computed_measure_format")+                        .val();+                    const uniqueId = new Date().getTime();+                    this.model+                        .createComputedMeasure(+                            uniqueId,+                            field1,+                            field2,+                            oper,+                            name,+                            format+                        )+                        .then(this.update.bind(this, {}, {reload: false}));+                }++                if (!hideMenu) {+                    event.stopPropagation();+                }++                return;+            }++            this._super.apply(this, arguments);+        },++        /**+         * Render computed measures menu+         *+         * @private+         */+        _renderComputedMeasures: function() {+            if (this.$buttons_measures_ex && this.$buttons_measures_ex.length) {+                this.$buttons_measures_ex.remove();+            }+            const self = this;
ernestotejeda

comment created time in 3 hours

Pull request review commentOCA/web

[13.0][MIG] web_pivot_computed_measure: Migration to 13.0

+/* Copyright 2020 Tecnativa - Alexandre Díaz+ * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */++odoo.define("web_pivot_computed_measure.PivotController", function(require) {+    "use strict";++    const core = require("web.core");+    const config = require("web.config");+    const PivotController = require("web.PivotController");++    const QWeb = core.qweb;++    PivotController.include({+        custom_events: _.extend({}, PivotController.prototype.custom_events, {+            add_measure: "_onAddMeasure",+            remove_measure: "_onRemoveMeasure",+        }),++        computed_measures_open: false,++        /**+         * Add the computed measures to the context. This+         * will be used when save a filter.+         *+         * @override+         */+        getOwnedQueryParams: function() {+            const res = this._super.apply(this, arguments);+            const state = this.model.get({raw: true});+            res.context.pivot_computed_measures = state.computed_measures;+            return res;+        },++        /**+         * @override+         */+        renderButtons: function($node) {+            this._super.apply(this, arguments);+            if ($node) {+                this._renderComputedMeasures();+            }+        },++        /**+         * Handle click event on measures menu to support computed measures sub-menu+         *+         * @override+         */+        _onButtonClick: function(event) {+            const $target = $(event.target);+            if ($target.parents("div[data-id='__computed__']").length) {+                let hideMenu = false;+                event.preventDefault();++                if (+                    $target.hasClass("dropdown-item") ||+                    $target.hasClass("o_submenu_switcher")+                ) {+                    this.computed_measures_open = !this.computed_measures_open;+                    this._renderComputedMeasures();+                } else if ($target.hasClass("o_add_computed_measure")) {+                    hideMenu = true;+                    const field1 = this.$buttons_measures_ex+                        .find("#computed_measure_field_1")+                        .val();+                    const field2 = this.$buttons_measures_ex+                        .find("#computed_measure_field_2")+                        .val();+                    var oper = this.$buttons_measures_ex+                        .find("#computed_measure_operation")+                        .val();+                    if (oper === "custom") {+                        oper = this.$buttons_measures_ex+                            .find("#computed_measure_operation_custom")+                            .val();+                    }+                    const name = this.$buttons_measures_ex+                        .find("#computed_measure_name")+                        .val();+                    const format = this.$buttons_measures_ex+                        .find("#computed_measure_format")+                        .val();+                    const uniqueId = new Date().getTime();+                    this.model+                        .createComputedMeasure(+                            uniqueId,+                            field1,+                            field2,+                            oper,+                            name,+                            format+                        )+                        .then(this.update.bind(this, {}, {reload: false}));+                }++                if (!hideMenu) {+                    event.stopPropagation();+                }++                return;+            }++            this._super.apply(this, arguments);+        },++        /**+         * Render computed measures menu+         *+         * @private+         */+        _renderComputedMeasures: function() {+            if (this.$buttons_measures_ex && this.$buttons_measures_ex.length) {+                this.$buttons_measures_ex.remove();+            }+            const self = this;+            const measures = _.sortBy(+                _.pairs(_.omit(this.measures, "__count")),+                function(x) {+                    return x[1].string.toLowerCase();+                }+            );+            this.$buttons_measures_ex = $(+                QWeb.render("web_pivot_computed_measure.ExtendedMenu", {+                    isOpen: this.computed_measures_open,+                    debug: config.isDebug(),+                    measures: measures,+                    computed_measures: _.map(+                        _.reject(measures, function(item) {+                            return !item[1].__computed_id;+                        }),+                        function(item) {
                        (item) => {
ernestotejeda

comment created time in 3 hours

Pull request review commentOCA/web

[13.0][MIG] web_pivot_computed_measure: Migration to 13.0

+/* Copyright 2020 Tecnativa - Alexandre Díaz+ * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */++odoo.define("web_pivot_computed_measure.PivotController", function(require) {+    "use strict";++    const core = require("web.core");+    const config = require("web.config");+    const PivotController = require("web.PivotController");++    const QWeb = core.qweb;++    PivotController.include({+        custom_events: _.extend({}, PivotController.prototype.custom_events, {+            add_measure: "_onAddMeasure",+            remove_measure: "_onRemoveMeasure",+        }),++        computed_measures_open: false,++        /**+         * Add the computed measures to the context. This+         * will be used when save a filter.+         *+         * @override+         */+        getOwnedQueryParams: function() {+            const res = this._super.apply(this, arguments);+            const state = this.model.get({raw: true});+            res.context.pivot_computed_measures = state.computed_measures;+            return res;+        },++        /**+         * @override+         */+        renderButtons: function($node) {+            this._super.apply(this, arguments);+            if ($node) {+                this._renderComputedMeasures();+            }+        },++        /**+         * Handle click event on measures menu to support computed measures sub-menu+         *+         * @override+         */+        _onButtonClick: function(event) {+            const $target = $(event.target);+            if ($target.parents("div[data-id='__computed__']").length) {+                let hideMenu = false;+                event.preventDefault();++                if (+                    $target.hasClass("dropdown-item") ||+                    $target.hasClass("o_submenu_switcher")+                ) {+                    this.computed_measures_open = !this.computed_measures_open;+                    this._renderComputedMeasures();+                } else if ($target.hasClass("o_add_computed_measure")) {+                    hideMenu = true;+                    const field1 = this.$buttons_measures_ex+                        .find("#computed_measure_field_1")+                        .val();+                    const field2 = this.$buttons_measures_ex+                        .find("#computed_measure_field_2")+                        .val();+                    var oper = this.$buttons_measures_ex+                        .find("#computed_measure_operation")+                        .val();+                    if (oper === "custom") {+                        oper = this.$buttons_measures_ex+                            .find("#computed_measure_operation_custom")+                            .val();+                    }+                    const name = this.$buttons_measures_ex+                        .find("#computed_measure_name")+                        .val();+                    const format = this.$buttons_measures_ex+                        .find("#computed_measure_format")+                        .val();+                    const uniqueId = new Date().getTime();+                    this.model+                        .createComputedMeasure(+                            uniqueId,+                            field1,+                            field2,+                            oper,+                            name,+                            format+                        )+                        .then(this.update.bind(this, {}, {reload: false}));+                }++                if (!hideMenu) {+                    event.stopPropagation();+                }++                return;+            }++            this._super.apply(this, arguments);+        },++        /**+         * Render computed measures menu+         *+         * @private+         */+        _renderComputedMeasures: function() {+            if (this.$buttons_measures_ex && this.$buttons_measures_ex.length) {+                this.$buttons_measures_ex.remove();+            }+            const self = this;+            const measures = _.sortBy(+                _.pairs(_.omit(this.measures, "__count")),+                function(x) {
                (x) => {
ernestotejeda

comment created time in 3 hours

Pull request review commentOCA/web

[13.0][MIG] web_pivot_computed_measure: Migration to 13.0

+/* Copyright 2020 Tecnativa - Alexandre Díaz+ * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) */++odoo.define("web_pivot_computed_measure.PivotModel", function(require) {+    "use strict";++    const core = require("web.core");+    const PivotModel = require("web.PivotModel");++    const _t = core._t;++    PivotModel.include({+        _computed_measures: [],++        /**+         * Create a new computed measure+         *+         * @param {String} id+         * @param {String} field1+         * @param {String} field2+         * @param {String} operation+         * @param {String} name+         * @param {String} format+         * @returns a promise+         */+        createComputedMeasure: function(id, field1, field2, operation, name, format) {+            const measure = _.find(this._computed_measures, function(item) {+                return (+                    item.field1 === field1 &&+                    item.field2 === field2 &&+                    item.operation === operation+                );+            });+            if (measure) {+                return Promise.resolve();+            }+            const fieldM1 = this.fields[field1];+            const fieldM2 = this.fields[field2];+            const cmId = "__computed_" + id;+            const oper = operation.replace(/m1/g, field1).replace(/m2/g, field2);+            const oper_human = operation+                .replace(+                    /m1/g,+                    fieldM1.__computed_id ? "(" + fieldM1.string + ")" : fieldM1.string+                )+                .replace(+                    /m2/g,+                    fieldM2.__computed_id ? "(" + fieldM2.string + ")" : fieldM2.string+                );+            const cmTotal = this._computed_measures.push({+                field1: field1,+                field2: field2,+                operation: oper,+                name: name || oper_human,+                id: cmId,+                format: format,+            });++            return this._createVirtualMeasure(this._computed_measures[cmTotal - 1]);+        },++        /**+         * Create and enable a measure based on a 'fake' field+         *+         * @private+         * @param {Object} cmDef+         * @param {List} fields *Optional*+         * @returns a promise+         */+        _createVirtualMeasure: function(cmDef, fields) {+            const arrFields = fields || this.fields;+            // This is a minimal 'fake' field info+            arrFields[cmDef.id] = {+                // Used to format the value+                type: cmDef.format,+                // Used to print the header name+                string: cmDef.name,+                // Used to know if is a computed measure field+                __computed_id: cmDef.id,+            };+            this.trigger_up("add_measure", {+                id: cmDef.id,+                def: arrFields[cmDef.id],+            });+            return this._activeMeasures([cmDef.field1, cmDef.field2, cmDef.id]);+        },++        /*+         * @private+         * @param {List of Strings} fields+         */+        _activeMeasures: function(fields) {+            var needLoad = false;+            for (const field of fields) {+                if (!this._isMeasureEnabled(field)) {+                    this.data.measures.push(field);+                    needLoad = true;+                }+            }+            if (needLoad) {+                return this._loadData();+            }+            return Promise.resolve();+        },++        /*+         * @private+         * @param {String} field+         */+        _isMeasureEnabled: function(field) {+            return _.contains(this.data.measures, field);+        },++        /**+         * Helper function to add computed measure fields data into a 'subGroupData'+         *+         * @private+         * @param {Object} subGroupData+         */+        _fillComputedMeasuresData: function(subGroupData) {+            const self = this;+            _.each(this._computed_measures, function(cm) {+                if (!self._isMeasureEnabled(cm.id)) return;+                if (subGroupData.__count === 0) {+                    subGroupData[cm.id] = false;+                } else {+                    // eslint-disable-next-line no-undef+                    subGroupData[cm.id] = py.eval(cm.operation, subGroupData);+                }+            });
            for (const cm of this._computed_measures) {
                if (!this._isMeasureEnabled(cm.id)) return;
                if (subGroupData.__count === 0) {
                    subGroupData[cm.id] = false;
                } else {
                    // eslint-disable-next-line no-undef
                    subGroupData[cm.id] = py.eval(cm.operation, subGroupData);
                }
            }
ernestotejeda

comment created time in 3 hours

pull request commentOCA/helpdesk

13.0 helpdesk time control

@Yajo I added all the suggestions thanks. The only one I don't especially agree with was the ordering of timesheets on tickets by date_time DESC. I hate that UI on editable tree views, where the newest item is at top, but you need to add new item at bottom, but editable="top" has its own issues. But I don't care enough to argue it, there are benefits both ways.

gdgellatly

comment created time in 3 hours

Pull request review commentcamptocamp/camptocamp-devops-stack

Adding thanos support on bucket

 module "cluster" {   repo_url        = var.repo_url   target_revision = var.target_revision +  enable_minio = true

Please enable metrics archive here so that acceptance tests are run

pburgisser

comment created time in 3 hours

Pull request review commentcamptocamp/camptocamp-devops-stack

Adding thanos support on bucket

 argo-cd:   server:     config:       admin.enabled: "false"--cert-manager:+kube-prometheus-stack:+  prometheus:+    serviceAccount:+      annotations:+        eks.amazonaws.com/role-arn: ${thanos_assumable_role_arn}+cert-amazonawsager:

WTF? :-)

pburgisser

comment created time in 4 hours

Pull request review commentcamptocamp/camptocamp-devops-stack

Adding thanos support on bucket

 variable "server_memory" {   default     = 2048 } +variable "enable_metrics_archives" {+  description = "Whether to enable prometheus to flush WAL to object storage"+  type        = bool+  default     = false+}++variable "thanos_archives_endpoint" {+  description = "S3 like endpoint for thanos long term storage"+  type        = string+  default     = ""+}++variable "thanos_archives_bucket_name" {+  description = "Bucket name for thanos"+  type        = string+  default     = "thanos"+}+ variable "agent_memory" {   description = "Agent RAM"   type        = number   default     = 2048 }+

Please remove extra empty line

pburgisser

comment created time in 4 hours

startedsbidoul/pip-deepfreeze

started time in 3 hours

more