Browse Source

Add OCA General/Partner Ledger PDF

pull/211/head
jcoux 9 years ago
parent
commit
af306bab1f
  1. 7
      account_financial_report_qweb/__openerp__.py
  2. 11
      account_financial_report_qweb/menuitems.xml
  3. 1
      account_financial_report_qweb/report/__init__.py
  4. 101
      account_financial_report_qweb/report/common.py
  5. 894
      account_financial_report_qweb/report/general_ledger.py
  6. 344
      account_financial_report_qweb/report/templates/general_ledger.xml
  7. 38
      account_financial_report_qweb/report/templates/layouts.xml
  8. 26
      account_financial_report_qweb/reports.xml
  9. 20
      account_financial_report_qweb/static/src/css/report.css
  10. 17
      account_financial_report_qweb/view/account_view.xml
  11. 2
      account_financial_report_qweb/wizard/__init__.py
  12. 96
      account_financial_report_qweb/wizard/general_ledger_wizard.py
  13. 97
      account_financial_report_qweb/wizard/general_ledger_wizard.xml
  14. 60
      account_financial_report_qweb/wizard/general_ledger_wizard_view.xml
  15. 54
      account_financial_report_qweb/wizard/ledger.sql
  16. 337
      account_financial_report_qweb/wizard/ledger_report_wizard.py
  17. 54
      account_financial_report_qweb/wizard/partner_ledger_wizard.xml

7
account_financial_report_qweb/__openerp__.py

@ -21,9 +21,8 @@
], ],
'data': [ 'data': [
'wizard/aged_partner_balance_wizard_view.xml', 'wizard/aged_partner_balance_wizard_view.xml',
'wizard/general_ledger_wizard.xml',
'wizard/general_ledger_wizard_view.xml',
'wizard/open_invoice_wizard_view.xml', 'wizard/open_invoice_wizard_view.xml',
'wizard/partner_ledger_wizard.xml',
'wizard/balance_common_wizard_view.xml', 'wizard/balance_common_wizard_view.xml',
'wizard/partner_balance_wizard_view.xml', 'wizard/partner_balance_wizard_view.xml',
'wizard/trial_balance_wizard_view.xml', 'wizard/trial_balance_wizard_view.xml',
@ -31,7 +30,9 @@
'menuitems.xml', 'menuitems.xml',
'reports.xml', 'reports.xml',
'report/templates/general_ledger.xml', 'report/templates/general_ledger.xml',
'report/templates/open_invoice_report.xml'
'report/templates/layouts.xml',
'report/templates/open_invoice_report.xml',
'view/account_view.xml'
], ],
'test': [ 'test': [
], ],

11
account_financial_report_qweb/menuitems.xml

@ -6,18 +6,13 @@
parent="account.menu_finance_reports" parent="account.menu_finance_reports"
id="menu_oca_reports" id="menu_oca_reports"
name="OCA reports" name="OCA reports"
groups="account.group_account_manager,account.group_account_user"
/> />
<menuitem <menuitem
parent="menu_oca_reports" parent="menu_oca_reports"
action="action_ledger_report_wizard"
id="menu_ledger_report_wizard"
/>
<menuitem
parent="menu_oca_reports"
action="action_partner_ledger_report_wizard"
id="menu_partner_ledger_report_wizard"
action="action_general_ledger_wizard"
id="menu_general_ledger_wizard"
/> />
<menuitem <menuitem

1
account_financial_report_qweb/report/__init__.py

@ -2,7 +2,6 @@
# © 2015 Yannick Vaucher (Camptocamp) # © 2015 Yannick Vaucher (Camptocamp)
# © 2016 Damien Crier (Camptocamp) # © 2016 Damien Crier (Camptocamp)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).- # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).-
from . import common
from . import general_ledger from . import general_ledger
from . import open_invoice from . import open_invoice
from . import general_ledger_xlsx from . import general_ledger_xlsx

101
account_financial_report_qweb/report/common.py

@ -1,101 +0,0 @@
# -*- encoding: utf-8 -*-
# © 2015 Yannick Vaucher
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import models, fields, api
class FinancialReportLine(models.AbstractModel):
"""Rappresentation of a report line."""
_name = 'financial.report.line'
_description = "Financial report line"
_order = 'account_id, date'
# TODO order by account_id.code
name = fields.Char()
ref = fields.Char()
date = fields.Date()
month = fields.Char()
partner_name = fields.Char()
partner_ref = fields.Char()
account_id = fields.Many2one('account.account')
account_code = fields.Char()
journal_id = fields.Many2one('account.journal')
currency_id = fields.Many2one('res.currency')
currency_code = fields.Char()
init_credit = fields.Float()
init_debit = fields.Float()
debit = fields.Float()
credit = fields.Float()
balance = fields.Float()
amount_currency = fields.Float()
cumul_credit = fields.Float()
cumul_debit = fields.Float()
cumul_balance = fields.Float()
cumul_balance_curr = fields.Float()
init_credit = fields.Float()
init_debit = fields.Float()
init_balance = fields.Float()
init_balance_curr = fields.Float()
debit_centralized = fields.Float()
credit_centralized = fields.Float()
balance_centralized = fields.Float()
balance_curr_centralized = fields.Float()
init_credit_centralized = fields.Float()
init_debit_centralized = fields.Float()
init_balance_centralized = fields.Float()
init_balance_curr_centralized = fields.Float()
move_name = fields.Char()
move_state = fields.Char()
invoice_number = fields.Char()
centralized = fields.Boolean()
class CommonFinancialReport(models.AbstractModel):
_name = 'account.report.common'
start_date = fields.Date()
end_date = fields.Date()
centralize = fields.Boolean()
target_move = fields.Char()
filter = fields.Selection(
[('filter_no', 'No Filters'),
('filter_date', 'Date'),
('filter_opening', 'Opening Only')],
"Filter by",
required=False,
help='Filter by date: no opening balance will be displayed. '
'(opening balance can only be computed based on period to be '
'correct).'
)
@api.multi
def _get_moves_from_dates_domain(self):
""" Prepare domain for `_get_moves_from_dates` """
domain = []
if self.centralize:
domain = [('centralized', '=', False)]
start_date = self.start_date
end_date = self.end_date
if start_date:
domain += [('date', '>=', start_date)]
if end_date:
domain += [('date', '<=', end_date)]
if self.target_move == 'posted':
domain += [('move_state', '=', 'posted')]
if self.account_ids:
domain += [('account_id', 'in', self.account_ids.ids)]
return domain

894
account_financial_report_qweb/report/general_ledger.py

@ -1,130 +1,802 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# © 2015 Yannick Vaucher (Camptocamp)
# © 2016 Julien Coux (Camptocamp)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import models, fields, api from openerp import models, fields, api
class FinancialReportLine(models.Model):
_inherit = 'financial.report.line'
_name = 'general.ledger.line'
_description = "General Ledger report line"
class GeneralLedgerReport(models.TransientModel):
""" Here, we just define class fields.
For methods, go more bottom at this file.
"""
_auto = False
_order = 'account_id, date'
_name = 'report_general_ledger_qweb'
@api.depends('invoice_number', 'name')
def _get_label(self):
for rec in self:
label = rec.name
if rec.invoice_number:
label += u' ({})'.format(rec.invoice_number)
rec.label = label
date_from = fields.Date()
date_to = fields.Date()
fy_start_date = fields.Date()
only_posted_moves = fields.Boolean()
hide_account_balance_at_0 = fields.Boolean()
company_id = fields.Many2one(comodel_name='res.company')
filter_account_ids = fields.Many2many(comodel_name='account.account')
filter_partner_ids = fields.Many2many(comodel_name='res.partner')
has_second_currency = fields.Boolean()
centralize = fields.Boolean()
show_cost_center = fields.Boolean(
default=lambda self: self.env.user.has_group(
'analytic.group_analytic_accounting'
)
)
label = fields.Char(compute='_get_label', readonly=True, store=False)
account_ids = fields.One2many(
comodel_name='report_general_ledger_qweb_account',
inverse_name='report_id'
)
class GeneralLedgerReport(models.TransientModel):
class GeneralLedgerReportAccount(models.TransientModel):
_name = 'report.account.report_generalledger_qweb'
_inherit = 'account.report.common'
_name = 'report_general_ledger_qweb_account'
_order = 'code ASC'
@api.multi
def _get_account_ids(self):
res = False
context = self.env.context
if (context.get('active_model') == 'account.account' and
context.get('active_ids')):
res = context['active_ids']
return res
report_id = fields.Many2one(
comodel_name='report_general_ledger_qweb',
ondelete='cascade',
index=True
)
account_id = fields.Many2one(
'account.account',
index=True
)
code = fields.Char()
name = fields.Char()
initial_debit = fields.Float(digits=(16, 2))
initial_credit = fields.Float(digits=(16, 2))
initial_balance = fields.Float(digits=(16, 2))
final_debit = fields.Float(digits=(16, 2))
final_credit = fields.Float(digits=(16, 2))
final_balance = fields.Float(digits=(16, 2))
is_partner_account = fields.Boolean()
move_line_ids = fields.One2many(
comodel_name='report_general_ledger_qweb_move_line',
inverse_name='report_account_id'
)
partner_ids = fields.One2many(
comodel_name='report_general_ledger_qweb_partner',
inverse_name='report_account_id'
)
class GeneralLedgerReportPartner(models.TransientModel):
_name = 'report_general_ledger_qweb_partner'
report_account_id = fields.Many2one(
comodel_name='report_general_ledger_qweb_account',
ondelete='cascade',
index=True
)
partner_id = fields.Many2one(
'res.partner',
index=True
)
name = fields.Char() name = fields.Char()
initial_balance = fields.Integer()
account_ids = fields.Many2many(
'account.account',
string='Filter on accounts',
default=_get_account_ids,
help="Only selected accounts will be printed. Leave empty to "
"print all accounts.")
journal_ids = fields.Many2many(
'account.journal',
string='Filter on jourvals',
help="Only selected journals will be printed. Leave empty to "
"print all journals.")
balance_mode = fields.Selection(
[('initial_balance', 'Initial balance'),
('opening_balance', 'Opening balance')]
)
display_account = fields.Char()
display_ledger_lines = fields.Boolean()
display_initial_balance = fields.Boolean()
MAPPING = {
'date_from': 'start_date',
'date_to': 'end_date',
initial_debit = fields.Float(digits=(16, 2))
initial_credit = fields.Float(digits=(16, 2))
initial_balance = fields.Float(digits=(16, 2))
final_debit = fields.Float(digits=(16, 2))
final_credit = fields.Float(digits=(16, 2))
final_balance = fields.Float(digits=(16, 2))
move_line_ids = fields.One2many(
comodel_name='report_general_ledger_qweb_move_line',
inverse_name='report_partner_id'
)
@api.model
def _generate_order_by(self, order_spec, query):
return """
ORDER BY
CASE
WHEN "report_general_ledger_qweb_partner"."partner_id" IS NOT NULL
THEN 0
ELSE 1
END,
"report_general_ledger_qweb_partner"."name"
"""
class GeneralLedgerReportMoveLine(models.TransientModel):
_name = 'report_general_ledger_qweb_move_line'
report_account_id = fields.Many2one(
comodel_name='report_general_ledger_qweb_account',
ondelete='cascade',
index=True
)
report_partner_id = fields.Many2one(
comodel_name='report_general_ledger_qweb_partner',
ondelete='cascade',
index=True
)
move_line_id = fields.Many2one('account.move.line')
date = fields.Date()
entry = fields.Char()
journal = fields.Char()
account = fields.Char()
partner = fields.Char()
label = fields.Char()
cost_center = fields.Char()
matching_number = fields.Char()
debit = fields.Float(digits=(16, 2))
credit = fields.Float(digits=(16, 2))
cumul_balance = fields.Float(digits=(16, 2))
currency_name = fields.Char()
amount_currency = fields.Float(digits=(16, 2))
class GeneralLedgerReportCompute(models.TransientModel):
_inherit = 'report_general_ledger_qweb'
@api.model
def print_report(self):
self.ensure_one()
self.compute_data_for_report()
return {
'type': 'ir.actions.report.xml',
'report_name':
'account_financial_report_qweb.report_general_ledger_qweb',
'datas': {'ids': [self.id]},
} }
@api.model @api.model
def _get_values_from_wizard(self, data):
""" Get values from wizard """
values = {}
for key, val in data.iteritems():
if key in self.MAPPING:
values[self.MAPPING[key]] = val
elif key == 'journal_ids':
if val:
values[key] = [(6, 0, val)]
else:
values[key] = val
return values
@api.multi
def _get_centralized_move_ids(self, domain):
""" Get last line of each selected centralized accounts """
# inverse search on centralized boolean to finish the search to get the
# ids of last lines of centralized accounts
# XXX USE DISTINCT to speed up ?
domain = domain[:]
centralize_index = domain.index(('centralized', '=', False))
domain[centralize_index] = ('centralized', '=', True)
gl_lines = self.env['general.ledger.line'].search(domain)
accounts = gl_lines.mapped('account_id')
line_ids = []
for acc in accounts:
acc_lines = gl_lines.filtered(lambda rec: rec.account_id == acc)
line_ids.append(acc_lines[-1].id)
return line_ids
@api.multi
def _get_moves_from_dates(self):
domain = self._get_moves_from_dates_domain()
def compute_data_for_report(self):
self.ensure_one()
self.inject_account_values()
self.inject_partner_values()
self.inject_line_not_centralized_values()
self.inject_line_not_centralized_values(is_account_line=False,
is_partner_line=True)
self.inject_line_not_centralized_values(is_account_line=False,
is_partner_line=True,
only_empty_partner_line=True)
if self.centralize: if self.centralize:
centralized_ids = self._get_centralized_move_ids(domain)
if centralized_ids:
domain.insert(0, '|')
domain.append(('id', 'in', centralized_ids))
return self.env['general.ledger.line'].search(domain)
@api.multi
def render_html(self, data=None):
report_name = 'account.report_generalledger_qweb'
if data is None:
return
values = self._get_values_from_wizard(data['form'])
report = self.create(values)
report_lines = report._get_moves_from_dates()
# TODO warning if no report_lines
self.env['report']._get_report_from_name(report_name)
docargs = {
'doc_ids': report.ids,
'doc_model': self._name,
'report_lines': report_lines,
'docs': report,
# XXX
'has_currency': True
}
return self.env['report'].render(report_name, docargs)
self.inject_line_centralized_values()
self.compute_has_second_currency()
def inject_account_values(self):
subquery_sum_amounts = """
SELECT
a.id AS account_id,
SUM(ml.debit) AS debit,
SUM(ml.credit) AS credit,
SUM(ml.balance) AS balance
FROM
accounts a
INNER JOIN
account_account_type at ON a.user_type_id = at.id
INNER JOIN
account_move_line ml
ON a.id = ml.account_id
AND ml.date <= %s
AND
(
at.include_initial_balance != TRUE AND ml.date >= %s
OR at.include_initial_balance = TRUE
)
"""
if self.only_posted_moves:
subquery_sum_amounts += """
INNER JOIN
account_move m ON ml.move_id = m.id AND m.state = 'posted'
"""
subquery_sum_amounts += """
GROUP BY
a.id
"""
query_inject_account = """
WITH
accounts AS
(
SELECT
a.id,
a.code,
a.name,
a.internal_type IN ('payable', 'receivable')
AS is_partner_account,
a.user_type_id
FROM
account_account a
"""
if self.filter_partner_ids:
query_inject_account += """
INNER JOIN
account_move_line ml ON a.id = ml.account_id
INNER JOIN
res_partner p ON ml.partner_id = p.id
"""
query_inject_account += """
WHERE
a.company_id = %s
"""
if self.filter_account_ids:
query_inject_account += """
AND
a.id IN %s
"""
if self.filter_partner_ids:
query_inject_account += """
AND
p.id IN %s
GROUP BY
a.id
"""
query_inject_account += """
),
initial_sum_amounts AS ( """ + subquery_sum_amounts + """ ),
final_sum_amounts AS ( """ + subquery_sum_amounts + """ )
INSERT INTO
report_general_ledger_qweb_account
(
report_id,
create_uid,
create_date,
account_id,
code,
name,
initial_debit,
initial_credit,
initial_balance,
final_debit,
final_credit,
final_balance,
is_partner_account
)
SELECT
%s AS report_id,
%s AS create_uid,
NOW() AS create_date,
a.id AS account_id,
a.code,
a.name,
COALESCE(i.debit, 0.0) AS initial_debit,
COALESCE(i.credit, 0.0) AS initial_credit,
COALESCE(i.balance, 0.0) AS initial_balance,
COALESCE(f.debit, 0.0) AS final_debit,
COALESCE(f.credit, 0.0) AS final_credit,
COALESCE(f.balance, 0.0) AS final_balance,
a.is_partner_account
FROM
accounts a
LEFT JOIN
initial_sum_amounts i ON a.id = i.account_id
LEFT JOIN
final_sum_amounts f ON a.id = f.account_id
WHERE
(
i.debit IS NOT NULL AND i.debit != 0
OR i.credit IS NOT NULL AND i.credit != 0
OR i.balance IS NOT NULL AND i.balance != 0
OR f.debit IS NOT NULL AND f.debit != 0
OR f.credit IS NOT NULL AND f.credit != 0
OR f.balance IS NOT NULL AND f.balance != 0
)
"""
if self.hide_account_balance_at_0:
query_inject_account += """
AND
f.balance IS NOT NULL AND f.balance != 0
"""
query_inject_account_params = (
self.company_id.id,
)
if self.filter_account_ids:
query_inject_account_params += (
tuple(self.filter_account_ids.ids),
)
if self.filter_partner_ids:
query_inject_account_params += (
tuple(self.filter_partner_ids.ids),
)
query_inject_account_params += (
self.date_from,
self.fy_start_date,
self.date_to,
self.fy_start_date,
self.id,
self.env.uid,
)
self.env.cr.execute(query_inject_account, query_inject_account_params)
def inject_partner_values(self):
subquery_sum_amounts = """
SELECT
ap.account_id AS account_id,
ap.partner_id AS partner_id,
SUM(ml.debit) AS debit,
SUM(ml.credit) AS credit,
SUM(ml.balance) AS balance
FROM
accounts_partners ap
INNER JOIN
account_move_line ml
ON ap.account_id = ml.account_id
AND (
ap.partner_id = ml.partner_id
OR ap.partner_id IS NULL AND ml.partner_id IS NULL
)
AND ml.date <= %s
AND (
ap.include_initial_balance != TRUE AND ml.date >= %s
OR ap.include_initial_balance = TRUE
)
"""
if self.only_posted_moves:
subquery_sum_amounts += """
INNER JOIN
account_move m ON ml.move_id = m.id AND m.state = 'posted'
"""
subquery_sum_amounts += """
GROUP BY
ap.account_id, ap.partner_id
"""
query_inject_partner = """
WITH
accounts_partners AS
(
SELECT
ra.id AS report_account_id,
a.id AS account_id,
at.include_initial_balance AS include_initial_balance,
p.id AS partner_id,
COALESCE(
CASE
WHEN
NULLIF(p.name, '') IS NOT NULL
AND NULLIF(p.ref, '') IS NOT NULL
THEN p.name || ' (' || p.ref || ')'
ELSE p.name
END,
'No partner allocated'
) AS partner_name
FROM
report_general_ledger_qweb_account ra
INNER JOIN
account_account a ON ra.account_id = a.id
INNER JOIN
account_account_type at ON a.user_type_id = at.id
INNER JOIN
account_move_line ml ON a.id = ml.account_id
LEFT JOIN
res_partner p ON ml.partner_id = p.id
WHERE
ra.report_id = %s
AND
ra.is_partner_account = TRUE
"""
if self.centralize:
query_inject_partner += """
AND
(a.centralized IS NULL OR a.centralized != TRUE)
"""
if self.filter_partner_ids:
query_inject_partner += """
AND
p.id IN %s
"""
query_inject_partner += """
GROUP BY
ra.id,
a.id,
p.id,
at.include_initial_balance
),
initial_sum_amounts AS ( """ + subquery_sum_amounts + """ ),
final_sum_amounts AS ( """ + subquery_sum_amounts + """ )
INSERT INTO
report_general_ledger_qweb_partner
(
report_account_id,
create_uid,
create_date,
partner_id,
name,
initial_debit,
initial_credit,
initial_balance,
final_debit,
final_credit,
final_balance
)
SELECT
ap.report_account_id,
%s AS create_uid,
NOW() AS create_date,
ap.partner_id,
ap.partner_name,
COALESCE(i.debit, 0.0) AS initial_debit,
COALESCE(i.credit, 0.0) AS initial_credit,
COALESCE(i.balance, 0.0) AS initial_balance,
COALESCE(f.debit, 0.0) AS final_debit,
COALESCE(f.credit, 0.0) AS final_credit,
COALESCE(f.balance, 0.0) AS final_balance
FROM
accounts_partners ap
LEFT JOIN
initial_sum_amounts i
ON
(
ap.partner_id = i.partner_id
OR ap.partner_id IS NULL AND i.partner_id IS NULL
)
AND ap.account_id = i.account_id
LEFT JOIN
final_sum_amounts f
ON
(
ap.partner_id = f.partner_id
OR ap.partner_id IS NULL AND f.partner_id IS NULL
)
AND ap.account_id = f.account_id
WHERE
(
i.debit IS NOT NULL AND i.debit != 0
OR i.credit IS NOT NULL AND i.credit != 0
OR i.balance IS NOT NULL AND i.balance != 0
OR f.debit IS NOT NULL AND f.debit != 0
OR f.credit IS NOT NULL AND f.credit != 0
OR f.balance IS NOT NULL AND f.balance != 0
)
"""
if self.hide_account_balance_at_0:
query_inject_partner += """
AND
f.balance IS NOT NULL AND f.balance != 0
"""
query_inject_partner_params = (
self.id,
)
if self.filter_partner_ids:
query_inject_partner_params += (
tuple(self.filter_partner_ids.ids),
)
query_inject_partner_params += (
self.date_from,
self.fy_start_date,
self.date_to,
self.fy_start_date,
self.env.uid,
)
print query_inject_partner_params
self.env.cr.execute(query_inject_partner, query_inject_partner_params)
def inject_line_not_centralized_values(self,
is_account_line=True,
is_partner_line=False,
only_empty_partner_line=False):
query_inject_move_line = """
INSERT INTO
report_general_ledger_qweb_move_line
(
"""
if is_account_line:
query_inject_move_line += """
report_account_id,
"""
elif is_partner_line:
query_inject_move_line += """
report_partner_id,
"""
query_inject_move_line += """
create_uid,
create_date,
move_line_id,
date,
entry,
journal,
account,
partner,
label,
cost_center,
matching_number,
debit,
credit,
cumul_balance,
currency_name,
amount_currency
)
SELECT
"""
if is_account_line:
query_inject_move_line += """
ra.id AS report_account_id,
"""
elif is_partner_line:
query_inject_move_line += """
rp.id AS report_partner_id,
"""
query_inject_move_line += """
%s AS create_uid,
NOW() AS create_date,
ml.id AS move_line_id,
ml.date,
m.name AS entry,
j.code AS journal,
a.code AS account,
"""
if not only_empty_partner_line:
query_inject_move_line += """
CASE
WHEN
NULLIF(p.name, '') IS NOT NULL
AND NULLIF(p.ref, '') IS NOT NULL
THEN p.name || ' (' || p.ref || ')'
ELSE p.name
END AS partner,
"""
elif only_empty_partner_line:
query_inject_move_line += """
'No partner allocated' AS partner,
"""
query_inject_move_line += """
CONCAT_WS(' - ', NULLIF(ml.ref, ''), NULLIF(ml.name, '')) AS label,
aa.name AS cost_center,
fr.name AS matching_number,
ml.debit,
ml.credit,
"""
if is_account_line:
query_inject_move_line += """
ra.initial_balance + (
SUM(ml.balance)
OVER (PARTITION BY a.code
ORDER BY a.code, ml.date, ml.id)
) AS cumul_balance,
"""
elif is_partner_line and not only_empty_partner_line:
query_inject_move_line += """
rp.initial_balance + (
SUM(ml.balance)
OVER (PARTITION BY a.code, p.name
ORDER BY a.code, p.name, ml.date, ml.id)
) AS cumul_balance,
"""
elif is_partner_line and only_empty_partner_line:
query_inject_move_line += """
rp.initial_balance + (
SUM(ml.balance)
OVER (PARTITION BY a.code
ORDER BY a.code, ml.date, ml.id)
) AS cumul_balance,
"""
query_inject_move_line += """
c.name AS currency_name,
ml.amount_currency
FROM
"""
if is_account_line:
query_inject_move_line += """
report_general_ledger_qweb_account ra
"""
elif is_partner_line:
query_inject_move_line += """
report_general_ledger_qweb_partner rp
INNER JOIN
report_general_ledger_qweb_account ra ON rp.report_account_id = ra.id
"""
query_inject_move_line += """
INNER JOIN
account_move_line ml ON ra.account_id = ml.account_id
INNER JOIN
account_move m ON ml.move_id = m.id
INNER JOIN
account_journal j ON ml.journal_id = j.id
INNER JOIN
account_account a ON ml.account_id = a.id
"""
if is_account_line:
query_inject_move_line += """
LEFT JOIN
res_partner p ON ml.partner_id = p.id
"""
elif is_partner_line and not only_empty_partner_line:
query_inject_move_line += """
INNER JOIN
res_partner p
ON ml.partner_id = p.id AND rp.partner_id = p.id
"""
query_inject_move_line += """
LEFT JOIN
account_full_reconcile fr ON ml.full_reconcile_id = fr.id
LEFT JOIN
res_currency c ON a.currency_id = c.id
LEFT JOIN
account_analytic_account aa ON ml.analytic_account_id = aa.id
WHERE
ra.report_id = %s
AND
"""
if is_account_line:
query_inject_move_line += """
(ra.is_partner_account IS NULL OR ra.is_partner_account != TRUE)
"""
elif is_partner_line:
query_inject_move_line += """
ra.is_partner_account = TRUE
"""
if self.centralize:
query_inject_move_line += """
AND
(a.centralized IS NULL OR a.centralized != TRUE)
"""
query_inject_move_line += """
AND
ml.date BETWEEN %s AND %s
"""
if self.only_posted_moves:
query_inject_move_line += """
AND
m.state = 'posted'
"""
if only_empty_partner_line:
query_inject_move_line += """
AND
ml.partner_id IS NULL
AND
rp.partner_id IS NULL
"""
if is_account_line:
query_inject_move_line += """
ORDER BY
a.code, ml.date, ml.id
"""
elif is_partner_line and not only_empty_partner_line:
query_inject_move_line += """
ORDER BY
a.code, p.name, ml.date, ml.id
"""
elif is_partner_line and only_empty_partner_line:
query_inject_move_line += """
ORDER BY
a.code, ml.date, ml.id
"""
self.env.cr.execute(
query_inject_move_line,
(self.env.uid,
self.id,
self.date_from,
self.date_to,)
)
def inject_line_centralized_values(self):
query_inject_move_line_centralized = """
WITH
move_lines AS
(
SELECT
ml.account_id,
(
DATE_TRUNC('month', ml.date) + interval '1 month'
- interval '1 day'
)::date AS date,
SUM(ml.debit) AS debit,
SUM(ml.credit) AS credit,
SUM(ml.balance) AS balance
FROM
report_general_ledger_qweb_account ra
INNER JOIN
account_move_line ml ON ra.account_id = ml.account_id
INNER JOIN
account_move m ON ml.move_id = m.id
INNER JOIN
account_account a ON ml.account_id = a.id
WHERE
ra.report_id = %s
AND
a.centralized = TRUE
AND
ml.date BETWEEN %s AND %s
"""
if self.only_posted_moves:
query_inject_move_line_centralized += """
AND
m.state = 'posted'
"""
query_inject_move_line_centralized += """
GROUP BY
ra.id, ml.account_id, a.code, 2
)
INSERT INTO
report_general_ledger_qweb_move_line
(
report_account_id,
create_uid,
create_date,
date,
account,
label,
debit,
credit,
cumul_balance
)
SELECT
ra.id AS report_account_id,
%s AS create_uid,
NOW() AS create_date,
ml.date,
a.code AS account,
'Centralized Entries' AS label,
ml.debit AS debit,
ml.credit AS credit,
ra.initial_balance + (
SUM(ml.balance)
OVER (PARTITION BY a.code ORDER BY ml.date)
) AS cumul_balance
FROM
report_general_ledger_qweb_account ra
INNER JOIN
move_lines ml ON ra.account_id = ml.account_id
INNER JOIN
account_account a ON ml.account_id = a.id
LEFT JOIN
res_currency c ON a.currency_id = c.id
WHERE
ra.report_id = %s
AND
(a.centralized IS NOT NULL AND a.centralized = TRUE)
ORDER BY
a.code, ml.date
"""
self.env.cr.execute(
query_inject_move_line_centralized,
(self.id,
self.date_from,
self.date_to,
self.env.uid,
self.id,)
)
def compute_has_second_currency(self):
query_update_has_second_currency = """
UPDATE
report_general_ledger_qweb
SET
has_second_currency =
(
SELECT
TRUE
FROM
report_general_ledger_qweb_move_line l
INNER JOIN
report_general_ledger_qweb_account a
ON l.report_account_id = a.id
WHERE
a.report_id = %s
AND l.currency_name IS NOT NULL
LIMIT 1
)
OR
(
SELECT
TRUE
FROM
report_general_ledger_qweb_move_line l
INNER JOIN
report_general_ledger_qweb_partner p
ON l.report_partner_id = p.id
INNER JOIN
report_general_ledger_qweb_account a
ON p.report_account_id = a.id
WHERE
a.report_id = %s
AND l.currency_name IS NOT NULL
LIMIT 1
)
WHERE id = %s
"""
params = (self.id,) * 3
self.env.cr.execute(query_update_has_second_currency, params)

344
account_financial_report_qweb/report/templates/general_ledger.xml

@ -1,110 +1,122 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<template id="assets_specific" inherit_id="report.assets_common">
<xpath expr="." position="inside">
<link href="/account_financial_report_qweb/static/src/css/report.css" rel="stylesheet"/>
</xpath>
</template>
<template id="account.report_generalledger_qweb">
<template id="account_financial_report_qweb.report_general_ledger_qweb">
<t t-call="report.html_container"> <t t-call="report.html_container">
<t t-set="data_report_margin_top" t-value="12"/>
<t t-set="data_report_header_spacing" t-value="9"/>
<t t-set="data_report_dpi" t-value="110"/>
<t t-foreach="docs" t-as="o"> <t t-foreach="docs" t-as="o">
<t t-set="show_cost_center" t-value="o.show_cost_center"/>
<t t-set="has_second_currency" t-value="o.has_second_currency"/>
<t t-call="report.internal_layout">
<t t-call="account_financial_report_qweb.internal_layout">
<t t-set="title" t-value='"General Ledger"'/>
<t t-set="company_name" t-value="o.company_id.name"/>
<div class="page"> <div class="page">
<div class="act_as_table data_table" style="width: 1205px">
<div class="act_as_table data_table" style="width: 1140px !important;">
<div class="act_as_row labels"> <div class="act_as_row labels">
<!--<div class="act_as_cell">Chart of Account</div>-->
<div class="act_as_cell">Fiscal Year</div>
<t t-if="o.start_date or o.end_date">
<div class="act_as_cell">Date range filter</div>
<div class="act_as_cell">Target moves filter</div>
<div class="act_as_cell">Account balance at 0 filter</div>
<div class="act_as_cell">Centralize filter</div>
</div>
<div class="act_as_row">
<div class="act_as_cell"> <div class="act_as_cell">
Dates Filter
From: <span t-field="o.date_from"/> To: <span t-field="o.date_to"/>
</div> </div>
</t>
<div class="act_as_cell">Accounts Filter</div>
<div class="act_as_cell">Journal Filter</div>
<div class="act_as_cell">Target Moves</div>
<div class="act_as_cell">
<t t-if="o.only_posted_moves">All posted entries</t>
<t t-if="not o.only_posted_moves">All entries</t>
</div> </div>
<div class="act_as_row">
<t t-if="o.start_date or o.end_date">
<div class="act_as_cell"> <div class="act_as_cell">
From:
<span t-field="o.start_date"/>
To:
<span t-field="o.end_date"/>
<t t-if="o.hide_account_balance_at_0">Hide</t>
<t t-if="not o.hide_account_balance_at_0">Show</t>
</div> </div>
</t>
<div class="act_as_cell"> <div class="act_as_cell">
<t t-if="o.account_ids">
<t t-raw="', '.join(o.account_ids.mapped('code'))"/>
<t t-if="o.centralize">Yes</t>
<t t-if="not o.centralize">No</t>
</div>
</div>
</div>
<t t-foreach="o.account_ids" t-as="account">
<div class="page_break">
<div class="act_as_table list_table" style="margin-top: 10px;"/>
<div class="act_as_caption account_title" style="width: 1141px !important;">
<span t-field="account.code"/> - <span t-field="account.name"/>
</div>
<t t-if="account.move_line_ids">
<t t-call="account_financial_report_qweb.report_general_ledger_qweb_lines">
<t t-set="account_or_partner_object" t-value="account"/>
</t> </t>
<t t-if="not o.account_ids">
All
</t> </t>
<t t-if="not account.move_line_ids">
<t t-if="account.is_partner_account">
<t t-foreach="account.partner_ids" t-as="partner">
<div class="page_break">
<div class="act_as_caption account_title">
<span t-field="partner.name"/>
</div> </div>
<div class="act_as_cell">
<t t-if="o.journal_ids">
<t t-raw="', '.join(o.journal_ids.mapped('code'))"/>
<t t-call="account_financial_report_qweb.report_general_ledger_qweb_lines">
<t t-set="account_or_partner_object" t-value="partner"/>
</t> </t>
<t t-if="not o.journal_ids">
All
<t t-call="account_financial_report_qweb.report_general_ledger_qweb_ending_cumul">
<t t-set="account_or_partner_object" t-value="partner"/>
<t t-set="type" t-value='"partner_type"'/>
</t> </t>
</div> </div>
<div class="act_as_cell"><span t-field="o.target_move"/></div>
</t>
</t>
</t>
<t t-call="account_financial_report_qweb.report_general_ledger_qweb_ending_cumul">
<t t-set="account_or_partner_object" t-value="account"/>
<t t-set="type" t-value='"account_type"'/>
</t>
</div> </div>
<t t-set="account" t-value="False"/>
<!-- we use div with css instead of table for tabular data because div do not cut rows at half at page breaks -->
<t t-foreach="report_lines" t-as="line">
<t t-if="account != line.account_id">
<t t-set="account" t-value="line.account_id"/>
&lt;div class="act_as_table list_table" style="margin-top: 10px;"&gt;
<div class="act_as_caption account_title">
<span t-field="account.code"/> - <span t-field="account.name"/>
</t>
</div> </div>
</t>
</t>
</t>
</template>
<template id="account_financial_report_qweb.report_general_ledger_qweb_lines">
<div class="act_as_table data_table" style="width: 1140px !important;">
<div class="act_as_thead"> <div class="act_as_thead">
<div class="act_as_row labels"> <div class="act_as_row labels">
<!--## date--> <!--## date-->
<div class="act_as_cell first_column" style="width: 50px;">Date</div>
<div class="act_as_cell first_column" style="width: 60px;">Date</div>
<!--## move--> <!--## move-->
<div class="act_as_cell" style="width: 100px;">Entry</div> <div class="act_as_cell" style="width: 100px;">Entry</div>
<!--## journal--> <!--## journal-->
<div class="act_as_cell" style="width: 70px;">Journal</div>
<div class="act_as_cell" style="width: 40px;">Journal</div>
<!--## account code--> <!--## account code-->
<div class="act_as_cell" style="width: 65px;">Account</div>
<div class="act_as_cell" style="width: 50px;">Account</div>
<!--## partner--> <!--## partner-->
<div class="act_as_cell" style="width: 140px;">Partner</div> <div class="act_as_cell" style="width: 140px;">Partner</div>
<!--## move reference-->
<div class="act_as_cell" style="width: 140px;">Reference</div>
<!--## label-->
<div class="act_as_cell" style="width: 160px;">Label</div>
<!--## ref - label-->
<div class="act_as_cell" style="width: 290px;">Ref - Label</div>
<t t-if="show_cost_center">
<!--## cost_center-->
<div class="act_as_cell" style="width: 100px;">Cost center</div>
</t>
<!--## matching_number-->
<div class="act_as_cell" style="width: 25px;">Rec.</div>
<!--## debit--> <!--## debit-->
<div class="act_as_cell amount" style="width: 75px;">Debit</div> <div class="act_as_cell amount" style="width: 75px;">Debit</div>
<!--## credit--> <!--## credit-->
<div class="act_as_cell amount" style="width: 75px;">Credit</div> <div class="act_as_cell amount" style="width: 75px;">Credit</div>
<!--## balance cumulated--> <!--## balance cumulated-->
<div class="act_as_cell amount" style="width: 75px;">Cumul. Bal.</div> <div class="act_as_cell amount" style="width: 75px;">Cumul. Bal.</div>
<t t-if="has_currency">
<!--## currency balance-->
<div class="act_as_cell amount sep_left" style="width: 75px;">Curr. Balance</div>
<!--## curency code-->
<div class="act_as_cell amount" style="width: 30px; text-align: right;">Curr.</div>
<t t-if="has_second_currency">
<!--## currency_name-->
<div class="act_as_cell" style="width: 35px;">Cur.</div>
<!--## amount_currency-->
<div class="act_as_cell amount" style="width: 75px;">Amount cur.</div>
</t> </t>
</div> </div>
</div> </div>
<t t-if="not account.user_type_id.include_initial_balance">
<t t-set="cumul_debit" t-value="0"/>
<t t-set="cumul_credit" t-value="0"/>
<t t-set="cumul_balance" t-value="0"/>
</t>
<!-- # init balance -->
<t t-if="account.user_type_id.include_initial_balance">
<div class="act_as_tbody">
<div class="act_as_row initial_balance">
<!-- # initial_balance line -->
<div class="act_as_row lines">
<!--## date--> <!--## date-->
<div class="act_as_cell first_column"></div>
<div class="act_as_cell"></div>
<!--## move--> <!--## move-->
<div class="act_as_cell"></div> <div class="act_as_cell"></div>
<!--## journal--> <!--## journal-->
@ -113,175 +125,101 @@
<div class="act_as_cell"></div> <div class="act_as_cell"></div>
<!--## partner--> <!--## partner-->
<div class="act_as_cell"></div> <div class="act_as_cell"></div>
<!--## move reference-->
<!--## ref - label-->
<div class="act_as_cell amount">Initial balance</div>
<t t-if="show_cost_center">
<!--## cost_center-->
<div class="act_as_cell"></div> <div class="act_as_cell"></div>
<!--## label-->
<div class="act_as_cell">Initial Balance</div>
<!--## debit-->
<div class="act_as_cell amount">
<t t-if="not line.centralized">
<span t-field="line.init_debit"/>
</t>
<t t-if="line.centralized">
<span t-field="line.init_debit_centralized"/>
</t> </t>
</div>
<!--## matching_number-->
<div class="act_as_cell"></div>
<!--## debit-->
<div class="act_as_cell amount"><span t-field="account_or_partner_object.initial_debit"/></div>
<!--## credit--> <!--## credit-->
<div class="act_as_cell amount">
<t t-if="not line.centralized">
<span t-field="line.init_credit"/>
</t>
<t t-if="line.centralized">
<span t-field="line.init_credit_centralized"/>
</t>
</div>
<div class="act_as_cell amount"><span t-field="account_or_partner_object.initial_credit"/></div>
<!--## balance cumulated--> <!--## balance cumulated-->
<div class="act_as_cell amount" style="padding-right: 1px;">
<t t-if="not line.centralized">
<span t-field="line.init_balance"/>
</t>
<t t-if="line.centralized">
<span t-field="line.init_balance"/>
</t>
</div>
<t t-if="has_currency">
<!--## currency balance-->
<div class="act_as_cell amount sep_left">
<t t-if="not line.centralized and account.currency_id">
<span t-field="line.init_balance_curr"/>
</t>
<t t-if="line.centralized and account.currency_id">
<span t-raw="line.init_balance_curr_centralized"/>
</t>
</div>
<!--## curency code-->
<div class="act_as_cell amount"></div>
<div class="act_as_cell amount"><span t-field="account_or_partner_object.initial_balance"/></div>
<t t-if="has_second_currency">
<!--## currency_name-->
<div class="act_as_cell"></div>
<!--## amount_currency-->
<div class="act_as_cell"></div>
</t> </t>
</div> </div>
</div>
</t>
</t>
<t t-foreach="account_or_partner_object.move_line_ids" t-as="line">
<!-- # lines or centralized lines --> <!-- # lines or centralized lines -->
<div class="act_as_row lines"> <div class="act_as_row lines">
<t t-if="not line.centralized">
<!--## date--> <!--## date-->
<div class="act_as_cell first_column"><span t-field="line.date"/></div>
<div class="act_as_cell left"><span t-field="line.date"/></div>
<!--## move--> <!--## move-->
<div class="act_as_cell"><span t-raw="line.move_name or ''"/></div>
<div class="act_as_cell left"><span t-field="line.entry"/></div>
<!--## journal--> <!--## journal-->
<div class="act_as_cell"><span t-field="line.journal_id.code"/></div>
<div class="act_as_cell left"><span t-field="line.journal"/></div>
<!--## account code--> <!--## account code-->
<div class="act_as_cell"><span t-field="account.code"/></div>
<div class="act_as_cell left"><span t-field="line.account"/></div>
<!--## partner--> <!--## partner-->
<div class="act_as_cell overflow_ellipsis"><span t-field="line.partner_name"/></div>
<!--## move reference-->
<div class="act_as_cell"><span t-field="line.ref"/></div>
<!--## label-->
<div class="act_as_cell"><span t-field="line.label"/></div>
<div class="act_as_cell left"><span t-field="line.partner"/></div>
<!--## ref - label-->
<div class="act_as_cell left"><span t-field="line.label"/></div>
<t t-if="show_cost_center">
<!--## cost_center-->
<div class="act_as_cell left"><span t-field="line.cost_center"/></div>
</t>
<!--## matching_number-->
<div class="act_as_cell"><span t-field="line.matching_number"/></div>
<!--## debit--> <!--## debit-->
<div class="act_as_cell amount"><span t-field="line.debit"/></div> <div class="act_as_cell amount"><span t-field="line.debit"/></div>
<!--## credit--> <!--## credit-->
<div class="act_as_cell amount"><span t-field="line.credit"/></div> <div class="act_as_cell amount"><span t-field="line.credit"/></div>
<!--## balance cumulated--> <!--## balance cumulated-->
<div class="act_as_cell amount" style="padding-right: 1px;">
<t t-if="not account.user_type_id.include_initial_balance">
<t t-set="cumul_debit" t-value="cumul_debit + line.debit"/>
<t t-set="cumul_credit" t-value="cumul_credit + line.credit"/>
<t t-set="cumul_balance" t-value="cumul_balance + line.balance"/>
<span t-raw="cumul_balance"/>
<div class="act_as_cell amount"><span t-field="line.cumul_balance"/></div>
<t t-if="has_second_currency">
<!--## currency_name-->
<div class="act_as_cell"><span t-field="line.currency_name"/></div>
<t t-if="line.currency_name">
<!--## amount_currency-->
<div class="act_as_cell amount"><span t-field="line.amount_currency"/></div>
</t>
<t t-if="not line.currency_name">
<!--## amount_currency-->
<div class="act_as_cell"></div>
</t> </t>
<t t-if="account.user_type_id.include_initial_balance">
<span t-field="line.cumul_balance"/>
</t> </t>
</div> </div>
<t t-if="has_currency">
<!--## currency balance-->
<div class="act_as_cell amount" style="padding-right: 1px;">
<span t-field="line.amount_currency"/>
</div>
<!--## curency code-->
<div class="act_as_cell amount" style="text-align: right;"><span t-field="line.currency_code"/></div>
</t>
</t>
<t t-if="line.centralized and line.period_last">
<!--## date-->
<div class="act_as_cell first_column"><span t-field="line.month"/></div>
<!--## move-->
<div class="act_as_cell">Month centralization</div>
<!--## journal-->
<div class="act_as_cell"><span t-field="line.journal_id.code"/></div>
<!--## account code-->
<div class="act_as_cell"><span t-field="account.code"/></div>
<!--## partner-->
<div class="act_as_cell overflow_ellipsis"><span t-field="line.partner_name"/> <span t-if="line.partner_ref" t-field="line.partner_ref"/></div>
<!--## move reference-->
<div class="act_as_cell"></div>
<!--## label-->
<div class="act_as_cell"></div>
<!--## debit-->
<div class="act_as_cell amount"><span t-field="line.debit_centralized"/></div>
<!--## credit-->
<div class="act_as_cell amount"><span t-field="line.credit_centralized"/></div>
<!--## balance cumulated-->
<div class="act_as_cell amount" style="padding-right: 1px;"><span t-field="line.cumul_balance"/></div>
<t t-if="has_currency">
<!--## currency balance-->
<div class="act_as_cell amount sep_left"><span t-if="account.currency_id" t-field="line.balance_curr_centralized"/></div>
<!--## curency code-->
<div class="act_as_cell amount" style="text-align: right;"><span t-field="line.currency_code"/></div>
</t>
</t> </t>
</div> </div>
<!-- # Total -->
</template>
<t t-if="(line_index + 1) == len(report_lines) or line.account_id != report_lines[line_index + 1].account_id">
<div class="act_as_table list_table">
<template id="account_financial_report_qweb.report_general_ledger_qweb_ending_cumul">
<div class="act_as_table list_table" style="width: 1141px !important;">
<div class="act_as_row labels" style="font-weight: bold;"> <div class="act_as_row labels" style="font-weight: bold;">
<!--## date--> <!--## date-->
<div class="act_as_cell first_column" style="width: 425;"><span t-field="account.code"/> - <span t-field="account.name"/></div>
<div class="act_as_cell" style="width: 300px;">Cumulated Balance on Account</div>
<!--## debit-->
<div class="act_as_cell amount" style="width: 75px;">
<t t-if="account.user_type_id.include_initial_balance">
<span t-field="line.cumul_debit"/>
<t t-if='type == "account_type"'>
<div class="act_as_cell first_column" style="width: 380px;"><span t-field="account_or_partner_object.code"/> - <span t-field="account_or_partner_object.name"/></div>
<div class="act_as_cell right" style="width: 290px;">Ending balance</div>
</t> </t>
<t t-if="not account.user_type_id.include_initial_balance">
<span t-raw="cumul_debit"/>
</t>
</div>
<!--## credit-->
<div class="act_as_cell amount" style="width: 75px;">
<t t-if="account.user_type_id.include_initial_balance">
<span t-field="line.cumul_credit"/>
<t t-if='type == "partner_type"'>
<div class="act_as_cell first_column" style="width: 380px;"></div>
<div class="act_as_cell right" style="width: 290px;">Partner ending balance</div>
</t> </t>
<t t-if="not account.user_type_id.include_initial_balance">
<span t-raw="cumul_credit"/>
<t t-if="show_cost_center">
<!--## cost_center-->
<div class="act_as_cell" style="width: 100px;"></div>
</t> </t>
</div>
<!--## matching_number-->
<div class="act_as_cell" style="width: 25px;"></div>
<!--## debit-->
<div class="act_as_cell amount" style="width: 75px;"><span t-field="account_or_partner_object.final_debit"/></div>
<!--## credit-->
<div class="act_as_cell amount" style="width: 75px;"><span t-field="account_or_partner_object.final_credit"/></div>
<!--## balance cumulated--> <!--## balance cumulated-->
<div class="act_as_cell amount" style="width: 75px; padding-right: 1px;">
<t t-if="account.user_type_id.include_initial_balance">
<span t-field="line.cumul_balance"/>
</t>
<t t-if="not account.user_type_id.include_initial_balance">
<span t-raw="cumul_balance"/>
<div class="act_as_cell amount" style="width: 75px; padding-right: 1px;"><span t-field="account_or_partner_object.final_balance"/></div>
<t t-if="has_second_currency">
<!--## currency_name + amount_currency-->
<div class="act_as_cell" style="width: 110px;"></div>
</t> </t>
</div> </div>
<t t-if="has_currency">
<!--## currency balance-->
<div class="act_as_cell amount sep_left" style="width: 75px;"><t t-if="account.currency_id"><span t-field="line.cumul_balance_curr"/></t></div>
<!--## curency code-->
<div class="act_as_cell amount" style="width: 30px; text-align: right;"></div>
</t>
</div>
&lt;/div&gt;
</div>
</t>
</t>
</div> </div>
</div>
</t>
</t>
</t>
</template> </template>
</odoo> </odoo>

