Merge pull request #666 from odoo-dev/master-statement-fixes-alot-qdp
evil pull request with fixes on the new bank statement reconciliation widget
This commit is contained in:
commit
af5ad37486
|
@ -26,6 +26,9 @@ from openerp.report import report_sxw
|
|||
|
||||
class account_bank_statement(osv.osv):
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
if vals.get('name', '/') == '/':
|
||||
journal_id = vals.get('journal_id', self._default_journal_id(cr, uid, context=context))
|
||||
vals['name'] = self._compute_default_statement_name(cr, uid, journal_id, context=context)
|
||||
if 'line_ids' in vals:
|
||||
for idx, line in enumerate(vals['line_ids']):
|
||||
line[2]['sequence'] = idx + 1
|
||||
|
@ -65,17 +68,14 @@ class account_bank_statement(osv.osv):
|
|||
return periods[0]
|
||||
return False
|
||||
|
||||
def _compute_default_statement_name(self, cr, uid, context=None):
|
||||
def _compute_default_statement_name(self, cr, uid, journal_id, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
obj_seq = self.pool.get('ir.sequence')
|
||||
default_journal_id = self._default_journal_id(cr, uid, context=context)
|
||||
if default_journal_id != False:
|
||||
period = self.pool.get('account.period').browse(cr, uid, self._get_period(cr, uid, context=context), context=context)
|
||||
context['fiscalyear_id'] = period.fiscalyear_id.id
|
||||
journal = self.pool.get('account.journal').browse(cr, uid, default_journal_id, None)
|
||||
return obj_seq.next_by_id(cr, uid, journal.sequence_id.id, context=context)
|
||||
return obj_seq.next_by_code(cr, uid, 'account.bank.statement', context=context)
|
||||
period = self.pool.get('account.period').browse(cr, uid, self._get_period(cr, uid, context=context), context=context)
|
||||
context['fiscalyear_id'] = period.fiscalyear_id.id
|
||||
journal = self.pool.get('account.journal').browse(cr, uid, journal_id, None)
|
||||
return obj_seq.next_by_id(cr, uid, journal.sequence_id.id, context=context)
|
||||
|
||||
def _currency(self, cursor, user, ids, name, args, context=None):
|
||||
res = {}
|
||||
|
@ -150,7 +150,7 @@ class account_bank_statement(osv.osv):
|
|||
}
|
||||
|
||||
_defaults = {
|
||||
'name': _compute_default_statement_name,
|
||||
'name': '/',
|
||||
'date': fields.date.context_today,
|
||||
'state': 'draft',
|
||||
'journal_id': _default_journal_id,
|
||||
|
@ -213,11 +213,8 @@ class account_bank_statement(osv.osv):
|
|||
|
||||
def _get_counter_part_account(sefl, cr, uid, st_line, context=None):
|
||||
"""Retrieve the account to use in the counterpart move.
|
||||
This method may be overridden to implement custom move generation (making sure to
|
||||
call super() to establish a clean extension chain).
|
||||
|
||||
:param browse_record st_line: account.bank.statement.line record to
|
||||
create the move from.
|
||||
:param browse_record st_line: account.bank.statement.line record to create the move from.
|
||||
:return: int/long of the account.account to use as counterpart
|
||||
"""
|
||||
if st_line.amount >= 0:
|
||||
|
@ -226,26 +223,19 @@ class account_bank_statement(osv.osv):
|
|||
|
||||
def _get_counter_part_partner(sefl, cr, uid, st_line, context=None):
|
||||
"""Retrieve the partner to use in the counterpart move.
|
||||
This method may be overridden to implement custom move generation (making sure to
|
||||
call super() to establish a clean extension chain).
|
||||
|
||||
:param browse_record st_line: account.bank.statement.line record to
|
||||
create the move from.
|
||||
:param browse_record st_line: account.bank.statement.line record to create the move from.
|
||||
:return: int/long of the res.partner to use as counterpart
|
||||
"""
|
||||
return st_line.partner_id and st_line.partner_id.id or False
|
||||
|
||||
def _prepare_bank_move_line(self, cr, uid, st_line, move_id, amount, company_currency_id, context=None):
|
||||
"""Compute the args to build the dict of values to create the counter part move line from a
|
||||
statement line by calling the _prepare_move_line_vals. This method may be
|
||||
overridden to implement custom move generation (making sure to call super() to
|
||||
establish a clean extension chain).
|
||||
statement line by calling the _prepare_move_line_vals.
|
||||
|
||||
:param browse_record st_line: account.bank.statement.line record to
|
||||
create the move from.
|
||||
:param browse_record st_line: account.bank.statement.line record to create the move from.
|
||||
:param int/long move_id: ID of the account.move to link the move line
|
||||
:param float amount: amount of the move line
|
||||
:param int/long account_id: ID of account to use as counter part
|
||||
:param int/long company_currency_id: ID of currency of the concerned company
|
||||
:return: dict of value to create() the bank account.move.line
|
||||
"""
|
||||
|
@ -258,7 +248,6 @@ class account_bank_statement(osv.osv):
|
|||
if st_line.statement_id.currency.id != company_currency_id:
|
||||
amt_cur = st_line.amount
|
||||
cur_id = st_line.currency_id or st_line.statement_id.currency.id
|
||||
# TODO : FIXME the amount should be in the journal currency
|
||||
if st_line.currency_id and st_line.amount_currency:
|
||||
amt_cur = st_line.amount_currency
|
||||
cur_id = st_line.currency_id.id
|
||||
|
@ -269,9 +258,7 @@ class account_bank_statement(osv.osv):
|
|||
def _prepare_move_line_vals(self, cr, uid, st_line, move_id, debit, credit, currency_id=False,
|
||||
amount_currency=False, account_id=False, partner_id=False, context=None):
|
||||
"""Prepare the dict of values to create the move line from a
|
||||
statement line. All non-mandatory args will replace the default computed one.
|
||||
This method may be overridden to implement custom move generation (making sure to
|
||||
call super() to establish a clean extension chain).
|
||||
statement line.
|
||||
|
||||
:param browse_record st_line: account.bank.statement.line record to
|
||||
create the move from.
|
||||
|
@ -342,21 +329,29 @@ class account_bank_statement(osv.osv):
|
|||
move_ids.append(st_line.journal_entry_id.id)
|
||||
self.pool.get('account.move').post(cr, uid, move_ids, context=context)
|
||||
self.message_post(cr, uid, [st.id], body=_('Statement %s confirmed, journal items were created.') % (st.name,), context=context)
|
||||
self.link_bank_to_partner(cr, uid, ids, context=context)
|
||||
return self.write(cr, uid, ids, {'state':'confirm'}, context=context)
|
||||
|
||||
def button_cancel(self, cr, uid, ids, context=None):
|
||||
done = []
|
||||
account_move_obj = self.pool.get('account.move')
|
||||
reconcile_pool = self.pool.get('account.move.reconcile')
|
||||
move_line_pool = self.pool.get('account.move.line')
|
||||
move_ids = []
|
||||
for st in self.browse(cr, uid, ids, context=context):
|
||||
if st.state=='draft':
|
||||
continue
|
||||
move_ids = []
|
||||
for line in st.line_ids:
|
||||
move_ids += [x.id for x in line.move_ids]
|
||||
if line.journal_entry_id:
|
||||
move_ids.append(line.journal_entry_id.id)
|
||||
for aml in line.journal_entry_id.line_id:
|
||||
if aml.reconcile_id:
|
||||
move_lines = [l.id for l in aml.reconcile_id.line_id]
|
||||
move_lines.remove(aml.id)
|
||||
reconcile_pool.unlink(cr, uid, [aml.reconcile_id.id], context=context)
|
||||
if len(move_lines) >= 2:
|
||||
move_line_pool.reconcile_partial(cr, uid, move_lines, 'auto', context=context)
|
||||
if move_ids:
|
||||
account_move_obj.button_cancel(cr, uid, move_ids, context=context)
|
||||
account_move_obj.unlink(cr, uid, move_ids, context)
|
||||
done.append(st.id)
|
||||
return self.write(cr, uid, done, {'state':'draft'}, context=context)
|
||||
return self.write(cr, uid, ids, {'state': 'draft'}, context=context)
|
||||
|
||||
def _compute_balance_end_real(self, cr, uid, journal_id, context=None):
|
||||
res = False
|
||||
|
@ -417,18 +412,35 @@ class account_bank_statement(osv.osv):
|
|||
|
||||
def number_of_lines_reconciled(self, cr, uid, id, context=None):
|
||||
bsl_obj = self.pool.get('account.bank.statement.line')
|
||||
return bsl_obj.search_count(cr, uid, [('statement_id','=',id), ('journal_entry_id','!=',False)], context=context)
|
||||
|
||||
return bsl_obj.search_count(cr, uid, [('statement_id', '=', id), ('journal_entry_id', '!=', False)], context=context)
|
||||
|
||||
def get_format_currency_js_function(self, cr, uid, id, context=None):
|
||||
""" Returns a string that can be used to instanciate a javascript function.
|
||||
That function formats a number according to the statement's journal currency """
|
||||
That function formats a number according to the statement line's currency or the statement currency"""
|
||||
company_currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id
|
||||
currency_obj = id and self.browse(cr, uid, id, context=context).journal_id.currency or company_currency
|
||||
st = id and self.browse(cr, uid, id, context=context)
|
||||
if not st:
|
||||
return
|
||||
statement_currency = st.journal_id.currency or company_currency
|
||||
digits = 2 # TODO : from currency_obj
|
||||
if currency_obj.position == 'after':
|
||||
return "return amount.toFixed("+str(digits)+") + ' "+currency_obj.symbol+"';"
|
||||
elif currency_obj.position == 'before':
|
||||
return "return '"+currency_obj.symbol+" ' + amount.toFixed("+str(digits)+");"
|
||||
function = ""
|
||||
done_currencies = []
|
||||
for st_line in st.line_ids:
|
||||
st_line_currency = st_line.currency_id or statement_currency
|
||||
if st_line_currency.id not in done_currencies:
|
||||
if st_line_currency.position == 'after':
|
||||
return_str = "return amount.toFixed(" + str(digits) + ") + ' " + st_line_currency.symbol + "';"
|
||||
else:
|
||||
return_str = "return '" + st_line_currency.symbol + " ' + amount.toFixed(" + str(digits) + ");"
|
||||
function += "if (currency_id === " + str(st_line_currency.id) + "){ " + return_str + " }"
|
||||
done_currencies.append(st_line_currency.id)
|
||||
return function
|
||||
|
||||
def link_bank_to_partner(self, cr, uid, ids, context=None):
|
||||
for statement in self.browse(cr, uid, ids, context=context):
|
||||
for st_line in statement.line_ids:
|
||||
if st_line.bank_account_id and st_line.partner_id and st_line.bank_account_id.partner_id.id != st_line.partner_id.id:
|
||||
self.pool.get('res.partner.bank').write(cr, uid, [st_line.bank_account_id.id], {'partner_id': st_line.partner_id.id}, context=context)
|
||||
|
||||
class account_bank_statement_line(osv.osv):
|
||||
|
||||
|
@ -444,35 +456,40 @@ class account_bank_statement_line(osv.osv):
|
|||
}
|
||||
for mv_line in reconciliation_data['reconciliation_proposition']:
|
||||
mv_line_ids_selected.append(mv_line['id'])
|
||||
ret.append(reconciliation_data);
|
||||
|
||||
ret.append(reconciliation_data)
|
||||
|
||||
# Check if, now that 'candidate' move lines were selected, there are moves left for statement lines
|
||||
for reconciliation_data in ret:
|
||||
if not reconciliation_data['st_line']['has_no_partner']:
|
||||
if self.get_move_lines_counterparts(cr, uid, reconciliation_data['st_line']['id'], excluded_ids=mv_line_ids_selected, count=True, context=context) == 0:
|
||||
reconciliation_data['st_line']['no_match'] = True
|
||||
#for reconciliation_data in ret:
|
||||
# if not reconciliation_data['st_line']['has_no_partner']:
|
||||
# st_line = self.browse(cr, uid, reconciliation_data['st_line']['id'], context=context)
|
||||
# if not self.get_move_lines_counterparts(cr, uid, st_line, excluded_ids=mv_line_ids_selected, count=True, context=context):
|
||||
# reconciliation_data['st_line']['no_match'] = True
|
||||
return ret
|
||||
|
||||
def get_statement_line_for_reconciliation(self, cr, uid, id, context=None):
|
||||
""" Returns the data required by the bank statement reconciliation use case """
|
||||
line = self.browse(cr, uid, id, context=context)
|
||||
statement_currency = line.journal_id.currency or line.journal_id.company_id.currency_id
|
||||
amount = line.amount
|
||||
rml_parser = report_sxw.rml_parse(cr, uid, 'statement_line_widget', context=context)
|
||||
amount_str = line.amount > 0 and line.amount or -line.amount
|
||||
amount_str = rml_parser.formatLang(amount_str, currency_obj=statement_currency)
|
||||
amount_currency_str = ""
|
||||
if line.amount_currency and line.currency_id:
|
||||
amount_currency_str = rml_parser.formatLang(line.amount_currency, currency_obj=line.currency_id)
|
||||
amount_currency_str = amount_str
|
||||
amount_str = rml_parser.formatLang(line.amount_currency, currency_obj=line.currency_id)
|
||||
amount = line.amount_currency
|
||||
|
||||
dict = {
|
||||
data = {
|
||||
'id': line.id,
|
||||
'ref': line.ref,
|
||||
'note': line.note or "",
|
||||
'name': line.name,
|
||||
'date': line.date,
|
||||
'amount': line.amount,
|
||||
'amount': amount,
|
||||
'amount_str': amount_str,
|
||||
'no_match': self.get_move_lines_counterparts(cr, uid, id, count=True, context=context) == 0 and line.partner_id.id,
|
||||
'currency_id': line.currency_id.id or statement_currency.id,
|
||||
'no_match': self.get_move_lines_counterparts(cr, uid, line, count=True, context=context) == 0,
|
||||
'partner_id': line.partner_id.id,
|
||||
'statement_id': line.statement_id.id,
|
||||
'account_code': line.journal_id.default_debit_account_id.code,
|
||||
|
@ -482,93 +499,116 @@ class account_bank_statement_line(osv.osv):
|
|||
'has_no_partner': not line.partner_id.id,
|
||||
}
|
||||
if line.partner_id.id:
|
||||
if line.amount > 0:
|
||||
dict['open_balance_account_id'] = line.partner_id.property_account_receivable.id
|
||||
else:
|
||||
dict['open_balance_account_id'] = line.partner_id.property_account_payable.id
|
||||
return dict
|
||||
data['open_balance_account_id'] = line.partner_id.property_account_payable.id
|
||||
if amount > 0:
|
||||
data['open_balance_account_id'] = line.partner_id.property_account_receivable.id
|
||||
return data
|
||||
|
||||
def search_structured_com(self, cr, uid, st_line, context=None):
|
||||
if not st_line.ref:
|
||||
return
|
||||
domain = [('ref', '=', st_line.ref)]
|
||||
if st_line.partner_id:
|
||||
domain += [('partner_id', '=', st_line.partner_id.id)]
|
||||
ids = self.pool.get('account.move.line').search(cr, uid, domain, limit=1, context=context)
|
||||
return ids and ids[0] or False
|
||||
|
||||
def get_reconciliation_proposition(self, cr, uid, id, excluded_ids=[], context=None):
|
||||
""" Returns move lines that constitute the best guess to reconcile a statement line. """
|
||||
st_line = self.browse(cr, uid, id, context=context)
|
||||
company_currency = st_line.journal_id.company_id.currency_id.id
|
||||
statement_currency = st_line.journal_id.currency.id or company_currency
|
||||
|
||||
# either use the unsigned debit/credit fields or the signed amount_currency field
|
||||
sign = 1
|
||||
if statement_currency == company_currency:
|
||||
amount_field = 'credit'
|
||||
if st_line.amount > 0:
|
||||
amount_field = 'debit'
|
||||
else:
|
||||
amount_field = 'credit'
|
||||
else:
|
||||
amount_field = 'amount_currency'
|
||||
if st_line.amount < 0:
|
||||
sign = -1
|
||||
|
||||
# look for structured communication
|
||||
exact_match_id = self.search_structured_com(cr, uid, st_line, context=context)
|
||||
if exact_match_id:
|
||||
return self.make_counter_part_lines(cr, uid, st_line, [exact_match_id], count=False, context=context)
|
||||
#we don't propose anything if there is no partner detected
|
||||
if not st_line.partner_id.id:
|
||||
return []
|
||||
# look for exact match
|
||||
exact_match_id = self.get_move_lines_counterparts(cr, uid, id, excluded_ids=excluded_ids, limit=1, additional_domain=[(amount_field,'=',(sign*st_line.amount))])
|
||||
exact_match_id = self.get_move_lines_counterparts(cr, uid, st_line, excluded_ids=excluded_ids, limit=1, additional_domain=[(amount_field, '=', (sign * st_line.amount))])
|
||||
if exact_match_id:
|
||||
return exact_match_id
|
||||
|
||||
# select oldest move lines
|
||||
if sign == -1:
|
||||
mv_lines = self.get_move_lines_counterparts(cr, uid, id, excluded_ids=excluded_ids, limit=50, additional_domain=[(amount_field,'<',0)])
|
||||
mv_lines = self.get_move_lines_counterparts(cr, uid, st_line, excluded_ids=excluded_ids, limit=50, additional_domain=[(amount_field, '<', 0)])
|
||||
else:
|
||||
mv_lines = self.get_move_lines_counterparts(cr, uid, id, excluded_ids=excluded_ids, limit=50, additional_domain=[(amount_field,'>',0)])
|
||||
mv_lines = self.get_move_lines_counterparts(cr, uid, st_line, excluded_ids=excluded_ids, limit=50, additional_domain=[(amount_field, '>', 0)])
|
||||
ret = []
|
||||
total = 0
|
||||
# get_move_lines_counterparts inverts debit and credit
|
||||
amount_field = 'debit' if amount_field == 'credit' else 'credit'
|
||||
for line in mv_lines:
|
||||
if total + line[amount_field] <= st_line.amount:
|
||||
if total + line[amount_field] <= abs(st_line.amount):
|
||||
ret.append(line)
|
||||
total += line[amount_field]
|
||||
else:
|
||||
if total >= abs(st_line.amount):
|
||||
break
|
||||
|
||||
return ret
|
||||
|
||||
def get_move_lines_counterparts(self, cr, uid, id, excluded_ids=[], str="", offset=0, limit=None, count=False, additional_domain=[], context=None):
|
||||
def get_move_lines_counterparts_id(self, cr, uid, st_line_id, excluded_ids=[], filter_str="", offset=0, limit=None, count=False, additional_domain=[], context=None):
|
||||
st_line = self.browse(cr, uid, st_line_id, context=context)
|
||||
return self.get_move_lines_counterparts(cr, uid, st_line, excluded_ids, filter_str, offset, limit, count, additional_domain, context=context)
|
||||
|
||||
def get_move_lines_counterparts(self, cr, uid, st_line, excluded_ids=[], filter_str="", offset=0, limit=None, count=False, additional_domain=[], context=None):
|
||||
""" Find the move lines that could be used to reconcile a statement line and returns the counterpart that could be created to reconcile them
|
||||
If count is true, only returns the count.
|
||||
|
||||
:param integer id: the id of the statement line
|
||||
:param st_line: the browse record of the statement line
|
||||
:param integers list excluded_ids: ids of move lines that should not be fetched
|
||||
:param string str: string to filter lines
|
||||
:param string filter_str: string to filter lines
|
||||
:param integer offset: offset of the request
|
||||
:param integer limit: number of lines to fetch
|
||||
:param boolean count: just return the number of records
|
||||
:param tuples list domain: additional domain restrictions
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
rml_parser = report_sxw.rml_parse(cr, uid, 'statement_line_counterpart_widget', context=context)
|
||||
st_line = self.browse(cr, uid, id, context=context)
|
||||
company_currency = st_line.journal_id.company_id.currency_id
|
||||
statement_currency = st_line.journal_id.currency or company_currency
|
||||
mv_line_pool = self.pool.get('account.move.line')
|
||||
currency_obj = self.pool.get('res.currency')
|
||||
|
||||
domain = additional_domain + [
|
||||
('partner_id', '=', st_line.partner_id.id),
|
||||
('reconcile_id', '=', False),
|
||||
('state','=','valid'),
|
||||
'|',('account_id.type', '=', 'receivable'),
|
||||
('account_id.type', '=', 'payable'), #Let the front-end warn the user if he tries to mix payable and receivable in the same reconciliation
|
||||
('state', '=', 'valid'),
|
||||
]
|
||||
if st_line.partner_id.id:
|
||||
domain += [('partner_id', '=', st_line.partner_id.id),
|
||||
'|', ('account_id.type', '=', 'receivable'),
|
||||
('account_id.type', '=', 'payable')]
|
||||
else:
|
||||
domain += [('account_id.reconcile', '=', True)]
|
||||
#domain += [('account_id.reconcile', '=', True), ('account_id.type', '=', 'other')]
|
||||
if excluded_ids:
|
||||
domain.append(('id', 'not in', excluded_ids))
|
||||
if str:
|
||||
domain += ['|', ('move_id.name', 'ilike', str), ('move_id.ref', 'ilike', str)]
|
||||
if filter_str:
|
||||
if not st_line.partner_id:
|
||||
domain += [ '|', ('partner_id.name', 'ilike', filter_str)]
|
||||
domain += ['|', ('move_id.name', 'ilike', filter_str), ('move_id.ref', 'ilike', filter_str)]
|
||||
line_ids = mv_line_pool.search(cr, uid, domain, offset=offset, limit=limit, order="date_maturity asc, id asc", context=context)
|
||||
return self.make_counter_part_lines(cr, uid, st_line, line_ids, count=count, context=context)
|
||||
|
||||
def make_counter_part_lines(self, cr, uid, st_line, line_ids, count=False, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
mv_line_pool = self.pool.get('account.move.line')
|
||||
currency_obj = self.pool.get('res.currency')
|
||||
company_currency = st_line.journal_id.company_id.currency_id
|
||||
statement_currency = st_line.journal_id.currency or company_currency
|
||||
rml_parser = report_sxw.rml_parse(cr, uid, 'statement_line_counterpart_widget', context=context)
|
||||
#partially reconciled lines can be displayed only once
|
||||
reconcile_partial_ids = []
|
||||
ids = mv_line_pool.search(cr, uid, domain, offset=offset, limit=limit, order="date_maturity asc, id asc", context=context)
|
||||
|
||||
if count:
|
||||
nb_lines = 0
|
||||
for line in mv_line_pool.browse(cr, uid, ids, context=context):
|
||||
for line in mv_line_pool.browse(cr, uid, line_ids, context=context):
|
||||
if line.reconcile_partial_id and line.reconcile_partial_id.id in reconcile_partial_ids:
|
||||
continue
|
||||
nb_lines += 1
|
||||
|
@ -577,7 +617,7 @@ class account_bank_statement_line(osv.osv):
|
|||
return nb_lines
|
||||
else:
|
||||
ret = []
|
||||
for line in mv_line_pool.browse(cr, uid, ids, context=context):
|
||||
for line in mv_line_pool.browse(cr, uid, line_ids, context=context):
|
||||
if line.reconcile_partial_id and line.reconcile_partial_id.id in reconcile_partial_ids:
|
||||
continue
|
||||
amount_currency_str = ""
|
||||
|
@ -595,8 +635,12 @@ class account_bank_statement_line(osv.osv):
|
|||
'period_name': line.period_id.name,
|
||||
'journal_name': line.journal_id.name,
|
||||
'amount_currency_str': amount_currency_str,
|
||||
'partner_id': line.partner_id.id,
|
||||
'partner_name': line.partner_id.name,
|
||||
'has_no_partner': not bool(st_line.partner_id.id),
|
||||
}
|
||||
if statement_currency.id != company_currency.id and line.currency_id and line.currency_id.id == statement_currency.id:
|
||||
st_line_currency = st_line.currency_id or statement_currency
|
||||
if st_line.currency_id and line.currency_id and line.currency_id.id == st_line.currency_id.id:
|
||||
if line.amount_residual_currency < 0:
|
||||
ret_line['debit'] = 0
|
||||
ret_line['credit'] = -line.amount_residual_currency
|
||||
|
@ -613,21 +657,46 @@ class account_bank_statement_line(osv.osv):
|
|||
ret_line['credit'] = line.amount_residual if line.debit != 0 else 0
|
||||
ctx = context.copy()
|
||||
ctx.update({'date': st_line.date})
|
||||
ret_line['debit'] = currency_obj.compute(cr, uid, statement_currency.id, company_currency.id, ret_line['debit'], context=ctx)
|
||||
ret_line['credit'] = currency_obj.compute(cr, uid, statement_currency.id, company_currency.id, ret_line['credit'], context=ctx)
|
||||
ret_line['debit_str'] = rml_parser.formatLang(ret_line['debit'], currency_obj=statement_currency)
|
||||
ret_line['credit_str'] = rml_parser.formatLang(ret_line['credit'], currency_obj=statement_currency)
|
||||
ret_line['debit'] = currency_obj.compute(cr, uid, st_line_currency.id, company_currency.id, ret_line['debit'], context=ctx)
|
||||
ret_line['credit'] = currency_obj.compute(cr, uid, st_line_currency.id, company_currency.id, ret_line['credit'], context=ctx)
|
||||
ret_line['debit_str'] = rml_parser.formatLang(ret_line['debit'], currency_obj=st_line_currency)
|
||||
ret_line['credit_str'] = rml_parser.formatLang(ret_line['credit'], currency_obj=st_line_currency)
|
||||
ret.append(ret_line)
|
||||
if line.reconcile_partial_id:
|
||||
reconcile_partial_ids.append(line.reconcile_partial_id.id)
|
||||
return ret
|
||||
|
||||
def get_currency_rate_line(self, cr, uid, st_line, currency_diff, move_id, context=None):
|
||||
if currency_diff < 0:
|
||||
account_id = st_line.company_id.expense_currency_exchange_account_id.id
|
||||
if not account_id:
|
||||
raise osv.except_osv(_('Insufficient Configuration!'), _("You should configure the 'Loss Exchange Rate Account' in the accounting settings, to manage automatically the booking of accounting entries related to differences between exchange rates."))
|
||||
else:
|
||||
account_id = st_line.company_id.income_currency_exchange_account_id.id
|
||||
if not account_id:
|
||||
raise osv.except_osv(_('Insufficient Configuration!'), _("You should configure the 'Gain Exchange Rate Account' in the accounting settings, to manage automatically the booking of accounting entries related to differences between exchange rates."))
|
||||
return {
|
||||
'move_id': move_id,
|
||||
'name': _('change') + ': ' + (st_line.name or '/'),
|
||||
'period_id': st_line.statement_id.period_id.id,
|
||||
'journal_id': st_line.journal_id.id,
|
||||
'partner_id': st_line.partner_id.id,
|
||||
'company_id': st_line.company_id.id,
|
||||
'statement_id': st_line.statement_id.id,
|
||||
'debit': currency_diff < 0 and -currency_diff or 0,
|
||||
'credit': currency_diff > 0 and currency_diff or 0,
|
||||
'date': st_line.date,
|
||||
'account_id': account_id
|
||||
}
|
||||
|
||||
def process_reconciliation(self, cr, uid, id, mv_line_dicts, context=None):
|
||||
""" Creates a move line for each item of mv_line_dicts and for the statement line. Reconcile a new move line with its counterpart_move_line_id if specified. Finally, mark the statement line as reconciled by putting the newly created move id in the column journal_entry_id.
|
||||
|
||||
:param int id: id of the bank statement line
|
||||
:param list of dicts mv_line_dicts: move lines to create. If counterpart_move_line_id is specified, reconcile with it
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
st_line = self.browse(cr, uid, id, context=context)
|
||||
company_currency = st_line.journal_id.company_id.currency_id
|
||||
statement_currency = st_line.journal_id.currency or company_currency
|
||||
|
@ -637,7 +706,7 @@ class account_bank_statement_line(osv.osv):
|
|||
currency_obj = self.pool.get('res.currency')
|
||||
|
||||
# Checks
|
||||
if st_line.journal_entry_id.id != False:
|
||||
if st_line.journal_entry_id.id:
|
||||
raise osv.except_osv(_('Error!'), _('The bank statement line was already reconciled.'))
|
||||
for mv_line_dict in mv_line_dicts:
|
||||
for field in ['debit', 'credit', 'amount_currency']:
|
||||
|
@ -657,37 +726,50 @@ class account_bank_statement_line(osv.osv):
|
|||
amount = currency_obj.compute(cr, uid, st_line.statement_id.currency.id, company_currency.id, st_line.amount, context=context)
|
||||
bank_st_move_vals = bs_obj._prepare_bank_move_line(cr, uid, st_line, move_id, amount, company_currency.id, context=context)
|
||||
aml_obj.create(cr, uid, bank_st_move_vals, context=context)
|
||||
st_line_currency_rate = bank_st_move_vals['amount_currency'] and statement_currency.id == company_currency.id and (bank_st_move_vals['amount_currency'] / st_line.amount) or False
|
||||
st_line_currency = bank_st_move_vals['currency_id']
|
||||
# Complete the dicts
|
||||
st_line_statement_id = st_line.statement_id.id
|
||||
st_line_journal_id = st_line.journal_id.id
|
||||
st_line_partner_id = st_line.partner_id.id
|
||||
st_line_company_id = st_line.company_id.id
|
||||
st_line_period_id = st_line.statement_id.period_id.id
|
||||
st_line_currency = st_line.currency_id or statement_currency
|
||||
st_line_currency_rate = st_line.currency_id and statement_currency.id == company_currency.id and (st_line.amount_currency / st_line.amount) or False
|
||||
to_create = []
|
||||
for mv_line_dict in mv_line_dicts:
|
||||
mv_line_dict['ref'] = move_name
|
||||
mv_line_dict['move_id'] = move_id
|
||||
mv_line_dict['period_id'] = st_line_period_id
|
||||
mv_line_dict['journal_id'] = st_line_journal_id
|
||||
mv_line_dict['partner_id'] = st_line_partner_id
|
||||
mv_line_dict['company_id'] = st_line_company_id
|
||||
mv_line_dict['statement_id'] = st_line_statement_id
|
||||
mv_line_dict['period_id'] = st_line.statement_id.period_id.id
|
||||
mv_line_dict['journal_id'] = st_line.journal_id.id
|
||||
mv_line_dict['company_id'] = st_line.company_id.id
|
||||
mv_line_dict['statement_id'] = st_line.statement_id.id
|
||||
if mv_line_dict.get('counterpart_move_line_id'):
|
||||
mv_line = aml_obj.browse(cr, uid, mv_line_dict['counterpart_move_line_id'], context=context)
|
||||
mv_line_dict['account_id'] = mv_line.account_id.id
|
||||
if statement_currency.id != company_currency.id:
|
||||
if st_line_currency.id != company_currency.id:
|
||||
mv_line_dict['amount_currency'] = mv_line_dict['debit'] - mv_line_dict['credit']
|
||||
mv_line_dict['currency_id'] = statement_currency.id
|
||||
mv_line_dict['debit'] = currency_obj.compute(cr, uid, statement_currency.id, company_currency.id, mv_line_dict['debit'])
|
||||
mv_line_dict['credit'] = currency_obj.compute(cr, uid, statement_currency.id, company_currency.id, mv_line_dict['credit'])
|
||||
elif st_line_currency and st_line_currency_rate:
|
||||
mv_line_dict['amount_currency'] = self.pool.get('res.currency').round(cr, uid, st_line.currency_id, (mv_line_dict['debit'] - mv_line_dict['credit']) * st_line_currency_rate)
|
||||
mv_line_dict['currency_id'] = st_line_currency
|
||||
|
||||
mv_line_dict['currency_id'] = st_line_currency.id
|
||||
if st_line.currency_id and statement_currency.id == company_currency.id and st_line_currency_rate:
|
||||
debit_at_current_rate = self.pool.get('res.currency').round(cr, uid, company_currency, mv_line_dict['debit'] / st_line_currency_rate)
|
||||
credit_at_current_rate = self.pool.get('res.currency').round(cr, uid, company_currency, mv_line_dict['credit'] / st_line_currency_rate)
|
||||
else:
|
||||
debit_at_current_rate = currency_obj.compute(cr, uid, st_line_currency.id, company_currency.id, mv_line_dict['debit'], context=context)
|
||||
credit_at_current_rate = currency_obj.compute(cr, uid, st_line_currency.id, company_currency.id, mv_line_dict['credit'], context=context)
|
||||
if mv_line_dict.get('counterpart_move_line_id'):
|
||||
#post an account line that use the same currency rate than the counterpart (to balance the account) and post the difference in another line
|
||||
ctx = context.copy()
|
||||
ctx['date'] = mv_line.date
|
||||
debit_at_old_rate = currency_obj.compute(cr, uid, st_line_currency.id, company_currency.id, mv_line_dict['debit'], context=ctx)
|
||||
credit_at_old_rate = currency_obj.compute(cr, uid, st_line_currency.id, company_currency.id, mv_line_dict['credit'], context=ctx)
|
||||
mv_line_dict['credit'] = credit_at_old_rate
|
||||
mv_line_dict['debit'] = debit_at_old_rate
|
||||
if debit_at_old_rate - debit_at_current_rate:
|
||||
currency_diff = debit_at_current_rate - debit_at_old_rate
|
||||
to_create.append(self.get_currency_rate_line(cr, uid, st_line, currency_diff, move_id, context=context))
|
||||
if credit_at_old_rate - credit_at_current_rate:
|
||||
currency_diff = credit_at_current_rate - credit_at_old_rate
|
||||
to_create.append(self.get_currency_rate_line(cr, uid, st_line, currency_diff, move_id, context=context))
|
||||
else:
|
||||
mv_line_dict['debit'] = debit_at_current_rate
|
||||
mv_line_dict['credit'] = credit_at_current_rate
|
||||
to_create.append(mv_line_dict)
|
||||
# Create move lines
|
||||
move_line_pairs_to_reconcile = []
|
||||
for mv_line_dict in mv_line_dicts:
|
||||
for mv_line_dict in to_create:
|
||||
counterpart_move_line_id = None # NB : this attribute is irrelevant for aml_obj.create() and needs to be removed from the dict
|
||||
if mv_line_dict.get('counterpart_move_line_id'):
|
||||
counterpart_move_line_id = mv_line_dict['counterpart_move_line_id']
|
||||
|
@ -723,7 +805,7 @@ class account_bank_statement_line(osv.osv):
|
|||
'bank_account_id': fields.many2one('res.partner.bank','Bank Account'),
|
||||
'statement_id': fields.many2one('account.bank.statement', 'Statement', select=True, required=True, ondelete='cascade'),
|
||||
'journal_id': fields.related('statement_id', 'journal_id', type='many2one', relation='account.journal', string='Journal', store=True, readonly=True),
|
||||
'ref': fields.char('Reference', size=32),
|
||||
'ref': fields.char('Structured Communication'),
|
||||
'note': fields.text('Notes'),
|
||||
'sequence': fields.integer('Sequence', select=True, help="Gives the sequence order when displaying a list of bank statement lines."),
|
||||
'company_id': fields.related('statement_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True),
|
||||
|
|
|
@ -127,8 +127,8 @@ class account_move_line(osv.osv):
|
|||
|
||||
if move_line.reconcile_id:
|
||||
continue
|
||||
if not move_line.account_id.type in ('payable', 'receivable'):
|
||||
#this function does not suport to be used on move lines not related to payable or receivable accounts
|
||||
if not move_line.account_id.reconcile:
|
||||
#this function does not suport to be used on move lines not related to a reconcilable account
|
||||
continue
|
||||
|
||||
if move_line.currency_id:
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<field name="balance_end_real" eval="3707.58"/>
|
||||
</record>
|
||||
<record id="demo_bank_statement_line_1" model="account.bank.statement.line">
|
||||
<field name="ref">001</field>
|
||||
<field name="ref"></field>
|
||||
<field name="statement_id" ref="demo_bank_statement_1"/>
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
|
@ -26,7 +26,7 @@
|
|||
<field name="partner_id" ref="base.res_partner_9"/>
|
||||
</record>
|
||||
<record id="demo_bank_statement_line_2" model="account.bank.statement.line">
|
||||
<field name="ref">002</field>
|
||||
<field name="ref">SAJ2014002</field>
|
||||
<field name="statement_id" ref="demo_bank_statement_1"/>
|
||||
<field name="sequence" eval="2"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
|
@ -37,7 +37,7 @@
|
|||
<field name="partner_id" ref="base.res_partner_9"/>
|
||||
</record>
|
||||
<record id="demo_bank_statement_line_3" model="account.bank.statement.line">
|
||||
<field name="ref">003</field>
|
||||
<field name="ref"></field>
|
||||
<field name="statement_id" ref="demo_bank_statement_1"/>
|
||||
<field name="sequence" eval="3"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
|
@ -47,7 +47,7 @@
|
|||
<field name="date" eval="time.strftime('%Y')+'-01-01'"/>
|
||||
</record>
|
||||
<record id="demo_bank_statement_line_4" model="account.bank.statement.line">
|
||||
<field name="ref">004</field>
|
||||
<field name="ref"></field>
|
||||
<field name="statement_id" ref="demo_bank_statement_1"/>
|
||||
<field name="sequence" eval="4"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
|
|
|
@ -120,8 +120,6 @@
|
|||
cursor: pointer; }
|
||||
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line.no_match:not(.no_partner) .toggle_match {
|
||||
visibility: hidden !important; }
|
||||
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line.no_partner .partner_name, .openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line.no_partner .line_open_balance {
|
||||
display: none !important; }
|
||||
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line > table > tbody > tr:nth-child(1) > td table {
|
||||
margin-bottom: 10px; }
|
||||
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line table.details td:first-child {
|
||||
|
@ -202,10 +200,6 @@
|
|||
cursor: pointer; }
|
||||
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view td:nth-child(6) {
|
||||
border-left: 1px solid black; }
|
||||
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view tr.initial_line > td:nth-child(5) {
|
||||
border-top: 1px solid black; }
|
||||
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .accounting_view tr.initial_line > td:nth-child(6) {
|
||||
border-top: 1px solid black; }
|
||||
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match .match_controls {
|
||||
padding: 0 0 5px 18px; }
|
||||
.openerp .oe_bank_statement_reconciliation .oe_bank_statement_reconciliation_line .match .match_controls .filter {
|
||||
|
|
|
@ -194,12 +194,6 @@ $initialLineBackground: #f0f0f0;
|
|||
}
|
||||
}
|
||||
|
||||
&.no_partner {
|
||||
.partner_name, .line_open_balance {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* gap between accounting_view and action view */
|
||||
> table > tbody > tr:nth-child(1) > td table {
|
||||
margin-bottom: 10px;
|
||||
|
@ -341,10 +335,6 @@ $initialLineBackground: #f0f0f0;
|
|||
|
||||
// accounting "T"
|
||||
td:nth-child(6) { border-left: $accountingBorder; }
|
||||
tr.initial_line > td {
|
||||
&:nth-child(5) { border-top: $accountingBorder; }
|
||||
&:nth-child(6) { border-top: $accountingBorder; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -171,7 +171,7 @@ openerp.account = function (instance) {
|
|||
deferred_promises.push(self.model_bank_statement
|
||||
.call("get_format_currency_js_function", [self.statement_id])
|
||||
.then(function(data){
|
||||
self.formatCurrency = new Function("amount", data);
|
||||
self.formatCurrency = new Function("amount, currency_id", data);
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -245,7 +245,7 @@ openerp.account = function (instance) {
|
|||
|
||||
keyboardShortcutsHandler: function(e) {
|
||||
var self = this;
|
||||
if (e.which === 13 && (e.ctrlKey || e.metaKey)) {
|
||||
if ((e.which === 13 || e.which === 10) && (e.ctrlKey || e.metaKey)) {
|
||||
$.each(self.getChildren(), function(i, o){
|
||||
if (o.is_valid && o.persistAndDestroy()) {
|
||||
self.lines_reconciled_with_ctrl_enter++;
|
||||
|
@ -789,6 +789,9 @@ openerp.account = function (instance) {
|
|||
line.q_amount = (line.debit !== 0 ? "- "+line.q_debit : "") + (line.credit !== 0 ? line.q_credit : "");
|
||||
line.q_popover = QWeb.render("bank_statement_reconciliation_move_line_details", {line: line});
|
||||
line.q_label = line.name;
|
||||
if (line.has_no_partner){
|
||||
line.q_label = line.partner_name + ': ' +line.q_label;
|
||||
}
|
||||
|
||||
// WARNING : pretty much of a ugly hack
|
||||
// The value of account_move.ref is either the move's communication or it's name without the slashes
|
||||
|
@ -981,6 +984,7 @@ openerp.account = function (instance) {
|
|||
lineOpenBalanceClickHandler: function() {
|
||||
var self = this;
|
||||
if (self.get("mode") === "create") {
|
||||
self.addLineBeingEdited();
|
||||
self.set("mode", "match");
|
||||
} else {
|
||||
self.set("mode", "create");
|
||||
|
@ -1038,7 +1042,8 @@ openerp.account = function (instance) {
|
|||
var slice_start = self.get("pager_index") * self.max_move_lines_displayed;
|
||||
var slice_end = (self.get("pager_index")+1) * self.max_move_lines_displayed;
|
||||
_( _.filter(self.mv_lines_deselected, function(o){
|
||||
return o.name.indexOf(self.filter) !== -1 || o.ref.indexOf(self.filter) !== -1 })
|
||||
return o.q_label.indexOf(self.filter) !== -1 || (o.ref && o.ref.indexOf(self.filter) !== -1)
|
||||
})
|
||||
.slice(slice_start, slice_end)).each(function(line){
|
||||
var $line = $(QWeb.render("bank_statement_reconciliation_move_line", {line: line, selected: false}));
|
||||
self.bindPopoverTo($line.find(".line_info_button"));
|
||||
|
@ -1057,7 +1062,6 @@ openerp.account = function (instance) {
|
|||
|
||||
updatePagerControls: function() {
|
||||
var self = this;
|
||||
|
||||
if (self.get("pager_index") === 0)
|
||||
self.$(".pager_control_left").addClass("disabled");
|
||||
else
|
||||
|
@ -1075,7 +1079,7 @@ openerp.account = function (instance) {
|
|||
balanceChanged: function() {
|
||||
var self = this;
|
||||
var balance = self.get("balance");
|
||||
|
||||
self.$(".tbody_open_balance").empty();
|
||||
// Special case hack : no identified partner
|
||||
if (self.st_line.has_no_partner) {
|
||||
if (Math.abs(balance).toFixed(3) === "0.000") {
|
||||
|
@ -1088,19 +1092,23 @@ openerp.account = function (instance) {
|
|||
self.$(".button_ok").attr("disabled", "disabled");
|
||||
self.$(".button_ok").text("OK");
|
||||
self.is_valid = false;
|
||||
var debit = (balance > 0 ? self.formatCurrency(balance, self.st_line.currency_id) : "");
|
||||
var credit = (balance < 0 ? self.formatCurrency(-1*balance, self.st_line.currency_id) : "");
|
||||
var $line = $(QWeb.render("bank_statement_reconciliation_line_open_balance", {debit: debit, credit: credit, account_code: self.map_account_id_code[self.st_line.open_balance_account_id]}));
|
||||
$line.find('.js_open_balance')[0].innerHTML = "Choose counterpart";
|
||||
self.$(".tbody_open_balance").append($line);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
self.$(".tbody_open_balance").empty();
|
||||
if (Math.abs(balance).toFixed(3) === "0.000") {
|
||||
self.$(".button_ok").addClass("oe_highlight");
|
||||
self.$(".button_ok").text("OK");
|
||||
} else {
|
||||
self.$(".button_ok").removeClass("oe_highlight");
|
||||
self.$(".button_ok").text("Keep open");
|
||||
var debit = (balance > 0 ? self.formatCurrency(balance) : "");
|
||||
var credit = (balance < 0 ? self.formatCurrency(-1*balance) : "");
|
||||
var debit = (balance > 0 ? self.formatCurrency(balance, self.st_line.currency_id) : "");
|
||||
var credit = (balance < 0 ? self.formatCurrency(-1*balance, self.st_line.currency_id) : "");
|
||||
var $line = $(QWeb.render("bank_statement_reconciliation_line_open_balance", {debit: debit, credit: credit, account_code: self.map_account_id_code[self.st_line.open_balance_account_id]}));
|
||||
self.$(".tbody_open_balance").append($line);
|
||||
}
|
||||
|
@ -1111,21 +1119,15 @@ openerp.account = function (instance) {
|
|||
|
||||
self.$(".action_pane.active").removeClass("active");
|
||||
|
||||
// Special case hack : if no_partner, either inactive or create
|
||||
// Special case hack : if no_partner and mode == inactive
|
||||
if (self.st_line.has_no_partner) {
|
||||
if (self.get("mode") === "inactive") {
|
||||
self.$(".match").slideUp(self.animation_speed);
|
||||
self.$(".create").slideUp(self.animation_speed);
|
||||
self.$(".toggle_match").removeClass("visible_toggle");
|
||||
self.el.dataset.mode = "inactive";
|
||||
} else {
|
||||
self.initializeCreateForm();
|
||||
self.$(".match").slideUp(self.animation_speed);
|
||||
self.$(".create").slideDown(self.animation_speed);
|
||||
self.$(".toggle_match").addClass("visible_toggle");
|
||||
self.el.dataset.mode = "create";
|
||||
}
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (self.get("mode") === "inactive") {
|
||||
|
@ -1198,6 +1200,8 @@ openerp.account = function (instance) {
|
|||
var self = this;
|
||||
var line_created_being_edited = self.get("line_created_being_edited");
|
||||
line_created_being_edited[0][elt.corresponding_property] = val.newValue;
|
||||
|
||||
line_created_being_edited[0].currency_id = self.st_line.currency_id;
|
||||
|
||||
// Specific cases
|
||||
if (elt === self.account_id_field)
|
||||
|
@ -1215,7 +1219,7 @@ openerp.account = function (instance) {
|
|||
var tax = data.taxes[0];
|
||||
var tax_account_id = (amount > 0 ? tax.account_collected_id : tax.account_paid_id)
|
||||
line_created_being_edited[0].amount = (data.total.toFixed(3) === amount.toFixed(3) ? amount : data.total);
|
||||
line_created_being_edited[1] = {id: line_created_being_edited[0].id, account_id: tax_account_id, account_num: self.map_account_id_code[tax_account_id], label: tax.name, amount: tax.amount, no_remove_action: true};
|
||||
line_created_being_edited[1] = {id: line_created_being_edited[0].id, account_id: tax_account_id, account_num: self.map_account_id_code[tax_account_id], label: tax.name, amount: tax.amount, no_remove_action: true, currency_id: self.st_line.currency_id};
|
||||
}
|
||||
);
|
||||
} else {
|
||||
|
@ -1228,10 +1232,9 @@ openerp.account = function (instance) {
|
|||
$.when(deferred_tax).then(function(){
|
||||
// Format amounts
|
||||
if (line_created_being_edited[0].amount)
|
||||
line_created_being_edited[0].amount_str = self.formatCurrency(Math.abs(line_created_being_edited[0].amount));
|
||||
line_created_being_edited[0].amount_str = self.formatCurrency(Math.abs(line_created_being_edited[0].amount), line_created_being_edited[0].currency_id);
|
||||
if (line_created_being_edited[1] && line_created_being_edited[1].amount)
|
||||
line_created_being_edited[1].amount_str = self.formatCurrency(Math.abs(line_created_being_edited[1].amount));
|
||||
|
||||
line_created_being_edited[1].amount_str = self.formatCurrency(Math.abs(line_created_being_edited[1].amount), line_created_being_edited[0].currency_id);
|
||||
self.set("line_created_being_edited", line_created_being_edited);
|
||||
self.createdLinesChanged(); // TODO For some reason, previous line doesn't trigger change handler
|
||||
});
|
||||
|
@ -1268,10 +1271,10 @@ openerp.account = function (instance) {
|
|||
line.initial_amount = line.debit !== 0 ? line.debit : -1 * line.credit;
|
||||
if (balance < 0) {
|
||||
line.debit -= balance;
|
||||
line.debit_str = self.formatCurrency(line.debit);
|
||||
line.debit_str = self.formatCurrency(line.debit, self.st_line.currency_id);
|
||||
} else {
|
||||
line.credit -= balance;
|
||||
line.credit_str = self.formatCurrency(line.credit);
|
||||
line.credit_str = self.formatCurrency(line.credit, self.st_line.currency_id);
|
||||
}
|
||||
line.propose_partial_reconcile = false;
|
||||
line.partial_reconcile = true;
|
||||
|
@ -1291,12 +1294,13 @@ openerp.account = function (instance) {
|
|||
},
|
||||
|
||||
unpartialReconcileLine: function(line) {
|
||||
var self = this;
|
||||
if (line.initial_amount > 0) {
|
||||
line.debit = line.initial_amount;
|
||||
line.debit_str = this.formatCurrency(line.debit);
|
||||
line.debit_str = self.formatCurrency(line.debit, self.st_line.currency_id);
|
||||
} else {
|
||||
line.credit = -1 * line.initial_amount;
|
||||
line.credit_str = this.formatCurrency(line.credit);
|
||||
line.credit_str = self.formatCurrency(line.credit, self.st_line.currency_id);
|
||||
}
|
||||
line.propose_partial_reconcile = true;
|
||||
line.partial_reconcile = false;
|
||||
|
@ -1359,16 +1363,15 @@ openerp.account = function (instance) {
|
|||
if (limit > 0) {
|
||||
// Load move lines
|
||||
deferred_move_lines = self.model_bank_statement_line
|
||||
.call("get_move_lines_counterparts", [self.st_line.id, excluded_ids, self.filter, offset, limit])
|
||||
.call("get_move_lines_counterparts_id", [self.st_line.id, excluded_ids, self.filter, offset, limit])
|
||||
.then(function (lines) {
|
||||
_(lines).each(self.decorateMoveLine.bind(self));
|
||||
move_lines = lines;
|
||||
});
|
||||
}
|
||||
|
||||
// Fetch the number of move lines corresponding to this statement line and this filter
|
||||
var deferred_total_move_lines_num = self.model_bank_statement_line
|
||||
.call("get_move_lines_counterparts", [self.st_line.id, excluded_ids, self.filter, offset, limit, true])
|
||||
.call("get_move_lines_counterparts_id", [self.st_line.id, excluded_ids, self.filter, 0, undefined, true])
|
||||
.then(function(num){
|
||||
move_lines_num = num;
|
||||
});
|
||||
|
|
|
@ -185,7 +185,7 @@
|
|||
<td><span class="toggle_create glyphicon glyphicon-play"></span></td>
|
||||
<td><t t-esc="account_code"/></td>
|
||||
<td></td>
|
||||
<td>Open balance</td>
|
||||
<td class="js_open_balance">Open balance</td>
|
||||
<td><t t-esc="debit"/></td>
|
||||
<td><t t-esc="credit"/></td>
|
||||
<td></td>
|
||||
|
|
|
@ -59,25 +59,7 @@ A removal of one object in the CODA processing results in the removal of the
|
|||
associated objects. The removal of a CODA File containing multiple Bank
|
||||
Statements will also remove those associated statements.
|
||||
|
||||
The following reconciliation logic has been implemented in the CODA processing:
|
||||
-------------------------------------------------------------------------------
|
||||
1) The Company's Bank Account Number of the CODA statement is compared against
|
||||
the Bank Account Number field of the Company's CODA Bank Account
|
||||
configuration records (whereby bank accounts defined in type='info'
|
||||
configuration records are ignored). If this is the case an 'internal transfer'
|
||||
transaction is generated using the 'Internal Transfer Account' field of the
|
||||
CODA File Import wizard.
|
||||
2) As a second step the 'Structured Communication' field of the CODA transaction
|
||||
line is matched against the reference field of in- and outgoing invoices
|
||||
(supported : Belgian Structured Communication Type).
|
||||
3) When the previous step doesn't find a match, the transaction counterparty is
|
||||
located via the Bank Account Number configured on the OpenERP Customer and
|
||||
Supplier records.
|
||||
4) In case the previous steps are not successful, the transaction is generated
|
||||
by using the 'Default Account for Unrecognized Movement' field of the CODA
|
||||
File Import wizard in order to allow further manual processing.
|
||||
|
||||
In stead of a manual adjustment of the generated Bank Statements, you can also
|
||||
Instead of a manual adjustment of the generated Bank Statements, you can also
|
||||
re-import the CODA after updating the OpenERP database with the information that
|
||||
was missing to allow automatic reconciliation.
|
||||
|
||||
|
|
|
@ -28,46 +28,4 @@ class account_bank_statement(osv.osv):
|
|||
}
|
||||
|
||||
|
||||
class account_bank_statement_line(osv.osv):
|
||||
_inherit = 'account.bank.statement.line'
|
||||
_columns = {
|
||||
'coda_account_number': fields.char('Account Number', help="The Counter Party Account Number")
|
||||
}
|
||||
|
||||
def create(self, cr, uid, data, context=None):
|
||||
"""
|
||||
This function creates a Bank Account Number if, for a bank statement line,
|
||||
the partner_id field and the coda_account_number field are set,
|
||||
and the account number does not exist in the database
|
||||
"""
|
||||
if 'partner_id' in data and data['partner_id'] and 'coda_account_number' in data and data['coda_account_number']:
|
||||
acc_number_ids = self.pool.get('res.partner.bank').search(cr, uid, [('acc_number', '=', data['coda_account_number'])])
|
||||
if len(acc_number_ids) == 0:
|
||||
try:
|
||||
type_model, type_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'bank_normal')
|
||||
type_id = self.pool.get('res.partner.bank.type').browse(cr, uid, type_id, context=context)
|
||||
self.pool.get('res.partner.bank').create(cr, uid, {'acc_number': data['coda_account_number'], 'partner_id': data['partner_id'], 'state': type_id.code}, context=context)
|
||||
except ValueError:
|
||||
pass
|
||||
return super(account_bank_statement_line, self).create(cr, uid, data, context=context)
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
super(account_bank_statement_line, self).write(cr, uid, ids, vals, context)
|
||||
"""
|
||||
Same as create function above, but for write function
|
||||
"""
|
||||
if 'partner_id' in vals:
|
||||
for line in self.pool.get('account.bank.statement.line').browse(cr, uid, ids, context=context):
|
||||
if line.coda_account_number:
|
||||
acc_number_ids = self.pool.get('res.partner.bank').search(cr, uid, [('acc_number', '=', line.coda_account_number)])
|
||||
if len(acc_number_ids) == 0:
|
||||
try:
|
||||
type_model, type_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'bank_normal')
|
||||
type_id = self.pool.get('res.partner.bank.type').browse(cr, uid, type_id, context=context)
|
||||
self.pool.get('res.partner.bank').create(cr, uid, {'acc_number': line.coda_account_number, 'partner_id': vals['partner_id'], 'state': type_id.code}, context=context)
|
||||
except ValueError:
|
||||
pass
|
||||
return True
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -32,5 +32,27 @@
|
|||
<field eval="'2011-01-31'" name="date_stop"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
</record>
|
||||
|
||||
<!-- invoice with BBA -->
|
||||
<record id="coda_demo_invoice_1" model="account.invoice">
|
||||
<field name="currency_id" ref="base.EUR"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="journal_id" ref="account.sales_journal"/>
|
||||
<field name="period_id" ref="period_1_2011"/>
|
||||
<field name="state">draft</field>
|
||||
<field name="type">out_invoice</field>
|
||||
<field name="account_id" ref="account.a_recv"/>
|
||||
<field name="partner_id" ref="base.res_partner_9"/>
|
||||
<field name="reference_type">bba</field>
|
||||
<field name="reference">+++240/2838/42818+++</field>
|
||||
</record>
|
||||
<record id="invoice_1_line_1" model="account.invoice.line">
|
||||
<field name="name">Otpez Laptop without OS</field>
|
||||
<field name="invoice_id" ref="coda_demo_invoice_1"/>
|
||||
<field name="price_unit">608.89</field>
|
||||
<field name="quantity">10</field>
|
||||
<field name="account_id" ref="account.a_sale"/>
|
||||
</record>
|
||||
<workflow action="invoice_open" model="account.invoice" ref="coda_demo_invoice_1"/>
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
2200010000 GKCCBEBB 1 0
|
||||
2300010000BE41063012345610 PARTNER 1 0 1
|
||||
3100010001OL44483FW SCTOFBIONLO001010001001PARTNER 1 0 0
|
||||
2100020000OL4414AC8BOVSOVSOVERS00000000030444501101110015000002010237 11011113501 0
|
||||
2100020000OL4414AC8BOVSOVSOVERS0000000003044450110111001500001101240283842818 11011113501 0
|
||||
2200020000 BBRUBEBB 1 0
|
||||
2300020000BE61310126985517 PARTNER 2 0 1
|
||||
3100020001OL4414AC8BOVSOVSOVERS001500001001PARTNER 2 1 0
|
||||
|
|
|
@ -291,79 +291,38 @@ class account_coda_import(osv.osv_memory):
|
|||
if 'counterpartyAddress' in line and line['counterpartyAddress'] != '':
|
||||
note.append(_('Counter Party Address') + ': ' + line['counterpartyAddress'])
|
||||
line['name'] = "\n".join(filter(None, [line['counterpartyName'], line['communication']]))
|
||||
partner = None
|
||||
partner_id = None
|
||||
invoice = False
|
||||
structured_com = ""
|
||||
bank_account_id = False
|
||||
if line['communication_struct'] and 'communication_type' in line and line['communication_type'] == '101':
|
||||
ids = self.pool.get('account.invoice').search(cr, uid, [('reference', '=', line['communication']), ('reference_type', '=', 'bba')])
|
||||
|
||||
# Gère les communications structurées
|
||||
# TODO : à faire primer sur resolution_proposition : si la communication indique une facture, on la sélectionne
|
||||
|
||||
# if ids:
|
||||
# invoice = self.pool.get('account.invoice').browse(cr, uid, ids[0])
|
||||
# partner = invoice.partner_id
|
||||
# partner_id = partner.id
|
||||
# if invoice.type in ['in_invoice', 'in_refund'] and line['debit'] == '1':
|
||||
# line['transaction_type'] = 'supplier'
|
||||
# elif invoice.type in ['out_invoice', 'out_refund'] and line['debit'] == '0':
|
||||
# line['transaction_type'] = 'customer'
|
||||
# line['account'] = invoice.account_id.id
|
||||
# line['reconcile'] = False
|
||||
# if invoice.type in ['in_invoice', 'out_invoice']:
|
||||
# iml_ids = self.pool.get('account.move.line').search(cr, uid, [('move_id', '=', invoice.move_id.id), ('reconcile_id', '=', False), ('account_id.reconcile', '=', True)])
|
||||
# if iml_ids:
|
||||
# line['reconcile'] = iml_ids[0]
|
||||
# if line['reconcile']:
|
||||
# voucher_vals = {
|
||||
# 'type': line['transaction_type'] == 'supplier' and 'payment' or 'receipt',
|
||||
# 'name': line['name'],
|
||||
# 'partner_id': partner_id,
|
||||
# 'journal_id': statement['journal_id'].id,
|
||||
# 'account_id': statement['journal_id'].default_credit_account_id.id,
|
||||
# 'company_id': statement['journal_id'].company_id.id,
|
||||
# 'currency_id': statement['journal_id'].company_id.currency_id.id,
|
||||
# 'date': line['entryDate'],
|
||||
# 'amount': abs(line['amount']),
|
||||
# 'period_id': statement['period_id'],
|
||||
# 'invoice_id': invoice.id,
|
||||
# }
|
||||
# context['invoice_id'] = invoice.id
|
||||
# voucher_vals.update(self.pool.get('account.voucher').onchange_partner_id(cr, uid, [],
|
||||
# partner_id=partner_id,
|
||||
# journal_id=statement['journal_id'].id,
|
||||
# amount=abs(line['amount']),
|
||||
# currency_id=statement['journal_id'].company_id.currency_id.id,
|
||||
# ttype=line['transaction_type'] == 'supplier' and 'payment' or 'receipt',
|
||||
# date=line['transactionDate'],
|
||||
# context=context
|
||||
# )['value'])
|
||||
# line_drs = []
|
||||
# for line_dr in voucher_vals['line_dr_ids']:
|
||||
# line_drs.append((0, 0, line_dr))
|
||||
# voucher_vals['line_dr_ids'] = line_drs
|
||||
# line_crs = []
|
||||
# for line_cr in voucher_vals['line_cr_ids']:
|
||||
# line_crs.append((0, 0, line_cr))
|
||||
# voucher_vals['line_cr_ids'] = line_crs
|
||||
# line['voucher_id'] = self.pool.get('account.voucher').create(cr, uid, voucher_vals, context=context)
|
||||
structured_com = line['communication']
|
||||
if 'counterpartyNumber' in line and line['counterpartyNumber']:
|
||||
ids = self.pool.get('res.partner.bank').search(cr, uid, [('acc_number', '=', str(line['counterpartyNumber']))])
|
||||
if ids and len(ids) > 0:
|
||||
partner = self.pool.get('res.partner.bank').browse(cr, uid, ids[0], context=context).partner_id
|
||||
partner_id = partner.id
|
||||
if ids:
|
||||
bank_account_id = ids[0]
|
||||
partner_id = self.pool.get('res.partner.bank').browse(cr, uid, bank_account_id, context=context).partner_id.id
|
||||
else:
|
||||
#create the bank account, not linked to any partner. The reconciliation will link the partner manually
|
||||
#chosen at the bank statement final confirmation time.
|
||||
try:
|
||||
type_model, type_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'bank_normal')
|
||||
type_id = self.pool.get('res.partner.bank.type').browse(cr, uid, type_id, context=context)
|
||||
bank_code = type_id.code
|
||||
except ValueError:
|
||||
bank_code = 'bank'
|
||||
bank_account_id = self.pool.get('res.partner.bank').create(cr, uid, {'acc_number': str(line['counterpartyNumber']), 'state': bank_code}, context=context)
|
||||
if 'communication' in line and line['communication'] != '':
|
||||
note.append(_('Communication') + ': ' + line['communication'])
|
||||
data = {
|
||||
'name': line['name'],
|
||||
'note': "\n".join(note),
|
||||
'note': "\n".join(note),
|
||||
'date': line['entryDate'],
|
||||
'amount': line['amount'],
|
||||
'partner_id': partner_id,
|
||||
'statement_id': statement['id'],
|
||||
'ref': line['ref'],
|
||||
'ref': structured_com,
|
||||
'sequence': line['sequence'],
|
||||
'coda_account_number': line['counterpartyNumber'],
|
||||
'bank_account_id': bank_account_id,
|
||||
}
|
||||
self.pool.get('account.bank.statement.line').create(cr, uid, data, context=context)
|
||||
if statement['coda_note'] != '':
|
||||
|
|
|
@ -128,8 +128,7 @@ class res_partner_bank(osv.osv):
|
|||
change_default=True, domain="[('country_id','=',country_id)]"),
|
||||
'company_id': fields.many2one('res.company', 'Company',
|
||||
ondelete='cascade', help="Only if this bank account belong to your company"),
|
||||
'partner_id': fields.many2one('res.partner', 'Account Owner', required=True,
|
||||
ondelete='cascade', select=True),
|
||||
'partner_id': fields.many2one('res.partner', 'Account Owner', ondelete='cascade', select=True),
|
||||
'state': fields.selection(_bank_type_get, 'Bank Account Type', required=True,
|
||||
change_default=True),
|
||||
'sequence': fields.integer('Sequence'),
|
||||
|
|
Loading…
Reference in New Issue