[FIX] account: rewrite of the reconciliation feature
With our new views, we broke almost all JS code, including the reconciliation widget, which was (and still is) dependant on the field widget. With this commit, we rewrite and simplify the reconciliation code. We also add some tests, to help with the maintenance. Work done by CHM
This commit is contained in:
committed by
Aaron Bohy
parent
905e01921f
commit
654f932b3c
@@ -518,6 +518,7 @@ class AccountBankStatementLine(models.Model):
|
||||
'partner_id': self.partner_id.id,
|
||||
'journal_id': self.journal_id.id,
|
||||
'statement_id': self.statement_id.id,
|
||||
'account_id': [self.journal_id.default_debit_account_id.id, self.journal_id.default_debit_account_id.display_name],
|
||||
'account_code': self.journal_id.default_debit_account_id.code,
|
||||
'account_name': self.journal_id.default_debit_account_id.name,
|
||||
'partner_name': self.partner_id.name,
|
||||
@@ -534,10 +535,10 @@ class AccountBankStatementLine(models.Model):
|
||||
return data
|
||||
|
||||
@api.multi
|
||||
def get_move_lines_for_reconciliation_widget(self, excluded_ids=None, str=False, offset=0, limit=None):
|
||||
def get_move_lines_for_reconciliation_widget(self, partner_id=None, excluded_ids=None, str=False, offset=0, limit=None):
|
||||
""" Returns move lines for the bank statement reconciliation widget, formatted as a list of dicts
|
||||
"""
|
||||
aml_recs = self.get_move_lines_for_reconciliation(excluded_ids=excluded_ids, str=str, offset=offset, limit=limit)
|
||||
aml_recs = self.get_move_lines_for_reconciliation(partner_id=partner_id, excluded_ids=excluded_ids, str=str, offset=offset, limit=limit)
|
||||
target_currency = self.currency_id or self.journal_id.currency_id or self.journal_id.company_id.currency_id
|
||||
return aml_recs.prepare_move_lines_for_reconciliation_widget(target_currency=target_currency, target_date=self.date)
|
||||
|
||||
@@ -545,9 +546,10 @@ class AccountBankStatementLine(models.Model):
|
||||
# Reconciliation methods
|
||||
####################################################
|
||||
|
||||
def get_move_lines_for_reconciliation(self, excluded_ids=None, str=False, offset=0, limit=None, additional_domain=None, overlook_partner=False):
|
||||
def get_move_lines_for_reconciliation(self, partner_id=None, excluded_ids=None, str=False, offset=0, limit=None, additional_domain=None, overlook_partner=False):
|
||||
""" Return account.move.line records which can be used for bank statement reconciliation.
|
||||
|
||||
:param partner_id:
|
||||
:param excluded_ids:
|
||||
:param str:
|
||||
:param offset:
|
||||
@@ -555,13 +557,16 @@ class AccountBankStatementLine(models.Model):
|
||||
:param additional_domain:
|
||||
:param overlook_partner:
|
||||
"""
|
||||
if partner_id is None:
|
||||
partner_id = self.partner_id.id
|
||||
|
||||
# Blue lines = payment on bank account not assigned to a statement yet
|
||||
reconciliation_aml_accounts = [self.journal_id.default_credit_account_id.id, self.journal_id.default_debit_account_id.id]
|
||||
domain_reconciliation = ['&', '&', ('statement_line_id', '=', False), ('account_id', 'in', reconciliation_aml_accounts), ('payment_id','<>', False)]
|
||||
|
||||
# Black lines = unreconciled & (not linked to a payment or open balance created by statement
|
||||
domain_matching = [('reconciled', '=', False)]
|
||||
if self.partner_id.id or overlook_partner:
|
||||
if partner_id or overlook_partner:
|
||||
domain_matching = expression.AND([domain_matching, [('account_id.internal_type', 'in', ['payable', 'receivable'])]])
|
||||
else:
|
||||
# TODO : find out what use case this permits (match a check payment, registered on a journal whose account type is other instead of liquidity)
|
||||
@@ -569,14 +574,17 @@ class AccountBankStatementLine(models.Model):
|
||||
|
||||
# Let's add what applies to both
|
||||
domain = expression.OR([domain_reconciliation, domain_matching])
|
||||
if self.partner_id.id and not overlook_partner:
|
||||
domain = expression.AND([domain, [('partner_id', '=', self.partner_id.id)]])
|
||||
if partner_id and not overlook_partner:
|
||||
domain = expression.AND([domain, [('partner_id', '=', partner_id)]])
|
||||
|
||||
# Domain factorized for all reconciliation use cases
|
||||
ctx = dict(self._context or {})
|
||||
ctx['bank_statement_line'] = self
|
||||
generic_domain = self.env['account.move.line'].with_context(ctx).domain_move_lines_for_reconciliation(excluded_ids=excluded_ids, str=str)
|
||||
domain = expression.AND([domain, generic_domain])
|
||||
if str:
|
||||
str_domain = self.env['account.move.line'].domain_move_lines_for_reconciliation(str=str)
|
||||
if not partner_id:
|
||||
str_domain = expression.OR([str_domain, ('partner_id.name', 'ilike', str)])
|
||||
domain = expression.AND([domain, str_domain])
|
||||
if excluded_ids:
|
||||
domain = expression.AND([[('id', 'not in', excluded_ids)], domain])
|
||||
|
||||
# Domain from caller
|
||||
if additional_domain is None:
|
||||
@@ -585,7 +593,7 @@ class AccountBankStatementLine(models.Model):
|
||||
additional_domain = expression.normalize_domain(additional_domain)
|
||||
domain = expression.AND([domain, additional_domain])
|
||||
|
||||
return self.env['account.move.line'].search(domain, offset=offset, limit=limit, order="date_maturity asc, id asc")
|
||||
return self.env['account.move.line'].search(domain, offset=offset, limit=limit, order="date_maturity desc, id desc")
|
||||
|
||||
def _get_common_sql_query(self, overlook_partner = False, excluded_ids = None, split = False):
|
||||
acc_type = "acc.internal_type IN ('payable', 'receivable')" if (self.partner_id or overlook_partner) else "acc.reconcile = true"
|
||||
@@ -629,7 +637,7 @@ class AccountBankStatementLine(models.Model):
|
||||
select_clause, from_clause, where_clause = self._get_common_sql_query(overlook_partner=True, excluded_ids=excluded_ids, split=True)
|
||||
sql_query = select_clause + add_to_select + from_clause + add_to_from + where_clause
|
||||
sql_query += " AND (aml.ref= %(ref)s or m.name = %(ref)s) \
|
||||
ORDER BY temp_field_order, date_maturity asc, aml.id asc"
|
||||
ORDER BY temp_field_order, date_maturity desc, aml.id desc"
|
||||
self.env.cr.execute(sql_query, params)
|
||||
results = self.env.cr.fetchone()
|
||||
if results:
|
||||
@@ -641,7 +649,7 @@ class AccountBankStatementLine(models.Model):
|
||||
liquidity_amt_clause = currency and '%(amount)s' or 'abs(%(amount)s)'
|
||||
sql_query = self._get_common_sql_query(excluded_ids=excluded_ids) + \
|
||||
" AND ("+field+" = %(amount)s OR (acc.internal_type = 'liquidity' AND "+liquidity_field+" = " + liquidity_amt_clause + ")) \
|
||||
ORDER BY date_maturity asc, aml.id asc LIMIT 1"
|
||||
ORDER BY date_maturity desc, aml.id desc LIMIT 1"
|
||||
self.env.cr.execute(sql_query, params)
|
||||
results = self.env.cr.fetchone()
|
||||
if results:
|
||||
@@ -805,6 +813,8 @@ class AccountBankStatementLine(models.Model):
|
||||
for aml_dict in datum.get('counterpart_aml_dicts', []):
|
||||
aml_dict['move_line'] = AccountMoveLine.browse(aml_dict['counterpart_aml_id'])
|
||||
del aml_dict['counterpart_aml_id']
|
||||
if datum.get('partner_id') is not None:
|
||||
st_line.write({'partner_id': datum['partner_id']})
|
||||
st_line.process_reconciliation(datum.get('counterpart_aml_dicts', []), payment_aml_rec, datum.get('new_aml_dicts', []))
|
||||
|
||||
def fast_counterpart_creation(self):
|
||||
|
||||
@@ -596,7 +596,7 @@ class AccountMoveLine(models.Model):
|
||||
AND NOT a.reconciled AND NOT b.reconciled
|
||||
AND a.account_id = %(account_id)s AND b.account_id = %(account_id)s
|
||||
{partner_id_condition}
|
||||
ORDER BY a.date asc
|
||||
ORDER BY a.date desc
|
||||
LIMIT 10
|
||||
""".format(**locals())
|
||||
self.env.cr.execute(query, locals())
|
||||
@@ -615,62 +615,50 @@ class AccountMoveLine(models.Model):
|
||||
return []
|
||||
|
||||
@api.model
|
||||
def domain_move_lines_for_reconciliation(self, excluded_ids=None, str=False):
|
||||
""" Returns the domain which is common to both manual and bank statement reconciliation.
|
||||
|
||||
:param excluded_ids: list of ids of move lines that should not be fetched
|
||||
def domain_move_lines_for_reconciliation(self, str):
|
||||
""" Returns the domain from the str search
|
||||
:param str: search string
|
||||
"""
|
||||
context = (self._context or {})
|
||||
if excluded_ids is None:
|
||||
excluded_ids = []
|
||||
domain = []
|
||||
|
||||
if excluded_ids:
|
||||
domain = expression.AND([domain, [('id', 'not in', excluded_ids)]])
|
||||
if str:
|
||||
str_domain = [
|
||||
'|', ('move_id.name', 'ilike', str),
|
||||
'|', ('move_id.ref', 'ilike', str),
|
||||
'|', ('date_maturity', 'like', str),
|
||||
'&', ('name', '!=', '/'), ('name', 'ilike', str)
|
||||
if not str:
|
||||
return []
|
||||
str_domain = [
|
||||
'|', ('move_id.name', 'ilike', str),
|
||||
'|', ('move_id.ref', 'ilike', str),
|
||||
'|', ('date_maturity', 'like', str),
|
||||
'&', ('name', '!=', '/'), ('name', 'ilike', str)
|
||||
]
|
||||
try:
|
||||
amount = float(str)
|
||||
amount_domain = [
|
||||
'|', ('amount_residual', '=', amount),
|
||||
'|', ('amount_residual_currency', '=', amount),
|
||||
'|', ('amount_residual', '=', -amount),
|
||||
'|', ('amount_residual_currency', '=', -amount),
|
||||
'&', ('account_id.internal_type', '=', 'liquidity'),
|
||||
'|', '|', ('debit', '=', amount), ('credit', '=', amount), ('amount_currency', '=', amount),
|
||||
]
|
||||
try:
|
||||
amount = float(str)
|
||||
amount_domain = [
|
||||
'|', ('amount_residual', '=', amount),
|
||||
'|', ('amount_residual_currency', '=', amount),
|
||||
'|', ('amount_residual', '=', -amount),
|
||||
'|', ('amount_residual_currency', '=', -amount),
|
||||
'&', ('account_id.internal_type', '=', 'liquidity'),
|
||||
'|', '|', ('debit', '=', amount), ('credit', '=', amount), ('amount_currency', '=', amount),
|
||||
]
|
||||
str_domain = expression.OR([str_domain, amount_domain])
|
||||
except:
|
||||
pass
|
||||
|
||||
# When building a domain for the bank statement reconciliation, if there's no partner
|
||||
# and a search string, search also a match in the partner names
|
||||
if 'bank_statement_line' in context and not context['bank_statement_line'].partner_id.id:
|
||||
str_domain = expression.OR([str_domain, [('partner_id.name', 'ilike', str)]])
|
||||
|
||||
domain = expression.AND([domain, str_domain])
|
||||
return domain
|
||||
str_domain = expression.OR([str_domain, amount_domain])
|
||||
except:
|
||||
pass
|
||||
return str_domain
|
||||
|
||||
def _domain_move_lines_for_manual_reconciliation(self, account_id, partner_id=False, excluded_ids=None, str=False):
|
||||
""" Create domain criteria that are relevant to manual reconciliation. """
|
||||
domain = ['&', ('reconciled', '=', False), ('account_id', '=', account_id)]
|
||||
if partner_id:
|
||||
domain = expression.AND([domain, [('partner_id', '=', partner_id)]])
|
||||
generic_domain = self.domain_move_lines_for_reconciliation(excluded_ids=excluded_ids, str=str)
|
||||
|
||||
return expression.AND([generic_domain, domain])
|
||||
if excluded_ids:
|
||||
domain = expression.AND([[('id', 'not in', excluded_ids)], domain])
|
||||
if str:
|
||||
str_domain = self.domain_move_lines_for_reconciliation(str=str)
|
||||
domain = expression.AND([domain, str_domain])
|
||||
return domain
|
||||
|
||||
@api.model
|
||||
def get_move_lines_for_manual_reconciliation(self, account_id, partner_id=False, excluded_ids=None, str=False, offset=0, limit=None, target_currency_id=False):
|
||||
""" Returns unreconciled move lines for an account or a partner+account, formatted for the manual reconciliation widget """
|
||||
domain = self._domain_move_lines_for_manual_reconciliation(account_id, partner_id, excluded_ids, str)
|
||||
lines = self.search(domain, offset=offset, limit=limit, order="date_maturity asc, id asc")
|
||||
lines = self.search(domain, offset=offset, limit=limit, order="date_maturity desc, id desc")
|
||||
if target_currency_id:
|
||||
target_currency = self.env['res.currency'].browse(target_currency_id)
|
||||
else:
|
||||
@@ -700,13 +688,14 @@ class AccountMoveLine(models.Model):
|
||||
'ref': line.move_id.ref or '',
|
||||
# For reconciliation between statement transactions and already registered payments (eg. checks)
|
||||
# NB : we don't use the 'reconciled' field because the line we're selecting is not the one that gets reconciled
|
||||
'account_id': [line.account_id.id, line.account_id.display_name],
|
||||
'already_paid': line.account_id.internal_type == 'liquidity',
|
||||
'account_code': line.account_id.code,
|
||||
'account_name': line.account_id.name,
|
||||
'account_type': line.account_id.internal_type,
|
||||
'date_maturity': line.date_maturity,
|
||||
'date': line.date,
|
||||
'journal_name': line.journal_id.name,
|
||||
'journal_id': [line.journal_id.id, line.journal_id.display_name],
|
||||
'partner_id': line.partner_id.id,
|
||||
'partner_name': line.partner_id.name,
|
||||
'currency_id': (line.currency_id and line.amount_currency) and line.currency_id.id or False,
|
||||
@@ -750,8 +739,9 @@ class AccountMoveLine(models.Model):
|
||||
actual_credit = credit > 0 and -amount or 0.0
|
||||
currency = company_currency
|
||||
if line_currency != target_currency:
|
||||
amount_currency_str = formatLang(self.env, abs(actual_debit or actual_credit), currency_obj=line_currency)
|
||||
total_amount_currency_str = formatLang(self.env, total_amount, currency_obj=line_currency)
|
||||
target_currency.compute(total_amount, line_currency)
|
||||
amount_currency_str = formatLang(self.env, target_currency.compute(abs(actual_debit or actual_credit), line_currency), currency_obj=line_currency)
|
||||
total_amount_currency_str = formatLang(self.env, target_currency.compute(total_amount, line_currency), currency_obj=line_currency)
|
||||
if currency != target_currency:
|
||||
ctx = context.copy()
|
||||
ctx.update({'date': target_date or line.date})
|
||||
@@ -781,7 +771,7 @@ class AccountMoveLine(models.Model):
|
||||
"""
|
||||
for datum in data:
|
||||
if len(datum['mv_line_ids']) >= 1 or len(datum['mv_line_ids']) + len(datum['new_mv_line_dicts']) >= 2:
|
||||
self.process_reconciliation(datum['mv_line_ids'], datum['new_mv_line_dicts'])
|
||||
self.browse(datum['mv_line_ids']).process_reconciliation(datum['new_mv_line_dicts'])
|
||||
|
||||
if datum['type'] == 'partner':
|
||||
partners = self.env['res.partner'].browse(datum['id'])
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
odoo.define('account.payment', function (require) {
|
||||
"use strict";
|
||||
|
||||
var AbstractField = require('web.AbstractField');
|
||||
var core = require('web.core');
|
||||
var form_common = require('web.form_common');
|
||||
var formats = require('web.formats');
|
||||
var Model = require('web.Model');
|
||||
var field_registry = require('web.field_registry');
|
||||
|
||||
var QWeb = core.qweb;
|
||||
|
||||
var ShowPaymentLineWidget = form_common.AbstractField.extend({
|
||||
render_value: function() {
|
||||
|
||||
var ShowPaymentLineWidget = AbstractField.extend({
|
||||
supportedFieldTypes: ['text'],
|
||||
render: function() {
|
||||
var self = this;
|
||||
var info = JSON.parse(this.get('value'));
|
||||
var info = JSON.parse(this.value);
|
||||
var invoice_id = info.invoice_id;
|
||||
if (info !== false) {
|
||||
_.each(info.content, function(k,v){
|
||||
@@ -22,23 +24,26 @@ var ShowPaymentLineWidget = form_common.AbstractField.extend({
|
||||
}
|
||||
});
|
||||
this.$el.html(QWeb.render('ShowPaymentInfo', {
|
||||
'lines': info.content,
|
||||
'outstanding': info.outstanding,
|
||||
'lines': info.content,
|
||||
'outstanding': info.outstanding,
|
||||
'title': info.title
|
||||
}));
|
||||
this.$('.outstanding_credit_assign').click(function(){
|
||||
var id = $(this).data('id') || false;
|
||||
new Model("account.invoice")
|
||||
.call("assign_outstanding_credit", [invoice_id, id])
|
||||
.then(function (result) {
|
||||
self.view.reload();
|
||||
});
|
||||
self.trigger_up('perform_model_rpc', {
|
||||
model: 'account.invoice',
|
||||
method: 'assign_outstanding_credit',
|
||||
args: [invoice_id, id],
|
||||
on_success: function () {
|
||||
self.trigger_up('reload');
|
||||
}
|
||||
});
|
||||
});
|
||||
_.each(this.$('.js_payment_info'), function(k, v){
|
||||
var options = {
|
||||
'content': QWeb.render('PaymentPopOver', {
|
||||
'name': info.content[v].name,
|
||||
'journal_name': info.content[v].journal_name,
|
||||
'name': info.content[v].name,
|
||||
'journal_name': info.content[v].journal_name,
|
||||
'date': info.content[v].date,
|
||||
'amount': info.content[v].amount,
|
||||
'currency': info.content[v].currency,
|
||||
@@ -54,20 +59,23 @@ var ShowPaymentLineWidget = form_common.AbstractField.extend({
|
||||
'delay': { "show": 0, "hide": 100 },
|
||||
};
|
||||
$(k).popover(options);
|
||||
$(k).on('shown.bs.popover', function(event){
|
||||
$(k).on('shown.bs.popover', function(){
|
||||
$(this).parent().find('.js_unreconcile_payment').click(function(){
|
||||
var payment_id = parseInt($(this).attr('payment-id'))
|
||||
if (payment_id !== undefined && payment_id !== NaN){
|
||||
new Model("account.move.line")
|
||||
.call("remove_move_reconcile", [payment_id, {'invoice_id': self.view.datarecord.id}])
|
||||
.then(function (result) {
|
||||
self.view.reload();
|
||||
});
|
||||
var payment_id = parseInt($(this).attr('payment-id'));
|
||||
if (payment_id !== undefined && !isNaN(payment_id)){
|
||||
self.trigger_up('perform_model_rpc', {
|
||||
model: 'account.move.line',
|
||||
method: 'remove_move_reconcile',
|
||||
args: [payment_id, {'invoice_id': self.res_id}],
|
||||
on_success: function () {
|
||||
self.trigger_up('reload');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
$(this).parent().find('.js_open_payment').click(function(){
|
||||
var move_id = parseInt($(this).attr('move-id'))
|
||||
if (move_id !== undefined && move_id !== NaN){
|
||||
var move_id = parseInt($(this).attr('move-id'));
|
||||
if (move_id !== undefined && !isNaN(move_id)){
|
||||
//Open form view of account.move with id = move_id
|
||||
self.do_action({
|
||||
type: 'ir.actions.act_window',
|
||||
@@ -85,8 +93,11 @@ var ShowPaymentLineWidget = form_common.AbstractField.extend({
|
||||
this.$el.html('');
|
||||
}
|
||||
},
|
||||
has_no_value: function() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
core.form_widget_registry.add('payment', ShowPaymentLineWidget);
|
||||
field_registry.add('payment', ShowPaymentLineWidget);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@ var core = require('web.core');
|
||||
var data = require('web.data');
|
||||
var ListView = require('web.ListView');
|
||||
var Model = require('web.DataModel');
|
||||
var view_registry = require('web.view_registry');
|
||||
|
||||
var QWeb = core.qweb;
|
||||
|
||||
@@ -99,6 +100,7 @@ var QuickAddListView = ListView.extend({
|
||||
return self.old_search(compound_domain, self.last_context, self.last_group_by);
|
||||
},
|
||||
});
|
||||
core.view_registry.add('tree_account_move_line_quickadd', QuickAddListView);
|
||||
|
||||
view_registry.add('tree_account_move_line_quickadd', QuickAddListView);
|
||||
|
||||
});
|
||||
|
||||
@@ -0,0 +1,285 @@
|
||||
odoo.define('account.ReconciliationClientAction', function (require) {
|
||||
"use strict";
|
||||
|
||||
var ReconciliationModel = require('account.ReconciliationModel');
|
||||
var ReconciliationRenderer = require('account.ReconciliationRenderer');
|
||||
var ControlPanelMixin = require('web.ControlPanelMixin');
|
||||
var Widget = require('web.Widget');
|
||||
var core = require('web.core');
|
||||
|
||||
|
||||
/**
|
||||
* Widget used as action for 'account.bank.statement' reconciliation
|
||||
*/
|
||||
var StatementAction = Widget.extend(ControlPanelMixin, {
|
||||
title: core._t('Bank reconciliation'),
|
||||
template: 'reconciliation',
|
||||
custom_events: {
|
||||
change_mode: '_onAction',
|
||||
change_filter: '_onAction',
|
||||
change_offset: '_onAction',
|
||||
change_partner: '_onAction',
|
||||
add_proposition: '_onAction',
|
||||
remove_proposition: '_onAction',
|
||||
update_proposition: '_onAction',
|
||||
create_proposition: '_onAction',
|
||||
quick_create_proposition: '_onAction',
|
||||
toggle_partial_reconcile: '_onAction',
|
||||
auto_reconciliation: '_onValidate',
|
||||
validate: '_onValidate',
|
||||
validate_all_balanced: '_onValidate',
|
||||
change_name: '_onChangeName',
|
||||
},
|
||||
config: {
|
||||
// used to instanciate the model
|
||||
Model: ReconciliationModel.StatementModel,
|
||||
// used to instanciate the action interface
|
||||
ActionRenderer: ReconciliationRenderer.StatementRenderer,
|
||||
// used to instanciate each widget line
|
||||
LineRenderer: ReconciliationRenderer.LineRenderer
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @param {Object} params
|
||||
* @param {Object} params.context
|
||||
*
|
||||
*/
|
||||
init: function (parent, params) {
|
||||
this._super.apply(this, arguments);
|
||||
this.action_manager = parent;
|
||||
this.params = params;
|
||||
this.model = new this.config.Model(this, {modelName: "account.bank.statement.line"});
|
||||
this.widgets = [];
|
||||
if (!this.action_manager) {
|
||||
this.set_cp_bus(new Widget());
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* instantiate the action renderer
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
willStart: function () {
|
||||
var self = this;
|
||||
var def = this.model.load(this.params.context).then(this._super.bind(this));
|
||||
return def.then(function () {
|
||||
self.title = self.model.bank_statement_id ? self.model.bank_statement_id.display_name : self.title;
|
||||
self.renderer = new self.config.ActionRenderer(self, self.model, {
|
||||
'bank_statement_id': self.model.bank_statement_id,
|
||||
'valuenow': self.model.valuenow,
|
||||
'valuemax': self.model.valuemax,
|
||||
'title': self.title,
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* append the renderer and instantiate the line renderers
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
start: function () {
|
||||
var self = this;
|
||||
|
||||
this.set("title", this.title);
|
||||
var breadcrumbs = this.action_manager && this.action_manager.get_breadcrumbs() || [{ title: this.title, action: this }];
|
||||
this.update_control_panel({breadcrumbs: breadcrumbs, search_view_hidden: true}, {clear: true});
|
||||
|
||||
this.renderer.prependTo(self.$('.o_form_sheet'));
|
||||
_.each(this.model.lines, function (line, handle) {
|
||||
var widget = new self.config.LineRenderer(self, self.model, line);
|
||||
widget.handle = handle;
|
||||
self.widgets.push(widget);
|
||||
widget.appendTo(self.$('.o_reconciliation_lines'));
|
||||
});
|
||||
this._openFirstLine();
|
||||
},
|
||||
|
||||
/**
|
||||
* update the control panel and breadcrumbs
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
do_show: function () {
|
||||
this._super.apply(this, arguments);
|
||||
if (this.action_manager) {
|
||||
var breadcrumbs = this.action_manager && this.action_manager.get_breadcrumbs() || [{ title: this.title, action: this }];
|
||||
while (breadcrumbs.length) {
|
||||
if (breadcrumbs[breadcrumbs.length-1].action.widget === this) {
|
||||
break;
|
||||
}
|
||||
breadcrumbs.pop();
|
||||
}
|
||||
this.update_control_panel({breadcrumbs: breadcrumbs, search_view_hidden: true}, {clear: true});
|
||||
this.action_manager.do_push_state({
|
||||
action: this.params.tag,
|
||||
active_id: this.params.res_id,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {string} handle
|
||||
* @returns {Widget} widget line
|
||||
*/
|
||||
_getWidget: function (handle) {
|
||||
return _.find(this.widgets, function (widget) {return widget.handle===handle;});
|
||||
},
|
||||
|
||||
/**
|
||||
* sitch to 'match' the first available line
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_openFirstLine: function () {
|
||||
var self = this;
|
||||
|
||||
var handle = _.compact(_.map(this.model.lines, function (line, handle) {
|
||||
return line.reconciled ? null : handle;
|
||||
}))[0];
|
||||
if (handle) {
|
||||
var line = this.model.getLine(handle);
|
||||
this.model.changeMode(handle, 'match').always(function () {
|
||||
self._getWidget(handle).update(line);
|
||||
});
|
||||
}
|
||||
return handle;
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* dispatch on the camelcased event name to model method then update the
|
||||
* line renderer with the new state. If the mode was switched from 'inactive'
|
||||
* to 'create' or 'match', the other lines switch to 'inactive' mode
|
||||
*
|
||||
* @private
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
_onAction: function (event) {
|
||||
var self = this;
|
||||
var handle = event.target.handle;
|
||||
var line = this.model.getLine(handle);
|
||||
var mode = line.mode;
|
||||
this.model[_.str.camelize(event.name)](handle, event.data.data).always(function () {
|
||||
self._getWidget(handle).update(line);
|
||||
if (mode === 'inactive' && line.mode !== 'inactive') {
|
||||
_.each(self.model.lines, function (line, _handle) {
|
||||
if (line.mode !== 'inactive' && _handle !== handle) {
|
||||
self.model.changeMode(_handle, 'inactive');
|
||||
self._getWidget(_handle).update(line);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* call 'changeName' model method
|
||||
*
|
||||
* @private
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
_onChangeName: function (event) {
|
||||
var self = this;
|
||||
var title = event.data.data;
|
||||
this.model.changeName(title).then(function () {
|
||||
self.title = title;
|
||||
self.set("title", title);
|
||||
self.renderer.update({
|
||||
'valuenow': self.model.valuenow,
|
||||
'valuemax': self.model.valuemax,
|
||||
'title': title,
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* call 'validate' or 'autoReconciliation' model method then destroy the
|
||||
* validated lines and update the action renderer with the new status bar
|
||||
* values and notifications then open the first available line
|
||||
*
|
||||
* @private
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
_onValidate: function (event) {
|
||||
var self = this;
|
||||
var handle = event.target.handle;
|
||||
var method = event.name.indexOf('auto_reconciliation') === -1 ? 'validate' : 'autoReconciliation';
|
||||
this.model[method](handle).then(function (result) {
|
||||
self.renderer.update({
|
||||
'valuenow': self.model.valuenow,
|
||||
'valuemax': self.model.valuemax,
|
||||
'title': self.title,
|
||||
'time': Date.now()-self.time,
|
||||
'notifications': result.notifications,
|
||||
});
|
||||
_.each(result.handles, function (handle) {
|
||||
self._getWidget(handle).destroy();
|
||||
});
|
||||
self._openFirstLine();
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Widget used as action for 'account.move.line' and 'res.partner' for the
|
||||
* manual reconciliation and mark data as reconciliate
|
||||
*/
|
||||
var ManualAction = StatementAction.extend({
|
||||
title: core._t('Journal Items to Reconcile'),
|
||||
config: {
|
||||
Model: ReconciliationModel.ManualModel,
|
||||
ActionRenderer: ReconciliationRenderer.ManualRenderer,
|
||||
LineRenderer: ReconciliationRenderer.ManualLineRenderer
|
||||
},
|
||||
/**
|
||||
* call 'validate' or 'autoReconciliation' model method then destroy the
|
||||
* reconcilied lines, update the not reconcilied and update the action
|
||||
* renderer with the new status bar values and notifications then open the
|
||||
* first available line
|
||||
*
|
||||
* @private
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
_onValidate: function (event) {
|
||||
var self = this;
|
||||
var handle = event.target.handle;
|
||||
var method = event.name.indexOf('auto_reconciliation') === -1 ? 'validate' : 'autoReconciliation';
|
||||
this.model[method](handle).then(function (result) {
|
||||
self.renderer.update({
|
||||
'valuenow': self.model.valuenow,
|
||||
'valuemax': self.model.valuemax,
|
||||
'title': self.title,
|
||||
'time': Date.now()-self.time,
|
||||
'notifications': result.notifications,
|
||||
});
|
||||
_.each(result.reconciled, function (handle) {
|
||||
self._getWidget(handle).destroy();
|
||||
});
|
||||
_.each(result.updated, function (handle) {
|
||||
self._getWidget(handle).update(self.model.getLine(handle));
|
||||
});
|
||||
self._openFirstLine();
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
core.action_registry.add('bank_statement_reconciliation_view', StatementAction);
|
||||
core.action_registry.add('manual_reconciliation_view', ManualAction);
|
||||
|
||||
return {
|
||||
StatementAction: StatementAction,
|
||||
ManualAction: ManualAction,
|
||||
};
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,631 @@
|
||||
odoo.define('account.ReconciliationRenderer', function (require) {
|
||||
"use strict";
|
||||
|
||||
var Widget = require('web.Widget');
|
||||
var FieldManagerMixin = require('web.FieldManagerMixin');
|
||||
var relational_fields = require('web.relational_fields');
|
||||
var basic_fields = require('web.basic_fields');
|
||||
var core = require('web.core');
|
||||
var time = require('web.time');
|
||||
var qweb = core.qweb;
|
||||
var _t = core._t;
|
||||
|
||||
|
||||
/**
|
||||
* rendering of the bank statement action contains progress bar, title and
|
||||
* auto reconciliation button
|
||||
*/
|
||||
var StatementRenderer = Widget.extend(FieldManagerMixin, {
|
||||
template: 'reconciliation.statement',
|
||||
events: {
|
||||
'click div:first button.o_automatic_reconciliation': '_onAutoReconciliation',
|
||||
'click div:first h1.statement_name': '_onClickStatementName',
|
||||
'click div:first h1.statement_name_edition button': '_onValidateName',
|
||||
"click *[rel='do_action']": "_onDoAction",
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
init: function (parent, model, state) {
|
||||
this._super(parent);
|
||||
this.model = model;
|
||||
this._initialState = state;
|
||||
},
|
||||
/**
|
||||
* display iniial state and create the name statement field
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
start: function () {
|
||||
this._super();
|
||||
this.time = Date.now();
|
||||
this.$progress = this.$('.progress');
|
||||
|
||||
if (this._initialState.bank_statement_id) {
|
||||
this.handleNameRecord = this.model.makeRecord("account.bank.statement", [{
|
||||
type: 'char',
|
||||
name: 'name',
|
||||
attrs: {string: ""},
|
||||
value: this._initialState.bank_statement_id.display_name
|
||||
}]);
|
||||
this.name = new basic_fields.FieldChar(this,
|
||||
'name', this.model.get(this.handleNameRecord),
|
||||
{mode: 'edit', required: true});
|
||||
|
||||
this.name.appendTo(this.$('.statement_name_edition'));
|
||||
this.$('.statement_name').text(this._initialState.bank_statement_id.display_name);
|
||||
}
|
||||
|
||||
this.$('h1.statement_name').text(this._initialState.title);
|
||||
|
||||
delete this._initialState;
|
||||
|
||||
this.enterHandler = function (e) {
|
||||
if ((e.which === 13 || e.which === 10) && (e.ctrlKey || e.metaKey)) {
|
||||
this.trigger_up('validate_all_balanced');
|
||||
}
|
||||
}.bind(this);
|
||||
$('body').on('keyup', this.enterHandler);
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
destroy: function () {
|
||||
this._super();
|
||||
$('body').off('keyup', this.enterHandler);
|
||||
},
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* update the statement rendering
|
||||
*
|
||||
* @param {object} state - statement data
|
||||
* @param {integer} state.valuenow - for the progress bar
|
||||
* @param {integer} state.valuemax - for the progress bar
|
||||
* @param {string} state.title - for the progress bar
|
||||
* @param {[object]} [state.notifications]
|
||||
*/
|
||||
update: function (state) {
|
||||
this.$progress.find('.valuenow').text(state.valuenow);
|
||||
this.$progress.find('.valuemax').text(state.valuemax);
|
||||
this.$progress.find('.progress-bar')
|
||||
.attr('aria-valuenow', state.valuenow)
|
||||
.attr('aria-valuemax', state.valuemax)
|
||||
.css('width', (state.valuenow/state.valuemax*100) + '%');
|
||||
|
||||
if (state.valuenow === state.valuemax) {
|
||||
var dt = Date.now()-this.time;
|
||||
var $done = $(qweb.render("reconciliation.done", {
|
||||
'duration': moment(dt).utc().format(time.strftime_to_moment_format(_t.database.parameters.time_format)),
|
||||
'number': state.valuenow,
|
||||
'timePerTransaction': Math.round(dt/1000/state.valuemax)
|
||||
}));
|
||||
$done.appendTo(this.$el.first());
|
||||
this.$('.o_automatic_reconciliation').hide();
|
||||
}
|
||||
|
||||
if (state.notifications) {
|
||||
this._renderNotifications(state.notifications);
|
||||
}
|
||||
|
||||
this.$('h1.statement_name').text(state.title);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* render the notifications
|
||||
*
|
||||
* @param {[object]} notifications
|
||||
*/
|
||||
_renderNotifications: function(notifications) {
|
||||
for (var i=0; i<notifications.length; i++) {
|
||||
var $notification = $(qweb.render("reconciliation.notification", {
|
||||
type: notifications[i].type,
|
||||
message: notifications[i].message,
|
||||
details: notifications[i].details,
|
||||
})).hide();
|
||||
$notification.appendTo(this.$(".notification_area")).slideDown(300);
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onAutoReconciliation: function () {
|
||||
this.trigger_up('auto_reconciliation');
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onClickStatementName: function () {
|
||||
this.$('.statement_name, .statement_name_edition').toggle();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onValidateName: function () {
|
||||
var name = this.model.get(this.handleNameRecord).data.name;
|
||||
this.trigger_up('change_name', {'data': name});
|
||||
this.$('.statement_name, .statement_name_edition').toggle();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onDoAction: function(e) {
|
||||
e.preventDefault();
|
||||
var name = e.currentTarget.dataset.action_name;
|
||||
var model = e.currentTarget.dataset.model;
|
||||
var ids = e.currentTarget.dataset.ids.split(",").map(Number);
|
||||
this.do_action({
|
||||
name: name,
|
||||
res_model: model,
|
||||
domain: [['id', 'in', ids]],
|
||||
views: [[false, 'list'], [false, 'form']],
|
||||
type: 'ir.actions.act_window',
|
||||
view_type: "list",
|
||||
view_mode: "list"
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* rendering of the bank statement line, contains line data, proposition and
|
||||
* view for 'match' and 'create' mode
|
||||
*/
|
||||
var LineRenderer = Widget.extend(FieldManagerMixin, {
|
||||
template: "reconciliation.line",
|
||||
events: {
|
||||
'click .accounting_view caption .o_buttons button': '_onValidate',
|
||||
'click .accounting_view thead td': '_onTogglePanel',
|
||||
'click .accounting_view tfoot td': '_onShowPanel',
|
||||
'input input.filter': '_onFilterChange',
|
||||
'click .match_controls .fa-chevron-left:not(.disabled)': '_onPrevious',
|
||||
'click .match_controls .fa-chevron-right:not(.disabled)': '_onNext',
|
||||
'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 .cell_right .line_info_button': '_onTogglePartialReconcile',
|
||||
},
|
||||
custom_events: _.extend({}, FieldManagerMixin.custom_events, {
|
||||
'field_changed': '_onFieldChanged',
|
||||
}),
|
||||
|
||||
/**
|
||||
* create partner_id field in editable mode
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
init: function (parent, model, state) {
|
||||
this._super(parent);
|
||||
FieldManagerMixin.init.call(this);
|
||||
|
||||
this.model = model;
|
||||
this._initialState = state;
|
||||
|
||||
this.fields = {
|
||||
'partner_id' : new relational_fields.FieldMany2One(this,
|
||||
'partner_id',
|
||||
this._makePartnerRecord(state.st_line.partner_id, state.st_line.partner_name),
|
||||
{mode: 'edit'}
|
||||
)
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
start: function () {
|
||||
this.fields.partner_id.appendTo(this.$('.accounting_view caption'));
|
||||
this.$('thead .line_info_button').attr("data-content", qweb.render('reconciliation.line.statement_line.details', {'state': this._initialState}));
|
||||
this.$el.popover({
|
||||
'selector': '.line_info_button',
|
||||
'placement': 'left',
|
||||
'container': this.$el,
|
||||
'html': true,
|
||||
'trigger': 'hover',
|
||||
'animation': false,
|
||||
'toggle': 'popover'
|
||||
});
|
||||
delete this._initialState;
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* update the statement line rendering
|
||||
*
|
||||
* @param {object} state - statement line
|
||||
*/
|
||||
update: function (state) {
|
||||
// isValid
|
||||
this.$('caption .o_buttons button.o_validate').toggleClass('hidden', !!state.balance.type);
|
||||
this.$('caption .o_buttons button.o_reconcile').toggleClass('hidden', state.balance.type <= 0);
|
||||
this.$('caption .o_buttons .o_no_valid').toggleClass('hidden', state.balance.type >= 0);
|
||||
|
||||
// parnter_id
|
||||
var record = this._makePartnerRecord(state.st_line.partner_id, state.st_line.partner_name);
|
||||
this.fields.partner_id.reset(record);
|
||||
this.$el.attr('data-partner', state.st_line.partner_id);
|
||||
|
||||
// mode
|
||||
this.$('.create, .match').each(function () {
|
||||
var $panel = $(this);
|
||||
$panel.css('-webkit-transition', 'none');
|
||||
$panel.css('-moz-transition', 'none');
|
||||
$panel.css('-o-transition', 'none');
|
||||
$panel.css('transition', 'none');
|
||||
$panel.css('max-height', $panel.height());
|
||||
$panel.css('-webkit-transition', '');
|
||||
$panel.css('-moz-transition', '');
|
||||
$panel.css('-o-transition', '');
|
||||
$panel.css('transition', '');
|
||||
});
|
||||
this.$el.data('mode', state.mode).attr('data-mode', state.mode);
|
||||
this.$('.create, .match').each(function () {
|
||||
$(this).removeAttr('style');
|
||||
});
|
||||
|
||||
// reconciliation_proposition
|
||||
var $props = this.$('.accounting_view tbody').empty();
|
||||
var props = _.filter(state.reconciliation_proposition, {'display': true});
|
||||
_.each(props, 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"/>')
|
||||
.appendTo($line.find('.cell_info_popover'))
|
||||
.attr("data-content", qweb.render('reconciliation.line.mv_line.details', {'line': line}));
|
||||
}
|
||||
|
||||
if (state.balance.amount < 0 && props.length === 1) {
|
||||
var text = !line.partial_reconcile ?
|
||||
_t("This move's amount is higher than the transaction's amount. Click to register a partial payment and keep the payment balance open."):
|
||||
_t("Undo the partial reconciliation.");
|
||||
$('<span class="do_partial_reconcile_'+(!line.partial_reconcile)+' line_info_button fa fa-exclamation-triangle"/>')
|
||||
.prependTo($line.find('.cell_right'))
|
||||
.attr("data-content", text);
|
||||
}
|
||||
$props.append($line);
|
||||
});
|
||||
|
||||
// mv_lines
|
||||
var $mv_lines = this.$('.match table tbody').empty();
|
||||
_.each(state.mv_lines.slice(0,5), 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"/>')
|
||||
.appendTo($line.find('.cell_info_popover'))
|
||||
.attr("data-content", qweb.render('reconciliation.line.mv_line.details', {'line': line}));
|
||||
}
|
||||
$mv_lines.append($line);
|
||||
});
|
||||
this.$('.match .fa-chevron-right').toggleClass('disabled', state.mv_lines.length <= 5);
|
||||
this.$('.match .fa-chevron-left').toggleClass('disabled', !state.offset);
|
||||
this.$('.match').css('max-height', !state.mv_lines.length && !state.filter.length ? '0px' : '');
|
||||
|
||||
// balance
|
||||
this.$('table tfoot').html(qweb.render("reconciliation.line.balance", {'state': state}));
|
||||
|
||||
// create form
|
||||
if (state.createForm) {
|
||||
if (!this.fields.account_id) {
|
||||
this._renderCreate(state);
|
||||
}
|
||||
var data = this.model.get(this.handleCreateRecord).data;
|
||||
this.model.notifyChanges(this.handleCreateRecord, state.createForm);
|
||||
record = this.model.get(this.handleCreateRecord);
|
||||
_.each(this.fields, function (field, fieldName) {
|
||||
if (fieldName === "partner_id") return;
|
||||
if ((data[fieldName] || state.createForm[fieldName]) && !_.isEqual(state.createForm[fieldName], data[fieldName])) {
|
||||
field.reset(record);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.$('.create .add_line').toggle(!!state.balance.amount);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {integer} partnerID
|
||||
* @param {string} partnerName
|
||||
* @returns {object} dataPoint
|
||||
*/
|
||||
_makePartnerRecord: function (partnerID, partnerName) {
|
||||
var recordID = this.model.makeRecord('account.bank.statement.line', [{
|
||||
relation: 'res.partner',
|
||||
type: 'many2one',
|
||||
name: 'partner_id',
|
||||
value: [partnerID, partnerName]
|
||||
}]);
|
||||
return this.model.get(recordID);
|
||||
},
|
||||
|
||||
/**
|
||||
* create account_id, tax_id, analytic_account_id, label and amount field
|
||||
*
|
||||
* @private
|
||||
* @param {object} state - statement line
|
||||
*/
|
||||
_renderCreate: function (state) {
|
||||
this.handleCreateRecord = this.model.makeRecord('account.bank.statement.line', [{
|
||||
relation: 'account.account',
|
||||
type: 'many2one',
|
||||
name: 'account_id',
|
||||
}, {
|
||||
relation: 'account.journal',
|
||||
type: 'many2one',
|
||||
name: 'journal_id',
|
||||
}, {
|
||||
relation: 'account.tax',
|
||||
type: 'many2one',
|
||||
name: 'tax_id',
|
||||
}, {
|
||||
relation: 'account.analytic.account',
|
||||
type: 'many2one',
|
||||
name: 'analytic_account_id',
|
||||
}, {
|
||||
type: 'char',
|
||||
name: 'label',
|
||||
attrs: {string: ""}
|
||||
}, {
|
||||
type: 'float',
|
||||
name: 'amount',
|
||||
attrs: {string: ""},
|
||||
}]);
|
||||
var record = this.model.get(this.handleCreateRecord);
|
||||
|
||||
this.fields.account_id = new relational_fields.FieldMany2One(this,
|
||||
'account_id', record, {mode: 'edit', required: true});
|
||||
|
||||
this.fields.journal_id = new relational_fields.FieldMany2One(this,
|
||||
'journal_id', record, {mode: 'edit', required: true});
|
||||
|
||||
this.fields.tax_id = new relational_fields.FieldMany2One(this,
|
||||
'tax_id', record, {mode: 'edit'});
|
||||
|
||||
this.fields.analytic_account_id = new relational_fields.FieldMany2One(this,
|
||||
'analytic_account_id', record, {mode: 'edit'});
|
||||
|
||||
this.fields.label = new basic_fields.FieldChar(this,
|
||||
'label', record, {mode: 'edit', required: true});
|
||||
|
||||
this.fields.amount = new basic_fields.FieldFloat(this,
|
||||
'amount', record, {mode: 'edit', required: true});
|
||||
|
||||
var $create = $(qweb.render("reconciliation.line.create", {'state': state}));
|
||||
this.fields.account_id.appendTo($create.find('.create_account_id .o_td_field'));
|
||||
this.fields.journal_id.appendTo($create.find('.create_journal_id .o_td_field'));
|
||||
this.fields.tax_id.appendTo($create.find('.create_tax_id .o_td_field'));
|
||||
this.fields.analytic_account_id.appendTo($create.find('.create_analytic_account_id .o_td_field'));
|
||||
this.fields.label.appendTo($create.find('.create_label .o_td_field'));
|
||||
this.fields.amount.appendTo($create.find('.create_amount .o_td_field'));
|
||||
this.$('.create').append($create);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
_onFieldChanged: function (event) {
|
||||
event.stopPropagation();
|
||||
var fieldName = event.target.name;
|
||||
if (fieldName === 'partner_id') {
|
||||
var partner_id = event.data.changes.partner_id;
|
||||
this.trigger_up('change_partner', {'data': partner_id});
|
||||
} else {
|
||||
if (event.data.changes.amount && isNaN(event.data.changes.amount)) {
|
||||
return;
|
||||
}
|
||||
this.trigger_up('update_proposition', {'data': event.data.changes});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onTogglePanel: function () {
|
||||
var mode = this.$el.data('mode') === 'inactive' ? 'match' : 'inactive';
|
||||
this.trigger_up('change_mode', {'data': mode});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onShowPanel: function () {
|
||||
var mode = (this.$el.data('mode') === 'inactive' || this.$el.data('mode') === 'match') ? 'create' : 'match';
|
||||
this.trigger_up('change_mode', {'data': mode});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onFilterChange: function () {
|
||||
this.trigger_up('change_filter', {'data': _.str.strip($(event.target).val())});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onPrevious: function () {
|
||||
this.trigger_up('change_offset', {'data': -5});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onNext: function () {
|
||||
this.trigger_up('change_offset', {'data': 5});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onSelectMoveLine: function (event) {
|
||||
var mv_line_id = $(event.target).closest('.mv_line').data('line-id');
|
||||
this.trigger_up('add_proposition', {'data': mv_line_id});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onSelectProposition: function (event) {
|
||||
var mv_line_id = $(event.target).closest('.mv_line').data('line-id');
|
||||
this.trigger_up('remove_proposition', {'data': mv_line_id});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onQuickCreateProposition: function (event) {
|
||||
document.activeElement && document.activeElement.blur();
|
||||
this.trigger_up('quick_create_proposition', {'data': $(event.target).data('reconcile-model-id')});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onCreateProposition: function () {
|
||||
document.activeElement && document.activeElement.blur();
|
||||
this.trigger_up('create_proposition');
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onValidate: function () {
|
||||
this.trigger_up('validate');
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onTogglePartialReconcile: function (e) {
|
||||
e.stopPropagation();
|
||||
var popover = $(e.target).data('bs.popover');
|
||||
popover && popover.destroy();
|
||||
this.trigger_up('toggle_partial_reconcile');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* rendering of the manual reconciliation action contains progress bar, title
|
||||
* and auto reconciliation button
|
||||
*/
|
||||
var ManualRenderer = StatementRenderer.extend({
|
||||
template: "reconciliation.manual.statement",
|
||||
|
||||
/**
|
||||
* avoid statement name edition
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
*/
|
||||
_onClickStatementName: function () {}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* rendering of the manual reconciliation, contains line data, proposition and
|
||||
* view for 'match' mode
|
||||
*/
|
||||
var ManualLineRenderer = LineRenderer.extend({
|
||||
template: "reconciliation.manual.line",
|
||||
|
||||
/**
|
||||
* create partner_id field in readonly mode
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
init: function (parent, model, state) {
|
||||
this._super.apply(this, arguments);
|
||||
if (state.partner_id) {
|
||||
this.fields.partner_id = new relational_fields.FieldMany2One(this,
|
||||
'partner_id',
|
||||
this._makePartnerRecord(state.partner_id, state.partner_name),
|
||||
{mode: 'readonly'}
|
||||
);
|
||||
} else {
|
||||
this.fields.title_account_id = new relational_fields.FieldMany2One(this,
|
||||
'account_id',
|
||||
this.model.get(this.model.makeRecord('account.move.line', [{
|
||||
relation: 'account.account',
|
||||
type: 'many2one',
|
||||
name: 'account_id',
|
||||
value: [state.account_id.id, state.account_id.display_name]
|
||||
}])),
|
||||
{mode: 'readonly'}
|
||||
);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
* @param {string} handle
|
||||
* @param {number} proposition id (move line id)
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
removeProposition: function (handle, id) {
|
||||
if (!id) {
|
||||
return $.when();
|
||||
}
|
||||
return this._super(handle, id);
|
||||
},
|
||||
/**
|
||||
* move the partner field
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
start: function () {
|
||||
this._super();
|
||||
if (!this.fields.title_account_id) {
|
||||
this.fields.partner_id.$el.prependTo(this.$('.accounting_view thead td:eq(1) span:first'));
|
||||
} else {
|
||||
this.fields.partner_id.destroy();
|
||||
this.fields.title_account_id.appendTo(this.$('.accounting_view thead td:eq(1) span:first'));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
update: function (state) {
|
||||
this._super(state);
|
||||
var props = _.filter(state.reconciliation_proposition, {'display': true});
|
||||
if (!props.length) {
|
||||
var $line = $(qweb.render("reconciliation.line.mv_line", {'line': {}, 'state': state}));
|
||||
this.$('.accounting_view tbody').append($line);
|
||||
}
|
||||
},
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
/**
|
||||
* display journal_id field
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_renderCreate: function (state) {
|
||||
this._super(state);
|
||||
this.$('.create .create_journal_id').show();
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
|
||||
return {
|
||||
StatementRenderer: StatementRenderer,
|
||||
ManualRenderer: ManualRenderer,
|
||||
LineRenderer: LineRenderer,
|
||||
ManualLineRenderer: ManualLineRenderer,
|
||||
};
|
||||
});
|
||||
@@ -35,77 +35,8 @@
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.o_kanban_graph_section {
|
||||
.o_dashboard_graph {
|
||||
.o-position-absolute(auto, 0, 0, 0);
|
||||
.o_graph_linechart {
|
||||
> svg {
|
||||
height: 75px;
|
||||
|
||||
// X axis
|
||||
g.nv-x.nv-axis {
|
||||
transform: translateY(50px);
|
||||
|
||||
// Remove max and min labels
|
||||
g.nv-axisMaxMin {
|
||||
display: none;
|
||||
}
|
||||
g.tick.major {
|
||||
// Don't know why, but leads to strange bold text
|
||||
// stroke: @odoo-brand-primary;
|
||||
|
||||
line {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// !important are needed because nvd3 uses inline style on elements
|
||||
|
||||
// Remove strokes
|
||||
g.nv-linesWrap {
|
||||
g.nv-group.nv-series-0 {
|
||||
fill-opacity: 0.3 !important;
|
||||
fill: @odoo-brand-primary !important;
|
||||
stroke: @odoo-brand-primary !important;
|
||||
|
||||
.nv-point {
|
||||
visibility: hidden;
|
||||
r: 3;
|
||||
stroke: @odoo-brand-primary !important;
|
||||
fill: white;
|
||||
stroke-width: 2;
|
||||
}
|
||||
.nv-point:nth-child(5n+1) {
|
||||
visibility: visible;
|
||||
fill-opacity: .95 !important;
|
||||
stroke-opacity: .95 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.o_graph_barchart {
|
||||
> svg {
|
||||
height: 75px;
|
||||
overflow: visible;
|
||||
g.nv-barsWrap {
|
||||
g.nv-group.nv-series-0 {
|
||||
g.past {
|
||||
opacity: 0.5;
|
||||
fill: @odoo-brand-primary !important;
|
||||
}
|
||||
g.future {
|
||||
opacity: 0.5;
|
||||
fill: @odoo-brand-optional !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_invisible .o_kanban_graph_section {
|
||||
display: none; // This fix a bug on firefox
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,3 +44,77 @@
|
||||
min-width: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Style for the widget "dashboard_graph"
|
||||
.o_dashboard_graph {
|
||||
&.o_graph_linechart {
|
||||
> svg {
|
||||
height: 75px;
|
||||
|
||||
// X axis
|
||||
g.nv-x.nv-axis {
|
||||
transform: translateY(50px);
|
||||
|
||||
// Remove max and min labels
|
||||
g.nv-axisMaxMin {
|
||||
display: none;
|
||||
}
|
||||
g.tick.major {
|
||||
// Don't know why, but leads to strange bold text
|
||||
// stroke: @odoo-brand-primary;
|
||||
|
||||
line {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// !important are needed because nvd3 uses inline style on elements
|
||||
|
||||
// Remove strokes
|
||||
g.nv-linesWrap {
|
||||
g.nv-group.nv-series-0 {
|
||||
fill-opacity: 0.3 !important;
|
||||
fill: @odoo-brand-primary !important;
|
||||
stroke: @odoo-brand-primary !important;
|
||||
|
||||
.nv-point {
|
||||
visibility: hidden;
|
||||
r: 3;
|
||||
stroke: @odoo-brand-primary !important;
|
||||
fill: white;
|
||||
stroke-width: 2;
|
||||
}
|
||||
.nv-point:nth-child(5n+1) {
|
||||
visibility: visible;
|
||||
fill-opacity: .95 !important;
|
||||
stroke-opacity: .95 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.o_graph_barchart {
|
||||
> svg {
|
||||
height: 75px;
|
||||
overflow: visible;
|
||||
g.nv-barsWrap {
|
||||
g.nv-group.nv-series-0 {
|
||||
g.past {
|
||||
opacity: 0.5;
|
||||
fill: @odoo-brand-primary !important;
|
||||
}
|
||||
g.future {
|
||||
opacity: 0.5;
|
||||
fill: @odoo-brand-optional !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_invisible .o_dashboard_graph {
|
||||
display: none; // This fix a bug on firefox
|
||||
}
|
||||
|
||||
@@ -4,641 +4,327 @@
|
||||
@accountingBorder: 1px solid #000;
|
||||
@initialLineBackground: #f0f0f0;
|
||||
@infoColor: #44c;
|
||||
// Warning, this value is also specified in the abstractReconciliation widget
|
||||
@aestetic_animation_speed: 300ms;
|
||||
|
||||
|
||||
.o_reconciliation {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
cursor: default;
|
||||
font-size: 12px;
|
||||
|
||||
// Why on earth does bootstrap set font-size to 14px in popovers ?
|
||||
.popover {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.oe_form_sheetbg {
|
||||
padding-top: 0;
|
||||
|
||||
.oe_form_sheet {
|
||||
position: relative;
|
||||
padding: 20px 15px 20px 15px;
|
||||
border-top: 0;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.clearer {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.oe_view_nocontent {
|
||||
max-width: none;
|
||||
|
||||
> p {
|
||||
padding: 0 10%;
|
||||
}
|
||||
}
|
||||
|
||||
h1 input, h2 input {
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
h1 {
|
||||
width: 48%;
|
||||
padding: 0 0 0 @actionColWidth;
|
||||
padding: 0 0 0 15px;
|
||||
margin: 0 0 25px 0;
|
||||
float: left;
|
||||
font-size: 2em;
|
||||
height: 1.5em;
|
||||
}
|
||||
|
||||
.statement_name span {
|
||||
line-height: 1.5em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.change_statement_name_container {
|
||||
display: none;
|
||||
width: 95%;
|
||||
|
||||
td:first-child, td:first-child > input {
|
||||
width: 99%;
|
||||
&.statement_name_edition input {
|
||||
width: 85%;
|
||||
}
|
||||
td:last-child {
|
||||
width: 1%;
|
||||
padding-left: 3px;
|
||||
|
||||
button {
|
||||
height: 100%;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
.progress {
|
||||
width: 49%;
|
||||
margin: 10px @actionColWidth 0 0;
|
||||
margin: 10px 15px 0 0;
|
||||
float: right;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
.progress-bar {
|
||||
background-color: #7c7bad;
|
||||
}
|
||||
.progress-text {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
top: 1px;
|
||||
z-index: 10;
|
||||
text-shadow:
|
||||
-1px -1px 0 #f5f5f5,
|
||||
1px -1px 0 #f5f5f5,
|
||||
-1px 1px 0 #f5f5f5,
|
||||
1px 1px 0 #f5f5f5;
|
||||
}
|
||||
.progress-bar {
|
||||
background-color: @odoo-brand-optional;
|
||||
}
|
||||
}
|
||||
|
||||
.show_more_container {
|
||||
text-align: center;
|
||||
margin-bottom: 15px;
|
||||
|
||||
.show_more {
|
||||
display: none;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
.notification_area {
|
||||
margin: 0 @actionColWidth;
|
||||
.fa {
|
||||
font-size: 20px;
|
||||
margin-left: 7px;
|
||||
line-height: 14px;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.interface_options {
|
||||
margin-bottom: 25px;
|
||||
padding-left: @actionColWidth;
|
||||
|
||||
.oe_radio_input, .o_radio_input {
|
||||
border: none;
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
.done_message {
|
||||
padding: 70px 20% 10px 20%;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
.fa {
|
||||
position: absolute;
|
||||
right: 20%;
|
||||
}
|
||||
}
|
||||
|
||||
.notification_area {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.o_view_nocontent {
|
||||
max-width: none;
|
||||
padding: 0 10%;
|
||||
color: @odoo-main-color-muted;
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
.accounting_view {
|
||||
width: 100%;
|
||||
padding: 0 20%;
|
||||
margin-top: 50px;
|
||||
margin-bottom: 50px;
|
||||
|
||||
h2 {
|
||||
margin-bottom: 30px;
|
||||
|
||||
.congrats_icon {
|
||||
float: right;
|
||||
font-size: 2em;
|
||||
position: relative;
|
||||
top: -0.25em;
|
||||
}
|
||||
.cell_left {
|
||||
border-right: 1px solid #333;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.achievements {
|
||||
margin-top: 30px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
|
||||
.achievement {
|
||||
font-size: 4em;
|
||||
margin: 0 0.3em;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
text-shadow: 2px 2px 0px rgba(0,0,0,0.2);
|
||||
|
||||
i {
|
||||
font-size: 0.5em;
|
||||
color: white;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -0.55em;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
//text-shadow: 1px 1px 0 black;
|
||||
}
|
||||
}
|
||||
.do_partial_reconcile_true {
|
||||
color: #7c7bad;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.action_buttons {
|
||||
text-align: center;
|
||||
.do_partial_reconcile_false {
|
||||
color: #f0eeee;
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
/* icons */
|
||||
.fa {
|
||||
&.line_info_button {
|
||||
color: #ccc !important;
|
||||
.o_multi_currency {
|
||||
margin-right: 5px;
|
||||
&.o_multi_currency_color_0 {
|
||||
color: #dd6666;
|
||||
}
|
||||
&.o_multi_currency_color_1 {
|
||||
color: #aaaaaa;
|
||||
}
|
||||
&.o_multi_currency_color_2 {
|
||||
color: #66dd66;
|
||||
}
|
||||
&.o_multi_currency_color_3 {
|
||||
color: #6666dd;
|
||||
}
|
||||
&.o_multi_currency_color_4 {
|
||||
color: #dddd66;
|
||||
}
|
||||
&.o_multi_currency_color_5 {
|
||||
color: #dd66dd;
|
||||
}
|
||||
&.o_multi_currency_color_6 {
|
||||
color: #66dddd;
|
||||
}
|
||||
&.o_multi_currency_color_7 {
|
||||
color: #aaa333;
|
||||
}
|
||||
}
|
||||
.accounting_view .fa-add-remove:before {
|
||||
content: "\f068";
|
||||
}
|
||||
.match .fa-add-remove:before {
|
||||
content: "\f067";
|
||||
}
|
||||
|
||||
// reconciliationLine widget
|
||||
.o_reconciliation_line {
|
||||
margin-bottom: 30px;
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
vertical-align: top;
|
||||
}
|
||||
tr {
|
||||
cursor: pointer;
|
||||
}
|
||||
tr.already_reconciled {
|
||||
color: @infoColor;
|
||||
}
|
||||
tr.invalid {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
thead td {
|
||||
border-top: @lightBorder;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 5px;
|
||||
background-color: @initialLineBackground;
|
||||
}
|
||||
tfoot td {
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
// modes : default
|
||||
/* columns */
|
||||
|
||||
.cell_action {
|
||||
width: 15px;
|
||||
color: @gray;
|
||||
background: #fff;
|
||||
border: 0;
|
||||
.fa-add-remove:before {
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
tr:hover .cell_action .fa-add-remove:before {
|
||||
content: "\f068";
|
||||
}
|
||||
.is_tax .cell_action .fa-add-remove:before {
|
||||
position: relative;
|
||||
top: -18px;
|
||||
}
|
||||
.cell_account_code {
|
||||
width: 80px;
|
||||
}
|
||||
.cell_due_date {
|
||||
width: 100px;
|
||||
}
|
||||
.cell_label {
|
||||
width: auto;
|
||||
}
|
||||
.cell_left {
|
||||
padding-right: 5px;
|
||||
}
|
||||
.cell_right, .cell_left {
|
||||
text-align: right;
|
||||
width: 120px;
|
||||
}
|
||||
.cell_info_popover {
|
||||
text-align: right;
|
||||
width: 15px;
|
||||
color: #ccc;
|
||||
background: #fff;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* info popover */
|
||||
|
||||
table.details {
|
||||
vertical-align: top;
|
||||
td:first-child {
|
||||
vertical-align: top;
|
||||
padding-right: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
tr.one_line_info {
|
||||
td {
|
||||
padding-top: 10px;
|
||||
text-align: center;
|
||||
color: @infoColor;
|
||||
}
|
||||
}
|
||||
|
||||
/* Icons */
|
||||
|
||||
.toggle_match, .toggle_create {
|
||||
-webkit-transition-property: -webkit-transform;
|
||||
-moz-transition-property: -moz-transform;
|
||||
-ms-transition-property: -ms-transform;
|
||||
-o-transition-property: -o-transform;
|
||||
transition-property: transform;
|
||||
-webkit-transform: rotate(0deg);
|
||||
-moz-transform: rotate(0deg);
|
||||
-ms-transform: rotate(0deg);
|
||||
-o-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
-webkit-transition-duration: @aestetic_animation_speed;
|
||||
-moz-transition-duration: @aestetic_animation_speed;
|
||||
-ms-transition-duration: @aestetic_animation_speed;
|
||||
-o-transition-duration: @aestetic_animation_speed;
|
||||
transition-duration: @aestetic_animation_speed;
|
||||
.o-transform(rotate(0deg));
|
||||
.o-transition(transform, 300ms);
|
||||
}
|
||||
|
||||
.visible_toggle {
|
||||
visibility: visible !important;
|
||||
-webkit-transform: rotate(90deg);
|
||||
-moz-transform: rotate(90deg);
|
||||
-ms-transform: rotate(90deg);
|
||||
-o-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
.o-transform(rotate(90deg));
|
||||
}
|
||||
|
||||
.partner_name {
|
||||
color: #444;
|
||||
|
||||
.change_partner {
|
||||
color: @odoo-brand-optional;
|
||||
display: none;
|
||||
cursor: pointer;
|
||||
margin: 0 10px 0 5px;
|
||||
}
|
||||
&:hover .change_partner {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
.change_partner_container {
|
||||
width: 200px;
|
||||
display: none;
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
// modes : specific
|
||||
&[data-mode="match"] {
|
||||
.toggle_match {
|
||||
.visible_toggle;
|
||||
}
|
||||
}
|
||||
|
||||
&[data-mode="create"] {
|
||||
.toggle_create {
|
||||
.visible_toggle;
|
||||
}
|
||||
|
||||
&.no_partner {
|
||||
.toggle_match {
|
||||
.visible_toggle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&[data-mode="inactive"] {
|
||||
.initial_line > td {
|
||||
background-color: (@initialLineBackground + #080808) !important;
|
||||
}
|
||||
/* Match view & Create view */
|
||||
|
||||
> .match, > .create {
|
||||
max-height: 0px;
|
||||
overflow: hidden;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
.o-transition(max-height, 250ms);
|
||||
}
|
||||
|
||||
&.no_match:not(.no_partner) {
|
||||
.initial_line {
|
||||
cursor: default !important;
|
||||
|
||||
.line_info_button {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.toggle_match {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
&[data-mode="match"] > .match {
|
||||
max-height: 130px;
|
||||
.o-transition(max-height, 400ms);
|
||||
}
|
||||
|
||||
/* gap between accounting_view and action view */
|
||||
> table > tbody > tr:nth-child(1) > td table {
|
||||
margin-bottom: 10px;
|
||||
&[data-mode="create"] > .create {
|
||||
max-height: 210px;
|
||||
.o-transition(max-height, 400ms);
|
||||
}
|
||||
}
|
||||
|
||||
/* Match view */
|
||||
|
||||
/* popover */
|
||||
table.details {
|
||||
td:first-child {
|
||||
padding-right: 10px;
|
||||
font-weight: bold;
|
||||
.match {
|
||||
> div {
|
||||
padding: 1px;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.cell_action .fa-add-remove:before {
|
||||
content: "";
|
||||
}
|
||||
tr:hover .cell_action .fa-add-remove:before {
|
||||
content: "\f067";
|
||||
}
|
||||
.match_controls {
|
||||
padding: 0 0 5px (@actionColWidth+@mainTableBordersPadding);
|
||||
|
||||
.filter {
|
||||
width: 240px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
tr.one_line_info {
|
||||
td {
|
||||
padding-top: 10px;
|
||||
text-align: center;
|
||||
color: @infoColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* arrays of move lines */
|
||||
.accounting_view, .match table {
|
||||
width: 100%;
|
||||
|
||||
tbody tr {
|
||||
.fa-chevron-left, .fa-chevron-right {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
tr.already_reconciled {
|
||||
color: @infoColor;
|
||||
.fa-chevron-left {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 1px 8px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
td.cell_action, td.cell_info_popover {
|
||||
width: @actionColWidth;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
td.cell_action {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
td.cell_account_code {
|
||||
width: 80px;
|
||||
padding-left: @mainTableBordersPadding;
|
||||
}
|
||||
|
||||
td.cell_due_date {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
td.cell_label {
|
||||
|
||||
}
|
||||
|
||||
td.cell_debit {
|
||||
text-align: right;
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
td.cell_credit {
|
||||
width: 15%;
|
||||
text-align: right;
|
||||
padding-right: @mainTableBordersPadding;
|
||||
}
|
||||
|
||||
td.cell_info_popover {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
tr.line_open_balance {
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
tr {
|
||||
.toggle_create, .toggle_match, .fa-add-remove {
|
||||
visibility: hidden;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
&:hover, &:active, &:focus {
|
||||
.toggle_create, .toggle_match, .fa-add-remove {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tr .do_partial_reconcile_button {
|
||||
color: @odoo-brand-optional;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
tr .undo_partial_reconcile_button {
|
||||
color: @odoo-brand-secondary;
|
||||
padding-right: 5px;
|
||||
.fa-chevron-left.disabled, .fa-chevron-right.disabled {
|
||||
color: #ddd;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
/* Partie infos */
|
||||
.accounting_view {
|
||||
border-collapse: separate;
|
||||
|
||||
.initial_line > td {
|
||||
border-top: @lightBorder;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 5px;
|
||||
background-color: @initialLineBackground;
|
||||
-webkit-transition-property: background-color;
|
||||
-moz-transition-property: background-color;
|
||||
-ms-transition-property: background-color;
|
||||
transition-property: background-color;
|
||||
-webkit-transition-duration: @aestetic_animation_speed;
|
||||
-moz-transition-duration: @aestetic_animation_speed;
|
||||
-ms-transition-duration: @aestetic_animation_speed;
|
||||
-o-transition-duration: @aestetic_animation_speed;
|
||||
transition-duration: @aestetic_animation_speed;
|
||||
|
||||
&.cell_action, &.cell_info_popover {
|
||||
border-top: none;
|
||||
background: white !important;
|
||||
// Hack pour l'alignement au px près
|
||||
padding-top: 6px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
caption {
|
||||
text-align: left;
|
||||
height: 26px;
|
||||
margin: 0 @actionColWidth 4px @actionColWidth;
|
||||
padding: 0;
|
||||
|
||||
.partner_name {
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tip_reconciliation_not_balanced {
|
||||
color: red;
|
||||
float: right;
|
||||
padding-right: 7px;
|
||||
}
|
||||
|
||||
button {
|
||||
float: right;
|
||||
position: relative;
|
||||
top: -4px;
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
> span, > input {
|
||||
position: relative; top: 7px; /* meh */
|
||||
}
|
||||
}
|
||||
|
||||
// accounting "T"
|
||||
td.cell_credit { border-left: @accountingBorder; }
|
||||
.show_more {
|
||||
display: inline-block;
|
||||
margin-left: (@actionColWidth+@mainTableBordersPadding);
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Match view */
|
||||
.match {
|
||||
display: none;
|
||||
padding: 1px;
|
||||
.match_controls {
|
||||
padding: 0 0 5px (@actionColWidth+@mainTableBordersPadding);
|
||||
|
||||
.filter {
|
||||
width: 240px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.pager_control_left, .pager_control_right {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pager_control_left {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.pager_control_left.disabled, .pager_control_right.disabled {
|
||||
color: #ddd;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
.show_more {
|
||||
display: inline-block;
|
||||
margin-left: (@actionColWidth+@mainTableBordersPadding);
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Action create */
|
||||
.create {
|
||||
display: none;
|
||||
/* Create view */
|
||||
.create {
|
||||
> div {
|
||||
margin: 0 @actionColWidth;
|
||||
border: 1px solid #d5d5d5;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
overflow: auto;
|
||||
|
||||
.quick_add {
|
||||
position: relative;
|
||||
margin-bottom: 10px;
|
||||
clear: both;
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.presets_config {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
|
||||
.dropdown-menu {
|
||||
font-size: 1em; // Since there's no dropdown-menu-sm class in bootstrap
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .presets_config, .presets_config.open {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
.o_form > table {
|
||||
width: 49%;
|
||||
margin: 0;
|
||||
vertical-align: top;
|
||||
|
||||
&.create_group_left { float: left; }
|
||||
&.create_group_right { float: right; }
|
||||
|
||||
td {
|
||||
width: 99%;
|
||||
padding-left: 8px;
|
||||
|
||||
.oe_m2o_cm_button {
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
td.o_td_label {
|
||||
line-height: 26px;
|
||||
font-weight: bold;
|
||||
padding-right: 8px;
|
||||
min-width: 100px;
|
||||
border-right: 1px solid #ddd;
|
||||
white-space: nowrap;
|
||||
width: 1%;
|
||||
}
|
||||
|
||||
input, select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.add_line_container {
|
||||
clear: both;
|
||||
line-height: 26px;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
padding-top: 7px;
|
||||
}
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
}
|
||||
table {
|
||||
width: 49%;
|
||||
margin: 0;
|
||||
vertical-align: top;
|
||||
}
|
||||
td {
|
||||
width: 99%;
|
||||
padding-left: 8px;
|
||||
}
|
||||
tr .o_td_label {
|
||||
vertical-align: top;
|
||||
line-height: 26px;
|
||||
font-weight: bold;
|
||||
padding-right: 8px;
|
||||
min-width: 100px;
|
||||
border-right: 1px solid #ddd;
|
||||
white-space: nowrap;
|
||||
width: 1%;
|
||||
}
|
||||
.btn {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.add_line_container {
|
||||
text-align: center;
|
||||
clear: both;
|
||||
color: @infoColor;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_manual_reconciliation {
|
||||
.o_manual_reconciliation_line {
|
||||
.button_reconcile {
|
||||
float: right;
|
||||
position: relative;
|
||||
top: 1.1em;
|
||||
/*Manual Reconciliation*/
|
||||
.o_manual_statement {
|
||||
.accounting_view {
|
||||
td[colspan="3"] span:first-child {
|
||||
width: 50%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.accounting_view {
|
||||
thead {
|
||||
background: none;
|
||||
|
||||
td {
|
||||
vertical-align: bottom !important;
|
||||
}
|
||||
|
||||
td:nth-child(2) {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.cell_item_name {
|
||||
display: inline-block;
|
||||
min-width: 135px;
|
||||
}
|
||||
|
||||
.cell_last_time_entries_checked {
|
||||
font-weight: normal;
|
||||
display: inline-block;
|
||||
}
|
||||
.cell_item_name + .cell_last_time_entries_checked {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.cell_title_account_code {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
tr:first-child td {
|
||||
border-bottom: @lightBorder;
|
||||
|
||||
&.cell_action, &.cell_info_popover {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.cell_title_account_code {
|
||||
border-bottom: 1px solid #000 !important;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.filler_line td {
|
||||
height: 22px;
|
||||
cursor: default !important;
|
||||
}
|
||||
|
||||
tbody.tbody_matched_lines tr:first-child td {
|
||||
padding-top: 4px;
|
||||
}
|
||||
td[colspan="2"] {
|
||||
border-bottom: 1px solid #333;
|
||||
text-align: center;
|
||||
width: 240px;
|
||||
}
|
||||
|
||||
td.cell_due_date {
|
||||
padding-left: @mainTableBordersPadding !important;
|
||||
.do_partial_reconcile_true {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,369 +2,248 @@
|
||||
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<!-- abstract or shared templates -->
|
||||
<div t-name="reconciliation" class="o_reconciliation">
|
||||
<div class="o_form_view">
|
||||
<div class="o_form_sheet_bg">
|
||||
<div class="o_form_sheet"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<t t-name="reconciliation">
|
||||
<div class="o_form_view"><div class="oe_form_sheetbg o_form_sheet_bg"><div class="oe_form_sheet oe_form_sheet_width o_form_sheet">
|
||||
<h1><t t-esc="title"/></h1>
|
||||
<div t-if="! hide_progress" class="progress progress-striped">
|
||||
<div class="progress-text"><span class="valuenow">0</span> / <span class="valuemax"><t t-esc="total_lines"/></span></div>
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" t-att-aria-valuemax="total_lines" style="width: 0%;">
|
||||
<t t-name="reconciliation.statement">
|
||||
<div t-if="widget._initialState.valuemax">
|
||||
<div>
|
||||
<h1 class="statement_name"/>
|
||||
<h1 class="statement_name_edition" style="display: none;"><button class="btn btn-primary btn-sm pull-right">OK</button></h1>
|
||||
<div class="progress progress-striped">
|
||||
<div class="progress-text">
|
||||
<span class="valuenow"><t t-esc="widget._initialState.valuenow"/></span> / <span class="valuemax"><t t-esc="widget._initialState.valuemax"/></span>
|
||||
</div>
|
||||
<div aria-valuemin="0" t-att-aria-valuenow="widget._initialState.valuenow" class="progress-bar" role="progressbar" style="width: 0%;" t-att-aria-valuemax="widget._initialState.valuemax"></div>
|
||||
</div>
|
||||
<button class="btn btn-default js_automatic_reconciliation pull-right" title="Let odoo try to reconcile entries for the user">Automatic reconciliation</button>
|
||||
<div class="oe_clear clearer"></div>
|
||||
<div class="notification_area"></div>
|
||||
<div class="interface_options oe_form o_form"></div>
|
||||
<div class="reconciliation_lines_container"></div>
|
||||
<div class="show_more_container"><button class="show_more btn btn-default btn-sm">Show more... (<span class="num_items_remaining"></span> remaining)</button></div>
|
||||
<p class="o_protip text-muted" align="right">Tip: Hit CTRL-Enter to reconcile all the balanced items in the sheet.</p>
|
||||
</div></div></div>
|
||||
</t>
|
||||
<button class="btn btn-default o_automatic_reconciliation pull-right" title="Let odoo try to reconcile entries for the user">Automatic reconciliation</button>
|
||||
<div class="notification_area"/>
|
||||
</div>
|
||||
<div class="o_reconciliation_lines"/>
|
||||
<div class="pull-right text-muted">Tip: Hit CTRL-Enter to reconcile all the balanced items in the sheet.</div>
|
||||
</div>
|
||||
<div t-else="" class="o_view_nocontent">
|
||||
<p><b>Good Job!</b> Bank statements are fully reconciled.</p>
|
||||
<p>This page displays all the bank transactions that are to be reconciled and provides with a neat interface to do so.</p>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="nothing_to_reconcile">
|
||||
<div class="oe_form_sheetbg o_form_view"><div class="oe_form_sheet o_form_sheet oe_form_sheet_width">
|
||||
<div class="notification_area"></div>
|
||||
<div class="oe_view_nocontent"></div>
|
||||
</div></div>
|
||||
<t t-name="reconciliation.manual.statement" t-extend="reconciliation.statement">
|
||||
<t t-jquery="div:first" t-operation="attributes">
|
||||
<attribute name="class">o_manual_statement</attribute>
|
||||
</t>
|
||||
<t t-jquery="h1:last" t-operation="replace"></t>
|
||||
<t t-jquery=".o_view_nocontent p" t-operation="replace"></t>
|
||||
<t t-jquery=".o_view_nocontent" t-operation="append">
|
||||
<p><b>Good Job!</b> There is nothing to reconcile.</p>
|
||||
<p>All invoices and payments have been matched, your accounts' balances are clean.</p>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="reconciliation_done_message">
|
||||
<div class='done_message'>
|
||||
<h2><t t-raw="title" /></h2>
|
||||
<p class="action_buttons"></p>
|
||||
<div t-name="reconciliation.done" class="done_message">
|
||||
<i class="fa fa-4x fa-thumbs-o-up congrats_icon pull-right"></i>
|
||||
<h2>Congrats, you're all done !</h2>
|
||||
<p>It took you <strong><t t-esc="duration"/></strong> to reconcile <strong><t t-esc="number"/> transactions.</strong><br/>That's on average <t t-esc="timePerTransaction"/> seconds per transaction.</p>
|
||||
</div>
|
||||
|
||||
<t t-name="reconciliation.line">
|
||||
<t t-set="state" t-value="widget._initialState"/>
|
||||
<div class="o_reconciliation_line" t-att-data-mode="state.mode">
|
||||
<table class="accounting_view">
|
||||
<caption>
|
||||
<div class="pull-right o_buttons">
|
||||
<button t-attf-class="o_validate btn btn-default btn-sm #{!state.balance.type ? '' : 'hidden'}">Validate</button>
|
||||
<button t-attf-class="o_reconcile btn btn-primary btn-sm #{state.balance.type > 0 ? '' : 'hidden'}">Reconcile</button>
|
||||
<span t-attf-class="o_no_valid text-danger #{state.balance.type < 0 ? '' : 'hidden'}">Select a partner or choose a counterpart</span>
|
||||
</div>
|
||||
</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<td class="cell_action"><span class="toggle_match fa fa-cog"></span></td>
|
||||
<td class="cell_account_code"><t t-esc="state.st_line.account_code"/></td>
|
||||
<td class="cell_due_date"><t t-esc="state.st_line.date"/></td>
|
||||
<td class="cell_label"><t t-if="state.st_line.name" t-esc="state.st_line.name"/> <t t-if="state.st_line.amount_currency_str"> (<t t-esc="state.st_line.amount_currency_str"/>)</t></td>
|
||||
<td class="cell_left"><t t-if="state.st_line.amount > 0"><t t-raw="state.st_line.amount_str"/></t></td>
|
||||
<td class="cell_right"><t t-if="state.st_line.amount < 0"><t t-raw="state.st_line.amount_str"/></t></td>
|
||||
<td class="cell_info_popover"></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-foreach="state.reconciliation_proposition" t-as="line"><t t-call="reconciliation.line.mv_line"/></t>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<t t-call="reconciliation.line.balance"/>
|
||||
</tfoot>
|
||||
</table>
|
||||
<div class="match">
|
||||
<t t-call="reconciliation.line.match"/>
|
||||
</div>
|
||||
<div class="create"></div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="reconciliation.manual.line" t-extend="reconciliation.line">
|
||||
<t t-jquery=".o_buttons" t-operation="replace">
|
||||
<div class="pull-right o_buttons">
|
||||
<button t-attf-class="o_validate btn btn-default btn-sm #{!state.balance.type ? '' : 'hidden'}">Reconcile</button>
|
||||
<button t-attf-class="o_reconcile btn btn-primary btn-sm #{state.balance.type > 0 ? '' : 'hidden'}">Reconcile</button>
|
||||
<button t-attf-class="o_no_valid btn btn-default btn-sm #{state.balance.type < 0 ? '' : 'hidden'}">Skip</button>
|
||||
</div>
|
||||
</t>
|
||||
<t t-jquery=".accounting_view tbody" t-operation="append">
|
||||
<t t-if='!_.filter(state.reconciliation_proposition, {"display": true}).length'>
|
||||
<t t-set="line" t-value='{}'/>
|
||||
<t t-call="reconciliation.line.mv_line"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-jquery=".accounting_view thead tr" t-operation="replace">
|
||||
<tr>
|
||||
<td class="cell_action"><span class="toggle_match fa fa-cog"></span></td>
|
||||
<td colspan="3"><span/><span t-if="state.last_time_entries_checked">Last Reconciliation: <t t-esc="state.last_time_entries_checked"/></span></td>
|
||||
<td colspan="2"><t t-esc="state.st_line.account_code"/></td>
|
||||
<td class="cell_info_popover"></td>
|
||||
</tr>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="reconciliation_notification">
|
||||
<div t-att-class="'notification alert-dismissible alert alert-' + type" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true" class="fa fa-times"></span><span class="sr-only">Close</span></button>
|
||||
<t t-esc="message" />
|
||||
<t t-if="details !== undefined">
|
||||
<a class="fa fa-external-link" rel="do_action" href="javascript:void(0)"
|
||||
t-att-data-action_nam="details.name"
|
||||
t-att-data-model="details.model"
|
||||
t-att-data-ids="details.ids">
|
||||
</a>
|
||||
<t t-name="reconciliation.line.balance">
|
||||
<tr t-if="state.balance.amount">
|
||||
<td class="cell_action"><span class="toggle_create fa fa-play"></span></td>
|
||||
<td class="cell_account_code"><t t-esc="state.balance.account_code"/></td>
|
||||
<td class="cell_due_date"></td>
|
||||
<td class="cell_label"><t t-if="state.balance.amount < 0">Create Write-off</t><t t-elif="state.st_line.partner_id">Open balance</t><t t-else="">Choose counterpart</t></td>
|
||||
<td class="cell_left"><t t-if="state.balance.amount < 0"><t t-raw="state.balance.amount_str"/></t></td>
|
||||
<td class="cell_right"><t t-if="state.balance.amount > 0"><t t-raw="state.balance.amount_str"/></t></td>
|
||||
<td class="cell_info_popover"></td>
|
||||
</tr>
|
||||
</t>
|
||||
|
||||
|
||||
<div t-name="reconciliation.line.match">
|
||||
<div class="match_controls">
|
||||
<input class="filter" placeholder="Filter..." type="text" value=""/>
|
||||
<span class="pull-right fa fa-chevron-right disabled"></span>
|
||||
<span class="pull-right fa fa-chevron-left disabled"></span>
|
||||
</div>
|
||||
<table>
|
||||
<tbody>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
<div t-name="reconciliation.line.create">
|
||||
<div class="quick_add">
|
||||
<div class="btn-group btn-group-sm o_reconcile_models" t-if="state.reconcileModels">
|
||||
<t t-foreach="state.reconcileModels" t-as="reconcileModel">
|
||||
<button class="btn btn-default" t-att-data-reconcile-model-id="reconcileModel.id"><t t-esc="reconcileModel.name"/></button>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="reconciliation_line">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<table class="accounting_view">
|
||||
<caption></caption>
|
||||
<tbody class="tbody_matched_lines"></tbody>
|
||||
<tbody class="tbody_created_lines"></tbody>
|
||||
<tbody class="tbody_open_balance"></tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="action_pane match">
|
||||
<div class="match_controls">
|
||||
<input type="text" class="filter" placeholder="Filter..." value="" />
|
||||
<span class="pager_control_right pull-right fa fa-chevron-right"></span>
|
||||
<span class="pager_control_left pull-right fa fa-chevron-left"></span>
|
||||
</div>
|
||||
<table></table>
|
||||
</div>
|
||||
<div class="action_pane create">
|
||||
<div t-if="!presets">
|
||||
<p style="color: #bbb;">You did not configure any reconcile model yet, you can do it <a style="cursor: pointer;" class="goto_create_preset">there</a>.</p>
|
||||
</div>
|
||||
<div class="quick_add" t-att-style="(!presets ? 'display: none' : undefined)">
|
||||
<div class="btn-group btn-group-sm presets_container"><t t-raw="presets" /></div>
|
||||
<div class="dropdown presets_config">
|
||||
<a data-toggle="dropdown" href="#"><span class="fa fa-cog"></span></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="Presets config">
|
||||
<li><a class="presets_config_create" href="#">Create model</a></li>
|
||||
<li><a class="presets_config_edit" href="#">Modify models</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oe_form o_form create_form">
|
||||
<table class="o_group o_inner_group o_group_col_6 create_group_left"><!-- here come some form_create_field --></table>
|
||||
<table class="o_group o_inner_group o_group_col_6 create_group_right"><!-- here come some form_create_field --></table>
|
||||
<p class="add_line_container"><a href="javascript:void(0)" class="add_line"><i class="fa fa-plus-circle"></i> Save and New</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</t>
|
||||
|
||||
<t t-name="preset_button">
|
||||
<button type='button' class='btn btn-default preset' t-att-data-presetid="id">
|
||||
<t t-esc="name"/>
|
||||
</button>
|
||||
</t>
|
||||
|
||||
<t t-name="presets_dropdown">
|
||||
<div class="btn-group btn-group-sm">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
More <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<t t-foreach="presets" t-as="preset">
|
||||
<li><a href="javascript:void(0)" class='preset' t-att-data-presetid="preset.id"><t t-esc="preset.name"/></a></li>
|
||||
</t>
|
||||
<div class="dropdown pull-right">
|
||||
<a data-toggle="dropdown" href="#"><span class="fa fa-cog"/></a>
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="Presets config">
|
||||
<li><a class="presets_config_create" href="#">Create model</a></li>
|
||||
<li><a class="presets_config_edit" href="#">Modify models</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="form_create_field">
|
||||
<tr t-att-class='"create_" + id'>
|
||||
<td class="o_td_label"><t t-esc="label"/></td>
|
||||
<td t-att-class='"o_td_field create_" + id + "_container"'></td>
|
||||
</div>
|
||||
<table class="pull-left">
|
||||
<tr class="create_account_id">
|
||||
<td class="o_td_label">Account</td>
|
||||
<td class="o_td_field"></td>
|
||||
</tr>
|
||||
</t>
|
||||
|
||||
<t t-name="filter_no_match">
|
||||
<tr><td style='text-align: center;'>No result matching '<t t-esc="filter_str" />'</td></tr>
|
||||
</t>
|
||||
|
||||
<t t-name="reconciliation_move_line">
|
||||
<tr t-att-class="'mv_line'+(line.already_paid ? ' already_reconciled' : '')" t-att-data-lineid="line.id" t-att-data-selected="selected">
|
||||
<td class="cell_action"><i class="fa fa-add-remove"></i></td>
|
||||
<td class="cell_account_code" t-if="line.account_code"><t t-esc="line.account_code"/></td>
|
||||
<td class="cell_due_date"><t t-esc="line.q_due_date"/></td>
|
||||
<td class="cell_label"><t t-esc="line.q_label"/></td>
|
||||
<td class="cell_debit"><t t-if="line.debit !== 0"><t t-if="line.propose_partial_reconcile" t-call="icon_do_partial_reconciliation"></t><t t-if="line.partial_reconcile" t-call="icon_undo_partial_reconciliation"></t><t t-esc="line.amount_str"/></t></td>
|
||||
<td class="cell_credit"><t t-if="line.credit !== 0"><t t-if="line.propose_partial_reconcile"><t t-call="icon_do_partial_reconciliation" /></t><t t-if="line.partial_reconcile"><t t-call="icon_undo_partial_reconciliation" /></t><t t-esc="line.amount_str"/></t></td>
|
||||
<td class="cell_info_popover"><span class="line_info_button fa fa-info-circle" t-att-data-content="line.q_popover"></span></td>
|
||||
<tr class="create_tax_id">
|
||||
<td class="o_td_label">Tax</td>
|
||||
<td class="o_td_field"></td>
|
||||
</tr>
|
||||
</t>
|
||||
|
||||
<t t-name="reconciliation_move_line_details">
|
||||
<table class='details'>
|
||||
<tr t-if="line.account_code"><td>Account</td><td><t t-esc="line.account_code"/> <t t-esc="line.account_name"/></td></tr>
|
||||
<tr><td>Journal</td><td><t t-esc="line.journal_name"/></td></tr>
|
||||
<tr><td>Date</td><td><t t-esc="line.date"/></td></tr>
|
||||
<tr><td>Due Date</td><td><t t-esc="line.q_due_date"/></td></tr>
|
||||
<t t-if="line.is_partially_reconciled">
|
||||
<tr><td>Total</td><td>
|
||||
<t t-esc="line.total_amount_str"/><t t-if="line.total_amount_currency_str"> (<t t-esc="line.total_amount_currency_str"/>)</t>
|
||||
</td></tr>
|
||||
</t>
|
||||
<tr><td><t t-if="line.is_partially_reconciled">Residual</t><t t-if="! line.is_partially_reconciled">Amount</t></td><td>
|
||||
<t t-esc="line.amount_str"/><t t-if="line.amount_currency_str"> (<t t-esc="line.amount_currency_str"/>)</t>
|
||||
</td></tr>
|
||||
<tr class="one_line_info" t-if='line.already_paid'>
|
||||
<td colspan="2">This payment is registered but not reconciled.</td>
|
||||
<tr class="create_analytic_account_id">
|
||||
<td class="o_td_label">Analytic Acc.</td>
|
||||
<td class="o_td_field"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="pull-right">
|
||||
<tbody>
|
||||
<tr class="create_journal_id" style="display: none;">
|
||||
<td class="o_td_label">Journal</td>
|
||||
<td class="o_td_field"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</t>
|
||||
<tr class="create_label">
|
||||
<td class="o_td_label">Label</td>
|
||||
<td class="o_td_field"></td>
|
||||
</tr>
|
||||
<tr class="create_amount">
|
||||
<td class="o_td_label">Amount</td>
|
||||
<td class="o_td_field"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="add_line_container">
|
||||
<a class="add_line" t-att-style="!state.balance.amout ? 'display: none;' : null"><i class="fa fa-plus-circle"/> Save and New</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<t t-name="reconciliation_created_line">
|
||||
<tr class="created_line" tabindex="0" t-att-data-lineid="line.id">
|
||||
<td class="cell_action"><t t-if="! line.no_remove_action"><span class="line_remove_button fa fa-times"></span></t></td>
|
||||
<td class="cell_account_code"><t t-esc="line.account_num"/></td>
|
||||
<td class="cell_due_date"></td>
|
||||
<td class="cell_label"><t t-esc="line.label"/></td>
|
||||
<td class="cell_debit"><t t-if="line.amount < 0"><t t-esc="line.amount_str"/></t></td>
|
||||
<td class="cell_credit"><t t-if="line.amount > 0"><t t-esc="line.amount_str"/></t></td>
|
||||
<td class="cell_info_popover"></td>
|
||||
|
||||
<t t-name="reconciliation.line.mv_line">
|
||||
<tr t-if="line.display !== false" t-attf-class="mv_line #{line.already_paid ? ' already_reconciled' : ''} #{line.__invalid ? 'invalid' : ''} #{line.is_tax ? 'is_tax' : ''}" t-att-data-line-id="line.id" t-att-data-selected="selected">
|
||||
<td class="cell_action"><span class="fa fa-add-remove"/></td>
|
||||
<td class="cell_account_code"><t t-esc="line.account_code"/></td>
|
||||
<td class="cell_due_date"><t t-esc="line.date_maturity === false ? line.date : line.date_maturity"/></td>
|
||||
<td class="cell_label"><t t-if="line.partner_id && line.partner_id !== state.st_line.partner_id"><t t-if="line.partner_name.length"><t t-esc="line.partner_name"/>: </t><t t-esc="line.label || line.name"/><t t-if="line.ref && line.ref.length"> : </t><t t-esc="line.ref"/></t><t t-else=""><t t-esc="line.ref && line.ref.length ? line.ref : line.label || line.name"/></t></td>
|
||||
<td class="cell_left"><t t-if="line.amount < 0"><span t-if="line.amount_currency_str" t-attf-class="o_multi_currency o_multi_currency_color_#{line.currency_id%8} line_info_button fa fa-money" t-att-data-content="line.amount_currency_str"/><t t-raw="line.amount_str"/></t></td>
|
||||
<td class="cell_right"><t t-if="line.amount > 0"><span t-if="line.amount_currency_str" t-attf-class="o_multi_currency o_multi_currency_color_#{line.currency_id%8} line_info_button fa fa-money" t-att-data-content="line.amount_currency_str"/><t t-raw="line.amount_str"/></t></td>
|
||||
<td class="cell_info_popover"></td>
|
||||
</tr>
|
||||
</t>
|
||||
|
||||
|
||||
<t t-name="reconciliation.line.mv_line.details">
|
||||
<table class='details'>
|
||||
<tr t-if="line.account_code"><td>Account</td><td><t t-esc="line.account_code"/> <t t-esc="line.account_name"/></td></tr>
|
||||
<tr><td>Journal</td><td><t t-esc="line.journal_id[1]"/></td></tr>
|
||||
<tr><td>Label</td><td><t t-esc="line.label"/></td></tr>
|
||||
<tr t-if="line.ref"><td>Ref</td><td><t t-esc="line.ref"/></td></tr>
|
||||
<tr t-if="line.partner_id"><td>Partner</td><td><t t-esc="line.partner_name"/></td></tr>
|
||||
<tr><td>Date</td><td><t t-esc="line.date"/></td></tr>
|
||||
<tr><td>Due Date</td><td><t t-esc="line.date_maturity === false ? line.date : line.date_maturity"/></td></tr>
|
||||
<tr><td><t t-if="line.is_partially_reconciled">Residual</t><t t-if="! line.is_partially_reconciled">Amount</t></td><td>
|
||||
<t t-raw="line.amount_str"/><t t-if="line.amount_currency_str"> (<t t-esc="line.amount_currency_str"/>)</t>
|
||||
</td></tr>
|
||||
<tr class="one_line_info" t-if='line.already_paid'>
|
||||
<td colspan="2">This payment is registered but not reconciled.</td>
|
||||
</tr>
|
||||
</t>
|
||||
|
||||
<t t-name="reconciliation_line_open_balance">
|
||||
<tr class="line_open_balance" tabindex="0">
|
||||
<td class="cell_action"><span class="toggle_create fa fa-play"></span></td>
|
||||
<td class="cell_account_code"><t t-if="account_code" t-esc="account_code"/></td>
|
||||
<td class="cell_due_date"></td>
|
||||
<td class="cell_label"><t t-esc="label" /></td>
|
||||
<td class="cell_debit"><t t-esc="debit"/></td>
|
||||
<td class="cell_credit"><t t-esc="credit"/></td>
|
||||
<td class="cell_info_popover"></td>
|
||||
</tr>
|
||||
</t>
|
||||
</table>
|
||||
</t>
|
||||
|
||||
|
||||
<!-- bank statement reconciliation -->
|
||||
<t t-name="reconciliation.line.statement_line.details">
|
||||
<table class='details'>
|
||||
<tr><td>Date</td><td><t t-esc="state.st_line.date"/></td></tr>
|
||||
<tr t-if="state.st_line.partner_name"><td>Partner</td><td><t t-esc="state.st_line.partner_name"/></td></tr>
|
||||
<tr t-if="state.st_line.ref"><td>Transaction</td><td><t t-esc="state.st_line.ref"/></td></tr>
|
||||
<tr><td>Description</td><td><t t-esc="state.st_line.name"/></td></tr>
|
||||
<tr><td>Amount</td><td><t t-raw="state.st_line.amount_str"/><t t-if="state.st_line.amount_currency_str"> (<t t-esc="state.st_line.amount_currency_str"/>)</t></td></tr>
|
||||
<tr><td>Account</td><td><t t-esc="state.st_line.account_code"/> <t t-esc="state.st_line.account_name"/></td></tr>
|
||||
<tr t-if="state.st_line.note"><td>Note</td><td><t t-esc="state.st_line.note"/></td></tr>
|
||||
</table>
|
||||
</t>
|
||||
|
||||
<t t-name="bank_statement_reconciliation" t-extend="reconciliation">
|
||||
<t t-jquery="h1" t-operation="replace">
|
||||
<t t-if="single_statement">
|
||||
<h1 class="statement_name">
|
||||
<span><t t-esc="title"/></span>
|
||||
<table class="change_statement_name_container oe_form o_form"><tr>
|
||||
<td><input class="change_statement_name_field" type="text"/></td>
|
||||
<td><button class="change_statement_name_button btn btn-primary btn-sm">OK</button></td>
|
||||
</tr></table>
|
||||
</h1>
|
||||
</t>
|
||||
<t t-if="!single_statement">
|
||||
<h1><t t-esc="title"/></h1>
|
||||
</t>
|
||||
<t t-name="reconciliation.notification">
|
||||
<div t-att-class="'notification alert-dismissible alert alert-' + type" role="alert">
|
||||
<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true" class="fa fa-times"></span><span class="sr-only">Close</span></button>
|
||||
<t t-esc="message" />
|
||||
<t t-if="details !== undefined">
|
||||
<a class="fa fa-external-link" rel="do_action" href="#"
|
||||
t-att-data-action_name="details.name"
|
||||
t-att-data-model="details.model"
|
||||
t-att-data-ids="details.ids">
|
||||
</a>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="bank_statement_nothing_to_reconcile" t-extend="nothing_to_reconcile">
|
||||
<t t-jquery=".oe_view_nocontent" t-operation="inner">
|
||||
<p><b>Good Job!</b> Bank statements are fully reconciled.</p>
|
||||
<p>This page displays all the bank transactions that are to be reconciled and provides with a neat interface to do so.</p>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="bank_statement_reconciliation_done_message" t-extend="reconciliation_done_message">
|
||||
<t t-jquery="h2" t-operation="after">
|
||||
<t t-if="! all_was_auto_reconciled">
|
||||
<p>It took you <strong><t t-esc="time_taken" /></strong> to reconcile <strong><t t-esc="transactions_done" /> transactions.<br/></strong> That's on average <t t-esc="sec_per_item" /> seconds per transaction.</p>
|
||||
<t t-if="done_with_ctrl_enter !== 0">
|
||||
<p>You validated <t t-esc="done_with_ctrl_enter" /> reconciliations with the ctrl-enter shortcut.</p>
|
||||
</t>
|
||||
<p class='achievements'>
|
||||
<t t-foreach="achievements" t-as="achievement">
|
||||
<i class='fa fa-certificate achievement' t-att-data-title='achievement.title' t-att-data-content='achievement.desc'><i t-att-class="'fa '+achievement.icon"></i></i>
|
||||
</t>
|
||||
</p>
|
||||
</t>
|
||||
</t>
|
||||
<t t-jquery=".action_buttons" t-operation="inner">
|
||||
<t t-if="single_statement or multiple_statements">
|
||||
<button class="button_back_to_statement btn btn-default btn-sm">Go to bank statements</button>
|
||||
<button class="button_close_statement btn btn-primary btn-sm">
|
||||
<t t-if="multiple_statements">Close the statements</t>
|
||||
<t t-else="">Close the statement</t>
|
||||
</button>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="bank_statement_reconciliation_line" t-extend="reconciliation_line">
|
||||
<t t-jquery=".accounting_view caption" t-operation="inner">
|
||||
<button class="button_ok btn btn-default btn-sm"></button>
|
||||
<span class="tip_reconciliation_not_balanced">Select a partner or choose a counterpart</span>
|
||||
<span t-if="! line.has_no_partner" class="partner_name">
|
||||
<t t-esc="line.partner_name"/>
|
||||
<span class="change_partner fa fa-times"></span>
|
||||
</span>
|
||||
<div class="change_partner_container oe_form o_form"></div>
|
||||
</t>
|
||||
<t t-jquery=".accounting_view caption" t-operation="after">
|
||||
<tbody class="tbody_initial_line">
|
||||
<tr class="initial_line" tabindex="0">
|
||||
<td class="cell_action"><span class="toggle_match fa fa-cog"></span></td>
|
||||
<td class="cell_account_code"><t t-esc="line.account_code"/></td>
|
||||
<td class="cell_due_date"><t t-esc="line.date"/></td>
|
||||
<td class="cell_label"><t t-if="line.name" t-esc="line.name"/>
|
||||
<t t-if="line.amount_currency_str"> (<t t-esc="line.amount_currency_str"/>)</t></td>
|
||||
<td class="cell_debit"><t t-if="line.amount > 0">
|
||||
<t t-esc="line.amount_str"/></t></td>
|
||||
<td class="cell_credit"><t t-if="line.amount < 0">
|
||||
<t t-esc="line.amount_str"/></t></td>
|
||||
<td class="cell_info_popover"><span class="line_info_button fa fa-info-circle" t-att-data-content="line.q_popover"></span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="bank_statement_reconciliation_statement_line_details">
|
||||
<table class='details'>
|
||||
<tr><td>Date</td><td><t t-esc="line.date"/></td></tr>
|
||||
<tr t-if="line.partner_name"><td>Partner</td><td><t t-esc="line.partner_name"/></td></tr>
|
||||
<tr t-if="line.ref"><td>Transaction</td><td><t t-esc="line.ref"/></td></tr>
|
||||
<tr><td>Description</td><td><t t-esc="line.name"/></td></tr>
|
||||
<tr><td>Amount</td><td><t t-esc="line.amount_str"/><t t-if="line.amount_currency_str"> (<t t-esc="line.amount_currency_str"/>)</t></td></tr>
|
||||
<tr><td>Account</td><td><t t-esc="line.account_code"/> <t t-esc="line.account_name"/></td></tr>
|
||||
<tr t-if="line.note"><td>Note</td><td><t t-esc="line.note"/></td></tr>
|
||||
</table>
|
||||
</t>
|
||||
|
||||
<t t-name="icon_do_partial_reconciliation">
|
||||
<t t-set="message_content">This move's amount is higher than the transaction's amount. Click to register a partial payment and keep the payment balance open.</t>
|
||||
<i class="do_partial_reconcile_button fa fa-exclamation-triangle" t-att-data-content="message_content"></i>
|
||||
</t>
|
||||
|
||||
<t t-name="icon_undo_partial_reconciliation">
|
||||
<t t-set="message_content">Undo the partial reconciliation.</t>
|
||||
<i class="undo_partial_reconcile_button fa fa-exclamation-triangle" t-att-data-content="message_content"></i>
|
||||
</t>
|
||||
|
||||
<!-- manual reconciliation -->
|
||||
|
||||
<t t-name="show_mode_selector_option">
|
||||
<div>
|
||||
<span class="oe_radio_input o_radio_input"><input type="radio" name="modeselektor" t-att-val="value" t-attf-id="mode_{{value}}" t-att-checked="(mode === value ? true : undefined)" /></span>
|
||||
<label t-attf-for="mode_{{value}}"><t t-esc="title"/></label>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="manual_reconciliation" t-extend="reconciliation">
|
||||
<t t-jquery=".interface_options" t-operation="append">
|
||||
<table t-if="show_mode_selector" border="0" cellpadding="0" cellspacing="0" class="oe_form_group o_form_group"><tbody>
|
||||
<tr class="oe_form_group_row o_form_group_row">
|
||||
<td class="oe_form_group_cell o_form_group_cell oe_form_group_cell_label o_form_group_cell_label" colspan="1">
|
||||
<label for="oe-field-input-5" class="oe_form_label o_form_label oe_align_right o_align_right">Show</label>
|
||||
</td>
|
||||
<td class="oe_form_group_cell o_form_group_cell" colspan="1" width="99%">
|
||||
<span class="oe_form_field o_form_field oe_form_field_radio o_form_field_radio oe_vertical o_vertical oe_form_required o_form_required">
|
||||
<span>
|
||||
<t t-if="display_mode_customers" t-call="show_mode_selector_option"><t t-set="value">customers</t><t t-set="title">Customers</t></t>
|
||||
<t t-if="display_mode_suppliers" t-call="show_mode_selector_option"><t t-set="value">suppliers</t><t t-set="title">Vendors</t></t>
|
||||
<t t-if="display_mode_others" t-call="show_mode_selector_option"><t t-set="value">others</t><t t-set="title">OtherAccounts</t></t>
|
||||
<t t-call="show_mode_selector_option"><t t-set="value">all</t><t t-set="title">All</t></t>
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="manual_reconciliation_nothing_to_reconcile" t-extend="nothing_to_reconcile">
|
||||
<t t-jquery=".oe_view_nocontent" t-operation="inner">
|
||||
<p><b>Good Job!</b> There is nothing to reconcile.</p>
|
||||
<p>All invoices and payments have been matched, your accounts' balances are clean.</p>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="manual_reconciliation_done_message">
|
||||
<div class='done_message'>
|
||||
<p><b>Good Job!</b> There is nothing to reconcile.</p>
|
||||
<p>All invoices and payments have been matched, your accounts' balances are clean.</p>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="manual_reconciliation_line" t-extend="reconciliation_line">
|
||||
<t t-jquery=".accounting_view" t-operation="before">
|
||||
<button class="button_reconcile btn btn-default btn-sm">Reconcile</button>
|
||||
</t>
|
||||
<t t-jquery=".accounting_view caption" t-operation="replace">
|
||||
<thead><tr>
|
||||
<td class="cell_action"></td>
|
||||
<td class="cell-title" colspan="2">
|
||||
<span class="cell_item_name"><t t-if="data.partner_name" t-esc="data.partner_name" /><t t-if="data.partner_name === undefined" t-esc="data.account_code" /></span>
|
||||
<span class="cell_last_time_entries_checked" t-if="data.last_time_entries_checked">Last Reconciliation : <t t-esc="data.last_time_entries_checked" /></span>
|
||||
</td>
|
||||
<td class="cell_title_account_code" colspan="2"><t t-esc="data.account_code" /></td>
|
||||
<td class="cell_info_popover"></td>
|
||||
</tr></thead>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="manual_reconciliation_line_open_balance" t-extend="reconciliation_line_open_balance">
|
||||
<t t-jquery=".cell_account_code" t-operation="replace"></t>
|
||||
</t>
|
||||
|
||||
<t t-name="manual_reconciliation_created_line" t-extend="reconciliation_created_line">
|
||||
<t t-jquery=".cell_account_code" t-operation="replace"></t>
|
||||
</t>
|
||||
|
||||
<t t-name="manual_reconciliation_move_line" t-extend="reconciliation_move_line">
|
||||
<t t-jquery=".cell_account_code" t-operation="replace"></t>
|
||||
<!--
|
||||
<t t-jquery=".cell_debit" t-operation="replace"><td class="cell_debit"><t t-if="line.debit !== 0"><t t-esc="line.amount_str"/>
|
||||
<t t-if="line.amount_currency_str"> (<t t-esc="line.amount_currency_str" />)</t>
|
||||
</t></td></t>
|
||||
<t t-jquery=".cell_credit" t-operation="replace"><td class="cell_credit"><t t-if="line.credit !== 0"><t t-esc="line.amount_str"/>
|
||||
<t t-if="line.amount_currency_str"> (<t t-esc="line.amount_currency_str" />)</t>
|
||||
</t></td></t>
|
||||
-->
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
||||
@@ -0,0 +1,914 @@
|
||||
odoo.define('account.reconciliationModel_tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
var ReconciliationClientAction = require('account.ReconciliationClientAction');
|
||||
var testUtils = require('web.test_utils');
|
||||
|
||||
QUnit.module('account', {
|
||||
beforeEach: function () {
|
||||
this.data = {
|
||||
"res.partner": {
|
||||
fields: {
|
||||
id: {string: "ID", type: "integer"},
|
||||
display_name: {string: "Displayed name", type: "char"},
|
||||
image: {string: "image", type: "integer"},
|
||||
},
|
||||
records: [
|
||||
{id: 1, display_name: "partner 1", image: 'AAA'},
|
||||
{id: 2, display_name: "partner 2", image: 'BBB'},
|
||||
{id: 3, display_name: "partner 3", image: 'CCC'},
|
||||
{id: 4, display_name: "partner 4", image: 'DDD'},
|
||||
{id: 8, display_name: "Agrolait", image: 'EEE'},
|
||||
{id: 12, display_name: "Camptocamp", image: 'FFF'},
|
||||
]
|
||||
},
|
||||
"account.account": {
|
||||
fields: {
|
||||
id: {string: "ID", type: "integer"},
|
||||
code: {string: "code", type: "integer"},
|
||||
display_name: {string: "Displayed name", type: "char"},
|
||||
},
|
||||
records: [
|
||||
{id: 282, code: 100000, display_name: "100000 Fixed Asset Account"},
|
||||
{id: 283, code: 101000, display_name: "101000 Current Assets"},
|
||||
{id: 284, code: 101110, display_name: "101110 Stock Valuation Account"},
|
||||
{id: 285, code: 101120, display_name: "101120 Stock Interim Account (Received)"},
|
||||
{id: 286, code: 101130, display_name: "101130 Stock Interim Account (Delivered)"},
|
||||
{id: 287, code: 101200, display_name: "101200 Account Receivable"},
|
||||
{id: 288, code: 101300, display_name: "101300 Tax Paid"},
|
||||
{id: 308, code: 101401, display_name: "101401 Bank"},
|
||||
]
|
||||
},
|
||||
"account.tax": {
|
||||
fields: {
|
||||
id: {string: "ID", type: "integer"},
|
||||
display_name: {string: "Displayed name", type: "char"},
|
||||
amount: {string: "amout", type: "float"},
|
||||
price_include: {string: "Included in Price", type: "boolean"},
|
||||
account_id: {string: "partner", type: 'many2one', relation: 'account.account'},
|
||||
},
|
||||
records: [
|
||||
{id: 6, display_name: "Tax 20.00%", amount: 20, price_include: false},
|
||||
{id: 7, display_name: "Tax 10.00% include", amount: 10, price_include: true, account_id: 288},
|
||||
]
|
||||
},
|
||||
"account.journal": {
|
||||
fields: {
|
||||
id: {string: "ID", type: "integer"},
|
||||
display_name: {string: "Displayed name", type: "char"},
|
||||
},
|
||||
records: []
|
||||
},
|
||||
"account.analytic.account": {
|
||||
fields: {
|
||||
id: {string: "ID", type: "integer"},
|
||||
display_name: {string: "Displayed name", type: "char"},
|
||||
},
|
||||
records: [
|
||||
{id: 16, display_name: "Administrative"},
|
||||
{id: 7, display_name: "Agrolait - Agrolait"},
|
||||
{id: 8, display_name: "Asustek - ASUSTeK"},
|
||||
{id: 15, display_name: "Camp to Camp - Camptocamp"},
|
||||
{id: 6, display_name: "CampToCamp - Camptocamp"},
|
||||
{id: 17, display_name: "Commercial & Marketing"},
|
||||
{id: 23, display_name: "Data Import/Export Plugin - Delta PC"},
|
||||
{id: 9, display_name: "Delta PC - Delta PC"},
|
||||
]
|
||||
},
|
||||
"account.bank.statement.line": {
|
||||
fields: {
|
||||
id: {string: "ID", type: "integer"},
|
||||
display_name: {string: "Displayed name", type: "char"},
|
||||
partner_id: {string: "partner", type: 'many2one', relation: 'res.partner'},
|
||||
},
|
||||
records: [
|
||||
{id: 5, display_name: "SAJ/2014/002 and SAJ/2014/003"},
|
||||
{id: 6, display_name: "Bank fees"},
|
||||
{id: 7, display_name: "Prepayment"},
|
||||
{id: 8, display_name: "First 2000 \u20ac of SAJ/2014/001"},
|
||||
]
|
||||
},
|
||||
"account.reconcile.model": {
|
||||
fields: {
|
||||
id: {string: "ID", type: "integer"},
|
||||
name: {string: "Button Label", type: "char"},
|
||||
has_second_line: {string: "Add a second line", type: "boolean"},
|
||||
account_id: {string: "Account", type: "many2one", relation:'account.account'},
|
||||
journal_id: {string: "Journal", type: "many2one", relation:'account.journal'},
|
||||
label: {string: "Journal Item Label", type: "char"},
|
||||
amount_type: {string: "amount_type", type: "selection", selection: [['fixed', 'Fixed'], ['percentage', 'Percentage of balance']], default:'percentage'},
|
||||
amount: {string: "Amount", type: "float", digits:0, help:"Fixed amount will count as a debit if it is negative, as a credit if it is positive.", default:100.0},
|
||||
tax_id: {string: "Tax", type: "many2one", relation:'account.tax', domain:[('type_tax_use', '=', 'purchase')]},
|
||||
analytic_account_id: {string: "Analytic Account", type: "many2one", relation:'account.analytic.account'},
|
||||
second_account_id: {string: "Second Account", type: "many2one", relation:'account.account', domain:[('deprecated', '=', false)]},
|
||||
second_journal_id: {string: "Second Journal", type: "many2one", relation:'account.journal', help:"This field is ignored in a bank statement reconciliation."},
|
||||
second_label: {string: "Second Journal Item Label", type: "char"},
|
||||
second_amount_type: {string: "Second amount_type", type: "selection", selection: [['fixed', 'Fixed'], ['percentage', 'Percentage of balance']], default:'percentage'},
|
||||
second_amount: {string: "Second Amount", type: "float", digits:0, help:"Fixed amount will count as a debit if it is negative, as a credit if it is positive.", default:100.0},
|
||||
second_tax_id: {string: "Second Tax", type: "many2one", relation:'account.tax', domain:[('type_tax_use', '=', 'purchase')]},
|
||||
second_analytic_account_id: {string: "Second Analytic Account", type: "many2one", relation:'account.analytic.account'},
|
||||
},
|
||||
records: [
|
||||
{"second_analytic_account_id": false, "second_amount_type": "percentage", "second_journal_id": false, "id": 4, "analytic_account_id": false, "display_name": "Int\u00e9rrets", "second_tax_id": false, "has_second_line": false, "journal_id": false, "label": false, "second_label": false, "second_account_id": false, "account_id": 282, "company_id": [1, "Demo SPRL"], "tax_id": false, "amount_type": "fixed", "name": "Int\u00e9rrets", "amount": 0.0, "second_amount": 100.0},
|
||||
{"second_analytic_account_id": false, "second_amount_type": "percentage", "second_journal_id": false, "id": 2, "analytic_account_id": false, "display_name": "Perte et Profit", "second_tax_id": false, "has_second_line": false, "journal_id": false, "label": false, "second_label": false, "second_account_id": false, "account_id": 283, "company_id": [1, "Demo SPRL"], "tax_id": false, "amount_type": "percentage", "name": "Perte et Profit", "amount": 100.0, "second_amount": 100.0},
|
||||
{"second_analytic_account_id": false, "second_amount_type": "percentage", "second_journal_id": false, "id": 5, "analytic_account_id": false, "display_name": "Fs bank", "second_tax_id": false, "has_second_line": false, "journal_id": false, "label": false, "second_label": false, "second_account_id": false, "account_id": 284, "company_id": [1, "Demo SPRL"], "tax_id": false, "amount_type": "percentage", "name": "Fs bank", "amount": 100.0, "second_amount": 100.0},
|
||||
{"second_analytic_account_id": false, "second_amount_type": "percentage", "second_journal_id": false, "id": 8, "analytic_account_id": false, "display_name": "Caisse Sand.", "second_tax_id": false, "has_second_line": false, "journal_id": false, "label": "Caisse Sand.", "second_label": false, "second_account_id": false, "account_id": 308, "company_id": [1, "Demo SPRL"], "tax_id": false, "amount_type": "percentage", "name": "Caisse Sand.", "amount": 100.0, "second_amount": 100.0},
|
||||
{"second_analytic_account_id": false, "second_amount_type": "percentage", "second_journal_id": false, "id": 3, "analytic_account_id": false, "display_name": "ATOS", "second_tax_id": 7, "has_second_line": true, "journal_id": false, "label": "ATOS Banque", "second_label": "ATOS Frais", "second_account_id": 286, "account_id": 285, "company_id": [1, "Demo SPRL"], "tax_id": 6, "amount_type": "percentage", "name": "ATOS", "amount": 97.5, "second_amount": 2.5},
|
||||
{"second_analytic_account_id": false, "second_amount_type": "percentage", "second_journal_id": false, "id": 10, "analytic_account_id": false, "display_name": "Double", "second_tax_id": false, "has_second_line": true, "journal_id": false, "label": "Double Banque", "second_label": "Double Frais", "second_account_id": 286, "account_id": 285, "company_id": [1, "Demo SPRL"], "tax_id": false, "amount_type": "percentage", "name": "Double", "amount": 97.5, "second_amount": 2.5},
|
||||
]
|
||||
}
|
||||
};
|
||||
var data_preprocess = {
|
||||
notifications: [],
|
||||
num_already_reconciled_lines: 0,
|
||||
st_lines_ids: [5, 6, 7, 8],
|
||||
statement_name: "BNK/2014/001",
|
||||
};
|
||||
var data_widget = [
|
||||
{
|
||||
"st_line": {
|
||||
"currency_id": 3,
|
||||
"communication_partner_name": false,
|
||||
"open_balance_account_id": 287,
|
||||
"name": "SAJ/2014/002 and SAJ/2014/003",
|
||||
"partner_name": "Agrolait",
|
||||
"partner_id": 8,
|
||||
"has_no_partner": false,
|
||||
"journal_id": 84,
|
||||
"account_name": "Bank",
|
||||
"note": "",
|
||||
"amount": 1175.0,
|
||||
"amount_str": "$ 1,175.00",
|
||||
"amount_currency_str": "",
|
||||
"date": "2017-01-01",
|
||||
"account_code": "101401",
|
||||
"ref": "",
|
||||
"id": 5,
|
||||
"statement_id": 2
|
||||
},
|
||||
"reconciliation_proposition": []
|
||||
},
|
||||
{
|
||||
"st_line": {
|
||||
"currency_id": 3,
|
||||
"communication_partner_name": false,
|
||||
"name": "Bank fees",
|
||||
"partner_name": false,
|
||||
"partner_id": false,
|
||||
"has_no_partner": true,
|
||||
"journal_id": 84,
|
||||
"account_name": "Bank",
|
||||
"note": "",
|
||||
"amount": -32.58,
|
||||
"amount_str": "$ 32.58",
|
||||
"amount_currency_str": "",
|
||||
"date": "2017-01-01",
|
||||
"account_code": "101401",
|
||||
"ref": "",
|
||||
"id": 6,
|
||||
"statement_id": 2
|
||||
},
|
||||
"reconciliation_proposition": []
|
||||
},
|
||||
{
|
||||
"st_line": {
|
||||
"currency_id": 3,
|
||||
"communication_partner_name": false,
|
||||
"open_balance_account_id": 287,
|
||||
"name": "Prepayment",
|
||||
"partner_name": "Camptocamp",
|
||||
"partner_id": 12,
|
||||
"has_no_partner": false,
|
||||
"journal_id": 84,
|
||||
"account_name": "Bank",
|
||||
"note": "",
|
||||
"amount": 650.0,
|
||||
"amount_str": "$ 650.00",
|
||||
"amount_currency_str": "",
|
||||
"date": "2017-01-01",
|
||||
"account_code": "101401",
|
||||
"ref": "",
|
||||
"id": 7,
|
||||
"statement_id": 2
|
||||
},
|
||||
"reconciliation_proposition": [
|
||||
{
|
||||
"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": 12,
|
||||
"account_name": "101200 Account Receivable",
|
||||
"name": "INV/2017/0012",
|
||||
"partner_name": "Camptocamp",
|
||||
"total_amount_currency_str": "",
|
||||
"id": 133,
|
||||
"credit": 0.0,
|
||||
"journal_id": [1, "Customer Invoices"],
|
||||
"amount_str": "$ 650.00",
|
||||
"debit": 650.0,
|
||||
"account_id": [287, "101200 Account Receivable"],
|
||||
"account_code": "101200",
|
||||
"ref": "",
|
||||
"already_paid": false
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
"st_line": {
|
||||
"currency_id": 3,
|
||||
"communication_partner_name": false,
|
||||
"open_balance_account_id": 285,
|
||||
"name": "First 2000 \u20ac of SAJ/2014/001",
|
||||
"partner_name": "Camptocamp",
|
||||
"partner_id": 12,
|
||||
"has_no_partner": false,
|
||||
"journal_id": 84,
|
||||
"account_name": "Bank",
|
||||
"note": "",
|
||||
"amount": 2000.0,
|
||||
"amount_str": "$ 2,000.00",
|
||||
"amount_currency_str": "",
|
||||
"date": "2017-01-01",
|
||||
"account_code": "101401",
|
||||
"ref": "",
|
||||
"id": 8,
|
||||
"statement_id": 2
|
||||
},
|
||||
"reconciliation_proposition": []
|
||||
},
|
||||
];
|
||||
var mv_lines = {
|
||||
'[]': [],
|
||||
'[5,"",0,6]': [
|
||||
{"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-07", "date": "2017-01-08", "total_amount_str": "$ 525.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": "$ 525.00", "debit": 525.0, "account_code": "101200", "ref": "", "already_paid": false}
|
||||
],
|
||||
'[5,"b",0,6]': [
|
||||
{"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": "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},
|
||||
],
|
||||
'[6,"",0,6]': [
|
||||
{"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": "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}
|
||||
],
|
||||
'[6,"",5,6]': [
|
||||
{"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}
|
||||
],
|
||||
'[7,"",0,6]': [
|
||||
{"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": 12, "account_name": "101200 Account Receivable", "name": "INV/2017/0012", "partner_name": "Camptocamp", "total_amount_currency_str": "", "id": 133, "credit": 0.0, "journal_id": [1, "Customer Invoices"], "amount_str": "$ 650.00", "debit": 650.0, "account_id": [287, "101200 Account Receivable"], "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_id": [287, "101200 Account Receivable"], "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_id": [284, "101110 Stock Valuation Account"], "account_code": "111100", "ref": "", "already_paid": false}
|
||||
],
|
||||
'[8,"",0,6]': [],
|
||||
};
|
||||
var auto_reconciliation = {
|
||||
"num_already_reconciled_lines": 1,
|
||||
"notifications": [{
|
||||
"message": "1 transaction was automatically reconciled.",
|
||||
"type": "info",
|
||||
"details": {
|
||||
"model": "account.move",
|
||||
"name": "Automatically reconciled items",
|
||||
"ids": [143]
|
||||
}
|
||||
}],
|
||||
"st_lines_ids": [5, 6, 8],
|
||||
"statement_name": false
|
||||
};
|
||||
var data_for_manual_reconciliation_widget = {
|
||||
'[null,null]': {
|
||||
"customers": [
|
||||
{"account_id": 287, "partner_name": "Agrolait", "reconciliation_proposition": [], "currency_id": 3, "max_date": "2017-02-14 12:30:31.256629", "last_time_entries_checked": null, "account_code": "101200", "partner_id": 8, "account_name": "101200 Account Receivable"},
|
||||
{"account_id": 7, "partner_name": "Camptocamp", "reconciliation_proposition": [], "currency_id": 3, "max_date": "2017-02-13 14:24:55.246469", "last_time_entries_checked": null, "account_code": "101200", "partner_id": 12, "account_name": "101200 Account Receivable"}
|
||||
],
|
||||
"accounts": [
|
||||
{
|
||||
"account_id": 283, "account_name": "101000 Current Assets", "currency_id": 3, "max_date": "2017-02-16 14:32:04.833986", "last_time_entries_checked": "2017-02-16", "account_code": "101000",
|
||||
"reconciliation_proposition": [
|
||||
{"account_id": 283, "account_type": "other", "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-02-16", "date": "2017-02-16", "total_amount_str": "$ 1,000.00", "partner_id": 8, "account_name": "101000 Current Assets", "name": "BNK1/2017/0006: Customer Payment", "partner_name": "Agrolait", "total_amount_currency_str": "", "id": 399, "credit": 1000.0, "journal_id": [3, "Bank"], "amount_str": "$ 1,000.00", "debit": 0.0, "account_code": "101000", "ref": "", "already_paid": false},
|
||||
{"account_id": 283, "account_type": "other", "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-03-18", "date": "2017-02-16", "total_amount_str": "$ 1,000.00", "partner_id": 8, "account_name": "101000 Current Assets", "name": "INV/2017/0006", "partner_name": "Agrolait", "total_amount_currency_str": "", "id": 402, "credit": 0.0, "journal_id": [1, "Customer Invoices"], "amount_str": "$ 1,000.00", "debit": 1000.0, "account_code": "101000", "ref": "", "already_paid": false}
|
||||
]
|
||||
}
|
||||
],
|
||||
"suppliers": [
|
||||
{
|
||||
"account_id": 284, "partner_name": "Agrolait",
|
||||
"reconciliation_proposition": [
|
||||
{"account_id": 284, "account_type": "other", "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-02-16", "date": "2017-02-16", "total_amount_str": "$ 1,000.00", "partner_id": 8, "account_name": "101000 Current Assets", "name": "BNK1/999: Customer Payment", "partner_name": "Agrolait", "total_amount_currency_str": "", "id": 999, "credit": 1000.0, "journal_id": [3, "Bank"], "amount_str": "$ 1,000.00", "debit": 0.0, "account_code": "111100", "ref": "", "already_paid": false},
|
||||
{"account_id": 284, "account_type": "other", "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-03-18", "date": "2017-02-16", "total_amount_str": "$ 1,000.00", "partner_id": 8, "account_name": "101000 Current Assets", "name": "INV/998", "partner_name": "Agrolait", "total_amount_currency_str": "", "id": 998, "credit": 0.0, "journal_id": [1, "Customer Invoices"], "amount_str": "$ 1,000.00", "debit": 1000.0, "account_code": "111100", "ref": "", "already_paid": false}
|
||||
],
|
||||
"currency_id": 3, "max_date": "2017-02-14 12:36:05.014302", "last_time_entries_checked": null, "account_code": "111100", "partner_id": 8, "account_name": "Account Payable"
|
||||
}, {
|
||||
"account_id": 284, "partner_name": "Camptocamp",
|
||||
"reconciliation_proposition": [
|
||||
{"account_id": 284, "account_type": "other", "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-02-16", "date": "2017-02-16", "total_amount_str": "$ 1,000.00", "partner_id": 12, "account_name": "101000 Current Assets", "name": "BNK1/1999: Customer Payment", "partner_name": "Camptocamp", "total_amount_currency_str": "", "id": 1999, "credit": 1000.0, "journal_id": [3, "Bank"], "amount_str": "$ 1,000.00", "debit": 0.0, "account_code": "111100", "ref": "", "already_paid": false},
|
||||
{"account_id": 284, "account_type": "other", "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-03-18", "date": "2017-02-16", "total_amount_str": "$ 1,000.00", "partner_id": 12, "account_name": "101000 Current Assets", "name": "INV/1998", "partner_name": "Camptocamp", "total_amount_currency_str": "", "id": 1998, "credit": 0.0, "journal_id": [1, "Customer Invoices"], "amount_str": "$ 1,000.00", "debit": 1000.0, "account_code": "111100", "ref": "", "already_paid": false}
|
||||
],
|
||||
"currency_id": 3, "max_date": "2017-02-14 12:36:05.014302", "last_time_entries_checked": null, "account_code": "111100", "partner_id": 12, "account_name": "Account Payable"
|
||||
}
|
||||
]
|
||||
},
|
||||
'["partner",null,"receivable"]': [
|
||||
{"account_id": 287, "partner_name": "Agrolait", "reconciliation_proposition": [], "currency_id": 3, "max_date": "2017-02-14 12:30:31.256629", "last_time_entries_checked": null, "account_code": "101200", "partner_id": 8, "account_name": "101200 Account Receivable"},
|
||||
{"account_id": 287, "partner_name": "Camptocamp", "reconciliation_proposition": [], "currency_id": 3, "max_date": "2017-02-13 14:24:55.246469", "last_time_entries_checked": null, "account_code": "101200", "partner_id": 12, "account_name": "101200 Account Receivable"}
|
||||
]
|
||||
};
|
||||
var move_lines_for_manual_reconciliation = {
|
||||
'[287,8,"",0,6]': [
|
||||
{"account_type": "receivable", "account_id": [287, "101200 Account Receivable"], "amount_currency_str": "10,222.00 €", "currency_id": 1, "date_maturity": "2017-02-08", "date": "2017-02-08", "total_amount_str": "$ 11,000.00", "partner_id": 8, "account_name": "101200 Account Receivable", "name": "INV/2017/0004: Customer Payment", "partner_name": "Agrolait", "total_amount_currency_str": "", "id": 17, "credit": 11000.0, "journal_id": [1, "Customer Invoices"], "amount_str": "$ 11,000.00", "debit": 0.0, "account_code": "101200", "ref": "", "already_paid": false},
|
||||
{"account_type": "receivable", "account_id": [7, "101200 Account Receivable"], "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-02-09", "date": "2017-02-09", "total_amount_str": "$ 1,000.00", "partner_id": 8, "account_name": "101200 Account Receivable", "name": "INV/2017/0005: Customer Payment", "partner_name": "Agrolait", "total_amount_currency_str": "", "id": 19, "credit": 1000.0, "journal_id": [1, "Customer Invoices"], "amount_str": "$ 1,000.00", "debit": 0.0, "account_code": "101200", "ref": "", "already_paid": false},
|
||||
{"account_type": "receivable", "account_id": [287, "101200 Account Receivable"], "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-02-09", "date": "2017-02-09", "total_amount_str": "$ 180.00", "partner_id": 8, "account_name": "101200 Account Receivable", "name": "BILL/2017/0003: Customer Payment", "partner_name": "Agrolait", "total_amount_currency_str": "", "id": 21, "credit": 180.0, "journal_id": [2, "Vendor Bills"], "amount_str": "$ 180.00", "debit": 0.0, "account_code": "101200", "ref": "fddfgfdgfdgsdfg", "already_paid": false},
|
||||
{"account_type": "receivable", "account_id": [287, "101200 Account Receivable"], "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-02-09", "date": "2017-02-09", "total_amount_str": "$ 90.00", "partner_id": 8, "account_name": "101200 Account Receivable", "name": "INV/2017/0006: Customer Payment", "partner_name": "Agrolait", "total_amount_currency_str": "", "id": 23, "credit": 90.0, "journal_id": [1, "Customer Invoices"], "amount_str": "$ 90.00", "debit": 0.0, "account_code": "101200", "ref": "", "already_paid": false},
|
||||
{"account_type": "receivable", "account_id": [287, "101200 Account Receivable"], "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-03-10", "date": "2017-02-08", "total_amount_str": "$ 650.00", "partner_id": 8, "account_name": "101200 Account Receivable", "name": "INV/2017/0012", "partner_name": "Agrolait", "total_amount_currency_str": "", "id": 6, "credit": 0.0, "journal_id": [1, "Customer Invoices"], "amount_str": "$ 1000.00", "debit": 1000.0, "account_code": "101200", "ref": "", "already_paid": false},
|
||||
{"account_type": "receivable", "account_id": [287, "101200 Account Receivable"], "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-03-10", "date": "2017-02-08", "total_amount_str": "$ 525.00", "partner_id": 8, "account_name": "101200 Account Receivable", "name": "INV/2017/0003", "partner_name": "Agrolait", "total_amount_currency_str": "", "id": 9, "credit": 0.0, "journal_id": [1, "Customer Invoices"], "amount_str": "$ 525.00", "debit": 525.0, "account_code": "101200", "ref": "", "already_paid": false}
|
||||
],
|
||||
'[7,12,"",0,6]': [
|
||||
{"account_type": "receivable", "account_id": [287, "101200 Account Receivable"], "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-02-08", "date": "2017-02-08", "total_amount_str": "$ 11,000.00", "partner_id": 12, "account_name": "101200 Account Receivable", "name": "INV/2017/0004: Customer Payment", "partner_name": "Camptocamp", "total_amount_currency_str": "", "id": 17, "credit": 11000.0, "journal_id": [1, "Customer Invoices"], "amount_str": "$ 11,000.00", "debit": 0.0, "account_code": "101200", "ref": "", "already_paid": false},
|
||||
{"account_type": "receivable", "account_id": [7, "101200 Account Receivable"], "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-02-09", "date": "2017-02-09", "total_amount_str": "$ 1,000.00", "partner_id": 12, "account_name": "101200 Account Receivable", "name": "INV/2017/0005: Customer Payment", "partner_name": "Camptocamp", "total_amount_currency_str": "", "id": 19, "credit": 1000.0, "journal_id": [1, "Customer Invoices"], "amount_str": "$ 1,000.00", "debit": 0.0, "account_code": "101200", "ref": "", "already_paid": false},
|
||||
{"account_type": "receivable", "account_id": [287, "101200 Account Receivable"], "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-02-09", "date": "2017-02-09", "total_amount_str": "$ 180.00", "partner_id": 12, "account_name": "101200 Account Receivable", "name": "BILL/2017/0003: Customer Payment", "partner_name": "Camptocamp", "total_amount_currency_str": "", "id": 21, "credit": 180.0, "journal_id": [2, "Vendor Bills"], "amount_str": "$ 180.00", "debit": 0.0, "account_code": "101200", "ref": "fddfgfdgfdgsdfg", "already_paid": false},
|
||||
],
|
||||
'[284,8,"",0,6]': [
|
||||
{"account_type": "receivable", "account_id": [284, "111100 Account Payable"], "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-02-08", "date": "2017-02-08", "total_amount_str": "$ 11,000.00", "partner_id": 8, "account_name": "101200 Account Receivable", "name": "INV/2017/0004: Customer Payment", "partner_name": "Agrolait", "total_amount_currency_str": "", "id": 17, "credit": 11000.0, "journal_id": [1, "Customer Invoices"], "amount_str": "$ 11,000.00", "debit": 0.0, "account_code": "111100", "ref": "", "already_paid": false},
|
||||
{"account_type": "receivable", "account_id": [284, "111100 Account Payable"], "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-02-09", "date": "2017-02-09", "total_amount_str": "$ 1,000.00", "partner_id": 8, "account_name": "101200 Account Receivable", "name": "INV/2017/0005: Customer Payment", "partner_name": "Agrolait", "total_amount_currency_str": "", "id": 19, "credit": 1000.0, "journal_id": [1, "Customer Invoices"], "amount_str": "$ 1,000.00", "debit": 0.0, "account_code": "111100", "ref": "", "already_paid": false},
|
||||
{"account_type": "receivable", "account_id": [284, "111100 Account Payable"], "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-02-09", "date": "2017-02-09", "total_amount_str": "$ 180.00", "partner_id": 8, "account_name": "101200 Account Receivable", "name": "BILL/2017/0003: Customer Payment", "partner_name": "Agrolait", "total_amount_currency_str": "", "id": 21, "credit": 180.0, "journal_id": [2, "Vendor Bills"], "amount_str": "$ 180.00", "debit": 0.0, "account_code": "111100", "ref": "fddfgfdgfdgsdfg", "already_paid": false},
|
||||
],
|
||||
'[283,null,"",0,6]': [
|
||||
{"account_type": "other", "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-02-16", "date": "2017-02-16", "total_amount_str": "$ 1,000.00", "partner_id": 8, "account_name": "101000 Current Assets", "name": "BNK1/2017/0006: Customer Payment", "partner_name": "Agrolait", "total_amount_currency_str": "", "id": 399, "credit": 1000.0, "journal_id": [3, "Bank"], "amount_str": "$ 1,000.00", "debit": 0.0, "account_code": "101000", "ref": "", "already_paid": false},
|
||||
{"account_type": "other", "amount_currency_str": "", "currency_id": false, "date_maturity": "2017-03-18", "date": "2017-02-16", "total_amount_str": "$ 1,000.00", "partner_id": 8, "account_name": "101000 Current Assets", "name": "INV/2017/0006", "partner_name": "Agrolait", "total_amount_currency_str": "", "id": 402, "credit": 0.0, "journal_id": [1, "Customer Invoices"], "amount_str": "$ 1,000.00", "debit": 1000.0, "account_code": "101000", "ref": "", "already_paid": false}
|
||||
],
|
||||
'[284,12,"",0,6]': [],
|
||||
};
|
||||
this.session = {
|
||||
currencies: {
|
||||
3: {
|
||||
digits: [69, 2],
|
||||
position: "before",
|
||||
symbol: "$"
|
||||
}
|
||||
}
|
||||
};
|
||||
this.mockRPC = function (route, args) {
|
||||
var key;
|
||||
var excluded_ids;
|
||||
var ids;
|
||||
if (args.method === "json_friendly_compute_all" && args.model === "account.tax") {
|
||||
var tax = _.find(this.data["account.tax"].records, {'id': args.args[0][0]});
|
||||
var amount = args.args[1];
|
||||
var tax_base = tax.price_include ? amount*100/(100+tax.amount) : amount;
|
||||
return $.when({
|
||||
"base": amount,
|
||||
"taxes": [{
|
||||
"id": tax.id,
|
||||
"amount": tax_base*tax.amount/100,
|
||||
"base": tax_base,
|
||||
"name": tax.display_name,
|
||||
"analytic": false,
|
||||
"refund_account_id": false,
|
||||
"account_id": tax.account_id
|
||||
}],
|
||||
"total_excluded": amount/100*(100-tax.amount),
|
||||
"total_included": amount,
|
||||
});
|
||||
}
|
||||
if (args.method === "reconciliation_widget_preprocess" && args.model === "account.bank.statement") {
|
||||
return $.when(data_preprocess);
|
||||
}
|
||||
if (args.method === "get_data_for_reconciliation_widget" && args.model === "account.bank.statement.line") {
|
||||
ids = args.args[0];
|
||||
return $.when(_.filter(data_widget, function (w) {return _.contains(ids, w.st_line.id);}));
|
||||
}
|
||||
if (args.method === "get_move_lines_for_reconciliation_widget" && args.model === "account.bank.statement.line") {
|
||||
var partner_id = args.args.splice(1, 1)[0];
|
||||
excluded_ids = args.args.splice(1, 1)[0];
|
||||
key = JSON.stringify(args.args);
|
||||
if (!mv_lines[key]) {
|
||||
throw new Error("Unknown parameters for get_move_lines_for_reconciliation_widget: '"+ key + "'");
|
||||
}
|
||||
return $.when(_.filter(mv_lines[key], function (line) {
|
||||
return excluded_ids.indexOf(line.id) === -1 && (!partner_id || partner_id === line.partner_id);
|
||||
}));
|
||||
}
|
||||
if (args.method === "reconciliation_widget_auto_reconcile" && args.model === "account.bank.statement.line") {
|
||||
return $.when(auto_reconciliation);
|
||||
}
|
||||
if (args.method === "get_data_for_manual_reconciliation_widget" && args.model === "account.move.line") {
|
||||
key = JSON.stringify(args.args);
|
||||
if (!data_for_manual_reconciliation_widget[key]) {
|
||||
throw new Error("Unknown parameters for get_data_for_manual_reconciliation_widget: '"+ key + "'");
|
||||
}
|
||||
return $.when(data_for_manual_reconciliation_widget[key]);
|
||||
}
|
||||
if (args.method === "get_move_lines_for_manual_reconciliation" && args.model === "account.move.line") {
|
||||
excluded_ids = args.args.splice(2, 1)[0];
|
||||
key = JSON.stringify(args.args);
|
||||
if (!move_lines_for_manual_reconciliation[key]) {
|
||||
throw new Error("Unknown parameters for get_move_lines_for_manual_reconciliation: '"+ key + "'");
|
||||
}
|
||||
return $.when(_.filter(move_lines_for_manual_reconciliation[key], function (line) {
|
||||
return excluded_ids.indexOf(line.id) === -1;
|
||||
}));
|
||||
}
|
||||
if (args.method === "process_reconciliations" && args.model === "account.move.line") {
|
||||
var datas = args.args[0];
|
||||
for (var i in datas) {
|
||||
var data = datas[i];
|
||||
for (var key in move_lines_for_manual_reconciliation) {
|
||||
move_lines_for_manual_reconciliation[key] = _.filter(move_lines_for_manual_reconciliation[key], function (mv_line) {
|
||||
return data.mv_line_ids.indexOf(mv_line.id) === -1;
|
||||
});
|
||||
}
|
||||
}
|
||||
return $.when();
|
||||
}
|
||||
if (args.method === "mark_as_reconciled") {
|
||||
return $.when();
|
||||
}
|
||||
return this._super(route, args);
|
||||
};
|
||||
this.options = {
|
||||
context: {
|
||||
statement_ids: [4]
|
||||
}
|
||||
};
|
||||
}
|
||||
}, function () {
|
||||
QUnit.module('Reconciliation');
|
||||
|
||||
QUnit.test('Reconciliation basic rendering', function (assert) {
|
||||
assert.expect(11);
|
||||
|
||||
var clientAction = new ReconciliationClientAction.StatementAction(null, this.options);
|
||||
testUtils.addMockEnvironment(clientAction, {
|
||||
'data': this.data,
|
||||
mockRPC: this.mockRPC,
|
||||
});
|
||||
clientAction.appendTo($('#qunit-fixture'));
|
||||
|
||||
var widget = clientAction.widgets[0];
|
||||
|
||||
assert.ok(widget.$el.hasClass('o_reconciliation_line'), "should instance of widget reconciliation");
|
||||
assert.strictEqual(widget.$('.accounting_view').length, 1, "should have one view");
|
||||
assert.strictEqual(widget.$('.match').length, 1, "should have 'match' panel");
|
||||
assert.strictEqual(widget.$('.create').length, 1, "should have 'create' panel");
|
||||
|
||||
assert.strictEqual(widget.$('thead').text().replace(/[\n\r\s]+/g, ' '), " 101401 2017-01-01 SAJ/2014/002 and SAJ/2014/003 $ 1,175.00 ", "should display the line information");
|
||||
assert.ok(widget.$('caption .o_form_field.o_form_field_many2one').length, "should display the many2one with to select a partner");
|
||||
|
||||
assert.strictEqual(clientAction.$('[data-mode="inactive"]').length, 3, "should be as 'inactive' mode by default");
|
||||
assert.strictEqual(widget.$el.data('mode'), 'match', "the first one should automatically switch to match mode");
|
||||
|
||||
widget.$('.accounting_view thead td:first').trigger('click');
|
||||
assert.strictEqual(widget.$el.data('mode'), 'inactive', "should switch to 'inactive' mode");
|
||||
|
||||
widget.$('.accounting_view tfoot td:first').trigger('click');
|
||||
assert.strictEqual(widget.$el.data('mode'), 'create', "should switch to 'create' mode");
|
||||
widget.$('.accounting_view tfoot td:first').trigger('click');
|
||||
assert.strictEqual(widget.$el.data('mode'), 'match', "should switch to 'match' mode");
|
||||
|
||||
clientAction.destroy();
|
||||
});
|
||||
|
||||
|
||||
QUnit.test('Reconciliation fields', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
var clientAction = new ReconciliationClientAction.StatementAction(null, this.options);
|
||||
testUtils.addMockEnvironment(clientAction, {
|
||||
'data': this.data,
|
||||
mockRPC: this.mockRPC,
|
||||
});
|
||||
clientAction.appendTo($('#qunit-fixture'));
|
||||
|
||||
var widget = clientAction.widgets[0];
|
||||
|
||||
assert.strictEqual(widget.$('.o_form_input_dropdown input').val(), "Agrolait", "the partner many2one should display agrolait");
|
||||
assert.strictEqual(clientAction.widgets[2].$('.o_form_input_dropdown input').val(), "Camptocamp", "the partner many2one should display Camptocamp");
|
||||
widget.$('.accounting_view tfoot td:first').trigger('click');
|
||||
assert.strictEqual(widget.$('.create .o_form_input').length, 6,
|
||||
"create panel should display 5 fields (account_id, tax_id, analytic_account_id, label, amount)");
|
||||
assert.strictEqual(widget.$('.create .create_account_id .o_form_required, .create .create_label .o_form_required, .create .create_amount .o_form_required').length, 3,
|
||||
"account_id, label and amount should be required fields");
|
||||
assert.strictEqual(widget.$('.create .create_label input').val(), 'SAJ/2014/002 and SAJ/2014/003',
|
||||
"should use the name of the reconciliation line for the default label value");
|
||||
assert.strictEqual(widget.$('.create .create_amount input').val(), '1175.00',
|
||||
"should have the balance amout as default value for the amout field");
|
||||
|
||||
clientAction.destroy();
|
||||
});
|
||||
|
||||
|
||||
QUnit.test('Reconciliation basic data', function (assert) {
|
||||
assert.expect(20);
|
||||
|
||||
var clientAction = new ReconciliationClientAction.StatementAction(null, this.options);
|
||||
testUtils.addMockEnvironment(clientAction, {
|
||||
'data': this.data,
|
||||
mockRPC: this.mockRPC,
|
||||
});
|
||||
|
||||
clientAction.appendTo($('#qunit-fixture'));
|
||||
|
||||
var widget = clientAction.widgets[0];
|
||||
|
||||
assert.strictEqual(widget.$('.mv_line').length, 2, "should display 2 account move lines");
|
||||
assert.strictEqual(widget.$('.mv_line').text().replace(/[\n\r\s]+/g, ' '),
|
||||
" 101200 2017-02-07 INV/2017/0002 $ 650.00 101200 2017-02-07 INV/2017/0003 $ 525.00 ",
|
||||
"should display 4 account move lines who contains the account_code, due_date, label and the credit");
|
||||
assert.strictEqual(widget.$('.mv_line .cell_right:not(:empty)').length, 2, "should display only the credit account move lines (hide the debit)");
|
||||
|
||||
clientAction.widgets[1].$('.accounting_view thead td:first').trigger('click');
|
||||
assert.strictEqual(clientAction.widgets[1].$('.mv_line').length, 5, "should display 5 account move lines");
|
||||
assert.strictEqual(clientAction.widgets[1].$('.mv_line .cell_right:not(:empty)').length, 4, "should display only the credit account move lines (hide the debit)");
|
||||
assert.strictEqual(clientAction.widgets[1].$('.mv_line.already_reconciled').length, 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 ",
|
||||
"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:not(:empty)').length, 1, "should display only 1 debit account move lines");
|
||||
clientAction.widgets[1].$('.match_controls .fa-chevron-right').trigger('click');
|
||||
assert.strictEqual(clientAction.widgets[1].$('.mv_line').text().replace(/[\n\r\s]+/g, ' '),
|
||||
" 101200 2017-02-28 Camptocamp: INV/2017/0001 $ 4,610.00 111100 2017-02-28 Camptocamp: BILL/2017/0001 $ 10,000.00 111100 2017-02-28 ASUSTeK: BILL/2017/0002 $ 5,749.99 ",
|
||||
"should display the next 5 account move lines");
|
||||
|
||||
assert.ok(clientAction.widgets[0].$('caption button.btn-default:visible').length, "should display the 'validate' button");
|
||||
assert.ok(clientAction.widgets[1].$('caption .text-danger:visible').length, "should display the 'Select a partner or choose a counterpart' message");
|
||||
assert.ok(clientAction.widgets[2].$('caption button.btn-primary:visible').length, "should display the 'Reconcile' button");
|
||||
|
||||
clientAction.widgets[3].$('.accounting_view thead td:first').trigger('click');
|
||||
assert.strictEqual(clientAction.widgets[3].$el.data('mode'), 'create', "should switch to 'create' mode instead 'match' mode when 'match' mode is empty");
|
||||
|
||||
widget = clientAction.widgets[2];
|
||||
|
||||
assert.notOk( widget.$('.cell_right .line_info_button').length, "should not display the partial reconciliation alert");
|
||||
assert.ok( widget.$('button.btn-primary:not(hidden)').length, "should display the reconcile button");
|
||||
widget.$('.accounting_view thead td:first').trigger('click');
|
||||
widget.$('.match td.cell_label:first').trigger('click');
|
||||
assert.ok( widget.$('.text-danger:not(hidden)').length, "should display counterpart alert");
|
||||
widget.$('.accounting_view tbody td.cell_label:first').trigger('click');
|
||||
assert.ok( widget.$('.text-danger:not(hidden)').length, "should display counterpart alert");
|
||||
assert.strictEqual(widget.$('.cell_right .line_info_button').length, 1, "should display a partial reconciliation alert");
|
||||
widget.$('.cell_right .line_info_button').trigger('click');
|
||||
assert.ok(widget.$('.cell_right .line_info_button').hasClass('do_partial_reconcile_false'), "should display the partial reconciliation information");
|
||||
assert.ok( widget.$('button.btn-default:not(hidden)').length, "should display the validate button");
|
||||
|
||||
clientAction.destroy();
|
||||
});
|
||||
|
||||
|
||||
QUnit.test('Reconciliation title', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
var clientAction = new ReconciliationClientAction.StatementAction(null, this.options);
|
||||
testUtils.addMockEnvironment(clientAction, {
|
||||
'data': this.data,
|
||||
mockRPC: this.mockRPC,
|
||||
});
|
||||
|
||||
clientAction.appendTo($('#qunit-fixture'));
|
||||
|
||||
assert.strictEqual(clientAction.$('h1.statement_name:visible').text(), "BNK/2014/001", "Should display the statement name");
|
||||
clientAction.$('h1.statement_name').trigger('click');
|
||||
assert.strictEqual(clientAction.$('h1.statement_name:visible').length, 0, "Should hide the statement name title to edit the content");
|
||||
assert.strictEqual(clientAction.$('h1.statement_name_edition:visible').length, 1, "Should show the edition field of statement name");
|
||||
clientAction.$('h1.statement_name_edition input').val('BNK/2014/001-BB').trigger('input');
|
||||
clientAction.$('h1.statement_name_edition button').trigger('click');
|
||||
assert.strictEqual(clientAction.$('h1.statement_name_edition:visible').length, 0, "Should hide the edition field of statement name");
|
||||
assert.strictEqual(clientAction.$('h1.statement_name:visible').length, 1, "Should show the statement name");
|
||||
assert.strictEqual(clientAction.$('h1.statement_name:visible').text(), "BNK/2014/001-BB", "Should update the statement name");
|
||||
|
||||
clientAction.destroy();
|
||||
});
|
||||
|
||||
|
||||
QUnit.test('Reconciliation currencies', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var clientAction = new ReconciliationClientAction.StatementAction(null, this.options);
|
||||
|
||||
testUtils.addMockEnvironment(clientAction, {
|
||||
'data': this.data,
|
||||
mockRPC: this.mockRPC,
|
||||
session: this.session,
|
||||
translateParameters: {
|
||||
date_format: "%m/%d/%Y",
|
||||
direction:"ltr",
|
||||
name:"English",
|
||||
thousands_sep: ",",
|
||||
time_format: "%H:%M:%S",
|
||||
decimal_point: ".",
|
||||
id:1,
|
||||
grouping: [3,0],
|
||||
}
|
||||
});
|
||||
clientAction.appendTo($('#qunit-fixture'));
|
||||
|
||||
var widget = clientAction.widgets[0];
|
||||
|
||||
assert.strictEqual(clientAction.$('.accounting_view tfoot .cell_right, .accounting_view tfoot .cell_left').text().replace(/[\n\r\s]+/g, ' '),
|
||||
"$ 1,175.00$ 32.58$ 2,000.00", "should display the different amounts with the currency");
|
||||
widget.$('.accounting_view thead .mv_line td:first').trigger('click');
|
||||
|
||||
assert.strictEqual(clientAction.$('.accounting_view tbody').text().replace(/[\n\r\s]+/g, ' '),
|
||||
" 101200 2017-02-07 INV/2017/0012 $ 650.00 ", "should display the created reconciliation line with the currency");
|
||||
|
||||
clientAction.destroy();
|
||||
});
|
||||
|
||||
|
||||
QUnit.test('Reconciliation create line', function (assert) {
|
||||
assert.expect(21);
|
||||
|
||||
var clientAction = new ReconciliationClientAction.StatementAction(null, this.options);
|
||||
|
||||
testUtils.addMockEnvironment(clientAction, {
|
||||
'data': this.data,
|
||||
mockRPC: this.mockRPC,
|
||||
});
|
||||
clientAction.appendTo($('#qunit-fixture'));
|
||||
|
||||
assert.strictEqual(clientAction.$('.accounting_view tfoot .cell_right, .accounting_view tfoot .cell_left').text().replace(/[$, ]+/g, ''), "1175.0032.582000.00", "should display the open balance values");
|
||||
|
||||
var widget = clientAction.widgets[0];
|
||||
|
||||
assert.strictEqual(widget.$('.accounting_view tfoot .cell_label').text(), 'Open balance', "should display 'Open Balance' line with the rest to reconcile");
|
||||
|
||||
widget.$('.accounting_view tfoot td:first').trigger('click');
|
||||
widget.$('.create .create_account_id input').trigger('click');
|
||||
$('.ui-autocomplete .ui-menu-item a:contains(101200 Account Receivable)').trigger('mouseenter').trigger('click');
|
||||
|
||||
assert.notOk(widget.$('.accounting_view tfoot .cell_label').text(), "should not display 'Open Balance' line because the rest to reconcile is null");
|
||||
assert.strictEqual(widget.$('.accounting_view tbody tr').length, 1, "should have only the created reconcile line");
|
||||
assert.strictEqual(widget.$('.accounting_view tbody tr').text().replace(/[\n\r\s$,]+/g, ' '), " 101200 SAJ/2014/002 and SAJ/2014/003 1175.00 ",
|
||||
"the new line should have the selected account, name and amout");
|
||||
assert.ok(widget.$('caption button.btn-primary:visible').length, "should display the 'Reconcile' button");
|
||||
|
||||
widget.$('.create .create_amount input').val('1100.00').trigger('input');
|
||||
|
||||
assert.strictEqual(widget.$('.accounting_view tbody .cell_right').text(), "1100.00", "should display the value 1100.00 in right column");
|
||||
assert.strictEqual(widget.$('.accounting_view tfoot .cell_right').text(), "75.00", "should display 'Open Balance' line because the rest to reconcile is 75.00");
|
||||
assert.strictEqual(widget.$('.accounting_view tbody tr').length, 1, "should have ever only the created reconcile line");
|
||||
assert.strictEqual(widget.$('.accounting_view tbody tr').text().replace(/[\n\r\s$,]+/g, ' '), " 101200 SAJ/2014/002 and SAJ/2014/003 1100.00 ",
|
||||
"the new line should be update the amout");
|
||||
assert.ok(widget.$('caption button.btn-default:visible').length, "should display the 'validate' button");
|
||||
|
||||
widget.$('.create .add_line').trigger('click').trigger('click');
|
||||
widget.$('.create .create_amount input').val('-100').trigger('input');
|
||||
widget.$('.create .create_account_id input').trigger('click');
|
||||
$('.ui-autocomplete .ui-menu-item a:contains(101000 Current Assets)').trigger('mouseenter').trigger('click');
|
||||
widget.$('.create .create_label input').val('test0').trigger('input');
|
||||
|
||||
assert.strictEqual(widget.$('.accounting_view tbody .cell_left:last').text(), "100.00", "should display the value 100.00 in left column");
|
||||
assert.strictEqual(widget.$('.accounting_view tfoot .cell_label').text(), "Open balance", "should display 'Open Balance'");
|
||||
assert.strictEqual(widget.$('.accounting_view tfoot .cell_right').text(), "175.00", "should display 'Open Balance' line because the rest to reconcile is 175.00");
|
||||
assert.strictEqual(widget.$('.accounting_view tbody tr').length, 2, "should have 2 created reconcile lines");
|
||||
assert.strictEqual(widget.$('.accounting_view tbody tr:eq(1)').text().replace(/[\n\r\s$,]+/g, ' '), " 101000 test0 100.00 ",
|
||||
"the new line should have the selected account, name and amout");
|
||||
|
||||
widget.$('.accounting_view tfoot td:first').trigger('click');
|
||||
widget.$('.accounting_view tfoot td:first').trigger('click');
|
||||
|
||||
assert.strictEqual(widget.$('.create .create_amount input').val(), "175.00", "should have '175.00' as default amount value");
|
||||
|
||||
widget.$('.create .create_amount input').val('200').trigger('input');
|
||||
widget.$('.create .create_account_id input').trigger('click');
|
||||
$('.ui-autocomplete .ui-menu-item a:contains(101000 Current Assets)').trigger('mouseenter').trigger('click');
|
||||
widget.$('.create .create_label input').val('test1').trigger('input');
|
||||
|
||||
assert.strictEqual(widget.$('.accounting_view tbody .cell_right:last').text(), "200.00", "should display the value 100.00 in left column");
|
||||
assert.strictEqual(widget.$('.accounting_view tfoot .cell_label').text(), "Create Write-off", "should display 'Create Write-off'");
|
||||
assert.strictEqual(widget.$('.accounting_view tfoot .cell_left').text(), "25.00", "should display 'Create Write-off' with 25.00 in left column");
|
||||
assert.strictEqual(widget.$('.accounting_view tbody tr').length, 3, "should have 3 created reconcile lines");
|
||||
|
||||
clientAction.destroy();
|
||||
});
|
||||
|
||||
|
||||
QUnit.test('Reconciliation create line with taxes', function (assert) {
|
||||
assert.expect(13);
|
||||
|
||||
var clientAction = new ReconciliationClientAction.StatementAction(null, this.options);
|
||||
|
||||
testUtils.addMockEnvironment(clientAction, {
|
||||
'data': this.data,
|
||||
mockRPC: this.mockRPC,
|
||||
});
|
||||
clientAction.appendTo($('#qunit-fixture'));
|
||||
|
||||
var widget = clientAction.widgets[0];
|
||||
|
||||
widget.$('.accounting_view tfoot td:first').trigger('click');
|
||||
widget.$('.create .create_account_id input').trigger('click');
|
||||
$('.ui-autocomplete .ui-menu-item a:contains(101000 Current Assets)').trigger('mouseenter').trigger('click');
|
||||
widget.$('.create .create_label input').val('test1').trigger('input');
|
||||
widget.$('.create .create_amount input').val('1100').trigger('input');
|
||||
|
||||
assert.strictEqual(widget.$('.accounting_view tbody .cell_right:last').text(), "1100.00", "should display the value 1100.00 in left column");
|
||||
assert.strictEqual(widget.$('.accounting_view tfoot .cell_label').text(), "Open balance", "should display 'Open Balance'");
|
||||
assert.strictEqual(widget.$('.accounting_view tfoot .cell_right').text(), "75.00", "should display 'Open Balance' with 75.00 in right column");
|
||||
assert.strictEqual(widget.$('.accounting_view tbody tr').length, 1, "should have 1 created reconcile lines");
|
||||
|
||||
widget.$('.create .create_tax_id input').trigger('click');
|
||||
$('.ui-autocomplete .ui-menu-item a:contains(10.00%)').trigger('mouseenter').trigger('click');
|
||||
|
||||
assert.strictEqual(widget.$('.accounting_view tbody .cell_right').text().replace('$_', ''), "1000.00100.00", "should have 2 created reconcile lines with right column values");
|
||||
assert.strictEqual(widget.$('.accounting_view tfoot .cell_label').text(), "Open balance", "should display 'Open Balance'");
|
||||
assert.strictEqual(widget.$('.accounting_view tfoot .cell_right').text(), "75.00", "should display 'Open Balance' with 75.00 in right column");
|
||||
assert.strictEqual(widget.$('.accounting_view tfoot .cell_left').text(), "", "should display 'Open Balance' without any value in left column");
|
||||
assert.strictEqual(widget.$('.accounting_view tbody tr').length, 2, "should have 2 created reconcile lines");
|
||||
|
||||
widget.$('.create .create_tax_id input').trigger('click');
|
||||
$('.ui-autocomplete .ui-menu-item a:contains(20.00%)').trigger('mouseenter').trigger('click');
|
||||
|
||||
assert.strictEqual(widget.$('.accounting_view tbody .cell_right').text().replace('$_', ''), "1100.00220.00", "should have 2 created reconcile lines with right column values");
|
||||
assert.strictEqual(widget.$('.accounting_view tfoot .cell_label').text(), "Create Write-off", "should display 'Create Write-off'");
|
||||
assert.strictEqual(widget.$('.accounting_view tfoot .cell_left').text(), "145.00", "should display 'Create Write-off' with 145.00 in right column");
|
||||
assert.strictEqual(widget.$('.accounting_view tbody tr').length, 2, "should have 2 created reconcile lines");
|
||||
|
||||
clientAction.destroy();
|
||||
});
|
||||
|
||||
|
||||
QUnit.test('Reconciliation create line from reconciliation model', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
var clientAction = new ReconciliationClientAction.StatementAction(null, this.options);
|
||||
|
||||
testUtils.addMockEnvironment(clientAction, {
|
||||
'data': this.data,
|
||||
mockRPC: this.mockRPC,
|
||||
});
|
||||
clientAction.appendTo($('#qunit-fixture'));
|
||||
|
||||
var widget = clientAction.widgets[0];
|
||||
|
||||
widget.$('.accounting_view tfoot td:first').trigger('click');
|
||||
widget.$('.create .quick_add button:contains(ATOS)').trigger('click');
|
||||
|
||||
assert.strictEqual(widget.$('.accounting_view tbody .cell_label, .accounting_view tbody .cell_right').text().replace(/[\n\r\s$,]+/g, ' '),
|
||||
"ATOS Banque1145.62Tax 20.00%229.12ATOS Frais26.71Tax 10.00% include2.67", "should display 4 lines");
|
||||
assert.strictEqual(widget.$('.accounting_view tfoot .cell_label, .accounting_view tfoot .cell_left').text().replace(/[\n\r\s$,]+/g, ' '),
|
||||
"Create Write-off229.12", "should display the 'Create Write-off' line with value in left column");
|
||||
|
||||
widget.$('.create .create_amount input').val('100').trigger('input');
|
||||
|
||||
assert.strictEqual(widget.$('.accounting_view tbody').text().replace(/[\n\r\s$,]+/g, ' '),
|
||||
" 101120 ATOS Banque 1075.00 101120 Tax 20.00% 215.00 101130 ATOS Frais 90.91 101300 Tax 10.00% include 9.09 ",
|
||||
"should update the value of the 4 lines (because the line must have 100% of the value)");
|
||||
assert.strictEqual(widget.$('.accounting_view tfoot .cell_label, .accounting_view tfoot .cell_left').text().replace(/[\n\r\s$,]+/g, ' '),
|
||||
"Create Write-off215.00", "should change the 'Create Write-off' line because the 20.00% tax is not an include tax");
|
||||
|
||||
widget.$('.accounting_view tbody .cell_account_code:first').trigger('click');
|
||||
widget.$('.accounting_view tbody .cell_label:first').trigger('click');
|
||||
|
||||
assert.strictEqual(widget.$('.accounting_view tbody').text().replace(/[\n\r\s$,]+/g, ' '), "", "should removed every line");
|
||||
|
||||
widget.$('.create .quick_add button:contains(Double)').trigger('click');
|
||||
|
||||
assert.strictEqual(widget.$('.accounting_view tbody').text().replace(/[\n\r\s$,]+/g, ' '),
|
||||
" 101120 Double Banque 1145.62 101130 Double Frais 29.38 ",
|
||||
"should have a sum of reconciliation proposition amounts equal to the line amount");
|
||||
|
||||
clientAction.destroy();
|
||||
});
|
||||
|
||||
|
||||
QUnit.test('Reconciliation auto reconciliation', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
var clientAction = new ReconciliationClientAction.StatementAction(null, this.options);
|
||||
|
||||
testUtils.addMockEnvironment(clientAction, {
|
||||
'data': this.data,
|
||||
mockRPC: this.mockRPC,
|
||||
});
|
||||
clientAction.appendTo($('body'));
|
||||
|
||||
clientAction.$('button.o_automatic_reconciliation').trigger('click');
|
||||
|
||||
assert.strictEqual(clientAction.$('.progress .valuenow').text(), "1", "should reconciled one line");
|
||||
assert.strictEqual(clientAction.$('.progress .valuemax').text(), "4", "should have maximum 4 lines to reconciled");
|
||||
assert.strictEqual(clientAction.$('thead .cell_label').text().replace(/[\n\r\s$,]+/g, ' '),
|
||||
"SAJ/2014/002 and SAJ/2014/003 Bank fees First 2000 € of SAJ/2014/001 ", "should rest 3 lines to reconciled");
|
||||
assert.ok(clientAction.$('.notification_area .notification').length, "should display the notification");
|
||||
var do_action = false;
|
||||
clientAction.on('do_action', clientAction, function (data) {
|
||||
do_action = data.data.action;
|
||||
});
|
||||
clientAction.$('.notification_area a.fa-external-link').trigger('click');
|
||||
assert.deepEqual(_.pick(do_action, "res_model", "domain", "type"),
|
||||
{"res_model":"account.move", "domain":[["id","in",[143]]], "type":"ir.actions.act_window"},
|
||||
"should try to open the record form view");
|
||||
clientAction.$('.notification_area .close').trigger('click');
|
||||
assert.notOk(clientAction.$('.notification_area .notification').length, "should close the notification");
|
||||
|
||||
clientAction.destroy();
|
||||
});
|
||||
|
||||
|
||||
QUnit.test('Reconciliation manual open record', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var clientAction = new ReconciliationClientAction.ManualAction(null, this.options);
|
||||
|
||||
testUtils.addMockEnvironment(clientAction, {
|
||||
'data': this.data,
|
||||
mockRPC: this.mockRPC,
|
||||
});
|
||||
clientAction.appendTo($('#qunit-fixture'));
|
||||
|
||||
testUtils.intercept(clientAction, 'call_service', function (event) {
|
||||
if (event.data.args[0].indexOf('get_formview_action') !== -1) {
|
||||
assert.equal(event.data.args[1].model, "account.account", "should open the account.account from view ");
|
||||
event.data.callback($.when());
|
||||
}
|
||||
});
|
||||
clientAction.$('.accounting_view:first thead .o_form_uri').trigger('click');
|
||||
|
||||
testUtils.intercept(clientAction, 'call_service', function (event) {
|
||||
if (event.data.args[0].indexOf('get_formview_action') !== -1) {
|
||||
assert.equal(event.data.args[1].model, "res.partner", "should open the res.partner from view ");
|
||||
event.data.callback($.when());
|
||||
}
|
||||
});
|
||||
clientAction.$('.accounting_view:eq(1) thead .o_form_uri').trigger('click');
|
||||
|
||||
clientAction.destroy();
|
||||
});
|
||||
|
||||
|
||||
QUnit.test('Reconciliation manual', function (assert) {
|
||||
assert.expect(9);
|
||||
|
||||
var clientAction = new ReconciliationClientAction.ManualAction(null, this.options);
|
||||
|
||||
testUtils.addMockEnvironment(clientAction, {
|
||||
'data': this.data,
|
||||
mockRPC: this.mockRPC,
|
||||
session: this.session,
|
||||
});
|
||||
clientAction.appendTo($('#qunit-fixture'));
|
||||
|
||||
assert.strictEqual(clientAction.$('.accounting_view:first thead').text().replace(/[\n\r\s]+/g, ' '),
|
||||
" 101000 Current AssetsLast Reconciliation: 2017-02-16 101000 ",
|
||||
"should display the account as title");
|
||||
assert.strictEqual(clientAction.$('.o_reconciliation_line:first').data('mode'), "inactive", "should be in 'inactive' mode because no line to displayed and the balance amount is null");
|
||||
assert.strictEqual(clientAction.$('.accounting_view:first tbody tr').length, 2, "should have 2 propositions");
|
||||
assert.strictEqual(clientAction.$('.accounting_view:first .o_reconcile:visible').length, 1, "should display the reconcile button");
|
||||
|
||||
clientAction.$('.accounting_view:first .o_reconcile:visible').trigger('click');
|
||||
|
||||
assert.strictEqual(clientAction.$('.progress .progress-bar').attr('aria-valuenow'), "1", "should display a progress bar with 1 reconciled line");
|
||||
|
||||
assert.strictEqual(clientAction.$('.accounting_view:first thead').text().replace(/[\n\r\s]+/g, ' '),
|
||||
" Agrolait 101200 ",
|
||||
"should display the partner and the account code as title");
|
||||
|
||||
assert.strictEqual(clientAction.$('.o_reconciliation_line:first .match tr:first .cell_left').text(),
|
||||
"$ 11,000.00", "sould display the line in $");
|
||||
assert.strictEqual(clientAction.$('.o_reconciliation_line:first .match tr:first .cell_left .o_multi_currency').data('content'),
|
||||
"10,222.00 €", "sould display the monetary information in €");
|
||||
|
||||
assert.strictEqual(clientAction.$('.accounting_view:first .o_no_valid:visible').length, 1, "should display the skip button");
|
||||
|
||||
clientAction.destroy();
|
||||
});
|
||||
|
||||
|
||||
QUnit.test('Reconciliation manual validate all', function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
var clientAction = new ReconciliationClientAction.ManualAction(null, this.options);
|
||||
|
||||
testUtils.addMockEnvironment(clientAction, {
|
||||
'data': this.data,
|
||||
mockRPC: this.mockRPC,
|
||||
session: this.session,
|
||||
});
|
||||
|
||||
clientAction.prependTo($('#qunit-fixture'));
|
||||
|
||||
assert.strictEqual(clientAction.$('.o_reconciliation_line[data-mode="match"]').length, 0, "should have every widgets in 'inactive' mode");
|
||||
assert.strictEqual(clientAction.$('.o_reconciliation_line').length, 5, "should have 5 widgets to reconciled");
|
||||
assert.strictEqual(clientAction.$('.o_reconciliation_line button.o_reconcile:visible').length, 3, "should have 3 widgets who display 'reconcile' button");
|
||||
|
||||
var e = $.Event("keyup");
|
||||
e.which = 13; // # Enter code value
|
||||
e.ctrlKey = true; // Ctrl key pressed
|
||||
$("body").trigger(e);
|
||||
|
||||
assert.strictEqual(clientAction.$('.o_reconciliation_line').length, 3, "should have 2 already reconciled widgets");
|
||||
assert.strictEqual(clientAction.$('.progress .progress-bar').attr('aria-valuenow'), "2", "should display a progress bar with 2 reconciled line");
|
||||
assert.strictEqual(clientAction.$('.o_reconciliation_line[data-mode="match"]').length, 1, "should display the 'match' mode for the first line");
|
||||
|
||||
clientAction.destroy();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,18 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<template id="assets_backend" name="account assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<link rel="stylesheet" href="/account/static/src/css/account_bank_and_cash.css"/>
|
||||
<link rel="stylesheet" href="/account/static/src/css/account.css"/>
|
||||
<link rel="stylesheet" href="/account/static/src/less/account_reconciliation.less"/>
|
||||
<link rel="stylesheet" href="/account/static/src/less/account_journal_dashboard.less"/>
|
||||
<template id="assets_backend" name="account assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<link rel="stylesheet" href="/account/static/src/css/account_bank_and_cash.css"/>
|
||||
<link rel="stylesheet" href="/account/static/src/css/account.css"/>
|
||||
<link rel="stylesheet" href="/account/static/src/less/account_reconciliation.less"/>
|
||||
<link rel="stylesheet" href="/account/static/src/less/account_journal_dashboard.less"/>
|
||||
|
||||
<script type="text/javascript" src="/account/static/src/js/account_reconciliation_widgets.js"></script>
|
||||
<script type="text/javascript" src="/account/static/src/js/move_line_quickadd.js"></script>
|
||||
<!-- <script type="text/javascript" src="/account/static/src/js/tour_bank_statement_reconciliation.js"></script> -->
|
||||
<script type="text/javascript" src="/account/static/src/js/account_payment_widget.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
</data>
|
||||
<script type="text/javascript" src="/account/static/src/js/reconciliation/reconciliation_action.js"></script>
|
||||
<script type="text/javascript" src="/account/static/src/js/reconciliation/reconciliation_model.js"></script>
|
||||
<script type="text/javascript" src="/account/static/src/js/reconciliation/reconciliation_renderer.js"></script>
|
||||
|
||||
<script type="text/javascript" src="/account/static/src/js/move_line_quickadd.js"></script>
|
||||
<!-- <script type="text/javascript" src="/account/static/src/js/tour_bank_statement_reconciliation.js"></script> -->
|
||||
<script type="text/javascript" src="/account/static/src/js/account_payment_widget.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="qunit_suite" name="account_reconciliation tests" inherit_id="web.qunit_suite">
|
||||
<xpath expr="//script[contains(@src, '/web/static/test/views/kanban_tests.js')]" position="after">
|
||||
<script type="text/javascript" src="/account/static/test/account_reconciliation.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
</odoo>
|
||||
|
||||
@@ -7,9 +7,10 @@
|
||||
<field name="name">account.invoice.calendar</field>
|
||||
<field name="model">account.invoice</field>
|
||||
<field name="arch" type="xml">
|
||||
<calendar string="Invoices" color="journal_id" date_start="date_invoice">
|
||||
<calendar string="Invoices" date_start="date_invoice">
|
||||
<field name="partner_id"/>
|
||||
<field name="amount_total_signed"/>
|
||||
<filter name="journal_id" color="True"/>
|
||||
</calendar>
|
||||
</field>
|
||||
</record>
|
||||
@@ -173,7 +174,7 @@
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<span class="pull-right text-right">
|
||||
<field name="state" widget="kanban_label_selection" options="{'classes': {'draft': 'default', 'cancel': 'default', 'none': 'danger', 'open': 'warning',
|
||||
<field name="state" widget="label_selection" options="{'classes': {'draft': 'default', 'cancel': 'default', 'none': 'danger', 'open': 'warning',
|
||||
'paid': 'success'}}"/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -294,9 +294,7 @@
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="JournalBodyGraph">
|
||||
<div class="o_kanban_graph_section">
|
||||
<field name="kanban_dashboard_graph" t-att-graph_type="_.contains(['cash','bank'],journal_type) ? 'line' : 'bar'" widget="dashboard_graph"/>
|
||||
</div>
|
||||
<field name="kanban_dashboard_graph" t-att-graph_type="_.contains(['cash','bank'],journal_type) ? 'line' : 'bar'" widget="dashboard_graph"/>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
|
||||
Reference in New Issue
Block a user