38
account_financial_report_qweb/report/templates/layouts.xml

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="assets_specific" inherit_id="report.assets_common">
<xpath expr="." position="inside">
<link href="/account_financial_report_qweb/static/src/css/report.css" rel="stylesheet"/>
</xpath>
</template>
<template id="account_financial_report_qweb.internal_layout">
<div class="header">
<div class="row">
<div class="col-xs-6">
<span t-esc="title"/>
</div>
<div class="col-xs-6 text-right">
<span t-esc="company_name"/>
</div>
</div>
</div>
<t t-raw="0" />
<div class="footer">
<div class="row">
<div class="col-xs-6 custom_footer">
<span t-esc="context_timestamp(datetime.datetime.now()).strftime('%Y-%m-%d %H:%M')"/>
</div>
<div class="col-xs-6 text-right custom_footer">
<ul class="list-inline">
<li><span class="page"/></li>
<li>/</li>
<li><span class="topage"/></li>
</ul>
</div>
</div>
</div>
</template>
</odoo>

26
account_financial_report_qweb/reports.xml

@ -4,11 +4,11 @@
<report <report
id="action_report_general_ledger_qweb" id="action_report_general_ledger_qweb"
model="report.account.report_generalledger_qweb"
model="report_general_ledger_qweb"
string="General Ledger" string="General Ledger"
report_type="qweb-pdf" report_type="qweb-pdf"
name="account.report_generalledger_qweb"
file="account.report_generalledger_qweb"
name="account_financial_report_qweb.report_general_ledger_qweb"
file="account_financial_report_qweb.report_general_ledger_qweb"
/> />
<!--PaperFormat A4 internal open invoice--> <!--PaperFormat A4 internal open invoice-->
@ -45,5 +45,25 @@
<field name="auto" eval="False"/> <field name="auto" eval="False"/>
</record> </record>
<record id="report_qweb_paperformat" model="report.paperformat">
<field name="name">Account financial report qweb paperformat</field>
<field name="default" eval="True"/>
<field name="format">custom</field>
<field name="page_height">297</field>
<field name="page_width">210</field>
<field name="orientation">Portrait</field>
<field name="margin_top">12</field>
<field name="margin_bottom">8</field>
<field name="margin_left">5</field>
<field name="margin_right">5</field>
<field name="header_line" eval="False"/>
<field name="header_spacing">10</field>
<field name="dpi">110</field>
</record>
<record id="action_report_general_ledger_qweb" model="ir.actions.report.xml">
<field name="paperformat_id" ref="report_qweb_paperformat"/>
</record>
</data> </data>
</openerp> </openerp>

