Alexis de Lattre
8 years ago
9 changed files with 356 additions and 0 deletions
-
65account_bank_reconciliation_summary_xlsx/README.rst
-
4account_bank_reconciliation_summary_xlsx/__init__.py
-
18account_bank_reconciliation_summary_xlsx/__manifest__.py
-
3account_bank_reconciliation_summary_xlsx/models/__init__.py
-
22account_bank_reconciliation_summary_xlsx/models/account_bank_statement.py
-
3account_bank_reconciliation_summary_xlsx/report/__init__.py
-
200account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py
-
18account_bank_reconciliation_summary_xlsx/report/report.xml
-
23account_bank_reconciliation_summary_xlsx/views/account_bank_statement_view.xml
@ -0,0 +1,65 @@ |
|||||
|
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
||||
|
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html |
||||
|
:alt: License: AGPL-3 |
||||
|
|
||||
|
=============================== |
||||
|
Bank Reconciliation Report XLSX |
||||
|
=============================== |
||||
|
|
||||
|
This module adds a Bank Reconciliation Report in Odoo in XLSX format. For each bank journal, the report displays: |
||||
|
|
||||
|
1. The balance of the bank account in the accounting, |
||||
|
2. The list of journal items of the bank account not linked to any bank statement lines, |
||||
|
3. The list of draft bank statement lines not linked to any journal items, |
||||
|
4. The computed balance of the bank account at the bank. |
||||
|
|
||||
|
The last field (computed balance of the bank account at the bank) must be compared to the real bank account balance at the bank. If there is a difference, you need to find the erreor in the accounting. The field *Computed balance of the bank account at the bank* is a formula, so you can easily change its computation to try to find the difference with the real bank account balance at the bank. |
||||
|
|
||||
|
Configuration |
||||
|
============= |
||||
|
|
||||
|
This module doesn't require any configuration. |
||||
|
|
||||
|
Usage |
||||
|
===== |
||||
|
|
||||
|
You can get the Bank Reconciliation Report from: |
||||
|
|
||||
|
* the form view of a bank bournal: click on *Print > Bank Reconciliation XLSX* |
||||
|
* the tree view of journals: select one or several journals and click on *Print > Bank Reconciliation XLSX* (if you selected several bank journals, you will get one tab per journal) |
||||
|
* the form view of a bank statement: click on the button *Bank Reconciliation Report*. |
||||
|
|
||||
|
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas |
||||
|
:alt: Try me on Runbot |
||||
|
:target: https://runbot.odoo-community.org/runbot/91/10.0 |
||||
|
|
||||
|
Bug Tracker |
||||
|
=========== |
||||
|
|
||||
|
Bugs are tracked on `GitHub Issues |
||||
|
<https://github.com/OCA/account-financial-reporting/issues>`_. In case of trouble, please |
||||
|
check there if your issue has already been reported. If you spotted it first, |
||||
|
help us smashing it by providing a detailed and welcomed feedback. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Contributors |
||||
|
------------ |
||||
|
|
||||
|
* Alexis de Lattre <alexis.delattre@akretion.com> |
||||
|
|
||||
|
Maintainer |
||||
|
---------- |
||||
|
|
||||
|
.. image:: https://odoo-community.org/logo.png |
||||
|
:alt: Odoo Community Association |
||||
|
:target: https://odoo-community.org |
||||
|
|
||||
|
This module is maintained by the OCA. |
||||
|
|
||||
|
OCA, or the Odoo Community Association, is a nonprofit organization whose |
||||
|
mission is to support the collaborative development of Odoo features and |
||||
|
promote its widespread use. |
||||
|
|
||||
|
To contribute to this module, please visit https://odoo-community.org. |
@ -0,0 +1,4 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from . import models |
||||
|
from . import report |
@ -0,0 +1,18 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
{ |
||||
|
'name': 'Account Bank Statement Reconciliation Summary', |
||||
|
'version': '10.0.1.0.0', |
||||
|
'license': 'AGPL-3', |
||||
|
'author': "Akretion,Odoo Community Association (OCA)", |
||||
|
'website': 'http://www.akretion.com', |
||||
|
'summary': 'Adds an XLSX report to help on bank statement reconciliation', |
||||
|
'depends': ['account', 'report_xlsx'], |
||||
|
'data': [ |
||||
|
'report/report.xml', |
||||
|
'views/account_bank_statement_view.xml', |
||||
|
], |
||||
|
'installable': True, |
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from . import account_bank_statement |
@ -0,0 +1,22 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2017 Akretion France (Alexis de Lattre <alexis.delattre@akretion.com>) |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from odoo import models |
||||
|
|
||||
|
|
||||
|
class AccountBankStatement(models.Model): |
||||
|
_inherit = 'account.bank.statement' |
||||
|
|
||||
|
def print_reconciliation_xlsx(self): |
||||
|
self.ensure_one() |
||||
|
action = { |
||||
|
'type': 'ir.actions.report.xml', |
||||
|
'report_name': 'bank.reconciliation.xlsx', |
||||
|
'datas': { |
||||
|
'model': 'account.journal', |
||||
|
'ids': [self.journal_id.id], |
||||
|
}, |
||||
|
'context': self._context, |
||||
|
} |
||||
|
return action |
@ -0,0 +1,3 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from . import bank_reconciliation_xlsx |
@ -0,0 +1,200 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2017 Akretion France (Alexis de Lattre <alexis.delattre@akretion.com>) |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
|
||||
|
from odoo.addons.report_xlsx.report.report_xlsx import ReportXlsx |
||||
|
from odoo import _ |
||||
|
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT |
||||
|
from datetime import datetime |
||||
|
|
||||
|
|
||||
|
class BankReconciliationXlsx(ReportXlsx): |
||||
|
|
||||
|
def generate_xlsx_report(self, workbook, data, journals): |
||||
|
no_bank_journal = True |
||||
|
for o in journals.filtered(lambda o: o.type == 'bank'): |
||||
|
no_bank_journal = False |
||||
|
# Start styles |
||||
|
doc_title = workbook.add_format({'bold': True, 'font_size': 16}) |
||||
|
col_title = workbook.add_format({ |
||||
|
'bold': True, 'bg_color': '#e2e2fa', |
||||
|
'text_wrap': True, 'font_size': 10, |
||||
|
}) |
||||
|
title_right = workbook.add_format({ |
||||
|
'bold': True, 'bg_color': '#e6e6fa', |
||||
|
'font_size': 10, 'align': 'right', |
||||
|
}) |
||||
|
label_bold = workbook.add_format({ |
||||
|
'bold': True, 'text_wrap': False, 'font_size': 10}) |
||||
|
none = workbook.add_format({ |
||||
|
'bold': True, 'font_size': 10, 'align': 'right'}) |
||||
|
regular = workbook.add_format({'font_size': 10}) |
||||
|
lang_code = self.env.user.lang |
||||
|
lang = False |
||||
|
if lang_code: |
||||
|
lang = self.env['res.lang'].search([('code', '=', lang_code)]) |
||||
|
if not lang: |
||||
|
lang = self.env['res.lang'].search([], limit=1) |
||||
|
xls_date_format = lang.date_format.replace('%Y', 'yyyy').\ |
||||
|
replace('%m', 'mm').replace('%d', 'dd').replace('%y', 'yy') |
||||
|
if '%' in xls_date_format: |
||||
|
# fallback |
||||
|
xls_date_format = 'yyyy-mm-dd' |
||||
|
regular_date = workbook.add_format({ |
||||
|
'num_format': xls_date_format, |
||||
|
'font_size': 10, |
||||
|
'align': 'left'}) |
||||
|
cur_format = u'#%s##0%s00 %s' % ( |
||||
|
lang.thousands_sep or '', |
||||
|
lang.decimal_point or '', |
||||
|
o.company_id.currency_id.symbol or |
||||
|
o.company_id.currency_id.name) |
||||
|
regular_currency = workbook.add_format( |
||||
|
{'num_format': cur_format, 'font_size': 10}) |
||||
|
regular_currency_bg = workbook.add_format({ |
||||
|
'num_format': cur_format, 'font_size': 10, |
||||
|
'bg_color': '#f6f6ff'}) |
||||
|
# End styles |
||||
|
|
||||
|
sheet = workbook.add_worksheet(o.code or o.name) |
||||
|
sheet.write( |
||||
|
0, 0, _('%s - Bank Reconciliation') % o.display_name, |
||||
|
doc_title) |
||||
|
sheet.set_row(0, 26) |
||||
|
sheet.set_row(1, 25) |
||||
|
sheet.set_column(0, 0, 10) |
||||
|
sheet.set_column(1, 1, 40) |
||||
|
sheet.set_column(2, 2, 15) |
||||
|
sheet.set_column(3, 3, 25) |
||||
|
sheet.set_column(4, 4, 12) |
||||
|
sheet.set_column(5, 5, 14) |
||||
|
sheet.set_column(6, 6, 22) |
||||
|
row = 2 |
||||
|
sheet.write(row, 0, _("Date:"), label_bold) |
||||
|
# I can't use fields.Date.context_today(self) |
||||
|
sheet.write(row, 1, datetime.today(), regular_date) |
||||
|
# 1) Show accounting balance of bank account |
||||
|
bank_account = o.default_debit_account_id |
||||
|
sheet.write( |
||||
|
row, 3, |
||||
|
_('Balance %s:') % bank_account.code, title_right) |
||||
|
amount_field = 'balance' |
||||
|
# TODO: add support for bank accounts in foreign currency |
||||
|
# if not o.currency_id else 'amount_currency' |
||||
|
query = """ |
||||
|
SELECT sum(%s) FROM account_move_line |
||||
|
WHERE account_id=%%s""" % (amount_field,) |
||||
|
self.env.cr.execute(query, (bank_account.id,)) |
||||
|
query_results = self.env.cr.dictfetchall() |
||||
|
if query_results: |
||||
|
account_bal = query_results[0].get('sum') or 0.0 |
||||
|
else: |
||||
|
account_bal = 0.0 |
||||
|
|
||||
|
sheet.write(row, 4, account_bal, regular_currency_bg) |
||||
|
bank_bal = account_bal |
||||
|
formula = '=E%d' % (row + 1) |
||||
|
# 2) Show account move line that are not linked to bank account |
||||
|
row += 2 |
||||
|
sheet.write( |
||||
|
row, 0, _( |
||||
|
'Journal items of account %s not linked to a bank ' |
||||
|
'statement line:') % bank_account.code, |
||||
|
label_bold) |
||||
|
mlines = self.env['account.move.line'].search([ |
||||
|
('account_id', '=', bank_account.id), |
||||
|
('journal_id', '=', o.id), # to avoid initial line |
||||
|
('statement_id', '=', False)]) |
||||
|
if not mlines: |
||||
|
sheet.write(row, 4, _('NONE'), none) |
||||
|
else: |
||||
|
row += 1 |
||||
|
sheet.write(row, 0, _('Date'), col_title) |
||||
|
sheet.write(row, 1, _('Label'), col_title) |
||||
|
sheet.write(row, 2, _('Ref.'), col_title) |
||||
|
sheet.write(row, 3, _('Partner'), col_title) |
||||
|
sheet.write(row, 4, _('Amount'), col_title) |
||||
|
sheet.write(row, 5, _('Move Number'), col_title) |
||||
|
sheet.write(row, 6, _('Counter-part'), col_title) |
||||
|
m_start_row = m_end_row = row + 1 |
||||
|
for mline in mlines: |
||||
|
row += 1 |
||||
|
m_end_row = row |
||||
|
move = mline.move_id |
||||
|
bank_bal -= mline.balance |
||||
|
date_dt = datetime.strptime( |
||||
|
mline.date, DEFAULT_SERVER_DATE_FORMAT) |
||||
|
sheet.write(row, 0, date_dt, regular_date) |
||||
|
sheet.write(row, 1, mline.name, regular) |
||||
|
sheet.write(row, 2, mline.ref or '', regular) |
||||
|
sheet.write( |
||||
|
row, 3, mline.partner_id.display_name or '', regular) |
||||
|
sheet.write(row, 4, mline.balance, regular_currency) |
||||
|
sheet.write(row, 5, move.name, regular) |
||||
|
# counter-part accounts |
||||
|
cpart = [] |
||||
|
for line in move.line_ids: |
||||
|
if ( |
||||
|
line.account_id != bank_account and |
||||
|
line.account_id.code not in cpart): |
||||
|
cpart.append(line.account_id.code) |
||||
|
sheet.write(row, 6, ' ,'.join(cpart), regular) |
||||
|
|
||||
|
formula += '-SUM(E%d:E%d)' % (m_start_row + 1, m_end_row + 1) |
||||
|
|
||||
|
# 3) Add draft bank statement lines |
||||
|
row += 2 # skip 1 line |
||||
|
sheet.write( |
||||
|
row, 0, _( |
||||
|
'Draft bank statement lines:'), |
||||
|
label_bold) |
||||
|
blines = self.env['account.bank.statement.line'].search([ |
||||
|
('journal_entry_ids', '=', False), |
||||
|
('journal_id', '=', o.id)]) |
||||
|
if not blines: |
||||
|
sheet.write(row, 4, _('NONE'), none) |
||||
|
else: |
||||
|
row += 1 |
||||
|
sheet.write(row, 0, _('Date'), col_title) |
||||
|
sheet.write(row, 1, _('Label'), col_title) |
||||
|
sheet.write(row, 2, _('Ref.'), col_title) |
||||
|
sheet.write(row, 3, _('Partner'), col_title) |
||||
|
sheet.write(row, 4, _('Amount'), col_title) |
||||
|
sheet.write(row, 5, _('Statement Ref.'), col_title) |
||||
|
b_start_row = b_end_row = row + 1 |
||||
|
for bline in blines: |
||||
|
row += 1 |
||||
|
b_end_row = row |
||||
|
bank_bal += bline.amount |
||||
|
date_dt = datetime.strptime( |
||||
|
bline.date, DEFAULT_SERVER_DATE_FORMAT) |
||||
|
sheet.write(row, 0, date_dt, regular_date) |
||||
|
sheet.write(row, 1, bline.name, regular) |
||||
|
sheet.write(row, 2, bline.ref or '', regular) |
||||
|
sheet.write( |
||||
|
row, 3, bline.partner_id.display_name or '', regular) |
||||
|
sheet.write(row, 4, bline.amount, regular_currency) |
||||
|
sheet.write( |
||||
|
row, 5, bline.statement_id.name or '', |
||||
|
regular_currency) |
||||
|
formula += '+SUM(E%d:E%d)' % (b_start_row + 1, b_end_row + 1) |
||||
|
|
||||
|
# 4) Theoric bank account balance at the bank |
||||
|
row += 2 |
||||
|
sheet.write( |
||||
|
row, 3, _('Computed Bank Account Balance at the Bank:'), |
||||
|
title_right) |
||||
|
sheet.write_formula( |
||||
|
row, 4, formula, regular_currency_bg, bank_bal) |
||||
|
if no_bank_journal: |
||||
|
sheet = workbook.add_worksheet(_('No Bank Journal')) |
||||
|
sheet.set_row(0, 30) |
||||
|
warn_msg = workbook.add_format( |
||||
|
{'bold': True, 'font_size': 16, 'font_color': '#003b6f'}) |
||||
|
sheet.write( |
||||
|
0, 0, _( |
||||
|
"No bank journal selected. " |
||||
|
"This report is only for bank journals."), warn_msg) |
||||
|
|
||||
|
|
||||
|
BankReconciliationXlsx('report.bank.reconciliation.xlsx', 'account.journal') |
@ -0,0 +1,18 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<!-- |
||||
|
© 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
||||
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
--> |
||||
|
|
||||
|
<odoo> |
||||
|
|
||||
|
<report |
||||
|
id="bank_reconciliation_xlsx" |
||||
|
model="account.journal" |
||||
|
string="Bank Reconciliation XLSX" |
||||
|
report_type="xlsx" |
||||
|
name="bank.reconciliation.xlsx" |
||||
|
file="bank.reconciliation.xlsx" |
||||
|
/> |
||||
|
|
||||
|
</odoo> |
@ -0,0 +1,23 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<!-- |
||||
|
© 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>) |
||||
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). |
||||
|
--> |
||||
|
|
||||
|
<odoo> |
||||
|
|
||||
|
|
||||
|
<record id="view_bank_statement_form" model="ir.ui.view"> |
||||
|
<field name="name">bank_rec_summary.account.bank.statement.form</field> |
||||
|
<field name="model">account.bank.statement</field> |
||||
|
<field name="inherit_id" ref="account.view_bank_statement_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<button name="check_confirm_bank" position="after"> |
||||
|
<button name="print_reconciliation_xlsx" type="object" |
||||
|
string="Bank Reconciliation Report"/> |
||||
|
</button> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
|
||||
|
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue