diff options
| author | Christophe Simonis <chs@odoo.com> | 2018-08-01 17:23:03 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2018-08-01 17:23:03 +0200 |
| commit | 8d9366197e174d33fdf6962364a24ea40a1131b1 (patch) | |
| tree | a900c27006510633f14827b00b80df8f01eeef1a /addons | |
| parent | 8be798375eadefb6b66e3065a1af3f5eef9ab78a (diff) | |
| parent | 691dd65e0ecca5ef1ab4fa1ff363562a9349c1d4 (diff) | |
[MERGE] forward port branch saas-11.3 up to 691dd65e0ec
Diffstat (limited to 'addons')
| -rw-r--r-- | addons/account/models/account_move.py | 5 | ||||
| -rw-r--r-- | addons/account/models/account_payment.py | 1 | ||||
| -rw-r--r-- | addons/account/report/account_aged_partner_balance.py | 2 | ||||
| -rw-r--r-- | addons/account/static/src/js/reconciliation/reconciliation_model.js | 18 | ||||
| -rw-r--r-- | addons/account/static/src/js/reconciliation/reconciliation_renderer.js | 7 | ||||
| -rw-r--r-- | addons/account/static/tests/reconciliation_tests.js | 160 | ||||
| -rw-r--r-- | addons/account/views/account_view.xml | 14 | ||||
| -rw-r--r-- | addons/im_livechat/static/src/js/im_livechat.js | 4 | ||||
| -rw-r--r-- | addons/purchase_stock/models/stock.py | 2 | ||||
| -rw-r--r-- | addons/stock/views/product_views.xml | 1 | ||||
| -rw-r--r-- | addons/web/static/tests/helpers/test_utils.js | 5 | ||||
| -rw-r--r-- | addons/website_sale/models/website.py | 4 | ||||
| -rw-r--r-- | addons/website_sale_wishlist/views/website_sale_wishlist_template.xml | 2 |
13 files changed, 209 insertions, 16 deletions
diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index c66b1efa82d..0144258ecb8 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -646,8 +646,11 @@ class AccountMoveLine(models.Model): #compute the default credit/debit of the next line in case of a manual entry balance = 0 for line in self._context['line_ids']: - if line[2]: + if line[2]: # in case of command 0: add a record with values balance += line[2].get('debit', 0) - line[2].get('credit', 0) + elif line[0] == 2: # line has been deleted + line_obj = self.browse(line[1]) + balance -= line_obj.debit - line_obj.credit if balance < 0: rec.update({'debit': -balance}) if balance > 0: diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py index 0cbb74dd7a4..0da4a3da3fe 100644 --- a/addons/account/models/account_payment.py +++ b/addons/account/models/account_payment.py @@ -259,6 +259,7 @@ class account_register_payments(models.TransientModel): 'currency_id': self.currency_id.id, 'partner_id': invoices[0].commercial_partner_id.id, 'partner_type': MAP_INVOICE_TYPE_PARTNER_TYPE[invoices[0].type], + 'multi': False, } @api.multi diff --git a/addons/account/report/account_aged_partner_balance.py b/addons/account/report/account_aged_partner_balance.py index 95a01bfd0c2..8748a03ff34 100644 --- a/addons/account/report/account_aged_partner_balance.py +++ b/addons/account/report/account_aged_partner_balance.py @@ -77,7 +77,7 @@ class ReportAgedPartnerBalance(models.AbstractModel): partner_ids = [partner['partner_id'] for partner in partners if partner['partner_id']] lines = dict((partner['partner_id'] or False, []) for partner in partners) if not partner_ids: - return [], [], [] + return [], [], {} # This dictionary will store the not due amount of all partners undue_amounts = {} diff --git a/addons/account/static/src/js/reconciliation/reconciliation_model.js b/addons/account/static/src/js/reconciliation/reconciliation_model.js index 87bd379879d..f42943f6027 100644 --- a/addons/account/static/src/js/reconciliation/reconciliation_model.js +++ b/addons/account/static/src/js/reconciliation/reconciliation_model.js @@ -130,6 +130,20 @@ var StatementModel = BasicModel.extend({ var line = this.getLine(handle); var prop = _.clone(_.find(line.mv_lines, {'id': mv_line_id})); this._addProposition(line, prop); + + // Check whether we have some propositions left + // If we don't, it means we are on an empty page + // so let's go back to the previous page + // Through the offset + var propLineIds = _.map(line.reconciliation_proposition, function(prop) { + return prop.id; + }); + var leftOversProps = _.filter(line.mv_lines, function(mv_line) { + return propLineIds.indexOf(mv_line.id) === -1; + }); + if (line.offset && !leftOversProps.length) { + line.offset -= line.limitMoveLines; + } return $.when(this._computeLine(line), this._performMoveLine(handle)); }, /** @@ -665,7 +679,7 @@ var StatementModel = BasicModel.extend({ return !isNaN(prop.id) && prop.already_paid; }), 'id'), "new_aml_dicts": _.map(_.filter(props, function (prop) { - return isNaN(prop.id); + return isNaN(prop.id) && prop.display; }), self._formatToProcessReconciliation.bind(self, line)), }; @@ -1262,7 +1276,7 @@ var ManualModel = StatementModel.extend({ }); } else { var mv_line_ids = _.pluck(_.filter(props, function (prop) {return !isNaN(prop.id);}), 'id'); - var new_mv_line_dicts = _.map(_.filter(props, function (prop) {return isNaN(prop.id);}), self._formatToProcessReconciliation.bind(self, line)); + var new_mv_line_dicts = _.map(_.filter(props, function (prop) {return isNaN(prop.id) && prop.display;}), self._formatToProcessReconciliation.bind(self, line)); process_reconciliations.push({ id: null, type: null, diff --git a/addons/account/static/src/js/reconciliation/reconciliation_renderer.js b/addons/account/static/src/js/reconciliation/reconciliation_renderer.js index 7578f9c4d1d..8a4ac8b25e7 100644 --- a/addons/account/static/src/js/reconciliation/reconciliation_renderer.js +++ b/addons/account/static/src/js/reconciliation/reconciliation_renderer.js @@ -423,7 +423,8 @@ var LineRenderer = Widget.extend(FieldManagerMixin, { // mv_lines var $mv_lines = this.$('.match table tbody').empty(); - _.each(state.mv_lines.slice(0, state.limitMoveLines), function (line) { + var stateMvLines = state.mv_lines || []; + _.each(stateMvLines.slice(0, state.limitMoveLines), function (line) { var $line = $(qweb.render("reconciliation.line.mv_line", {'line': line, 'state': state})); if (!isNaN(line.id)) { $('<span class="line_info_button fa fa-info-circle"/>') @@ -432,9 +433,9 @@ var LineRenderer = Widget.extend(FieldManagerMixin, { } $mv_lines.append($line); }); - this.$('.match .fa-chevron-right').toggleClass('disabled', state.mv_lines.length <= state.limitMoveLines); + this.$('.match .fa-chevron-right').toggleClass('disabled', stateMvLines.length <= state.limitMoveLines); this.$('.match .fa-chevron-left').toggleClass('disabled', !state.offset); - this.$('.match').css('max-height', !state.mv_lines.length && !state.filter.length ? '0px' : ''); + this.$('.match').css('max-height', !stateMvLines.length && !state.filter.length ? '0px' : ''); // balance this.$('.popover').remove(); diff --git a/addons/account/static/tests/reconciliation_tests.js b/addons/account/static/tests/reconciliation_tests.js index 4fb3f997368..93a8a1818b4 100644 --- a/addons/account/static/tests/reconciliation_tests.js +++ b/addons/account/static/tests/reconciliation_tests.js @@ -1720,5 +1720,165 @@ QUnit.module('account', { clientAction.destroy(); }); + + QUnit.test('Manual Reconciliation: remove a prop to attain balance and reconcile', function (assert) { + assert.expect(5); + + // tweak the data to fit our needs + this.params.data_for_manual_reconciliation_widget['[283, null, "", 0, 6]'] = _.extend({}, this.params.data_for_manual_reconciliation_widget['[null,null]']); + this.params.data_for_manual_reconciliation_widget['[283, null, "", 0, 6]'].accounts[0].reconciliation_proposition = [ + {account_id: 283, account_type: "other", amount_currency_str: "", currency_id: false, date_maturity: "2017-03-18", date: "2017-02-16", + total_amount_str: "$ 500.00", partner_id: 8, account_name: "101000 Current Assets", name: "INV/2017/0987", partner_name: "Agrolait", + total_amount_currency_str: "", id: 999, credit: 0.0, journal_id: [1, "Customer Invoices"], amount_str: "$ 500.00", debit: 500.0, + account_code: "101000", ref: "", already_paid: false} + ]; + + var clientAction = new ReconciliationClientAction.ManualAction(null, this.params.options); + testUtils.addMockEnvironment(clientAction, { + data: this.params.data, + mockRPC: function (route, args) { + if (args.method === 'process_move_lines') { + assert.deepEqual(args.args, + [ + [{id: null, type: null, + mv_line_ids: [399, 402], + new_mv_line_dicts: []} + ] + ], "should call process_move_lines without the new mv line dict"); + } + + return this._super(route, args); + }, + session: { + currencies: { + 3: { + digits: [69, 2], + position: "before", + symbol: "$" + } + } + }, + }); + + clientAction.appendTo($('#qunit-fixture')); + + // The first reconciliation "line" is where it happens + var widget = clientAction.widgets[0]; + + // Add first prop + widget.$('.match .cell_account_code:first').trigger('click'); + assert.notOk( widget.$('.cell_right .line_info_button').length, + "should not display the partial reconciliation alert"); + + // Add second prop + widget.$('.match .cell_account_code:first').trigger('click'); + + // Check that a create form is here + var writeOffCreate = widget.$('div.create'); + + assert.equal(writeOffCreate.length, 1, + 'A write-off creation should be present'); + + assert.equal(writeOffCreate.find('input[name=amount]').val(), 500, + 'The right amount should be proposed for the write-off'); + + // remove the first line, the other two will balance one another + widget.$('tr[data-line-id="999"] td:first').click() + + var $buttonReconcile = widget.$('button.o_reconcile:not(hidden)'); + assert.equal($buttonReconcile.length, 1, + 'The reconcile button must be visible'); + + $buttonReconcile.click(); + + clientAction.destroy(); + }); + + QUnit.test('Manual Reconciliation: No lines for account', function (assert) { + assert.expect(2); + + var clientAction = new ReconciliationClientAction.ManualAction(null, this.params.options); + testUtils.addMockEnvironment(clientAction, { + data: this.params.data, + session: { + currencies: { + 3: { + digits: [69, 2], + position: "before", + symbol: "$" + } + } + }, + }); + + clientAction.appendTo($('#qunit-fixture')); + + // The second reconciliation "line" is where it happens + var widget = clientAction.widgets[1]; + + var emptyLine = widget.$('tr.mv_line'); + + assert.notOk('data-line-id' in emptyLine.getAttributes(), + 'Empty line should be empty'); + + emptyLine.find('td:first').click(); + + // Check that a create form is here + var writeOffCreate = widget.$('div.create .create_account_id'); + + assert.equal(writeOffCreate.length, 1, + 'A write-off creation should be present'); + + clientAction.destroy(); + }); + + QUnit.test('Automatic Reconciliation: Don\'t loose pager when adding last line of a page', function (assert) { + assert.expect(2); + + function standard_partner (list, partner_id) { + _.each(list, function (item) { + item.partner_id = partner_id; + }); + }; + + this.params.options.params.limitMoveLines = 1; + standard_partner(this.params.mv_lines['[5,"",0,6]'], 8); + + // Overlap of those requests is normal + // the pager is implemented as: + // if there is at least 1 more line than my limit, the pager is active + this.params.mv_lines['[5,"",0,2]'] = this.params.mv_lines['[5,"",0,6]'].slice(0,2); + this.params.mv_lines['[5,"",1,2]'] = this.params.mv_lines['[5,"",0,6]'].slice(1,2); + + var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); + testUtils.addMockEnvironment(clientAction, { + data: this.params.data, + session: { + currencies: { + 3: { + digits: [69, 2], + position: "before", + symbol: "$" + } + } + }, + }); + clientAction.appendTo($('#qunit-fixture')); + + var widget = clientAction.widgets[0]; + + var $nextPage = widget.$('.match .match_controls .fa-chevron-right:not(disabled)'); + assert.ok($nextPage.length, + 'We should have a next page'); + $nextPage.click(); + + // Add the second's page record + widget.$('.match tr[data-line-id=112] td:first').click(); + + assert.ok(widget.$('.match tr[data-line-id=109]').length, + 'the record of the first page must be proposed'); + + clientAction.destroy(); + }); }); }); diff --git a/addons/account/views/account_view.xml b/addons/account/views/account_view.xml index 996eff10cd2..141388fbfd2 100644 --- a/addons/account/views/account_view.xml +++ b/addons/account/views/account_view.xml @@ -320,7 +320,7 @@ <group> <group> <field name="company_partner_id" invisible="1"/> - <field name="bank_account_id"/> + <field name="bank_account_id" context="{'default_partner_id': company_partner_id, 'form_view_ref': 'account.view_company_partner_bank_form'}"/> <field name="bank_id"/> </group> <group > @@ -364,6 +364,18 @@ </field> </record> + <record id="view_company_partner_bank_form" model="ir.ui.view"> + <field name="name">company.res.partner.bank.form</field> + <field name="model">res.partner.bank</field> + <field name="inherit_id" ref="base.view_partner_bank_form"/> + <field name="mode">primary</field> + <field name="arch" type="xml"> + <xpath expr="//field[@name='partner_id']" position="attributes"> + <attribute name="invisible">1</attribute> + </xpath> + </field> + </record> + <record id="view_account_bank_journal_tree" model="ir.ui.view"> <field name="name">account.bank.journal.tree</field> <field name="model">account.journal</field> diff --git a/addons/im_livechat/static/src/js/im_livechat.js b/addons/im_livechat/static/src/js/im_livechat.js index acdf3460ecc..b2b944cc631 100644 --- a/addons/im_livechat/static/src/js/im_livechat.js +++ b/addons/im_livechat/static/src/js/im_livechat.js @@ -2,6 +2,7 @@ odoo.define('im_livechat.im_livechat', function (require) { "use strict"; var bus = require('bus.bus').bus; +var concurrency = require('web.concurrency'); var config = require('web.config'); var core = require('web.core'); var session = require('web.session'); @@ -313,6 +314,7 @@ var Feedback = Widget.extend({ this.channel_uuid = channel_uuid; this.server_origin = session.origin; this.rating = undefined; + this.dp = new concurrency.DropPrevious(); }, on_click_smiley: function (ev) { @@ -348,7 +350,7 @@ var Feedback = Widget.extend({ rate: this.rating, reason : options.reason }; - return session.rpc('/im_livechat/feedback', args).then(function () { + this.dp.add(session.rpc('/im_livechat/feedback', args)).then(function () { if (options.close) { var emoji = RATING_TO_EMOJI[self.rating] || "??" ; var content = _.str.sprintf(_t("Rating: %s"), emoji); diff --git a/addons/purchase_stock/models/stock.py b/addons/purchase_stock/models/stock.py index a108f0bec2a..b3d336ceddc 100644 --- a/addons/purchase_stock/models/stock.py +++ b/addons/purchase_stock/models/stock.py @@ -215,6 +215,6 @@ class PushedFlow(models.Model): _inherit = "stock.location.path" def _prepare_move_copy_values(self, move_to_copy, new_date): - res = super()._prepare_move_copy_values(move_to_copy, new_date) + res = super(PushedFlow, self)._prepare_move_copy_values(move_to_copy, new_date) res['purchase_line_id'] = None return res diff --git a/addons/stock/views/product_views.xml b/addons/stock/views/product_views.xml index f59ae7baf5c..5b58670e5ab 100644 --- a/addons/stock/views/product_views.xml +++ b/addons/stock/views/product_views.xml @@ -11,7 +11,6 @@ <group string="Logistics"> <field name="route_ids" widget="many2many_tags" groups="stock.group_adv_location"/> <div colspan="2" attrs="{'invisible': [('parent_id', '=', False)]}"> - The following routes will apply to the products in this category taking into account parent categories: <field name="total_route_ids" nolabel="1" widget="many2many_tags"/> </div> <field name="removal_strategy_id" options="{'no_create': True}"/> diff --git a/addons/web/static/tests/helpers/test_utils.js b/addons/web/static/tests/helpers/test_utils.js index 6c05076ef98..4720d166a4c 100644 --- a/addons/web/static/tests/helpers/test_utils.js +++ b/addons/web/static/tests/helpers/test_utils.js @@ -547,10 +547,11 @@ function dragAndDrop($el, $to, options) { var toOffset = $to.offset(); toOffset.top += $to.outerHeight()/2; toOffset.left += $to.outerWidth()/2; + var vertical_offset = (toOffset.top < elementCenter.top) ? -1 : 1; if (position === 'top') { - toOffset.top -= $to.outerHeight()/2; + toOffset.top -= $to.outerHeight()/2 + vertical_offset; } else if (position === 'bottom') { - toOffset.top += $to.outerHeight()/2; + toOffset.top += $to.outerHeight()/2 - vertical_offset; } else if (position === 'left') { toOffset.left -= $to.outerWidth()/2; } else if (position === 'right') { diff --git a/addons/website_sale/models/website.py b/addons/website_sale/models/website.py index 13594353abf..64c6bc05ab9 100644 --- a/addons/website_sale/models/website.py +++ b/addons/website_sale/models/website.py @@ -60,8 +60,8 @@ class Website(models.Model): if not pricelists: # no pricelist for this country, or no GeoIP pricelists |= all_pl.filtered(lambda pl: not show_visible or pl.selectable or pl.id in (current_pl, order_pl)) - else: - pricelists |= all_pl.filtered(lambda pl: not show_visible and pl.sudo().code) + if not show_visible and not country_code: + pricelists |= all_pl.filtered(lambda pl: pl.sudo().code) # This method is cached, must not return records! See also #8795 return pricelists.ids diff --git a/addons/website_sale_wishlist/views/website_sale_wishlist_template.xml b/addons/website_sale_wishlist/views/website_sale_wishlist_template.xml index 6be0378297c..3ee63021073 100644 --- a/addons/website_sale_wishlist/views/website_sale_wishlist_template.xml +++ b/addons/website_sale_wishlist/views/website_sale_wishlist_template.xml @@ -69,7 +69,7 @@ <del class='text-danger'><t t-esc='wish.price' t-options="{'widget': 'monetary', 'display_currency': wish.currency_id}"/></del> <br/> </t> - <t t-esc='wish.price_new' t-options="{'widget': 'monetary', 'display_currency': wish.currency_id}"/> + <t t-esc="wish.product_id.website_price" t-options="{'widget': 'monetary', 'display_currency': website.pricelist_id.currency_id}"/> </td> <td class='text-center td-wish-btn'> <input name="product_id" t-att-value="wish.product_id.id" type="hidden"/> |