20
account_financial_report_qweb/static/src/css/report.css

@ -29,7 +29,7 @@ body, table, td, span, div {
border-left:0px; border-left:0px;
border-right:0px; border-right:0px;
text-align:left; text-align:left;
font-size:9px;
font-size:10px;
padding-right:3px; padding-right:3px;
padding-left:3px; padding-left:3px;
padding-top:2px; padding-top:2px;
@ -58,14 +58,22 @@ body, table, td, span, div {
font-style:italic; font-style:italic;
} }
.account_title { .account_title {
font-size:10px;
font-size:11px;
font-weight:bold; font-weight:bold;
page-break-after: avoid;
}
.account_title.labels {
background-color:#F0F0F0 !important;
} }
.act_as_cell.amount { .act_as_cell.amount {
word-wrap:normal; word-wrap:normal;
text-align:right; text-align:right;
} }
.act_as_cell.left {
text-align:left;
}
.act_as_cell.right {
text-align:right;
}
.list_table .act_as_cell{ .list_table .act_as_cell{
padding-left: 5px; padding-left: 5px;
/* border-right:1px solid lightGrey; uncomment to active column lines */ /* border-right:1px solid lightGrey; uncomment to active column lines */
@ -79,3 +87,9 @@ body, table, td, span, div {
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
} }
.custom_footer {
font-size:7px !important;
}
.page_break {
page-break-inside: avoid;
}

17
account_financial_report_qweb/view/account_view.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="view_account_specific_form">
<field name="name">account.account.form.inherit</field>
<field name="inherit_id" ref="account.view_account_form"/>
<field name="model">account.account</field>
<field name="type">form</field>
<field name="arch" type="xml">
<field name="deprecated" position="after">
<field name="centralized"/>
</field>
</field>
</record>
</data>
</openerp>

2
account_financial_report_qweb/wizard/__init__.py

@ -3,6 +3,6 @@
# Copyright 2016 Camptocamp SA # Copyright 2016 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import aged_partner_balance_wizard from . import aged_partner_balance_wizard
from . import ledger_report_wizard
from . import balance_common_wizard from . import balance_common_wizard
from . import general_ledger_wizard
from . import open_invoice_wizard from . import open_invoice_wizard

96
account_financial_report_qweb/wizard/general_ledger_wizard.py

@ -0,0 +1,96 @@
# -*- coding: utf-8 -*-
# Author: Damien Crier
# Author: Julien Coux
# Copyright 2016 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import models, fields, api
class GeneralLedgerReportWizard(models.TransientModel):
"""General ledger report wizard."""
_name = "general.ledger.report.wizard"
_description = "General Ledger Report Wizard"
company_id = fields.Many2one(
comodel_name='res.company',
default=lambda self: self.env.user.company_id
)
date_range_id = fields.Many2one(comodel_name='date.range', required=True)
date_from = fields.Date(required=True)
date_to = fields.Date(required=True)
fy_start_date = fields.Date(required=True)
target_move = fields.Selection([('posted', 'All Posted Entries'),
('all', 'All Entries')],
string='Target Moves',
required=True,
default='all')
account_ids = fields.Many2many(
comodel_name='account.account',
string='Filter accounts',
)
centralize = fields.Boolean(string='Activate centralization',
default=True)
hide_account_balance_at_0 = fields.Boolean(
string='Hide account ending balance at 0',
help='Use this filter to hide an account or a partner '
'with an ending balance at 0. '
'If partners are filtered, '
'debits and credits totals will not match the trial balance.',
default=False)
receivable_accounts_only = fields.Boolean()
payable_accounts_only = fields.Boolean()
partner_ids = fields.Many2many(
comodel_name='res.partner',
string='Filter partners',
)
@api.onchange('date_range_id')
def onchange_date_range_id(self):
"""Handle date range change."""
self.date_from = self.date_range_id.date_start
self.date_to = self.date_range_id.date_end
if self.date_from:
self.fy_start_date = self.env.user.company_id.find_daterange_fy(
fields.Date.from_string(self.date_range_id.date_start)
).date_start
@api.onchange('receivable_accounts_only', 'payable_accounts_only')
def onchange_type_accounts_only(self):
"""Handle receivable/payable accounts only change."""
if self.receivable_accounts_only or self.payable_accounts_only:
domain = []
if self.receivable_accounts_only and self.payable_accounts_only:
domain += [('internal_type', 'in', ('receivable', 'payable'))]
elif self.receivable_accounts_only:
domain += [('internal_type', '=', 'receivable')]
elif self.payable_accounts_only:
domain += [('internal_type', '=', 'payable')]
self.account_ids = self.env['account.account'].search(domain)
else:
self.account_ids = None
@api.onchange('partner_ids')
def onchange_partner_ids(self):
"""Handle partners change."""
if self.partner_ids:
self.receivable_accounts_only = self.payable_accounts_only = True
else:
self.receivable_accounts_only = self.payable_accounts_only = False
@api.multi
def button_export_pdf(self):
model = self.env['report_general_ledger_qweb']
report = model.create({
'date_from': self.date_from,
'date_to': self.date_to,
'only_posted_moves': self.target_move == 'posted',
'hide_account_balance_at_0': self.hide_account_balance_at_0,
'company_id': self.company_id.id,
'filter_account_ids': [(6, 0, self.account_ids.ids)],
'filter_partner_ids': [(6, 0, self.partner_ids.ids)],
'centralize': self.centralize,
'fy_start_date': self.fy_start_date,
})
return report.print_report()

97
account_financial_report_qweb/wizard/general_ledger_wizard.xml

@ -1,97 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- GENERAL LEDGER -->
<record id="ledger_general_wizard" model="ir.ui.view">
<field name="name">General Ledger</field>
<field name="model">ledger.report.wizard</field>
<field name="arch" type="xml">
<form>
<group name="main_info">
<field name="company_id"/>
</group>
<group name="date_currency_filter">
<group name="date_ranger">
<field name="date_range_id"/>
<field name="date_from"/>
<field name="date_to"/>
<field name="fy_start_date" invisible="1"/>
</group>
<group name="extra_info">
<field name="amount_currency"/>
<field name="centralize"/>
</group>
</group>
<group name="other_filters">
<group name="moves">
<field name="target_move" widget="radio"/>
</group>
</group>
<label for="account_ids"/>
<field name="account_ids" nolabel="1"/>
<footer>
<button name="button_view" string="View" type="object" default_focus="1" class="oe_highlight"/>
or
<button name="check_report_xlsx" string="Export XLSX" type="object"/>
or
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="ledger_report_wizard_line_tree_view"
model="ir.ui.view">
<field name="name">General Ledger Line tree</field>
<field name="model">ledger.report.wizard.line</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="General Ledger">
<field name="date"/>
<field name="account_id"/>
<field name="move_name"/>
<field name="init_balance"/>
<field name="debit"/>
<field name="credit"/>
<field name="cumul_balance"/>
</tree>
</field>
</record>
<record id="ledger_report_wizard_line_search_view"
model="ir.ui.view">
<field name="name">General Ledger Line search</field>
<field name="model">ledger.report.wizard.line</field>
<field name="arch" type="xml">
<search string="Line search">
<group expand="1" string="Group By">
<filter
name="group_by_account_id"
string="Account"
domain="[]"
context="{'group_by' : 'account_id'}"
/>
<filter
name="group_by_date"
string="Month"
domain="[]"
context="{'group_by' : 'date:month'}"
/>
</group>
</search>
</field>
</record>
<record id="action_ledger_report_wizard" model="ir.actions.act_window">
<field name="name">General Ledger</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ledger.report.wizard</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="ledger_general_wizard"/>
<field name="target">new</field>
</record>
</data>
</openerp>

60
account_financial_report_qweb/wizard/general_ledger_wizard_view.xml

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- GENERAL LEDGER -->
<record id="general_ledger_wizard" model="ir.ui.view">
<field name="name">General Ledger</field>
<field name="model">general.ledger.report.wizard</field>
<field name="arch" type="xml">
<form>
<group name="main_info">
<field name="company_id" groups="base.group_multi_company"/>
</group>
<group name="filters">
<group name="date_ranger">
<field name="date_range_id" domain="[('company_id','=',company_id)]"/>
<field name="date_from"/>
<field name="date_to"/>
<field name="fy_start_date" invisible="1"/>
</group>
<group name="other_filters">
<field name="target_move" widget="radio"/>
<field name="centralize"/>
<field name="hide_account_balance_at_0"/>
</group>
</group>
<label for="partner_ids"/>
<field name="partner_ids" nolabel="1"/>
<group/>
<label for="account_ids"/>
<group col="4">
<field name="receivable_accounts_only"/>
<field name="payable_accounts_only"/>
</group>
<field name="account_ids" nolabel="1"/>
<footer>
<button name="button_export_pdf" string="Export PDF" type="object" default_focus="1" class="oe_highlight"/>
<!--
or
<button name="check_report_xlsx" string="Export XLSX" type="object"/>
-->
or
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="action_general_ledger_wizard" model="ir.actions.act_window">
<field name="name">General Ledger</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">general.ledger.report.wizard</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="general_ledger_wizard"/>
<field name="target">new</field>
</record>
</data>
</openerp>

54
account_financial_report_qweb/wizard/ledger.sql

@ -1,54 +0,0 @@
WITH view_q as (
SELECT
ml.date,
acc.id AS account_id,
ml.debit,
ml.credit,
ml.name AS name,
ml.ref,
ml.journal_id,
ml.partner_id,
SUM(debit - credit) OVER w_account - (debit - credit) AS init_balance,
SUM(debit - credit) OVER w_account AS cumul_balance
FROM account_account AS acc
LEFT JOIN account_move_line AS ml ON (ml.account_id = acc.id)
INNER JOIN account_move AS m ON (ml.move_id = m.id)
INNER JOIN account_account_type aat ON (acc.user_type_id = aat.id)
WHERE ml.date >= %(fy_date)s OR aat.include_initial_balance IS TRUE
WINDOW w_account AS (
PARTITION BY acc.code
ORDER BY ml.date, ml.id
)
ORDER BY acc.id, ml.date
)
INSERT INTO ledger_report_wizard_line (
date,
name,
journal_id,
account_id,
partner_id,
ref,
label,
--counterpart
init_balance,
debit,
credit,
cumul_balance,
wizard_id
)
SELECT
date,
name,
journal_id,
account_id,
partner_id,
ref,
' TODO label ' AS label,
--counterpart
init_balance,
debit,
credit,
cumul_balance,
%(wizard_id)s AS wizard_id
FROM view_q
WHERE date BETWEEN %(date_from)s AND %(date_to)s;

337
account_financial_report_qweb/wizard/ledger_report_wizard.py

@ -1,337 +0,0 @@
# -*- coding: utf-8 -*-
# Author: Damien Crier
# Copyright 2016 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from operator import itemgetter
from pkg_resources import resource_string
from openerp import models, fields, api, _
# order to be placed on the report: field
FIELDS_TO_READ = {1: 'date',
0: 'account_id',
4: 'account_code',
2: 'move_name',
3: 'journal_id',
5: 'partner_name',
6: 'ref',
7: 'label',
8: 'debit',
9: 'credit',
30: 'amount_currency',
40: 'currency_code',
50: 'month',
60: 'partner_ref',
10: 'cumul_balance',
70: 'init_balance',
}
class LedgerReportWizard(models.TransientModel):
"""Base ledger report wizard."""
_name = "ledger.report.wizard"
_description = "Ledger Report Wizard"
company_id = fields.Many2one(comodel_name='res.company')
date_range_id = fields.Many2one(comodel_name='date.range', required=True)
date_from = fields.Date(required=True)
date_to = fields.Date(required=True)
fy_start_date = fields.Date(required=True)
target_move = fields.Selection([('posted', 'All Posted Entries'),
('all', 'All Entries')],
string='Target Moves',
required=True,
default='posted')
account_ids = fields.Many2many(
comodel_name='account.account',
string='Filter accounts',
)
amount_currency = fields.Boolean(string='With currency',
default=False)
centralize = fields.Boolean(string='Activate centralization',
default=False)
result_selection = fields.Selection(
[
('customer', 'Receivable Accounts'),
('supplier', 'Payable Accounts'),
('customer_supplier', 'Receivable and Payable Accounts'),
],
string="Partner's",
default='customer')
partner_ids = fields.Many2many(
comodel_name='res.partner',
string='Filter partners',
)
line_ids = fields.One2many(comodel_name='ledger.report.wizard.line',
inverse_name='wizard_id')
def _query(self):
"""Execute query.
Short summary:
Prepare all lines for report
by calculating debit/credit amounts
plus the cumulative one.
Narrow the search by using PG windows.
Insert all the rows in `ledger_report_wizard_line`
at once, so that we have real model objects
and we can filter/group them in the tree view.
"""
query = resource_string(__name__, 'ledger.sql')
params = dict(fy_date=self.fy_start_date, wizard_id=self.id,
date_from=self.date_from, date_to=self.date_to)
self.env.cr.execute(query, params)
return True
@api.multi
def _print_report(self, data):
# we update form with display account value
data = self.pre_print_report(data)
Report = self.env['report'].with_context(landscape=True)
return Report.get_action(
self, 'account.report_generalledger_qweb',
data=data)
def _build_contexts(self, data):
result = {}
result['journal_ids'] = (
'journal_ids' in data['form'] and
data['form']['journal_ids'] or False
)
result['state'] = (
'target_move' in data['form'] and
data['form']['target_move'] or ''
)
result['date_from'] = data['form']['date_from'] or False
result['date_to'] = data['form']['date_to'] or False
result['strict_range'] = True if result['date_from'] else False
return result
@api.multi
def button_view(self):
"""Open tree view w/ results."""
return self.process()
@api.multi
def process(self):
"""Process data and return window action."""
self._query()
return {
'domain': [('wizard_id', '=', self.id)],
'name': _('Ledger lines'),
'view_type': 'form',
'view_mode': 'tree',
'res_model': 'ledger.report.wizard.line',
'view_id': False,
'context': {
'search_default_group_by_account_id': True,
'search_default_group_by_date': True,
},
'type': 'ir.actions.act_window'
}
@api.onchange('date_range_id')
def onchange_date_range_id(self):
"""Handle date range change."""
self.date_from = self.date_range_id.date_start
self.date_to = self.date_range_id.date_end
if self.date_from:
self.fy_start_date = self.env.user.company_id.find_daterange_fy(
fields.Date.from_string(self.date_range_id.date_start)
).date_start
class LedgerReportWizardLine(models.TransientModel):
"""A wizard line.
Lines are populated on the fly when submitting the wizard.
"""
_name = 'ledger.report.wizard.line'
wizard_id = fields.Many2one(comodel_name='ledger.report.wizard')
name = fields.Char()
label = fields.Char()
ref = fields.Char()
date = fields.Date()
month = fields.Char()
partner_name = fields.Char()
partner_ref = fields.Char()
account_id = fields.Many2one('account.account')
account_code = fields.Char()
journal_id = fields.Many2one('account.journal')
partner_id = fields.Many2one('res.partner')
init_credit = fields.Float()
init_debit = fields.Float()
debit = fields.Float()
credit = fields.Float()
balance = fields.Float()
cumul_credit = fields.Float()
cumul_debit = fields.Float()
cumul_balance = fields.Float()
init_balance = fields.Float()
move_name = fields.Char()
move_state = fields.Char()
invoice_number = fields.Char()
centralized = fields.Boolean()
@api.multi
def check_report_xlsx(self):
self.ensure_one()
data = {}
data['ids'] = self.env.context.get('active_ids', [])
# data['model'] = 'general.ledger.line'
data['model'] = self.env.context.get('active_model', 'ir.ui.menu')
data['form'] = self.read(['date_from', 'date_to',
'journal_ids', 'target_move'])[0]
used_context = self._build_contexts(data)
data['form']['used_context'] = dict(
used_context,
lang=self.env.context.get('lang', 'en_US'))
return self._print_report_xlsx(data)
@api.multi
def _print_report_xlsx(self, data):
return {
'name': 'export xlsx general ledger',
'model': 'ledger.report.wizard',
'type': 'ir.actions.report.xml',
'report_name': 'ledger.report.wizard.xlsx',
'report_type': 'xlsx',
'context': self.env.context,
}
@api.multi
def _get_centralized_move_ids(self, domain):
""" Get last line of each selected centralized accounts """
# inverse search on centralized boolean to finish the search to get the
# ids of last lines of centralized accounts
# XXX USE DISTINCT to speed up ?
domain = domain[:]
centralize_index = domain.index(('centralized', '=', False))
domain[centralize_index] = ('centralized', '=', True)
gl_lines = self.env['general.ledger.line'].search(domain)
accounts = gl_lines.mapped('account_id')
line_ids = []
for acc in accounts:
acc_lines = gl_lines.filtered(lambda rec: rec.account_id == acc)
line_ids.append(acc_lines[-1].id)
return line_ids
@api.multi
def _get_moves_from_dates_domain(self):
""" Prepare domain for `_get_moves_from_dates` """
domain = []
if self.centralize:
domain = [('centralized', '=', False)]
start_date = self.date_from
end_date = self.date_to
if start_date:
domain += [('date', '>=', start_date)]
if end_date:
domain += [('date', '<=', end_date)]
if self.target_move == 'posted':
domain += [('move_state', '=', 'posted')]
if self.account_ids:
domain += [('account_id', 'in', self.account_ids.ids)]
return domain
def compute_domain(self):
ret = self._get_moves_from_dates_domain()
if self.centralize:
centralized_ids = self._get_centralized_move_ids(ret)
if centralized_ids:
ret.insert(0, '|')
ret.append(('id', 'in', centralized_ids))
return ret
def initial_balance_line(self, amount, account_name, account_code, date):
return {'date': date,
'account_id': account_name,
'account_code': account_code,
'move_name': '',
'journal_id': '',
'partner_name': '',
'ref': '',
'label': _('Initial Balance'),
'debit': '',
'credit': '',
'amount_currency': '',
'currency_code': '',
'month': '',
'partner_ref': '',
'cumul_balance': amount,
'init_balance': ''}
def group_general_ledger(self, report_lines, date_start):
"""
group lines by account and order by account then date
"""
result = {}
accounts = report_lines.mapped('account_id')
for account in accounts:
lines = report_lines.filtered(
lambda a: a.account_id.id == account.id)
acc_full_name = account.name_get()[0][1]
sorted_lines = sorted(lines.read(FIELDS_TO_READ.values()),
key=itemgetter('date'))
initial_balance = sorted_lines[0]['init_balance']
sorted_lines.insert(0, self.initial_balance_line(initial_balance,
acc_full_name,
account.code,
date_start))
result[acc_full_name] = sorted_lines
return result
def construct_header(self):
result = {}
result['title'] = _('General Ledger')
filters = {}
filters['centralized'] = _('%s' % self.centralize)
filters['start_date'] = self.date_from
filters['end_date'] = self.date_to
filters['target_moves'] = self.target_move
filters['accounts'] = _('All')
if self.account_ids:
filters['accounts'] = ', '.join([a.code for a in self.account_ids])
result['filters'] = filters
return result
@api.multi
def compute(self):
self.ensure_one()
# header filled with a dict
header = []
header.append(self.construct_header())
# content filled with dicts
content = []
domain = self.compute_domain()
report_lines = self.env['general.ledger.line'].search(domain)
lines_general_ledger = self.group_general_ledger(report_lines,
self.date_from)
content.append(lines_general_ledger)
return {'header': header,
'content': content}

54
account_financial_report_qweb/wizard/partner_ledger_wizard.xml

@ -1,54 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- PARTNER LEDGER -->
<record id="partner_ledger_report_wizard_view_form" model="ir.ui.view">
<field name="name">Partner Ledger</field>
<field name="model">ledger.report.wizard</field>
<field name="arch" type="xml">
<form>
<group name="main_info">
<field name="company_id"/>
</group>
<group name="date_currency_filter">
<group name="date_ranger">
<field name="date_range_id"/>
<field name="date_from"/>
<field name="date_to"/>
</group>
<group name="extra_info">
<field name="amount_currency"/>
</group>
</group>
<group name="other_filters">
<group name="moves">
<field name="target_move" widget="radio"/>
</group>
<group name="result_select">
<field name="result_selection" widget="radio"/>
</group>
</group>
<label for="partner_ids"/>
<field name="partner_ids" nolabel="1"/>
<footer>
<button name="check_report" string="Print" type="object" default_focus="1" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
<record id="action_partner_ledger_report_wizard" model="ir.actions.act_window">
<field name="name">Partner Ledger</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ledger.report.wizard</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="view_id" ref="partner_ledger_report_wizard_view_form"/>
<field name="target">new</field>
</record>
</data>
</openerp>
Loading…
Cancel
Save