Browse Source

add bank_statement_reconciliation_summary

pull/365/head
Jordi Ballester 7 years ago
parent
commit
cb5acc35b3
  1. 141
      bank_statement_reconciliation_summary/README.rst
  2. 3
      bank_statement_reconciliation_summary/__init__.py
  3. 20
      bank_statement_reconciliation_summary/__manifest__.py
  4. 3
      bank_statement_reconciliation_summary/report/__init__.py
  5. 33
      bank_statement_reconciliation_summary/report/report.xml
  6. 97
      bank_statement_reconciliation_summary/report/summary_report.py
  7. 221
      bank_statement_reconciliation_summary/report/summary_report.xml
  8. 3
      bank_statement_reconciliation_summary/wizard/__init__.py
  9. 42
      bank_statement_reconciliation_summary/wizard/bank_statement_reconciliation_summary_wizard.py
  10. 42
      bank_statement_reconciliation_summary/wizard/bank_statement_reconciliation_summary_wizard_view.xml

141
bank_statement_reconciliation_summary/README.rst

@ -0,0 +1,141 @@
.. 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 Statement Reconciliation Summary
=====================================
The Bank Reconciliation Summary shows how your actual bank statement balance
and the balance of the bank account in Odoo match, after taking into account
any unreconciled items.
This report is useful if your bank account's statement balance and balance
in Odoo do not match, and you need to check for duplicate or manually created
transactions that might cause the discrepancy.
This report was created, inspired by Xero’s bank reconciliation summary,
https://help.xero.com/Report_BankRec, and from a basic explanation of the
bank statement reconciliation summary:
http://www.accountingcoach.com/bank-reconciliation/explanation.
Usage
=====
Define Accounts
---------------
There are three accounts associated to a bank account:
* Bank account view
* Bank Account. Matches the statement
* Bank Clearing Account. Is used for uncleared payments and receipts. The
Bank Clearing Account is a reconcilable account.
In the definition of the bank account that is used to match with the bank
statement, define what will be the GL account used to record the uncleared
payments and receipts.
Define Account Journals
-----------------------
Create the following journals:
* Journal for Bank Statement reconciliation
* Journal to enter Payments and Receipts that have not yet cleared to the bank
Enter payments and receipts
---------------------------
Every time an invoice is paid, use the Journal to enter Payments and Receipts.
It will generate:
Dr. Accounts Payable
Cr. Bank Clearing Account
Create a bank statement
-----------------------
Create a bank statement and select the Journal defined for bank statement
reconciliation.
If you do not use a tool to integrate automatically the bank statement feed
into Odoo, you can press press the button “Import Payments and Receipts”
in order to add to the statements the payments and receipts that have been
generated, but that have not yet cleared the bank.
Use the “Reconcile” button to reconcile the entries in the bank statement
with the payments and receipts that have already cleared the bank.
If you chose to import the statement lines from uncleared payments and
receipts, this will be the moment where you will visually compare with the
online/paper bank statement, and reconcile the items that truly cleared the
bank.
The Odoo Bank Reconciliation Wizard will be used by the user to specifically
create the Bank Account entries by linking the Bank Statement lines with the
Bank Clearing Account items.
Dr. Bank Clearing Account
Cr. Bank Account
Once you have completed this process, some statement lines may be left
unreconciled (because they were truly not present in the online/physical
statement). In that case you can press the button “Remove Unreconciled”.
Print bank statement reconciliation summary
-------------------------------------------
It will report on the current balance of the Bank Account, and will show the
unreconciled entries of the Bank Clearing Account, classifying the them
between Outstanding Payments (that is, credits in the Bank Clearing Account)
and Outstanding Receipts (that is, debits in the Bank Clearing Account).
The application will also show the bank statement lines that have not yet
been reconciled yet, if any exists.
Once the user has fully processed the reconciliation with the bank clearing
account, all the entries in this bank clearing account should be reconciled,
and the bank account (used to match with the Statement) will truly
reflect the same information as the bank statement balance.
From a bank account perspective, the total amount held in the bank is the
sum of the balances of the bank clearing account (which should normally
show undeposited checks, for example) and the bank account used to match
with the statement.
.. 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/8.0
Known issues / Roadmap
======================
* For Odoo v9 there will be no need to use the clearing account.
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
`here <https://github.com/OCA/account-financial-reporting/issues/new?body=module:%20account_tax_report_no_zeroes%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits
=======
Contributors
------------
* Jordi Ballester Alomar <contact@eficent.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 http://odoo-community.org.

3
bank_statement_reconciliation_summary/__init__.py

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import report
from . import wizard

20
bank_statement_reconciliation_summary/__manifest__.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# Copyright 2016 Serpent Consulting Services Pvt. Ltd.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
'name': 'Bank Statement Reconciliation Summary',
'category': 'Account',
'summary': 'Bank Statement Reconciliation Summary',
'version': '10.0.1.0.0',
'author': 'Eficent, '
'Serpent Consulting Services Pvt. Ltd.,'
'Odoo Community Association (OCA)',
'depends': ['account'],
'data': [
'report/summary_report.xml',
'report/report.xml',
'wizard/bank_statement_reconciliation_summary_wizard_view.xml',
],
'installable': True,
}

3
bank_statement_reconciliation_summary/report/__init__.py

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
import summary_report

33
bank_statement_reconciliation_summary/report/report.xml

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record id="summary_report_paperformat" model="report.paperformat">
<field name="name">Bank Statement Reconcillation Summary Paperformat</field>
<field name="default" eval="True" />
<field name="format">A4</field>
<field name="page_height">0</field>
<field name="page_width">0</field>
<field name="orientation">Portrait</field>
<field name="margin_top">0</field>
<field name="margin_bottom">0</field>
<field name="margin_left">5</field>
<field name="margin_right">5</field>
<field name="header_line" eval="False" />
<field name="header_spacing">0</field>
<field name="dpi">90</field>
</record>
<report id="report_bank_stmt_reconcile_summary"
string="Bank Statement Reconcillation Summary"
model="bank.statement.reconciliation.summary.wizard"
report_type="qweb-pdf"
file="bank_statement_reconciliation_summary.summary_report"
name="bank_statement_reconciliation_summary.summary_report"/>
<record id="report_bank_stmt_reconcile_summary" model="ir.actions.report.xml">
<field name="paperformat_id" ref="summary_report_paperformat"/>
</record>
</data>
</openerp>

97
bank_statement_reconciliation_summary/report/summary_report.py

@ -0,0 +1,97 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# Copyright 2016 Serpent Consulting Services Pvt. Ltd.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
import time
from odoo import api, models, _
class SummaryReport(models.AbstractModel):
_name = 'report.bank_statement_reconciliation_summary.summary_report'
@api.model
def _plus_outstanding_payments(self, journals, end_date):
rec = {}
for journal in journals:
account_id = journal.default_debit_account_id.id
account_move_line_records = self.env['account.move.line'].search([
('account_id', '=', account_id),
('reconciled', '=', False),
('account_id.reconcile', '=', False),
('credit', '>', 0.00),
('date', '<=', end_date),
], order='date')
rec[journal.id] = account_move_line_records
return rec
@api.model
def _less_outstanding_receipts(self, journals, end_date):
rec = {}
for journal in journals:
account_id = journal.default_debit_account_id.id
account_move_line_records = self.env['account.move.line'].search([
('account_id', '=', account_id),
('reconciled', '=', False),
('account_id.reconcile', '=', False),
('debit', '>', 0.00),
('date', '<=', end_date),
], order='date')
rec[journal.id] = account_move_line_records
return rec
@api.model
def _plus_unreconciled_statement_lines(self, journals, end_date):
rec = {}
for journal in journals:
statement_lines = self.env['account.bank.statement.line'].search(
[('date', '<=', end_date),
('journal_id', '=', journal.id)])
for line in statement_lines:
if not line.journal_entry_ids:
statement_lines += line
rec[journal.id] = statement_lines or False
return rec
@api.model
def _get_bank_end_balance(self, journals, end_date):
rec = {}
for journal in journals:
bank_account = journal.default_credit_account_id
amount_field = 'balance'
query = """
SELECT sum(%s) FROM account_move_line
WHERE account_id=%%s
AND date<=%%s""" % (amount_field,)
self.env.cr.execute(query, (bank_account.id, end_date))
query_results = self.env.cr.dictfetchall()
if query_results:
account_bal = query_results[0].get('sum') or 0.0
else:
account_bal = 0.0
rec[journal.id] = account_bal
return rec
@api.multi
def render_html(self, docids, data=None):
Report = self.env['report']
report_name = 'bank_statement_reconciliation_summary.summary_report'
report = Report._get_report_from_name(report_name)
records = self.env['account.journal'].browse(docids)
docargs = {
'doc_ids': docids,
'doc_model': report.model,
'data': data,
'docs': records,
'time': time,
'plus_outstanding_payments':
self._plus_outstanding_payments(records, data['end_date']),
'less_outstanding_receipts':
self._less_outstanding_receipts(records, data['end_date']),
'plus_unreconciled_statement_lines':
self._plus_unreconciled_statement_lines(records,
data['end_date']),
'bank_end_balance': self._get_bank_end_balance(
records, data['end_date']),
'balance_end_real': data['balance_end_real']
}
return self.env['report'].render(report_name, docargs)

221
bank_statement_reconciliation_summary/report/summary_report.xml

@ -0,0 +1,221 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="summary_report">
<t t-call="report.html_container">
<t t-call="report.internal_layout">
<t t-foreach="docs" t-as="o">
<div class="page">
<link rel='stylesheet' href='/web/static/lib/bootstrap/css/bootstrap.css'/>
<style>
.lines {
border-top: solid;
border-top-width: 2px;
border-top-color: #edf3f8;
color: #5993c0;
}
</style>
<div class='row' style='background-color: #e6ffe6;box-shadow: 0px 2px 2px #cccccc;'>
<div style='padding:5px;'>
<div class='col-xs-3'><h4>Date</h4></div>
<div class='col-xs-3'><h4>Description</h4></div>
<div class='col-xs-3'><h4>Reference</h4></div>
<div class='col-xs-3 text-right'><h4>Amount</h4></div>
<div class='col-xs-3 text-right'><h4>Amount (foreign currency)</h4></div>
</div>
</div>
<div class='row mt16'>
<div class='col-xs-12'><h5><b><t t-esc='o.name'/> - Balance in Odoo</b></h5>
</div>
</div>
<t t-set='total_bank_odoo' t-value='0.00'/>
<div class='row lines'>
<div class='col-xs-12'>
<div class='col-xs-3'/>
<div class='col-xs-3'><t
t-esc='o.default_credit_account_id.code'/>-<t t-esc='o.default_credit_account_id.name'/></div>
<div class='col-xs-3'/>
<t t-set='total_bank_odoo'
t-value='bank_end_balance[o.id]'/>
<div class='col-xs-3 text-right'><t
t-esc='total_bank_odoo'
t-esc-options='{"widget": "monetary", "display_currency": "o.currency_id or o.company_id.currency_id"}'/></div>
<div class='col-xs-3'/>
</div>
</div>
<t t-set='total_bank_odoo' t-value='0.00'/>
<div class='row' style='border-top: groove;'>
<div class='col-xs-12'>
<div class='col-xs-3'/>
<div class='col-xs-6'><h5><b>Total Balance in Odoo</b></h5></div>
<div class='col-xs-3'/>
<t t-set='total_bank_odoo'
t-value='bank_end_balance[o.id]'/>
<div class='col-xs-3 text-right'>
<h5><b>
<t t-esc='total_bank_odoo'
t-esc-options='{"widget": "monetary", "display_currency": "o.currency_id or o.company_id.currency_id"}'/>
</b></h5></div>
<div class='col-xs-3'/>
</div>
</div>
<t t-set='total_payment' t-value='0.00'/>
<t t-if='plus_outstanding_payments[o.id]'>
<div class='row mt16'>
<div class='col-xs-12'><h5><b>Plus Outstanding Payments</b></h5></div>
</div>
<t t-foreach='plus_outstanding_payments[o.id]'
t-as='payment'>
<div class='row lines'>
<div class='col-xs-12'>
<div class='col-xs-3'><t t-esc='payment.date'/></div>
<div class='col-xs-3'><t t-esc='payment.name'/></div>
<div class='col-xs-3'><t t-esc='payment.ref'/></div>
<div class='col-xs-3 text-right'>
<t t-esc='payment.credit'/>
<t t-if="payment.amount_currency">
(
<t t-esc='payment.amount_currency'
t-esc-options='{"widget": "monetary", "display_currency": "payment.currency_id"}'/>
)
</t>
</div>
<t t-set='total_payment' t-value='total_payment + payment.credit'
t-esc-options='{"widget": "monetary", "display_currency": "o.currency_id or o.company_id.currency_id"}'/>
</div>
</div>
</t>
<div class='row' style='border-top: groove;'>
<div class='col-xs-12'>
<div class='col-xs-6'><h5><b>Total Outstanding Payments</b></h5></div>
<div class='col-xs-3 col-xs-offset-3 text-right'><h5><b><t t-esc='total_payment'
t-esc-options='{"widget": "monetary", "display_currency": "o.currency_id or o.company_id.currency_id"}'/></b></h5></div>
</div>
</div>
</t>
<t t-set='total_receipt' t-value='0.00'/>
<t t-if='less_outstanding_receipts[o.id]'>
<div class='row'>
<div class='col-xs-12'><h5><b>Less Outstanding Receipts</b></h5></div>
</div>
<t t-foreach='less_outstanding_receipts[o.id]'
t-as='receipt'>
<div class='row lines'>
<div class='col-xs-12'>
<div class='col-xs-3'><t t-esc='receipt.date'/></div>
<div class='col-xs-3'><t t-esc='receipt.name'/></div>
<div class='col-xs-3'><t t-esc='receipt.ref'/></div>
<div class='col-xs-3 text-right'>
<t t-esc='receipt.debit'/>
<t t-if='receipt.amount_currency'>
(
<t t-esc='receipt.amount_currency'
t-esc-options='{"widget": "monetary", "display_currency": "receipt.currency_id"}'/>
)
</t>
</div>
<t t-set='total_receipt' t-value='total_receipt + receipt.debit'
t-esc-options='{"widget": "monetary", "display_currency": "o.currency_id or o.company_id.currency_id"}'/>
</div>
</div>
</t>
<div class='row' style='border-top: groove;'>
<div class='col-xs-12'>
<div class='col-xs-6'><h5><b>Total Outstanding Receipts</b></h5></div>
<div class='col-xs-3 col-xs-offset-3 text-right'><h5><b><t t-esc='total_receipt'
t-esc-options='{"widget": "monetary", "display_currency": "o.currency_id or o.company_id.currency_id"}'/></b></h5></div>
</div>
</div>
</t>
<t t-set='bank_stmt_line_total' t-value='0.00'/>
<t t-if='plus_unreconciled_statement_lines[o.id]'>
<div class='row'>
<div class='col-xs-12'><h5><b>Plus Un-Reconciled Bank Statement Lines</b></h5></div>
</div>
<t t-foreach='plus_unreconciled_statement_lines[o.id]' t-as='line'>
<div class='row lines'>
<div class='col-xs-12'>
<div class='col-xs-3'><t t-esc='line.date'/></div>
<div class='col-xs-3'><t t-esc='line.name'/></div>
<div class='col-xs-3'><t t-esc='line.ref'/></div>
<div class='col-xs-3 text-right'>
<t t-esc='line.amount'
t-esc-options='{"widget": "monetary", "display_currency": "o.currency_id or o.company_id.currency_id"}'/>
<t t-if='line.amount_currency'>
(
<t t-esc='line.amount_currency'
t-esc-options='{"widget": "monetary", "display_currency": "line.currency_id or o.company_id.currency_id"}'/>
)
</t>
</div>
<t t-set='bank_stmt_line_total' t-value='bank_stmt_line_total + line.amount'
t-esc-options='{"widget": "monetary", "display_currency": "o.currency_id or o.company_id.currency_id"}'/>
</div>
</div>
</t>
<div class='row' style='border-top: groove;'>
<div class='col-xs-12'>
<div class='col-xs-6'><h5><b>Total Un-Reconciled Bank Statement Lines</b></h5></div>
<div class='col-xs-3 col-xs-offset-3 text-right'><h5><b><t t-esc='bank_stmt_line_total'
t-esc-options='{"widget": "monetary", "display_currency": "o.currency_id or o.company_id.currency_id"}'/></b></h5></div>
</div>
</div>
</t>
<t t-set='computed_statement_balance' t-value='total_bank_odoo + total_payment - total_receipt + bank_stmt_line_total'/>
<t
t-if='(balance_end_real - computed_statement_balance) == 0.0'>
<div class='row mt8' style='border-top: solid;border-bottom: solid;'>
<div class='col-xs-3'/>
<div class='col-xs-3'><h5><b>Statement Balance</b></h5></div>
<div class='col-xs-3'/>
<div class='col-xs-3 text-right'>
<t t-esc='computed_statement_balance'
t-esc-options='{"widget": "monetary", "display_currency": "o.currency_id or o.company_id.currency_id"}'/></div>
</div>
</t>
<t t-if='(balance_end_real - computed_statement_balance) != 0.0'>
<div class='row mt16'>
<div class='col-xs-12'><h5><b>Statement Balance</b></h5>
</div>
</div>
<div class='row lines'>
<div class='col-xs-12'>
<div class='col-xs-3'/>
<div class='col-xs-3'>Computed</div>
<div class='col-xs-3'/>
<div class='col-xs-3 text-right'>
<t t-esc='computed_statement_balance'
t-esc-options='{"widget": "monetary", "display_currency": "o.currency_id or o.company_id.currency_id"}'/></div>
</div>
</div>
<div class='row lines'>
<div class='col-xs-12'>
<div class='col-xs-3'/>
<div class='col-xs-3'>Actual</div>
<div class='col-xs-3'/>
<div class='col-xs-3 text-right'>
<t t-esc='balance_end_real'
t-esc-options='{"widget": "monetary", "display_currency": "o.currency_id or o.company_id.currency_id"}'/></div>
</div>
</div>
<div class='row lines'>
<div class='col-xs-12'>
<div class='col-xs-3'/>
<div class='col-xs-3'>Unencoded Statement Amount</div>
<div class='col-xs-3'/>
<div class='col-xs-3 text-right'>
<t t-esc='balance_end_real - computed_statement_balance'
t-esc-options='{"widget": "monetary", "display_currency": "o.currency_id or o.company_id.currency_id"}'/></div>
</div>
</div>
</t>
</div>
</t>
</t>
</t>
</template>
</data>
</odoo>

3
bank_statement_reconciliation_summary/wizard/__init__.py

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import bank_statement_reconciliation_summary_wizard

42
bank_statement_reconciliation_summary/wizard/bank_statement_reconciliation_summary_wizard.py

@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
class BankReconciliationReportWizard(models.TransientModel):
_name = "bank.statement.reconciliation.summary.wizard"
_description = "Bank Statement Reconciliation Summary Wizard"
@api.model
def _default_journal_id(self):
journal = self.env['account.journal'].search([
('type', '=', 'bank'),
('company_id', '=', self.env.user.company_id.id)], limit=1)
return journal
end_date = fields.Date(
required=True,
default=fields.Date.context_today)
journal_id = fields.Many2one(
'account.journal', string='Bank Journal',
domain=[('type', '=', 'bank')], required=True,
default=_default_journal_id)
balance_end_real = fields.Float('Bank Ending Balance')
def open_qweb(self):
action = {
'type': 'ir.actions.report.xml',
'report_name':
'bank_statement_reconciliation_summary.summary_report',
'docids': self.journal_id.ids,
'datas': {
'docids': self.journal_id.ids,
'ids': self.journal_id.ids,
'end_date': self.end_date,
'balance_end_real': self.balance_end_real,
},
'context': self._context,
}
return action

42
bank_statement_reconciliation_summary/wizard/bank_statement_reconciliation_summary_wizard_view.xml

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Eficent Business and IT Consulting Services, S.L.
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="bank_statement_reconciliation_summary_wizard_form"
model="ir.ui.view">
<field name="name">bank.statement.reconciliation.summary.wizard.form</field>
<field name="model">bank.statement.reconciliation.summary.wizard</field>
<field name="arch" type="xml">
<form string="Bank Reconciliation Report">
<group name="main">
<field name="end_date"/>
<field name="journal_id"/>
<field name="balance_end_real"/>
</group>
<footer>
<button name="open_qweb" string="Open" type="object"
class="btn-primary"/>
<button special="cancel" string="Cancel" class="oe_link"/>
</footer>
</form>
</field>
</record>
<record id="bank_statement_reconciliation_summary_action"
model="ir.actions.act_window">
<field name="name">Bank Statement Reconciliation</field>
<field name="res_model">bank.statement.reconciliation.summary.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<menuitem id="bank_statment_reconciliation_summary_wizard_menu"
action="bank_statement_reconciliation_summary_action" parent="account_financial_report_qweb.menu_oca_reports" groups="account.group_account_manager,account.group_account_user" sequence="100"/>
</odoo>
Loading…
Cancel
Save