diff --git a/addons/account/static/src/js/reconciliation/reconciliation_action.js b/addons/account/static/src/js/reconciliation/reconciliation_action.js
index bdca26fa15f..77f8a99e5c1 100644
--- a/addons/account/static/src/js/reconciliation/reconciliation_action.js
+++ b/addons/account/static/src/js/reconciliation/reconciliation_action.js
@@ -22,12 +22,12 @@ var StatementAction = AbstractAction.extend(ControlPanelMixin, {
change_offset: '_onAction',
change_partner: '_onAction',
add_proposition: '_onAction',
- search_balance_amount: '_onAction',
remove_proposition: '_onAction',
update_proposition: '_onAction',
create_proposition: '_onAction',
+ getPartialAmount: '_onActionPartialAmount',
quick_create_proposition: '_onAction',
- toggle_partial_reconcile: '_onAction',
+ partial_reconcile: '_onAction',
validate: '_onValidate',
change_name: '_onChangeName',
close_statement: '_onCloseStatement',
@@ -233,6 +233,14 @@ var StatementAction = AbstractAction.extend(ControlPanelMixin, {
});
},
+ _onActionPartialAmount: function(event) {
+ var self = this;
+ var handle = event.target.handle;
+ var line = this.model.getLine(handle);
+ var amount = this.model.getPartialReconcileAmount(handle, event.data);
+ self._getWidget(handle).updatePartialAmount(event.data.data, amount);
+ },
+
/**
* call 'changeName' model method
*
diff --git a/addons/account/static/src/js/reconciliation/reconciliation_model.js b/addons/account/static/src/js/reconciliation/reconciliation_model.js
index c76768103a9..d14110f10a2 100644
--- a/addons/account/static/src/js/reconciliation/reconciliation_model.js
+++ b/addons/account/static/src/js/reconciliation/reconciliation_model.js
@@ -43,7 +43,7 @@ var _t = core._t;
* mode: string ('inactive', 'match', 'create')
* reconciliation_proposition: {
* id: number|string
- * partial_reconcile: boolean
+ * partial_amount: number
* invalid: boolean - through the invalid line (without account, label...)
* is_tax: boolean
* account_code: string
@@ -533,24 +533,21 @@ var StatementModel = BasicModel.extend({
}
return $.when.apply($, defs);
},
- searchBalanceAmount: function (handle) {
+ getPartialReconcileAmount: function(handle, data) {
var line = this.getLine(handle);
- var amount = line.balance.amount;
- var amount_str = _.str.sprintf('%.2f', Math.abs(amount));
- amount_str = (amount > '0' ? '-' : '+') + amount_str;
- if (line.balance.currency_id && line.balance.amount_currency) {
- var amount_currency = line.balance.amount_currency;
- var amount_currency_str = _.str.sprintf('%.2f', Math.abs(amount_currency));
- amount_str += '|' + (amount_currency > '0' ? '-' : '+') + amount_currency_str;
+ var prop = _.find(line.reconciliation_proposition, {'id': data.data});
+ if (prop) {
+ var amount = prop.partial_amount || prop.amount;
+ // Check if we can get a partial amount that would directly set balance to zero
+ var partial = Math.abs(line.balance.amount + amount);
+ if (Math.abs(line.balance.amount) >= Math.abs(amount)) {
+ return Math.abs(amount);
+ }
+ if (partial <= Math.abs(prop.amount) && partial >= 0) {
+ return partial
+ }
+ return Math.abs(amount);
}
- if (amount_str === line.filter) {
- line.filter = '';
- line.offset = 0;
- return this.changeMode(handle, 'create');
- }
- line.filter = amount_str;
- line.offset = 0;
- return this.changeMode(handle, 'match');
},
/**
* Force the partial reconciliation to display the reconciliate button.
@@ -558,37 +555,35 @@ var StatementModel = BasicModel.extend({
* @param {string} handle
* @returns {Deferred}
*/
- togglePartialReconcile: function (handle) {
+ partialReconcile: function(handle, data) {
var line = this.getLine(handle);
-
- // Retrieve the toggle proposition
- var selected = _.filter(line.reconciliation_proposition, function(prop){return prop.display_triangle});
-
- // If no toggled proposition found, reject it
- if(selected.length != 1)
- return $.Deferred().reject();
-
- selected = selected[0];
-
- // Inverse partial_reconcile value
- selected.partial_reconcile = !selected.partial_reconcile;
- if (!selected.partial_reconcile) {
- return this._computeLine(line);
- }
-
- // Compute the write_off
- var format_options = { currency_id: line.st_line.currency_id };
- selected.write_off_amount = selected.amount + line.balance.amount;
- selected.write_off_amount_str = field_utils.format.monetary(Math.abs(selected.write_off_amount), {}, format_options);
- selected.write_off_amount_str = selected.write_off_amount_str.replace(' ', ' ');
-
- return this._computeLine(line).then(function () {
- if (selected.partial_reconcile) {
- line.balance.amount = 0;
- line.balance.type = 1;
- line.mode = 'inactive';
+ var prop = _.find(line.reconciliation_proposition, {'id' : data.mvLineId});
+ if (prop) {
+ var amount = data.amount;
+ try {
+ amount = field_utils.parse.float(data.amount);
}
- });
+ catch (err) {
+ amount = NaN;
+ }
+ // Amount can't be greater than line.amount and can not be negative and must be a number
+ // the amount we receive will be a string, so take sign of previous line amount in consideration in order to put
+ // the amount in the correct left or right column
+ if (amount >= Math.abs(prop.amount) || amount <= 0 || isNaN(amount)) {
+ delete prop.partial_amount_str;
+ delete prop.partial_amount;
+ if (isNaN(amount) || amount < 0) {
+ this.do_warn(_.str.sprintf(_t('The amount %s is not a valid partial amount'), data.amount));
+ }
+ return this._computeLine(line);
+ }
+ else {
+ var format_options = { currency_id: line.st_line.currency_id };
+ prop.partial_amount = (prop.amount > 0 ? 1 : -1)*amount;
+ prop.partial_amount_str = field_utils.format.monetary(Math.abs(prop.partial_amount), {}, format_options);
+ }
+ }
+ return this._computeLine(line);
},
/**
* Change the value of the editable proposition line or create a new one.
@@ -759,9 +754,6 @@ var StatementModel = BasicModel.extend({
}
line.reconciliation_proposition.push(prop);
- _.each(line.reconciliation_proposition, function (prop) {
- prop.partial_reconcile = false;
- });
},
/**
* stop the editable proposition line and remove it if it's invalid then
@@ -830,6 +822,9 @@ var StatementModel = BasicModel.extend({
}
return;
}
+ if (!prop.already_paid && parseInt(prop.id)) {
+ prop.is_move_line = true;
+ }
reconciliation_proposition.push(prop);
if (prop.tax_id && prop.__tax_to_recompute && prop.base_amount) {
@@ -891,7 +886,7 @@ var StatementModel = BasicModel.extend({
_.each(reconciliation_proposition, function (prop) {
if (!prop.invalid) {
- total -= prop.amount;
+ total -= prop.partial_amount || prop.amount;
if (isOtherCurrencyId) {
amount_currency -= (prop.amount < 0 ? -1 : 1) * Math.abs(prop.amount_currency);
}
@@ -915,6 +910,7 @@ var StatementModel = BasicModel.extend({
}) : false,
account_code: self.accounts[line.st_line.open_balance_account_id],
};
+ line.balance.show_balance = line.balance.amount_currency != 0;
line.balance.type = line.balance.amount_currency ? (line.st_line.partner_id ? 0 : -1) : 1;
});
},
@@ -1168,7 +1164,7 @@ var StatementModel = BasicModel.extend({
var line = this.getLine(handle);
var excluded_ids = _.compact(_.flatten(_.map(this.lines, function (line) {
return _.map(line.reconciliation_proposition, function (prop) {
- return !prop.partial_reconcile && _.isNumber(prop.id) ? prop.id : null;
+ return _.isNumber(prop.id) ? prop.id : null;
});
})));
var filter = line.filter || "";
@@ -1200,8 +1196,8 @@ var StatementModel = BasicModel.extend({
*/
_formatToProcessReconciliation: function (line, prop) {
var amount = -prop.amount;
- if (prop.partial_reconcile === true) {
- amount = -prop.write_off_amount;
+ if (prop.partial_amount) {
+ amount = -prop.partial_amount;
}
var result = {
@@ -1459,6 +1455,9 @@ var ManualModel = StatementModel.extend({
_computeLine: function (line) {
return this._super(line).then(function () {
var props = _.reject(line.reconciliation_proposition, 'invalid');
+ _.each(line.reconciliation_proposition, function(p) {
+ delete p.is_move_line;
+ });
line.balance.type = -1;
if (!line.balance.amount_currency && props.length) {
line.balance.type = 1;
@@ -1564,7 +1563,7 @@ var ManualModel = StatementModel.extend({
var line = this.getLine(handle);
var excluded_ids = _.compact(_.flatten(_.map(this.lines, function (line) {
return _.map(line.reconciliation_proposition, function (prop) {
- return !prop.partial_reconcile && _.isNumber(prop.id) ? prop.id : null;
+ return _.isNumber(prop.id) ? prop.id : null;
});
})));
var filter = line.filter || "";
diff --git a/addons/account/static/src/js/reconciliation/reconciliation_renderer.js b/addons/account/static/src/js/reconciliation/reconciliation_renderer.js
index 7d572bc74b3..1f2eaea2432 100644
--- a/addons/account/static/src/js/reconciliation/reconciliation_renderer.js
+++ b/addons/account/static/src/js/reconciliation/reconciliation_renderer.js
@@ -254,14 +254,13 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
'click .accounting_view caption .o_buttons button': '_onValidate',
'click .accounting_view thead td': '_onTogglePanel',
'click .accounting_view tfoot td:not(.cell_left,.cell_right)': '_onShowPanel',
- 'click tfoot .cell_left, tfoot .cell_right': '_onSearchBalanceAmount',
+ 'click .cell': '_onEditAmount',
'input input.filter': '_onFilterChange',
'click .match .load-more a': '_onLoadMore',
'click .match .mv_line td': '_onSelectMoveLine',
'click .accounting_view tbody .mv_line td': '_onSelectProposition',
'click .o_reconcile_models button': '_onQuickCreateProposition',
'click .create .add_line': '_onCreateProposition',
- 'click .accounting_view .line_info_button.fa-exclamation-triangle': '_onTogglePartialReconcile',
'click .reconcile_model_create': '_onCreateReconcileModel',
'click .reconcile_model_edit': '_onEditReconcileModel',
'keyup input': '_onInputKeyup',
@@ -284,7 +283,6 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
this.model = model;
this._initialState = state;
},
-
/**
* @override
*/
@@ -365,41 +363,15 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
// Search propositions that could be a partial credit/debit.
var props = [];
- var partialDebitProp;
- var partialCreditProp;
var balance = state.balance.amount_currency;
_.each(state.reconciliation_proposition, function (prop) {
if (prop.display) {
props.push(prop);
-
- /*
- Examples:
- statement line | 100 | |
- move line 1 | | 200 | <- can be a partial of 100
- balance: -100
-
- statement line | 500 | |
- move line 1 | | 300 | <- is not a eligible to be a partial due to the second line.
- move line 2 | | 300 | <- can be a partial of 200
- balance: -100
-
- statement line | 500 | |
- move line 1 | | 700 | <- must not be a partial (debit = 800 > 700 = credit).
- move line 2 | 300 | |
- balance: 100
- */
- if(!prop.display_new && balance < 0 && prop.amount > 0 && balance + prop.amount > 0)
- partialDebitProp = prop;
- else if(!prop.display_new && balance > 0 && prop.amount < 0 && balance + prop.amount < 0)
- partialCreditProp = prop;
}
});
_.each(props, function (line) {
- line.display_triangle = (line.already_paid === false &&
- ((state.balance.amount_currency < 0 || line.partial_reconcile) && partialDebitProp && partialDebitProp === line) ||
- ((state.balance.amount_currency > 0 || line.partial_reconcile) && partialCreditProp && partialCreditProp === line));
- var $line = $(qweb.render("reconciliation.line.mv_line", {'line': line, 'state': state}));
+ var $line = $(qweb.render("reconciliation.line.mv_line", {'line': line, 'state': state, 'proposition': true}));
if (!isNaN(line.id)) {
$('')
.appendTo($line.find('.cell_info_popover'))
@@ -477,6 +449,15 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
this.$('.create .add_line').toggle(!!state.balance.amount_currency);
},
+ updatePartialAmount: function(line_id, amount) {
+ var $line = $('.mv_line[data-line-id='+line_id+']');
+ $line.find('.edit_amount').addClass('d-none');
+ $line.find('.edit_amount_input').removeClass('d-none');
+ $line.find('.edit_amount_input').focus();
+ $line.find('.edit_amount_input').val(amount.toFixed(2));
+ $line.find('.line_amount').addClass('d-none');
+ },
+
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
@@ -625,6 +606,21 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
target: 'current'
});
},
+ _editAmount: function (event) {
+ event.stopPropagation();
+ var $line = $(event.target);
+ var moveLineId = $line.closest('.mv_line').data('line-id');
+ this.trigger_up('partial_reconcile', {'data': {mvLineId: moveLineId, 'amount': $line.val()}});
+ },
+ _onEditAmount: function (event) {
+ event.preventDefault();
+ event.stopPropagation();
+ // Don't call when clicking inside the input field
+ if (! $(event.target).hasClass('edit_amount_input')){
+ var $line = $(event.target);
+ this.trigger_up('getPartialAmount', {'data': $line.closest('.mv_line').data('line-id')});
+ }
+ },
/**
* @private
* @param {MouseEvent} event
@@ -664,12 +660,6 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
var mode = this.$el.data('mode') === 'inactive' ? 'match' : 'inactive';
this.trigger_up('change_mode', {'data': mode});
},
- /**
- * @private
- */
- _onSearchBalanceAmount: function () {
- this.trigger_up('search_balance_amount');
- },
/**
* @private
*/
@@ -694,12 +684,24 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
return;
}
if(event.keyCode === 13) {
+ if ($(event.target).hasClass('edit_amount_input')) {
+ this.$(event.target).blur();
+ return;
+ }
var created_lines = _.findWhere(this.model.lines, {mode: 'create'});
if (created_lines && created_lines.balance.amount) {
this._onCreateProposition();
}
return;
}
+ if ($(event.target).hasClass('edit_amount_input')) {
+ if (event.type === 'keyup') {
+ return;
+ }
+ else {
+ return this._editAmount(event);
+ }
+ }
var self = this;
for (var fieldName in this.fields) {
@@ -772,16 +774,6 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
*/
_onValidate: function () {
this.trigger_up('validate');
- },
- /**
- * @private
- * @param {MouseEvent} event
- */
- _onTogglePartialReconcile: function (e) {
- e.stopPropagation();
- var popover = $(e.target).data('bs.popover');
- popover && popover.dispose();
- this.trigger_up('toggle_partial_reconcile');
}
});
diff --git a/addons/account/static/src/js/reconciliation/tour_reconciliation.js b/addons/account/static/src/js/reconciliation/tour_reconciliation.js
index c672a24debb..f5eb679af51 100644
--- a/addons/account/static/src/js/reconciliation/tour_reconciliation.js
+++ b/addons/account/static/src/js/reconciliation/tour_reconciliation.js
@@ -27,7 +27,21 @@ Tour.register('bank_statement_reconciliation', {
},
{
content: "click on partial reconcile",
- trigger: '.o_reconciliation_line:last .accounting_view .do_partial_reconcile_true'
+ trigger: '.o_reconciliation_line:last .accounting_view .edit_amount',
+ },
+ {
+ content: "Edit amount",
+ trigger: '.o_reconciliation_line:last .accounting_view .edit_amount_input:not(.d-none)',
+ run: 'text 2000'
+ },
+ {
+ content: "Press enter to validate amount",
+ trigger: '.o_reconciliation_line:last .accounting_view .edit_amount_input:not(.d-none)',
+ run: 'keydown 13'
+ },
+ {
+ content: "Check that amount has changed",
+ trigger: '.o_reconciliation_line:last .accounting_view .line_amount:contains("2,000.00")'
},
{
content: "reconcile the line",
diff --git a/addons/account/static/src/scss/account_reconciliation.scss b/addons/account/static/src/scss/account_reconciliation.scss
index 6c21d14e8f2..0eda5d43fc0 100644
--- a/addons/account/static/src/scss/account_reconciliation.scss
+++ b/addons/account/static/src/scss/account_reconciliation.scss
@@ -58,14 +58,17 @@
border-right: 1px solid #333;
padding-right: 5px;
}
- .do_partial_reconcile_true {
- color: $o-community-color; // FIXME probably supposed to be primary to be auto-adapted in enterprise ?
- padding-right: 5px;
+ .edit_amount {
+ margin-left: 20px;
+ color: #bbb;
}
- .do_partial_reconcile_false {
- color: #f0eeee;
- padding-right: 5px;
+ .cell:hover .edit_amount {
+ color: #00A09D;
}
+ .strike_amount {
+ text-decoration: line-through;
+ }
+
}
.o_multi_currency {
diff --git a/addons/account/static/src/xml/account_reconciliation.xml b/addons/account/static/src/xml/account_reconciliation.xml
index ec9e668ac4f..7538f40df4c 100644
--- a/addons/account/static/src/xml/account_reconciliation.xml
+++ b/addons/account/static/src/xml/account_reconciliation.xml
@@ -130,7 +130,7 @@
-
+
|
|
|
@@ -220,17 +220,27 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
@@ -256,20 +266,12 @@
-
-
-
+
|
-
-
-
+
|
|
diff --git a/addons/account/static/tests/reconciliation_tests.js b/addons/account/static/tests/reconciliation_tests.js
index f2774ff6b30..f0028d664e9 100644
--- a/addons/account/static/tests/reconciliation_tests.js
+++ b/addons/account/static/tests/reconciliation_tests.js
@@ -423,11 +423,11 @@ var mv_lines = {
'[6,"",0,5]': [
{'account_type': "liquidity", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-01-23", 'date': "2017-01-23", 'total_amount_str': "$ 376.00", 'partner_id': 7, 'account_name': "Bank", 'name': "BNK1/2017/0002: SUPP.OUT/2017/0002", 'partner_name': "ASUSTeK", 'total_amount_currency_str': "", 'id': 392, 'credit': 376.0, 'journal_id': "Bank", 'amount_str': "$ 376.00", 'debit': 0.0, 'account_code': "101401", 'ref': "BILL/2017/0003", 'already_paid': true},
{'account_type': "liquidity", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-01-23", 'date': "2017-01-23", 'total_amount_str': "$ 100.00", 'partner_id': 8, 'account_name': "Bank", 'name': "BNK1/2017/0003: CUST.IN/2017/0001", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 394, 'credit': 0.0, 'journal_id': "Bank", 'amount_str': "$ 100.00", 'debit': 100.0, 'account_code': "101401", 'ref': "", 'already_paid': true},
+ {'account_type': "payable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-28", 'date': "2017-01-01", 'total_amount_str': "$ 10,000.00", 'partner_id': 12, 'account_name': "Account Payable", 'name': "BILL/2017/0001", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 114, 'credit': 10000.0, 'journal_id': [2, "Vendor Bills"], 'amount_str': "$ 10,000.00", 'debit': 0.0, 'account_code': "111100", 'ref': "", 'already_paid': false},
{'account_type': "liquidity", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-01-23", 'date': "2017-01-23", 'total_amount_str': "$ 525.50", 'partner_id': 8, 'account_name': "Bank", 'name': "BNK1/2017/0004: CUST.IN/2017/0002", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 396, 'credit': 0.0, 'journal_id': "Bank", 'amount_str': "$ 525.50", 'debit': 525.5, 'account_code': "101401", 'ref': "INV/2017/0003", 'already_paid': true},
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-07", 'date': "2017-01-08", 'total_amount_str': "$ 650.00", 'partner_id': 8, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0002", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 109, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 650.00", 'debit': 650.0, 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-22", 'date': "2017-01-23", 'total_amount_str': "$ 525.00", 'partner_id': 8, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0004", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 399, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 525.00", 'debit': 525.0, 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-28", 'date': "2017-01-01", 'total_amount_str': "$ 4,610.00", 'partner_id': 12, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0001", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 106, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 4,610.00", 'debit': 4610.0, 'account_code': "101200", 'ref': "", 'already_paid': false},
- {'account_type': "payable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-28", 'date': "2017-01-01", 'total_amount_str': "$ 10,000.00", 'partner_id': 12, 'account_name': "Account Payable", 'name': "BILL/2017/0001", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 114, 'credit': 10000.0, 'journal_id': [2, "Vendor Bills"], 'amount_str': "$ 10,000.00", 'debit': 0.0, 'account_code': "111100", 'ref': "", 'already_paid': false},
{'account_type': "payable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-28", 'date': "2017-01-15", 'total_amount_str': "$ 5,749.99", 'partner_id': 7, 'account_name': "Account Payable", 'name': "BILL/2017/0002", 'partner_name': "ASUSTeK", 'total_amount_currency_str': "", 'id': 117, 'credit': 5749.99, 'journal_id': [2, "Vendor Bills"], 'amount_str': "$ 5,749.99", 'debit': 0.0, 'account_code': "111100", 'ref': "", 'already_paid': false}
],
'[6,"",5,5]': [
@@ -689,12 +689,12 @@ QUnit.module('account', {
clientAction.widgets[1].$('.accounting_view thead td:first').trigger('click');
assert.containsN(clientAction.widgets[1], '.mv_line', 5, "should display 5 account move lines");
- assert.strictEqual(clientAction.widgets[1].$('.mv_line .cell_right:contains(".")').length, 4, "should display only the credit account move lines (hide the debit)");
+ assert.strictEqual(clientAction.widgets[1].$('.mv_line .cell_right:contains(".")').length, 3, "should display only the credit account move lines (hide the debit)");
assert.containsN(clientAction.widgets[1], '.mv_line.already_reconciled', 3, "should display 3 already reconciled account move lines");
assert.strictEqual(clientAction.widgets[1].$('.mv_line').text().replace(/[\n\r\s]+/g, ' '),
- " 101401 2017-01-23 ASUSTeK: BNK1/2017/0002: SUPP.OUT/2017/0002 : BILL/2017/0003 $ 376.00 101401 2017-01-23 Agrolait: BNK1/2017/0003: CUST.IN/2017/0001 $ 100.00 101401 2017-01-23 Agrolait: BNK1/2017/0004: CUST.IN/2017/0002 : INV/2017/0003 $ 525.50 101200 2017-02-07 Agrolait: INV/2017/0002 $ 650.00 101200 2017-02-22 Agrolait: INV/2017/0004 $ 525.00 ",
+ " 101401 2017-01-23 ASUSTeK: BNK1/2017/0002: SUPP.OUT/2017/0002 : BILL/2017/0003 $ 376.00 101401 2017-01-23 Agrolait: BNK1/2017/0003: CUST.IN/2017/0001 $ 100.00 111100 2017-02-28 Camptocamp: BILL/2017/0001 $ 10,000.00 101401 2017-01-23 Agrolait: BNK1/2017/0004: CUST.IN/2017/0002 : INV/2017/0003 $ 525.50 101200 2017-02-07 Agrolait: INV/2017/0002 $ 650.00 ",
"should display 4 account move lines who contains the account_code, due_date, label and the credit");
- assert.strictEqual(clientAction.widgets[1].$('.mv_line .cell_left:contains(".")').length, 1, "should display only 1 debit account move lines");
+ assert.strictEqual(clientAction.widgets[1].$('.mv_line .cell_left:contains(".")').length, 2, "should display only 2 debit account move lines");
// load more
assert.ok(clientAction.widgets[1].$('.match div.load-more a:visible').length, "should display the 'load more' button");
@@ -846,7 +846,7 @@ QUnit.module('account', {
});
QUnit.test('Reconciliation partial', function (assert) {
- assert.expect(10);
+ assert.expect(9);
var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options);
testUtils.mock.addMockEnvironment(clientAction, {
@@ -855,12 +855,19 @@ QUnit.module('account', {
console.log(args.method);
if (args.method === 'process_bank_statement_line') {
var lines = args.args['1'];
+ console.log(args.arsg);
assert.deepEqual(args.args, [
[6],
[{
partner_id: lines.length == 1 ? lines[0].partner_id : false,
- counterpart_aml_dicts:[],
- payment_aml_ids: [392],
+ counterpart_aml_dicts:[{
+ "analytic_tag_ids": [[6, null, []]],
+ "counterpart_aml_id": 114,
+ "credit": 0,
+ "debit": 32.58,
+ "name": "BILL/2017/0001"
+ }],
+ payment_aml_ids: [],
new_aml_dicts: [],
}]
], "should call process_bank_statement_line with partial reconcile values");
@@ -883,26 +890,29 @@ QUnit.module('account', {
var widget = clientAction.widgets[0];
widget.$('.match .cell_account_code:first').trigger('click');
- assert.notOk( widget.$('.cell_right .line_info_button').length, "should not display the partial reconciliation alert");
+ assert.equal( widget.$('.cell_right .edit_amount').length, 1, "should display the edition pencil");
widget = clientAction.widgets[1];
- assert.notOk( widget.$('.cell_left .line_info_button').length, "should not display the partial reconciliation alert");
widget.$('.accounting_view thead td:first').trigger('click');
- widget.$('.match .cell_account_code:first').trigger('click');
- assert.equal( widget.$('.accounting_view tbody .cell_left .line_info_button').length, 1, "should display the partial reconciliation alert");
+ assert.strictEqual(widget.$('.match .mv_line[data-line-id=114] .cell_account_code:first()').length, 1, 'Should have line')
+ widget.$('.match .mv_line[data-line-id=114] .cell_account_code').trigger('click');
+
+ assert.equal( widget.$('.accounting_view tbody .cell_left .edit_amount').length, 1, "should display the edition pencil");
// The partner has been set automatically, remove it.
widget.$('.o_input_dropdown input').trigger('click');
widget.$('.o_input_dropdown input').val('').trigger('keyup').trigger('blur');
- assert.containsNone(widget, 'button.btn-primary:visible', "should display the reconcile model buttons");
- assert.containsOnce(widget, '.text-danger:visible', "should display counterpart alert");
- widget.$('.accounting_view .cell_left .line_info_button').trigger('click');
- assert.containsOnce(widget, '.accounting_view .cell_left .line_info_button', "should display a partial reconciliation alert");
- assert.doesNotHaveClass(widget.$('.accounting_view .cell_left .line_info_button'), 'do_partial_reconcile_true', "should display the partial reconciliation information");
- assert.containsOnce(widget, 'button.btn-primary:visible', "should display the reconcile button");
- assert.strictEqual( widget.$el.data('mode'), "inactive", "should be inactive mode");
+ assert.strictEqual(widget.$('button.btn-primary:visible').length, 0, "should display the reconcile model buttons");
+ assert.strictEqual(widget.$('.text-danger:visible').length, 1, "should display counterpart alert");
+ widget.$('.accounting_view .cell_left .edit_amount').trigger('click');
+ assert.strictEqual(widget.$('.accounting_view .cell_left .edit_amount_input:not(.d-none)').length, 1, "should display the input field to edit amount");
+ // Edit amount
+ widget.$('.accounting_view .cell_left .edit_amount_input:not(.d-none)').val('32.58').trigger('blur');
+ assert.strictEqual(widget.$('.accounting_view .cell_left .line_amount').text().replace(/[\n\r\s]+/g, ' '), " $ 10000.00 $ 32.58 ", "should display previous amount and new amount")
+
+ assert.strictEqual(widget.$('button.btn-primary:visible').length, 1, "should display the reconcile button");
widget.$('button.btn-primary:visible').trigger('click');
clientAction.destroy();
@@ -1320,7 +1330,7 @@ QUnit.module('account', {
});
QUnit.test('Reconciliation: Payment < inv1 + inv2(partial)', function (assert) {
- assert.expect(4);
+ assert.expect(3);
/*
* One payment: $1175
@@ -1383,17 +1393,15 @@ QUnit.module('account', {
// Add first invoice to reconcile fully
widget.$('.match .cell_account_code:first').trigger('click');
- assert.notOk( widget.$('.cell_right .line_info_button').length,
- "should not display the partial reconciliation alert");
+ assert.ok( widget.$('.cell_right .edit_amount').length,
+ "should display the pencil to edit amount");
// Add second invoice to reconcile partially
widget.$('.match .cell_account_code:first').trigger('click');
- var $reconciliationAlert = widget.$('.cell_right .line_info_button');
- assert.ok($reconciliationAlert.length,
- "should display the partial reconciliation alert");
-
- testUtils.dom.click($reconciliationAlert);
+ // Edit amount on last invoice
+ testUtils.dom.click(widget.$('.edit_amount:last()'));
+ widget.$('.edit_amount_input:last()').val('525').trigger('blur');
var $buttonReconcile = widget.$('button.o_reconcile:not(hidden)');
@@ -1484,13 +1492,13 @@ QUnit.module('account', {
// Add first invoice
// There should be the opportunity to reconcile partially
widget.$('.match .cell_account_code:first').trigger('click');
- assert.ok(widget.$('.cell_right .line_info_button').length,
- "should display the partial reconciliation alert");
+ assert.ok(widget.$('.cell_right .edit_amount').length,
+ "should display the pencil to edit amount");
// Add second invoice
widget.$('.match .cell_account_code:first').trigger('click');
- assert.notOk(widget.$('.cell_right .line_info_button').length,
- "should not display the partial reconciliation alert");
+ assert.ok(widget.$('.cell_right .edit_amount').length,
+ "should display the pencil to edit amount");
var writeOffCreate = widget.$('div.create');
@@ -1513,6 +1521,103 @@ QUnit.module('account', {
clientAction.destroy();
});
+ QUnit.test('Reconciliation: partial payment of 2 invoices with one payment', function (assert) {
+ assert.expect(4);
+
+ /*
+ * One payment: $1175
+ * Two Invoices as Inv1 = 1200; Inv2 = 1200:
+ * Payment < Inv1 AND Payment < Inv2
+ * Assign 500 to inv1 and 675 to inv2
+ */
+
+ // modify the invoice line to have their amount > payment
+ var indexInv1 = _.findIndex(this.params.mv_lines['[5,"",0,5]'], function (line) {return line.id === 109});
+ this.params.mv_lines['[5,"",0,5]'][indexInv1] =
+ {account_type: "receivable", amount_currency_str: "", currency_id: false, date_maturity: "2017-02-07", date: "2017-01-08",
+ total_amount_str: "$ 1200.00", partner_id: 8, account_name: "101200 Account Receivable", name: "INV/2017/0002", partner_name: "Agrolait",
+ total_amount_currency_str: "", id: 109, credit: 0.0, journal_id: [1, "Customer Invoices"], amount_str: "$ 1200.00", debit: 1200.0,
+ account_code: "101200", ref: "", already_paid: false};
+
+ var indexInv2 = _.findIndex(this.params.mv_lines['[5,"",0,5]'], function (line) {return line.id === 112});
+ this.params.mv_lines['[5,"",0,5]'][indexInv2] =
+ {account_type: "receivable", amount_currency_str: "", currency_id: false, date_maturity: "2017-02-07", date: "2017-01-08",
+ total_amount_str: "$ 1200.00", partner_id: 8, account_name: "101200 Account Receivable", name: "INV/2017/0003",
+ partner_name: "Agrolait", total_amount_currency_str: "", id: 112, credit: 0.0, journal_id: [1, "Customer Invoices"],
+ amount_str: "$ 1200.00", debit: 1200.0, account_code: "101200", ref: "", already_paid: false};
+
+ var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options);
+ testUtils.addMockEnvironment(clientAction, {
+ data: this.params.data,
+ mockRPC: function (route, args) {
+ if (args.method === 'process_bank_statement_line') {
+ assert.deepEqual(args.args,
+ [
+ [5], // Id of the bank statement line
+
+ [{counterpart_aml_dicts:
+ [{name:"INV/2017/0002",
+ debit: 0,
+ credit: 500,
+ analytic_tag_ids: [[6, null, []]],
+ counterpart_aml_id: 109},
+
+ {name: "INV/2017/0003",
+ debit: 0,
+ credit: 675,
+ analytic_tag_ids: [[6, null, []]],
+ counterpart_aml_id: 112}],
+
+ payment_aml_ids: [],
+ partner_id: 8,
+ new_aml_dicts: []
+ }]
+ ], "should call process_bank_statement_line with correct counterpart_aml_dicts");
+ }
+ 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 invoice
+ // There should be the opportunity to reconcile partially
+ widget.$('.match .cell_account_code:first').trigger('click');
+ assert.ok(widget.$('.cell_right .edit_amount').length,
+ "should display the pencil to edit amount");
+
+ // Add second invoice
+ widget.$('.match .cell_account_code:first').trigger('click');
+ assert.ok(widget.$('.cell_right .edit_amount').length,
+ "should display the pencil to edit amount");
+
+ // Edit invoice first amount
+ widget.$('.edit_amount:first()').trigger('click');
+ widget.$('.edit_amount_input:first()').val('500').trigger('blur');
+ // Edit invoice second amount
+ var $buttonReconcile = widget.$('button.o_reconcile:not(hidden)');
+ widget.$('.edit_amount:last()').trigger('click');
+ widget.$('.edit_amount_input:last()').val('675').trigger('blur');
+
+ assert.equal($buttonReconcile.length, 1,
+ 'The reconcile button must be visible');
+
+ $buttonReconcile.click();
+
+ clientAction.destroy();
+ });
+
QUnit.test('Manual Reconciliation: remove a prop to attain balance and reconcile', function (assert) {
assert.expect(5);
@@ -1559,7 +1664,7 @@ QUnit.module('account', {
// Add first prop
widget.$('.match .cell_account_code:first').trigger('click');
- assert.equal( widget.$('.cell_right .line_info_button').length, 1, "should display the partial reconciliation alert");
+ assert.equal( widget.$('.cell_right .edit_amount').length, 0, "should not display the pencil to edit amount");
// Add second prop
widget.$('.match .cell_account_code:first').trigger('click');