Joan Sisquella
5 years ago
46 changed files with 5475 additions and 7967 deletions
-
10account_financial_report/__manifest__.py
-
22account_financial_report/models/account_group.py
-
5account_financial_report/readme/CONTRIBUTORS.rst
-
1account_financial_report/report/__init__.py
-
23account_financial_report/report/abstract_report.py
-
188account_financial_report/report/abstract_report_xlsx.py
-
972account_financial_report/report/aged_partner_balance.py
-
181account_financial_report/report/aged_partner_balance_xlsx.py
-
2353account_financial_report/report/general_ledger.py
-
176account_financial_report/report/general_ledger_xlsx.py
-
1168account_financial_report/report/journal_ledger.py
-
112account_financial_report/report/journal_ledger_xlsx.py
-
1209account_financial_report/report/open_items.py
-
121account_financial_report/report/open_items_xlsx.py
-
438account_financial_report/report/templates/aged_partner_balance.xml
-
347account_financial_report/report/templates/general_ledger.xml
-
110account_financial_report/report/templates/journal_ledger.xml
-
106account_financial_report/report/templates/open_items.xml
-
1033account_financial_report/report/templates/trial_balance.xml
-
172account_financial_report/report/templates/vat_report.xml
-
1191account_financial_report/report/trial_balance.py
-
110account_financial_report/report/trial_balance_xlsx.py
-
526account_financial_report/report/vat_report.py
-
38account_financial_report/report/vat_report_xlsx.py
-
152account_financial_report/reports.xml
-
4account_financial_report/tests/__init__.py
-
399account_financial_report/tests/abstract_test.py
-
78account_financial_report/tests/abstract_test_foreign_currency.py
-
75account_financial_report/tests/abstract_test_tax_report.py
-
41account_financial_report/tests/test_aged_partner_balance.py
-
561account_financial_report/tests/test_general_ledger.py
-
206account_financial_report/tests/test_journal_ledger.py
-
37account_financial_report/tests/test_open_items.py
-
649account_financial_report/tests/test_trial_balance.py
-
243account_financial_report/tests/test_vat_report.py
-
20account_financial_report/view/report_template.xml
-
49account_financial_report/wizard/aged_partner_balance_wizard.py
-
4account_financial_report/wizard/aged_partner_balance_wizard_view.xml
-
72account_financial_report/wizard/general_ledger_wizard.py
-
79account_financial_report/wizard/journal_ledger_wizard.py
-
53account_financial_report/wizard/open_items_wizard.py
-
1account_financial_report/wizard/open_items_wizard_view.xml
-
67account_financial_report/wizard/trial_balance_wizard.py
-
2account_financial_report/wizard/trial_balance_wizard_view.xml
-
36account_financial_report/wizard/vat_report_wizard.py
-
2requirements.txt
@ -1,23 +0,0 @@ |
|||||
# Copyright 2018 Camptocamp SA |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
|
|
||||
from odoo import models |
|
||||
from psycopg2.extensions import AsIs |
|
||||
|
|
||||
|
|
||||
class AbstractReport(models.AbstractModel): |
|
||||
_name = 'account_financial_report_abstract' |
|
||||
_description = 'Abstract Report' |
|
||||
|
|
||||
def _transient_clean_rows_older_than(self, seconds): |
|
||||
assert self._transient, \ |
|
||||
"Model %s is not transient, it cannot be vacuumed!" % self._name |
|
||||
# Never delete rows used in last 5 minutes |
|
||||
seconds = max(seconds, 300) |
|
||||
query = ( |
|
||||
"DELETE FROM %s" |
|
||||
" WHERE COALESCE(" |
|
||||
"write_date, create_date, (now() at time zone 'UTC'))" |
|
||||
"::timestamp < ((now() at time zone 'UTC') - interval %s)" |
|
||||
) |
|
||||
self.env.cr.execute(query, (AsIs(self._table), "%s seconds" % seconds)) |
|
@ -1,633 +1,375 @@ |
|||||
# © 2016 Julien Coux (Camptocamp) |
# © 2016 Julien Coux (Camptocamp) |
||||
|
# Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com) |
||||
# 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 odoo import models, fields, api |
|
||||
|
from odoo import models, api |
||||
|
from odoo.tools import float_is_zero |
||||
|
from datetime import date, datetime, timedelta |
||||
|
import pandas as pd |
||||
|
|
||||
|
|
||||
class AgedPartnerBalanceReport(models.TransientModel): |
|
||||
""" Here, we just define class fields. |
|
||||
For methods, go more bottom at this file. |
|
||||
|
|
||||
The class hierarchy is : |
|
||||
* AgedPartnerBalanceReport |
|
||||
** AgedPartnerBalanceReportAccount |
|
||||
*** AgedPartnerBalanceReportPartner |
|
||||
**** AgedPartnerBalanceReportLine |
|
||||
**** AgedPartnerBalanceReportMoveLine |
|
||||
If "show_move_line_details" is selected |
|
||||
""" |
|
||||
|
|
||||
_name = 'report_aged_partner_balance' |
|
||||
_inherit = 'account_financial_report_abstract' |
|
||||
|
|
||||
# Filters fields, used for data computation |
|
||||
date_at = fields.Date() |
|
||||
only_posted_moves = 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') |
|
||||
show_move_line_details = fields.Boolean() |
|
||||
|
|
||||
# Open Items Report Data fields, used as base for compute the data reports |
|
||||
open_items_id = fields.Many2one(comodel_name='report_open_items') |
|
||||
|
|
||||
# Data fields, used to browse report data |
|
||||
account_ids = fields.One2many( |
|
||||
comodel_name='report_aged_partner_balance_account', |
|
||||
inverse_name='report_id' |
|
||||
) |
|
||||
|
|
||||
|
|
||||
class AgedPartnerBalanceReportAccount(models.TransientModel): |
|
||||
_name = 'report_aged_partner_balance_account' |
|
||||
_inherit = 'account_financial_report_abstract' |
|
||||
_order = 'code ASC' |
|
||||
|
|
||||
report_id = fields.Many2one( |
|
||||
comodel_name='report_aged_partner_balance', |
|
||||
ondelete='cascade', |
|
||||
index=True |
|
||||
) |
|
||||
|
|
||||
# Data fields, used to keep link with real object |
|
||||
account_id = fields.Many2one( |
|
||||
'account.account', |
|
||||
index=True |
|
||||
) |
|
||||
|
|
||||
# Data fields, used for report display |
|
||||
code = fields.Char() |
|
||||
name = fields.Char() |
|
||||
|
|
||||
cumul_amount_residual = fields.Float(digits=(16, 2)) |
|
||||
cumul_current = fields.Float(digits=(16, 2)) |
|
||||
cumul_age_30_days = fields.Float(digits=(16, 2)) |
|
||||
cumul_age_60_days = fields.Float(digits=(16, 2)) |
|
||||
cumul_age_90_days = fields.Float(digits=(16, 2)) |
|
||||
cumul_age_120_days = fields.Float(digits=(16, 2)) |
|
||||
cumul_older = fields.Float(digits=(16, 2)) |
|
||||
|
|
||||
percent_current = fields.Float(digits=(16, 2)) |
|
||||
percent_age_30_days = fields.Float(digits=(16, 2)) |
|
||||
percent_age_60_days = fields.Float(digits=(16, 2)) |
|
||||
percent_age_90_days = fields.Float(digits=(16, 2)) |
|
||||
percent_age_120_days = fields.Float(digits=(16, 2)) |
|
||||
percent_older = fields.Float(digits=(16, 2)) |
|
||||
|
|
||||
# Data fields, used to browse report data |
|
||||
partner_ids = fields.One2many( |
|
||||
comodel_name='report_aged_partner_balance_partner', |
|
||||
inverse_name='report_account_id' |
|
||||
) |
|
||||
|
|
||||
|
|
||||
class AgedPartnerBalanceReportPartner(models.TransientModel): |
|
||||
_name = 'report_aged_partner_balance_partner' |
|
||||
_inherit = 'account_financial_report_abstract' |
|
||||
|
|
||||
report_account_id = fields.Many2one( |
|
||||
comodel_name='report_aged_partner_balance_account', |
|
||||
ondelete='cascade', |
|
||||
index=True |
|
||||
) |
|
||||
|
|
||||
# Data fields, used to keep link with real object |
|
||||
partner_id = fields.Many2one( |
|
||||
'res.partner', |
|
||||
index=True |
|
||||
) |
|
||||
|
|
||||
# Data fields, used for report display |
|
||||
name = fields.Char() |
|
||||
|
|
||||
# Data fields, used to browse report data |
|
||||
move_line_ids = fields.One2many( |
|
||||
comodel_name='report_aged_partner_balance_move_line', |
|
||||
inverse_name='report_partner_id' |
|
||||
) |
|
||||
line_ids = fields.One2many( |
|
||||
comodel_name='report_aged_partner_balance_line', |
|
||||
inverse_name='report_partner_id' |
|
||||
) |
|
||||
|
class AgedPartnerBalanceReport(models.AbstractModel): |
||||
|
_name = 'report.account_financial_report.aged_partner_balance' |
||||
|
_description = "Aged Partner Balance Report" |
||||
|
|
||||
@api.model |
@api.model |
||||
def _generate_order_by(self, order_spec, query): |
|
||||
"""Custom order to display "No partner allocated" at last position.""" |
|
||||
return """ |
|
||||
ORDER BY |
|
||||
CASE |
|
||||
WHEN |
|
||||
"report_aged_partner_balance_partner"."partner_id" IS NOT NULL |
|
||||
THEN 0 |
|
||||
ELSE 1 |
|
||||
END, |
|
||||
"report_aged_partner_balance_partner"."name" |
|
||||
""" |
|
||||
|
|
||||
|
|
||||
class AgedPartnerBalanceReportLine(models.TransientModel): |
|
||||
_name = 'report_aged_partner_balance_line' |
|
||||
_inherit = 'account_financial_report_abstract' |
|
||||
|
|
||||
report_partner_id = fields.Many2one( |
|
||||
comodel_name='report_aged_partner_balance_partner', |
|
||||
ondelete='cascade', |
|
||||
index=True |
|
||||
) |
|
||||
|
|
||||
# Data fields, used for report display |
|
||||
partner = fields.Char() |
|
||||
amount_residual = fields.Float(digits=(16, 2)) |
|
||||
current = fields.Float(digits=(16, 2)) |
|
||||
age_30_days = fields.Float(digits=(16, 2)) |
|
||||
age_60_days = fields.Float(digits=(16, 2)) |
|
||||
age_90_days = fields.Float(digits=(16, 2)) |
|
||||
age_120_days = fields.Float(digits=(16, 2)) |
|
||||
older = fields.Float(digits=(16, 2)) |
|
||||
|
|
||||
|
|
||||
class AgedPartnerBalanceReportMoveLine(models.TransientModel): |
|
||||
_name = 'report_aged_partner_balance_move_line' |
|
||||
_inherit = 'account_financial_report_abstract' |
|
||||
|
|
||||
report_partner_id = fields.Many2one( |
|
||||
comodel_name='report_aged_partner_balance_partner', |
|
||||
ondelete='cascade', |
|
||||
index=True |
|
||||
) |
|
||||
|
|
||||
# Data fields, used to keep link with real object |
|
||||
move_line_id = fields.Many2one('account.move.line') |
|
||||
|
|
||||
# Data fields, used for report display |
|
||||
date = fields.Date() |
|
||||
date_due = fields.Date() |
|
||||
entry = fields.Char() |
|
||||
journal = fields.Char() |
|
||||
account = fields.Char() |
|
||||
partner = fields.Char() |
|
||||
label = fields.Char() |
|
||||
|
def _initialize_account(self, ag_pb_data, acc_id): |
||||
|
ag_pb_data[acc_id] = {} |
||||
|
ag_pb_data[acc_id]['id'] = acc_id |
||||
|
ag_pb_data[acc_id]['residual'] = 0.0 |
||||
|
ag_pb_data[acc_id]['current'] = 0.0 |
||||
|
ag_pb_data[acc_id]['30_days'] = 0.0 |
||||
|
ag_pb_data[acc_id]['60_days'] = 0.0 |
||||
|
ag_pb_data[acc_id]['90_days'] = 0.0 |
||||
|
ag_pb_data[acc_id]['120_days'] = 0.0 |
||||
|
ag_pb_data[acc_id]['older'] = 0.0 |
||||
|
return ag_pb_data |
||||
|
|
||||
amount_residual = fields.Float(digits=(16, 2)) |
|
||||
current = fields.Float(digits=(16, 2)) |
|
||||
age_30_days = fields.Float(digits=(16, 2)) |
|
||||
age_60_days = fields.Float(digits=(16, 2)) |
|
||||
age_90_days = fields.Float(digits=(16, 2)) |
|
||||
age_120_days = fields.Float(digits=(16, 2)) |
|
||||
older = fields.Float(digits=(16, 2)) |
|
||||
|
|
||||
|
|
||||
class AgedPartnerBalanceReportCompute(models.TransientModel): |
|
||||
""" Here, we just define methods. |
|
||||
For class fields, go more top at this file. |
|
||||
""" |
|
||||
|
@api.model |
||||
|
def _initialize_partner(self, ag_pb_data, acc_id, prt_id): |
||||
|
ag_pb_data[acc_id][prt_id] = {} |
||||
|
ag_pb_data[acc_id][prt_id]['id'] = acc_id |
||||
|
ag_pb_data[acc_id][prt_id]['residual'] = 0.0 |
||||
|
ag_pb_data[acc_id][prt_id]['current'] = 0.0 |
||||
|
ag_pb_data[acc_id][prt_id]['30_days'] = 0.0 |
||||
|
ag_pb_data[acc_id][prt_id]['60_days'] = 0.0 |
||||
|
ag_pb_data[acc_id][prt_id]['90_days'] = 0.0 |
||||
|
ag_pb_data[acc_id][prt_id]['120_days'] = 0.0 |
||||
|
ag_pb_data[acc_id][prt_id]['older'] = 0.0 |
||||
|
ag_pb_data[acc_id][prt_id]['move_lines'] = [] |
||||
|
return ag_pb_data |
||||
|
|
||||
|
def _get_journals_data(self, journals_ids): |
||||
|
journals = self.env['account.journal'].browse(journals_ids) |
||||
|
journals_data = {} |
||||
|
for journal in journals: |
||||
|
journals_data.update({journal.id: {'id': journal.id, |
||||
|
'code': journal.code}}) |
||||
|
return journals_data |
||||
|
|
||||
|
def _get_accounts_data(self, accounts_ids): |
||||
|
accounts = self.env['account.account'].browse(accounts_ids) |
||||
|
accounts_data = {} |
||||
|
for account in accounts: |
||||
|
accounts_data.update({account.id: {'id': account.id, |
||||
|
'code': account.code, |
||||
|
'name': account.name}}) |
||||
|
return accounts_data |
||||
|
|
||||
_inherit = 'report_aged_partner_balance' |
|
||||
|
@api.model |
||||
|
def _get_move_lines_domain(self, company_id, account_ids, partner_ids, |
||||
|
only_posted_moves): |
||||
|
domain = [('account_id', 'in', account_ids), |
||||
|
('company_id', '=', company_id), |
||||
|
('reconciled', '=', False)] |
||||
|
if partner_ids: |
||||
|
domain += [('partner_id', 'in', partner_ids)] |
||||
|
if only_posted_moves: |
||||
|
domain += [('move_id.state', '=', 'posted')] |
||||
|
return domain |
||||
|
|
||||
@api.multi |
|
||||
def print_report(self, report_type): |
|
||||
self.ensure_one() |
|
||||
if report_type == 'xlsx': |
|
||||
report_name = 'a_f_r.report_aged_partner_balance_xlsx' |
|
||||
|
@api.model |
||||
|
def _calculate_amounts(self, ag_pb_data, acc_id, prt_id, residual, |
||||
|
due_date, date_at_object): |
||||
|
ag_pb_data[acc_id]['residual'] += residual |
||||
|
ag_pb_data[acc_id][prt_id]['residual'] += residual |
||||
|
today = date_at_object |
||||
|
if not due_date or today <= due_date: |
||||
|
ag_pb_data[acc_id]['current'] += residual |
||||
|
ag_pb_data[acc_id][prt_id]['current'] += residual |
||||
|
elif today <= due_date + timedelta(days=30): |
||||
|
ag_pb_data[acc_id]['30_days'] += residual |
||||
|
ag_pb_data[acc_id][prt_id]['30_days'] += residual |
||||
|
elif today <= due_date + timedelta(days=60): |
||||
|
ag_pb_data[acc_id]['60_days'] += residual |
||||
|
ag_pb_data[acc_id][prt_id]['60_days'] += residual |
||||
|
elif today <= due_date + timedelta(days=90): |
||||
|
ag_pb_data[acc_id]['90_days'] += residual |
||||
|
ag_pb_data[acc_id][prt_id]['90_days'] += residual |
||||
|
elif today <= due_date + timedelta(days=120): |
||||
|
ag_pb_data[acc_id]['120_days'] += residual |
||||
|
ag_pb_data[acc_id][prt_id]['120_days'] += residual |
||||
else: |
else: |
||||
report_name = 'account_financial_report.' \ |
|
||||
'report_aged_partner_balance_qweb' |
|
||||
report = self.env['ir.actions.report'].search( |
|
||||
[('report_name', '=', report_name), |
|
||||
('report_type', '=', report_type)], limit=1) |
|
||||
return report.report_action(self, config=False) |
|
||||
|
|
||||
def _get_html(self): |
|
||||
result = {} |
|
||||
rcontext = {} |
|
||||
context = dict(self.env.context) |
|
||||
report = self.browse(context.get('active_id')) |
|
||||
if report: |
|
||||
rcontext['o'] = report |
|
||||
result['html'] = self.env.ref( |
|
||||
'account_financial_report.report_aged_partner_balance').render( |
|
||||
rcontext) |
|
||||
return result |
|
||||
|
ag_pb_data[acc_id]['older'] += residual |
||||
|
ag_pb_data[acc_id][prt_id]['older'] += residual |
||||
|
return ag_pb_data |
||||
|
|
||||
|
def _get_account_partial_reconciled(self, company_id, date_at_object): |
||||
|
domain = [('max_date', '>=', date_at_object), |
||||
|
('company_id', '=', company_id)] |
||||
|
fields = ['debit_move_id', 'credit_move_id', 'amount'] |
||||
|
accounts_partial_reconcile = \ |
||||
|
self.env['account.partial.reconcile'].search_read( |
||||
|
domain=domain, |
||||
|
fields=fields |
||||
|
) |
||||
|
debit_amount = {} |
||||
|
credit_amount = {} |
||||
|
for account_partial_reconcile_data in accounts_partial_reconcile: |
||||
|
debit_move_id = account_partial_reconcile_data['debit_move_id'][0] |
||||
|
credit_move_id = account_partial_reconcile_data['credit_move_id'][0] |
||||
|
if debit_move_id not in debit_amount.keys(): |
||||
|
debit_amount[debit_move_id] = 0.0 |
||||
|
debit_amount[debit_move_id] += \ |
||||
|
account_partial_reconcile_data['amount'] |
||||
|
if credit_move_id not in credit_amount.keys(): |
||||
|
credit_amount[credit_move_id] = 0.0 |
||||
|
credit_amount[credit_move_id] += \ |
||||
|
account_partial_reconcile_data['amount'] |
||||
|
account_partial_reconcile_data.update({ |
||||
|
'debit_move_id': debit_move_id, |
||||
|
'credit_move_id': credit_move_id, |
||||
|
}) |
||||
|
return accounts_partial_reconcile, debit_amount, credit_amount |
||||
|
|
||||
@api.model |
@api.model |
||||
def get_html(self, given_context=None): |
|
||||
return self._get_html() |
|
||||
|
|
||||
def _prepare_report_open_items(self): |
|
||||
self.ensure_one() |
|
||||
return { |
|
||||
'date_at': self.date_at, |
|
||||
'only_posted_moves': self.only_posted_moves, |
|
||||
'company_id': self.company_id.id, |
|
||||
'filter_account_ids': [(6, 0, self.filter_account_ids.ids)], |
|
||||
'filter_partner_ids': [(6, 0, self.filter_partner_ids.ids)], |
|
||||
} |
|
||||
|
|
||||
@api.multi |
|
||||
def compute_data_for_report(self): |
|
||||
self.ensure_one() |
|
||||
# Compute Open Items Report Data. |
|
||||
# The data of Aged Partner Balance Report |
|
||||
# are based on Open Items Report data. |
|
||||
model = self.env['report_open_items'] |
|
||||
self.open_items_id = model.create(self._prepare_report_open_items()) |
|
||||
self.open_items_id.compute_data_for_report() |
|
||||
|
|
||||
# Compute report data |
|
||||
self._inject_account_values() |
|
||||
self._inject_partner_values() |
|
||||
self._inject_line_values() |
|
||||
self._inject_line_values(only_empty_partner_line=True) |
|
||||
if self.show_move_line_details: |
|
||||
self._inject_move_line_values() |
|
||||
self._inject_move_line_values(only_empty_partner_line=True) |
|
||||
self._compute_accounts_cumul() |
|
||||
# Refresh cache because all data are computed with SQL requests |
|
||||
self.invalidate_cache() |
|
||||
|
|
||||
def _inject_account_values(self): |
|
||||
"""Inject report values for report_aged_partner_balance_account""" |
|
||||
query_inject_account = """ |
|
||||
INSERT INTO |
|
||||
report_aged_partner_balance_account |
|
||||
( |
|
||||
report_id, |
|
||||
create_uid, |
|
||||
create_date, |
|
||||
account_id, |
|
||||
code, |
|
||||
name |
|
||||
) |
|
||||
SELECT |
|
||||
%s AS report_id, |
|
||||
%s AS create_uid, |
|
||||
NOW() AS create_date, |
|
||||
rao.account_id, |
|
||||
rao.code, |
|
||||
rao.name |
|
||||
FROM |
|
||||
report_open_items_account rao |
|
||||
WHERE |
|
||||
rao.report_id = %s |
|
||||
""" |
|
||||
query_inject_account_params = ( |
|
||||
self.id, |
|
||||
self.env.uid, |
|
||||
self.open_items_id.id, |
|
||||
|
def _get_new_move_lines_domain(self, new_ml_ids, account_ids, company_id, |
||||
|
partner_ids, only_posted_moves): |
||||
|
domain = [('account_id', 'in', account_ids), |
||||
|
('company_id', '=', company_id), |
||||
|
('id', 'in', new_ml_ids)] |
||||
|
if partner_ids: |
||||
|
domain += [('partner_id', 'in', partner_ids)] |
||||
|
if only_posted_moves: |
||||
|
domain += [('move_id.state', '=', 'posted')] |
||||
|
return domain |
||||
|
|
||||
|
def _recalculate_move_lines(self, move_lines, debit_ids, credit_ids, |
||||
|
debit_amount, credit_amount, ml_ids, |
||||
|
account_ids, company_id, partner_ids, |
||||
|
only_posted_moves): |
||||
|
reconciled_ids = list(debit_ids) + list(credit_ids) |
||||
|
new_ml_ids = [] |
||||
|
for reconciled_id in reconciled_ids: |
||||
|
if reconciled_id not in ml_ids and reconciled_id not in new_ml_ids: |
||||
|
new_ml_ids += [reconciled_id] |
||||
|
new_domain = self._get_new_move_lines_domain(new_ml_ids, account_ids, |
||||
|
company_id, partner_ids, |
||||
|
only_posted_moves) |
||||
|
ml_fields = [ |
||||
|
'id', 'name', 'date', 'move_id', 'journal_id', 'account_id', |
||||
|
'partner_id', 'amount_residual', 'date_maturity', 'ref', |
||||
|
'reconciled'] |
||||
|
new_move_lines = self.env['account.move.line'].search_read( |
||||
|
domain=new_domain, fields=ml_fields |
||||
) |
) |
||||
self.env.cr.execute(query_inject_account, query_inject_account_params) |
|
||||
|
|
||||
def _inject_partner_values(self): |
|
||||
"""Inject report values for report_aged_partner_balance_partner""" |
|
||||
query_inject_partner = """ |
|
||||
INSERT INTO |
|
||||
report_aged_partner_balance_partner |
|
||||
( |
|
||||
report_account_id, |
|
||||
create_uid, |
|
||||
create_date, |
|
||||
partner_id, |
|
||||
name |
|
||||
) |
|
||||
SELECT |
|
||||
ra.id AS report_account_id, |
|
||||
%s AS create_uid, |
|
||||
NOW() AS create_date, |
|
||||
rpo.partner_id, |
|
||||
rpo.name |
|
||||
FROM |
|
||||
report_open_items_partner rpo |
|
||||
INNER JOIN |
|
||||
report_open_items_account rao ON rpo.report_account_id = rao.id |
|
||||
INNER JOIN |
|
||||
report_aged_partner_balance_account ra ON rao.code = ra.code |
|
||||
WHERE |
|
||||
rao.report_id = %s |
|
||||
AND ra.report_id = %s |
|
||||
""" |
|
||||
query_inject_partner_params = ( |
|
||||
self.env.uid, |
|
||||
self.open_items_id.id, |
|
||||
self.id, |
|
||||
|
move_lines = move_lines + new_move_lines |
||||
|
for move_line in move_lines: |
||||
|
ml_id = move_line['id'] |
||||
|
if ml_id in debit_ids: |
||||
|
move_line['amount_residual'] += debit_amount[ml_id] |
||||
|
if ml_id in credit_ids: |
||||
|
move_line['amount_residual'] -= credit_amount[ml_id] |
||||
|
return move_lines |
||||
|
|
||||
|
def _get_move_lines_data( |
||||
|
self, company_id, account_ids, partner_ids, date_at_object, |
||||
|
only_posted_moves, show_move_line_details): |
||||
|
domain = self._get_move_lines_domain(company_id, account_ids, |
||||
|
partner_ids, only_posted_moves) |
||||
|
ml_fields = [ |
||||
|
'id', 'name', 'date', 'move_id', 'journal_id', 'account_id', |
||||
|
'partner_id', 'amount_residual', 'date_maturity', 'ref', |
||||
|
'reconciled'] |
||||
|
move_lines = self.env['account.move.line'].search_read( |
||||
|
domain=domain, fields=ml_fields |
||||
) |
) |
||||
self.env.cr.execute(query_inject_partner, query_inject_partner_params) |
|
||||
|
|
||||
def _inject_line_values(self, only_empty_partner_line=False): |
|
||||
""" Inject report values for report_aged_partner_balance_line. |
|
||||
|
ml_ids = set(pd.DataFrame(move_lines).id.to_list()) |
||||
|
journals_ids = set() |
||||
|
partners_ids = set() |
||||
|
partners_data = {} |
||||
|
ag_pb_data = {} |
||||
|
if date_at_object < date.today(): |
||||
|
acc_partial_rec, debit_amount, credit_amount = \ |
||||
|
self._get_account_partial_reconciled(company_id, date_at_object) |
||||
|
if acc_partial_rec: |
||||
|
acc_partial_rec_data = pd.DataFrame(acc_partial_rec) |
||||
|
debit_ids = set(acc_partial_rec_data.debit_move_id.to_list()) |
||||
|
credit_ids = set(acc_partial_rec_data.credit_move_id.to_list()) |
||||
|
move_lines = self._recalculate_move_lines( |
||||
|
move_lines, debit_ids, credit_ids, |
||||
|
debit_amount, credit_amount, ml_ids, account_ids, |
||||
|
company_id, partner_ids, only_posted_moves |
||||
|
) |
||||
|
moves_lines_to_remove = [] |
||||
|
for move_line in move_lines: |
||||
|
if move_line['date'] > date_at_object or \ |
||||
|
float_is_zero(move_line['amount_residual'], |
||||
|
precision_digits=2): |
||||
|
moves_lines_to_remove.append(move_line) |
||||
|
if len(moves_lines_to_remove) > 0: |
||||
|
for move_line_to_remove in moves_lines_to_remove: |
||||
|
move_lines.remove(move_line_to_remove) |
||||
|
for move_line in move_lines: |
||||
|
journals_ids.add(move_line['journal_id'][0]) |
||||
|
acc_id = move_line['account_id'][0] |
||||
|
if move_line['partner_id']: |
||||
|
prt_id = move_line['partner_id'][0] |
||||
|
prt_name = move_line['partner_id'][1] |
||||
|
else: |
||||
|
prt_id = 0 |
||||
|
prt_name = "" |
||||
|
if prt_id not in partners_ids: |
||||
|
partners_data.update({ |
||||
|
prt_id: {'id': prt_id, 'name': prt_name} |
||||
|
}) |
||||
|
partners_ids.add(prt_id) |
||||
|
if acc_id not in ag_pb_data.keys(): |
||||
|
ag_pb_data = self._initialize_account(ag_pb_data, acc_id) |
||||
|
if prt_id not in ag_pb_data[acc_id]: |
||||
|
ag_pb_data = self._initialize_partner(ag_pb_data, acc_id, |
||||
|
prt_id) |
||||
|
move_line_data = {} |
||||
|
if show_move_line_details: |
||||
|
move_line_data.update({ |
||||
|
'date': move_line['date'], |
||||
|
'entry': move_line['move_id'][1], |
||||
|
'jnl_id': move_line['journal_id'][0], |
||||
|
'acc_id': acc_id, |
||||
|
'partner': prt_name, |
||||
|
'ref': move_line['ref'], |
||||
|
'due_date': move_line['date_maturity'], |
||||
|
'residual': move_line['amount_residual'], |
||||
|
}) |
||||
|
ag_pb_data[acc_id][prt_id]['move_lines'].append(move_line_data) |
||||
|
ag_pb_data = self._calculate_amounts( |
||||
|
ag_pb_data, acc_id, prt_id, move_line['amount_residual'], |
||||
|
move_line['date_maturity'], date_at_object) |
||||
|
journals_data = self._get_journals_data(list(journals_ids)) |
||||
|
accounts_data = self._get_accounts_data(ag_pb_data.keys()) |
||||
|
return ag_pb_data, accounts_data, partners_data, journals_data |
||||
|
|
||||
The "only_empty_partner_line" value is used |
|
||||
to compute data without partner. |
|
||||
""" |
|
||||
query_inject_line = """ |
|
||||
WITH |
|
||||
date_range AS |
|
||||
( |
|
||||
SELECT |
|
||||
DATE %s AS date_current, |
|
||||
DATE %s - INTEGER '30' AS date_less_30_days, |
|
||||
DATE %s - INTEGER '60' AS date_less_60_days, |
|
||||
DATE %s - INTEGER '90' AS date_less_90_days, |
|
||||
DATE %s - INTEGER '120' AS date_less_120_days |
|
||||
) |
|
||||
INSERT INTO |
|
||||
report_aged_partner_balance_line |
|
||||
( |
|
||||
report_partner_id, |
|
||||
create_uid, |
|
||||
create_date, |
|
||||
partner, |
|
||||
amount_residual, |
|
||||
current, |
|
||||
age_30_days, |
|
||||
age_60_days, |
|
||||
age_90_days, |
|
||||
age_120_days, |
|
||||
older |
|
||||
) |
|
||||
SELECT |
|
||||
rp.id AS report_partner_id, |
|
||||
%s AS create_uid, |
|
||||
NOW() AS create_date, |
|
||||
rp.name, |
|
||||
SUM(rlo.amount_residual) AS amount_residual, |
|
||||
SUM( |
|
||||
CASE |
|
||||
WHEN rlo.date_due >= date_range.date_current |
|
||||
THEN rlo.amount_residual |
|
||||
END |
|
||||
) AS current, |
|
||||
SUM( |
|
||||
CASE |
|
||||
WHEN |
|
||||
rlo.date_due >= date_range.date_less_30_days |
|
||||
AND rlo.date_due < date_range.date_current |
|
||||
THEN rlo.amount_residual |
|
||||
END |
|
||||
) AS age_30_days, |
|
||||
SUM( |
|
||||
CASE |
|
||||
WHEN |
|
||||
rlo.date_due >= date_range.date_less_60_days |
|
||||
AND rlo.date_due < date_range.date_less_30_days |
|
||||
THEN rlo.amount_residual |
|
||||
END |
|
||||
) AS age_60_days, |
|
||||
SUM( |
|
||||
CASE |
|
||||
WHEN |
|
||||
rlo.date_due >= date_range.date_less_90_days |
|
||||
AND rlo.date_due < date_range.date_less_60_days |
|
||||
THEN rlo.amount_residual |
|
||||
END |
|
||||
) AS age_90_days, |
|
||||
SUM( |
|
||||
CASE |
|
||||
WHEN |
|
||||
rlo.date_due >= date_range.date_less_120_days |
|
||||
AND rlo.date_due < date_range.date_less_90_days |
|
||||
THEN rlo.amount_residual |
|
||||
END |
|
||||
) AS age_120_days, |
|
||||
SUM( |
|
||||
CASE |
|
||||
WHEN rlo.date_due < date_range.date_less_120_days |
|
||||
THEN rlo.amount_residual |
|
||||
END |
|
||||
) AS older |
|
||||
FROM |
|
||||
date_range, |
|
||||
report_open_items_move_line rlo |
|
||||
INNER JOIN |
|
||||
report_open_items_partner rpo ON rlo.report_partner_id = rpo.id |
|
||||
INNER JOIN |
|
||||
report_open_items_account rao ON rpo.report_account_id = rao.id |
|
||||
INNER JOIN |
|
||||
report_aged_partner_balance_account ra ON rao.code = ra.code |
|
||||
INNER JOIN |
|
||||
report_aged_partner_balance_partner rp |
|
||||
ON |
|
||||
ra.id = rp.report_account_id |
|
||||
""" |
|
||||
if not only_empty_partner_line: |
|
||||
query_inject_line += """ |
|
||||
AND rpo.partner_id = rp.partner_id |
|
||||
""" |
|
||||
elif only_empty_partner_line: |
|
||||
query_inject_line += """ |
|
||||
AND rpo.partner_id IS NULL |
|
||||
AND rp.partner_id IS NULL |
|
||||
""" |
|
||||
query_inject_line += """ |
|
||||
WHERE |
|
||||
rao.report_id = %s |
|
||||
AND ra.report_id = %s |
|
||||
GROUP BY |
|
||||
rp.id |
|
||||
""" |
|
||||
query_inject_line_params = (self.date_at,) * 5 |
|
||||
query_inject_line_params += ( |
|
||||
self.env.uid, |
|
||||
self.open_items_id.id, |
|
||||
self.id, |
|
||||
) |
|
||||
self.env.cr.execute(query_inject_line, query_inject_line_params) |
|
||||
|
|
||||
def _inject_move_line_values(self, only_empty_partner_line=False): |
|
||||
""" Inject report values for report_aged_partner_balance_move_line |
|
||||
|
@api.model |
||||
|
def _compute_maturity_date(self, ml, date_at_object): |
||||
|
ml.update({ |
||||
|
'current': 0.0, |
||||
|
'30_days': 0.0, |
||||
|
'60_days': 0.0, |
||||
|
'90_days': 0.0, |
||||
|
'120_days': 0.0, |
||||
|
'older': 0.0, |
||||
|
}) |
||||
|
due_date = ml['due_date'] |
||||
|
amount = ml['residual'] |
||||
|
today = date_at_object |
||||
|
if not due_date or today <= due_date: |
||||
|
ml['current'] += amount |
||||
|
elif today <= due_date + timedelta(days=30): |
||||
|
ml['30_days'] += amount |
||||
|
elif today <= due_date + timedelta(days=60): |
||||
|
ml['60_days'] += amount |
||||
|
elif today <= due_date + timedelta(days=90): |
||||
|
ml['90_days'] += amount |
||||
|
elif today <= due_date + timedelta(days=120): |
||||
|
ml['120_days'] += amount |
||||
|
else: |
||||
|
ml['older'] += amount |
||||
|
|
||||
|
def _create_account_list( |
||||
|
self, ag_pb_data, accounts_data, partners_data, journals_data, |
||||
|
show_move_line_details, date_at_oject): |
||||
|
aged_partner_data = [] |
||||
|
for account in accounts_data.values(): |
||||
|
acc_id = account['id'] |
||||
|
account.update({ |
||||
|
'residual': ag_pb_data[acc_id]['residual'], |
||||
|
'current': ag_pb_data[acc_id]['current'], |
||||
|
'30_days': ag_pb_data[acc_id]['30_days'], |
||||
|
'60_days': ag_pb_data[acc_id]['60_days'], |
||||
|
'90_days': ag_pb_data[acc_id]['90_days'], |
||||
|
'120_days': ag_pb_data[acc_id]['120_days'], |
||||
|
'older': ag_pb_data[acc_id]['older'], |
||||
|
'partners': [], |
||||
|
}) |
||||
|
for prt_id in ag_pb_data[acc_id]: |
||||
|
if isinstance(prt_id, int): |
||||
|
partner = { |
||||
|
'name': partners_data[prt_id]['name'], |
||||
|
'residual': ag_pb_data[acc_id][prt_id]['residual'], |
||||
|
'current': ag_pb_data[acc_id][prt_id]['current'], |
||||
|
'30_days': ag_pb_data[acc_id][prt_id]['30_days'], |
||||
|
'60_days': ag_pb_data[acc_id][prt_id]['60_days'], |
||||
|
'90_days': ag_pb_data[acc_id][prt_id]['90_days'], |
||||
|
'120_days': ag_pb_data[acc_id][prt_id]['120_days'], |
||||
|
'older': ag_pb_data[acc_id][prt_id]['older'], |
||||
|
} |
||||
|
if show_move_line_details: |
||||
|
move_lines = [] |
||||
|
for ml in ag_pb_data[acc_id][prt_id]['move_lines']: |
||||
|
ml.update({ |
||||
|
'journal': journals_data[ml['jnl_id']]['code'], |
||||
|
'account': accounts_data[ml['acc_id']]['code'], |
||||
|
}) |
||||
|
self._compute_maturity_date(ml, date_at_oject) |
||||
|
move_lines.append(ml) |
||||
|
partner.update({ |
||||
|
'move_lines': move_lines |
||||
|
}) |
||||
|
account['partners'].append(partner) |
||||
|
aged_partner_data.append(account) |
||||
|
return aged_partner_data |
||||
|
|
||||
The "only_empty_partner_line" value is used |
|
||||
to compute data without partner. |
|
||||
""" |
|
||||
query_inject_move_line = """ |
|
||||
WITH |
|
||||
date_range AS |
|
||||
( |
|
||||
SELECT |
|
||||
DATE %s AS date_current, |
|
||||
DATE %s - INTEGER '30' AS date_less_30_days, |
|
||||
DATE %s - INTEGER '60' AS date_less_60_days, |
|
||||
DATE %s - INTEGER '90' AS date_less_90_days, |
|
||||
DATE %s - INTEGER '120' AS date_less_120_days |
|
||||
) |
|
||||
INSERT INTO |
|
||||
report_aged_partner_balance_move_line |
|
||||
( |
|
||||
report_partner_id, |
|
||||
create_uid, |
|
||||
create_date, |
|
||||
move_line_id, |
|
||||
date, |
|
||||
date_due, |
|
||||
entry, |
|
||||
journal, |
|
||||
account, |
|
||||
partner, |
|
||||
label, |
|
||||
amount_residual, |
|
||||
current, |
|
||||
age_30_days, |
|
||||
age_60_days, |
|
||||
age_90_days, |
|
||||
age_120_days, |
|
||||
older |
|
||||
) |
|
||||
SELECT |
|
||||
rp.id AS report_partner_id, |
|
||||
%s AS create_uid, |
|
||||
NOW() AS create_date, |
|
||||
rlo.move_line_id, |
|
||||
rlo.date, |
|
||||
rlo.date_due, |
|
||||
rlo.entry, |
|
||||
rlo.journal, |
|
||||
rlo.account, |
|
||||
rlo.partner, |
|
||||
rlo.label, |
|
||||
rlo.amount_residual AS amount_residual, |
|
||||
CASE |
|
||||
WHEN rlo.date_due >= date_range.date_current |
|
||||
THEN rlo.amount_residual |
|
||||
END AS current, |
|
||||
CASE |
|
||||
WHEN |
|
||||
rlo.date_due >= date_range.date_less_30_days |
|
||||
AND rlo.date_due < date_range.date_current |
|
||||
THEN rlo.amount_residual |
|
||||
END AS age_30_days, |
|
||||
CASE |
|
||||
WHEN |
|
||||
rlo.date_due >= date_range.date_less_60_days |
|
||||
AND rlo.date_due < date_range.date_less_30_days |
|
||||
THEN rlo.amount_residual |
|
||||
END AS age_60_days, |
|
||||
CASE |
|
||||
WHEN |
|
||||
rlo.date_due >= date_range.date_less_90_days |
|
||||
AND rlo.date_due < date_range.date_less_60_days |
|
||||
THEN rlo.amount_residual |
|
||||
END AS age_90_days, |
|
||||
CASE |
|
||||
WHEN |
|
||||
rlo.date_due >= date_range.date_less_120_days |
|
||||
AND rlo.date_due < date_range.date_less_90_days |
|
||||
THEN rlo.amount_residual |
|
||||
END AS age_120_days, |
|
||||
CASE |
|
||||
WHEN rlo.date_due < date_range.date_less_120_days |
|
||||
THEN rlo.amount_residual |
|
||||
END AS older |
|
||||
FROM |
|
||||
date_range, |
|
||||
report_open_items_move_line rlo |
|
||||
INNER JOIN |
|
||||
report_open_items_partner rpo ON rlo.report_partner_id = rpo.id |
|
||||
INNER JOIN |
|
||||
report_open_items_account rao ON rpo.report_account_id = rao.id |
|
||||
INNER JOIN |
|
||||
report_aged_partner_balance_account ra ON rao.code = ra.code |
|
||||
INNER JOIN |
|
||||
report_aged_partner_balance_partner rp |
|
||||
ON |
|
||||
ra.id = rp.report_account_id |
|
||||
""" |
|
||||
if not only_empty_partner_line: |
|
||||
query_inject_move_line += """ |
|
||||
AND rpo.partner_id = rp.partner_id |
|
||||
""" |
|
||||
elif only_empty_partner_line: |
|
||||
query_inject_move_line += """ |
|
||||
AND rpo.partner_id IS NULL |
|
||||
AND rp.partner_id IS NULL |
|
||||
""" |
|
||||
query_inject_move_line += """ |
|
||||
WHERE |
|
||||
rao.report_id = %s |
|
||||
AND ra.report_id = %s |
|
||||
""" |
|
||||
query_inject_move_line_params = (self.date_at,) * 5 |
|
||||
query_inject_move_line_params += ( |
|
||||
self.env.uid, |
|
||||
self.open_items_id.id, |
|
||||
self.id, |
|
||||
) |
|
||||
self.env.cr.execute(query_inject_move_line, |
|
||||
query_inject_move_line_params) |
|
||||
|
@api.model |
||||
|
def _calculate_percent(self, aged_partner_data): |
||||
|
for account in aged_partner_data: |
||||
|
if abs(account['residual']) > 0.01: |
||||
|
total = account['residual'] |
||||
|
account.update({ |
||||
|
'percent_current': abs( |
||||
|
round((account['current'] / total) * 100, 2)), |
||||
|
'percent_30_days': abs( |
||||
|
round((account['30_days'] / total) * 100, |
||||
|
2)), |
||||
|
'percent_60_days': abs( |
||||
|
round((account['60_days'] / total) * 100, |
||||
|
2)), |
||||
|
'percent_90_days': abs( |
||||
|
round((account['90_days'] / total) * 100, |
||||
|
2)), |
||||
|
'percent_120_days': abs( |
||||
|
round((account['120_days'] / total) * 100, |
||||
|
2)), |
||||
|
'percent_older': abs( |
||||
|
round((account['older'] / total) * 100, 2)), |
||||
|
}) |
||||
|
else: |
||||
|
account.update({ |
||||
|
'percent_current': 0.0, |
||||
|
'percent_30_days': 0.0, |
||||
|
'percent_60_days': 0.0, |
||||
|
'percent_90_days': 0.0, |
||||
|
'percent_120_days': 0.0, |
||||
|
'percent_older': 0.0, |
||||
|
}) |
||||
|
return aged_partner_data |
||||
|
|
||||
def _compute_accounts_cumul(self): |
|
||||
""" Compute cumulative amount for |
|
||||
report_aged_partner_balance_account. |
|
||||
""" |
|
||||
query_compute_accounts_cumul = """ |
|
||||
WITH |
|
||||
cumuls AS |
|
||||
( |
|
||||
SELECT |
|
||||
ra.id AS report_account_id, |
|
||||
SUM(rl.amount_residual) AS cumul_amount_residual, |
|
||||
SUM(rl.current) AS cumul_current, |
|
||||
SUM(rl.age_30_days) AS cumul_age_30_days, |
|
||||
SUM(rl.age_60_days) AS cumul_age_60_days, |
|
||||
SUM(rl.age_90_days) AS cumul_age_90_days, |
|
||||
SUM(rl.age_120_days) AS cumul_age_120_days, |
|
||||
SUM(rl.older) AS cumul_older |
|
||||
FROM |
|
||||
report_aged_partner_balance_line rl |
|
||||
INNER JOIN |
|
||||
report_aged_partner_balance_partner rp |
|
||||
ON rl.report_partner_id = rp.id |
|
||||
INNER JOIN |
|
||||
report_aged_partner_balance_account ra |
|
||||
ON rp.report_account_id = ra.id |
|
||||
WHERE |
|
||||
ra.report_id = %s |
|
||||
GROUP BY |
|
||||
ra.id |
|
||||
) |
|
||||
UPDATE |
|
||||
report_aged_partner_balance_account |
|
||||
SET |
|
||||
cumul_amount_residual = c.cumul_amount_residual, |
|
||||
cumul_current = c.cumul_current, |
|
||||
cumul_age_30_days = c.cumul_age_30_days, |
|
||||
cumul_age_60_days = c.cumul_age_60_days, |
|
||||
cumul_age_90_days = c.cumul_age_90_days, |
|
||||
cumul_age_120_days = c.cumul_age_120_days, |
|
||||
cumul_older = c.cumul_older, |
|
||||
percent_current = |
|
||||
CASE |
|
||||
WHEN c.cumul_amount_residual != 0 |
|
||||
THEN 100 * c.cumul_current / c.cumul_amount_residual |
|
||||
END, |
|
||||
percent_age_30_days = |
|
||||
CASE |
|
||||
WHEN c.cumul_amount_residual != 0 |
|
||||
THEN 100 * c.cumul_age_30_days / c.cumul_amount_residual |
|
||||
END, |
|
||||
percent_age_60_days = |
|
||||
CASE |
|
||||
WHEN c.cumul_amount_residual != 0 |
|
||||
THEN 100 * c.cumul_age_60_days / c.cumul_amount_residual |
|
||||
END, |
|
||||
percent_age_90_days = |
|
||||
CASE |
|
||||
WHEN c.cumul_amount_residual != 0 |
|
||||
THEN 100 * c.cumul_age_90_days / c.cumul_amount_residual |
|
||||
END, |
|
||||
percent_age_120_days = |
|
||||
CASE |
|
||||
WHEN c.cumul_amount_residual != 0 |
|
||||
THEN 100 * c.cumul_age_120_days / c.cumul_amount_residual |
|
||||
END, |
|
||||
percent_older = |
|
||||
CASE |
|
||||
WHEN c.cumul_amount_residual != 0 |
|
||||
THEN 100 * c.cumul_older / c.cumul_amount_residual |
|
||||
END |
|
||||
FROM |
|
||||
cumuls c |
|
||||
WHERE |
|
||||
id = c.report_account_id |
|
||||
""" |
|
||||
params_compute_accounts_cumul = (self.id,) |
|
||||
self.env.cr.execute(query_compute_accounts_cumul, |
|
||||
params_compute_accounts_cumul) |
|
||||
|
@api.multi |
||||
|
def _get_report_values(self, docids, data): |
||||
|
wizard_id = data['wizard_id'] |
||||
|
company = self.env['res.company'].browse(data['company_id']) |
||||
|
company_id = data['company_id'] |
||||
|
account_ids = data['account_ids'] |
||||
|
partner_ids = data['partner_ids'] |
||||
|
date_at = data['date_at'] |
||||
|
date_at_object = datetime.strptime(date_at, '%Y-%m-%d').date() |
||||
|
only_posted_moves = data['only_posted_moves'] |
||||
|
show_move_line_details = data['show_move_line_details'] |
||||
|
ag_pb_data, accounts_data, partners_data, \ |
||||
|
journals_data = self._get_move_lines_data( |
||||
|
company_id, account_ids, partner_ids, date_at_object, |
||||
|
only_posted_moves, show_move_line_details) |
||||
|
aged_partner_data = self._create_account_list( |
||||
|
ag_pb_data, accounts_data, partners_data, journals_data, |
||||
|
show_move_line_details, date_at_object) |
||||
|
aged_partner_data = self._calculate_percent(aged_partner_data) |
||||
|
return { |
||||
|
'doc_ids': [wizard_id], |
||||
|
'doc_model': 'open.items.report.wizard', |
||||
|
'docs': self.env['open.items.report.wizard'].browse(wizard_id), |
||||
|
'company_name': company.display_name, |
||||
|
'currency_name': company.currency_id.name, |
||||
|
'date_at': date_at, |
||||
|
'only_posted_moves': only_posted_moves, |
||||
|
'aged_partner_balance': aged_partner_data, |
||||
|
'show_move_lines_details': show_move_line_details, |
||||
|
} |
2353
account_financial_report/report/general_ledger.py
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
1168
account_financial_report/report/journal_ledger.py
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
1209
account_financial_report/report/open_items.py
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
1033
account_financial_report/report/templates/trial_balance.xml
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
1191
account_financial_report/report/trial_balance.py
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,356 +1,190 @@ |
|||||
# Copyright 2018 Forest and Biomass Romania |
# Copyright 2018 Forest and Biomass Romania |
||||
|
# Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com) |
||||
# 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 odoo import api, fields, models |
|
||||
|
from odoo import models, api |
||||
|
|
||||
|
|
||||
class VATReport(models.TransientModel): |
|
||||
_name = "report_vat_report" |
|
||||
_inherit = 'account_financial_report_abstract' |
|
||||
""" Here, we just define class fields. |
|
||||
For methods, go more bottom at this file. |
|
||||
|
class VATReport(models.AbstractModel): |
||||
|
_name = 'report.account_financial_report.vat_report' |
||||
|
_description = "VAT Report" |
||||
|
|
||||
The class hierarchy is : |
|
||||
* VATReport |
|
||||
** VATReportTaxTags |
|
||||
*** VATReportTax |
|
||||
""" |
|
||||
|
|
||||
# Filters fields, used for data computation |
|
||||
company_id = fields.Many2one(comodel_name='res.company') |
|
||||
date_from = fields.Date() |
|
||||
date_to = fields.Date() |
|
||||
based_on = fields.Selection([('taxtags', 'Tax Tags'), |
|
||||
('taxgroups', 'Tax Groups')], |
|
||||
string='Based On', |
|
||||
required=True, |
|
||||
default='taxtags') |
|
||||
tax_detail = fields.Boolean('Tax Detail') |
|
||||
|
|
||||
# Data fields, used to browse report data |
|
||||
taxtags_ids = fields.One2many( |
|
||||
comodel_name='report_vat_report_taxtag', |
|
||||
inverse_name='report_id' |
|
||||
) |
|
||||
|
|
||||
|
|
||||
class VATReportTaxTags(models.TransientModel): |
|
||||
_name = 'report_vat_report_taxtag' |
|
||||
_inherit = 'account_financial_report_abstract' |
|
||||
_order = 'code ASC' |
|
||||
|
|
||||
report_id = fields.Many2one( |
|
||||
comodel_name='report_vat_report', |
|
||||
ondelete='cascade', |
|
||||
index=True |
|
||||
) |
|
||||
|
|
||||
# Data fields, used to keep link with real object |
|
||||
taxtag_id = fields.Many2one( |
|
||||
'account.account.tag', |
|
||||
index=True |
|
||||
) |
|
||||
taxgroup_id = fields.Many2one( |
|
||||
'account.tax.group', |
|
||||
index=True |
|
||||
) |
|
||||
|
|
||||
# Data fields, used for report display |
|
||||
code = fields.Char() |
|
||||
name = fields.Char() |
|
||||
net = fields.Float(digits=(16, 2)) |
|
||||
tax = fields.Float(digits=(16, 2)) |
|
||||
|
|
||||
# Data fields, used to browse report data |
|
||||
tax_ids = fields.One2many( |
|
||||
comodel_name='report_vat_report_tax', |
|
||||
inverse_name='report_tax_id', |
|
||||
string='Taxes' |
|
||||
) |
|
||||
|
|
||||
|
|
||||
class VATReportTax(models.TransientModel): |
|
||||
_name = 'report_vat_report_tax' |
|
||||
_inherit = 'account_financial_report_abstract' |
|
||||
_order = 'name ASC' |
|
||||
|
|
||||
report_tax_id = fields.Many2one( |
|
||||
comodel_name='report_vat_report_taxtag', |
|
||||
ondelete='cascade', |
|
||||
index=True |
|
||||
) |
|
||||
|
|
||||
# Data fields, used to keep link with real object |
|
||||
tax_id = fields.Many2one( |
|
||||
'account.tax', |
|
||||
index=True, |
|
||||
string='Tax ID', |
|
||||
) |
|
||||
|
|
||||
# Data fields, used for report display |
|
||||
code = fields.Char() |
|
||||
name = fields.Char() |
|
||||
net = fields.Float(digits=(16, 2)) |
|
||||
tax = fields.Float(digits=(16, 2)) |
|
||||
|
|
||||
|
|
||||
class VATReportCompute(models.TransientModel): |
|
||||
""" Here, we just define methods. |
|
||||
For class fields, go more top at this file. |
|
||||
""" |
|
||||
|
|
||||
_inherit = 'report_vat_report' |
|
||||
|
|
||||
@api.multi |
|
||||
def print_report(self, report_type='qweb'): |
|
||||
self.ensure_one() |
|
||||
if report_type == 'xlsx': |
|
||||
report_name = 'a_f_r.report_vat_report_xlsx' |
|
||||
else: |
|
||||
report_name = 'account_financial_report.report_vat_report_qweb' |
|
||||
context = dict(self.env.context) |
|
||||
action = self.env['ir.actions.report'].search( |
|
||||
[('report_name', '=', report_name), |
|
||||
('report_type', '=', report_type)], limit=1) |
|
||||
return action.with_context(context).report_action(self, config=False) |
|
||||
|
|
||||
def _get_html(self): |
|
||||
result = {} |
|
||||
rcontext = {} |
|
||||
context = dict(self.env.context) |
|
||||
report = self.browse(context.get('active_id')) |
|
||||
if report: |
|
||||
rcontext['o'] = report |
|
||||
result['html'] = self.env.ref( |
|
||||
'account_financial_report.report_vat_report').render( |
|
||||
rcontext) |
|
||||
return result |
|
||||
|
def _get_tax_data(self, tax_ids): |
||||
|
taxes = self.env['account.tax'].browse(tax_ids) |
||||
|
tax_data = {} |
||||
|
for tax in taxes: |
||||
|
tax_data.update({ |
||||
|
tax.id: { |
||||
|
'id': tax.id, |
||||
|
'name': tax.name, |
||||
|
'tax_group_id': tax.tax_group_id.id, |
||||
|
'tags_ids': tax.tag_ids.ids |
||||
|
} |
||||
|
}) |
||||
|
return tax_data |
||||
|
|
||||
@api.model |
@api.model |
||||
def get_html(self, given_context=None): |
|
||||
return self.with_context(given_context)._get_html() |
|
||||
|
|
||||
@api.multi |
|
||||
def compute_data_for_report(self): |
|
||||
self.ensure_one() |
|
||||
# Compute report data |
|
||||
if self.based_on == 'taxtags': |
|
||||
self._inject_taxtags_values() |
|
||||
self._inject_tax_taxtags_values() |
|
||||
elif self.based_on == 'taxgroups': |
|
||||
self._inject_taxgroups_values() |
|
||||
self._inject_tax_taxgroups_values() |
|
||||
# Refresh cache because all data are computed with SQL requests |
|
||||
self.refresh() |
|
||||
|
|
||||
def _inject_taxtags_values(self): |
|
||||
"""Inject report values for report_vat_report_taxtags.""" |
|
||||
query_inject_taxtags = """ |
|
||||
WITH |
|
||||
taxtags AS |
|
||||
(SELECT coalesce(regexp_replace(tag.name, |
|
||||
'[^0-9\\.]+', '', 'g'), ' ') AS code, |
|
||||
tag.name, tag.id, |
|
||||
coalesce(sum(movetax.tax_base_amount), 0.00) AS net, |
|
||||
coalesce(sum(movetax.balance), 0.00) AS tax |
|
||||
FROM |
|
||||
account_account_tag AS tag |
|
||||
INNER JOIN account_tax_account_tag AS taxtag |
|
||||
ON tag.id = taxtag.account_account_tag_id |
|
||||
INNER JOIN account_tax AS tax |
|
||||
ON tax.id = taxtag.account_tax_id |
|
||||
INNER JOIN account_move_line AS movetax |
|
||||
ON movetax.tax_line_id = tax.id |
|
||||
INNER JOIN account_move AS move |
|
||||
ON move.id = movetax.move_id |
|
||||
WHERE tag.id is not null AND movetax.tax_exigible |
|
||||
AND move.company_id = %s AND move.date >= %s |
|
||||
AND move.date <= %s AND move.state = 'posted' |
|
||||
GROUP BY tag.id |
|
||||
ORDER BY code, tag.name |
|
||||
|
def _get_vat_report_domain(self, company_id, date_from, date_to): |
||||
|
domain = [('company_id', '=', company_id), |
||||
|
('date', '>=', date_from), |
||||
|
('date', '<', date_to), |
||||
|
('tax_line_id', '!=', False), |
||||
|
('tax_exigible', '=', True)] |
||||
|
return domain |
||||
|
|
||||
|
def _get_vat_report_data(self, company_id, date_from, date_to): |
||||
|
domain = self._get_vat_report_domain(company_id, date_from, date_to) |
||||
|
ml_fields = ['id', 'tax_base_amount', 'balance', 'tax_line_id', |
||||
|
'analytic_tag_ids'] |
||||
|
tax_move_lines = self.env['account.move.line'].search_read( |
||||
|
domain=domain, |
||||
|
fields=ml_fields, |
||||
) |
) |
||||
INSERT INTO |
|
||||
report_vat_report_taxtag |
|
||||
( |
|
||||
report_id, |
|
||||
create_uid, |
|
||||
create_date, |
|
||||
taxtag_id, |
|
||||
code, |
|
||||
name, |
|
||||
net, tax |
|
||||
) |
|
||||
SELECT |
|
||||
%s AS report_id, |
|
||||
%s AS create_uid, |
|
||||
NOW() AS create_date, |
|
||||
tag.id, |
|
||||
tag.code, |
|
||||
tag.name, |
|
||||
abs(tag.net), |
|
||||
abs(tag.tax) |
|
||||
FROM |
|
||||
taxtags tag |
|
||||
""" |
|
||||
query_inject_taxtags_params = (self.company_id.id, self.date_from, |
|
||||
self.date_to, self.id, self.env.uid) |
|
||||
self.env.cr.execute(query_inject_taxtags, query_inject_taxtags_params) |
|
||||
|
vat_data = {} |
||||
|
tax_ids = set() |
||||
|
for tax_move_line in tax_move_lines: |
||||
|
tax_ml_id = tax_move_line['id'] |
||||
|
vat_data[tax_ml_id] = {} |
||||
|
vat_data[tax_ml_id].update({ |
||||
|
'id': tax_ml_id, |
||||
|
'net': tax_move_line['tax_base_amount'], |
||||
|
'tax': tax_move_line['balance'] if tax_move_line[ |
||||
|
'balance'] > 0 else (-1) * tax_move_line['balance'], |
||||
|
'tax_line_id': tax_move_line['tax_line_id'], |
||||
|
}) |
||||
|
tax_ids.add(tax_move_line['tax_line_id'][0]) |
||||
|
tax_data = self._get_tax_data(tax_ids) |
||||
|
return vat_data, tax_data |
||||
|
|
||||
|
def _get_tax_group_data(self, tax_group_ids): |
||||
|
tax_groups = self.env['account.tax.group'].browse(tax_group_ids) |
||||
|
tax_group_data = {} |
||||
|
for tax_group in tax_groups: |
||||
|
tax_group_data.update({ |
||||
|
tax_group.id: { |
||||
|
'id': tax_group.id, |
||||
|
'name': tax_group.name, |
||||
|
'code': str(tax_group.sequence), |
||||
|
} |
||||
|
}) |
||||
|
return tax_group_data |
||||
|
|
||||
|
def _get_vat_report_group_data(self, vat_report_data, tax_data, tax_detail): |
||||
|
vat_report = {} |
||||
|
for tax_move_line in vat_report_data.values(): |
||||
|
tax_id = tax_move_line['tax_line_id'][0] |
||||
|
tax_group_id = tax_data[tax_id]['tax_group_id'] |
||||
|
if tax_group_id not in vat_report.keys(): |
||||
|
vat_report[tax_group_id] = {} |
||||
|
vat_report[tax_group_id]['net'] = 0.0 |
||||
|
vat_report[tax_group_id]['tax'] = 0.0 |
||||
|
vat_report[tax_group_id][tax_id] = tax_data[tax_id] |
||||
|
vat_report[tax_group_id][tax_id].update( |
||||
|
{'net': 0.0, 'tax': 0.0} |
||||
|
) |
||||
|
else: |
||||
|
if tax_id not in vat_report[tax_group_id].keys(): |
||||
|
vat_report[tax_group_id][tax_id] = tax_data[tax_id] |
||||
|
vat_report[tax_group_id][tax_id].update( |
||||
|
{'net': 0.0, 'tax': 0.0} |
||||
|
) |
||||
|
vat_report[tax_group_id]['net'] += tax_move_line['net'] |
||||
|
vat_report[tax_group_id]['tax'] += tax_move_line['tax'] |
||||
|
vat_report[tax_group_id][tax_id]['net'] += tax_move_line['net'] |
||||
|
vat_report[tax_group_id][tax_id]['tax'] += tax_move_line['tax'] |
||||
|
tax_group_data = self._get_tax_group_data(vat_report.keys()) |
||||
|
vat_report_list = [] |
||||
|
for tax_group_id in vat_report.keys(): |
||||
|
vat_report[tax_group_id]['name'] = tax_group_data[ |
||||
|
tax_group_id]['name'] |
||||
|
vat_report[tax_group_id]['code'] = tax_group_data[ |
||||
|
tax_group_id]['code'] |
||||
|
if tax_detail: |
||||
|
vat_report[tax_group_id]['taxes'] = [] |
||||
|
for tax_id in vat_report[tax_group_id]: |
||||
|
if isinstance(tax_id, int): |
||||
|
vat_report[tax_group_id]['taxes'].append( |
||||
|
vat_report[tax_group_id][tax_id] |
||||
|
) |
||||
|
vat_report_list.append(vat_report[tax_group_id]) |
||||
|
return vat_report_list |
||||
|
|
||||
|
def _get_tags_data(self, tags_ids): |
||||
|
tags = self.env['account.account.tag'].browse(tags_ids) |
||||
|
tags_data = {} |
||||
|
for tag in tags: |
||||
|
tags_data.update({tag.id: { |
||||
|
'code': "", |
||||
|
'name': tag.name} |
||||
|
}) |
||||
|
return tags_data |
||||
|
|
||||
|
def _get_vat_report_tag_data(self, vat_report_data, tax_data, tax_detail): |
||||
|
vat_report = {} |
||||
|
for tax_move_line in vat_report_data.values(): |
||||
|
tax_id = tax_move_line['tax_line_id'][0] |
||||
|
tags_ids = tax_data[tax_id]['tags_ids'] |
||||
|
if tags_ids: |
||||
|
for tag_id in tags_ids: |
||||
|
if tag_id not in vat_report.keys(): |
||||
|
vat_report[tag_id] = {} |
||||
|
vat_report[tag_id]['net'] = 0.0 |
||||
|
vat_report[tag_id]['tax'] = 0.0 |
||||
|
vat_report[tag_id][tax_id] = tax_data[tax_id] |
||||
|
vat_report[tag_id][tax_id].update( |
||||
|
{'net': 0.0, 'tax': 0.0} |
||||
|
) |
||||
|
else: |
||||
|
if tax_id not in vat_report[tag_id].keys(): |
||||
|
vat_report[tag_id][tax_id] = tax_data[tax_id] |
||||
|
vat_report[tag_id][tax_id].update( |
||||
|
{'net': 0.0, 'tax': 0.0} |
||||
|
) |
||||
|
vat_report[tag_id][tax_id]['net'] += tax_move_line['net'] |
||||
|
vat_report[tag_id][tax_id]['tax'] += tax_move_line['tax'] |
||||
|
vat_report[tag_id]['net'] += tax_move_line['net'] |
||||
|
vat_report[tag_id]['tax'] += tax_move_line['tax'] |
||||
|
tags_data = self._get_tags_data(vat_report.keys()) |
||||
|
vat_report_list = [] |
||||
|
for tag_id in vat_report.keys(): |
||||
|
vat_report[tag_id]['name'] = tags_data[tag_id]['name'] |
||||
|
vat_report[tag_id]['code'] = tags_data[tag_id]['code'] |
||||
|
if tax_detail: |
||||
|
vat_report[tag_id]['taxes'] = [] |
||||
|
for tax_id in vat_report[tag_id]: |
||||
|
if isinstance(tax_id, int): |
||||
|
vat_report[tag_id]['taxes'].append( |
||||
|
vat_report[tag_id][tax_id] |
||||
|
) |
||||
|
vat_report_list.append(vat_report[tag_id]) |
||||
|
return vat_report_list |
||||
|
|
||||
def _inject_taxgroups_values(self): |
|
||||
"""Inject report values for report_vat_report_taxtags.""" |
|
||||
query_inject_taxgroups = """ |
|
||||
WITH |
|
||||
taxgroups AS |
|
||||
(SELECT coalesce(taxgroup.sequence, 0) AS code, |
|
||||
taxgroup.name, taxgroup.id, |
|
||||
coalesce(sum(movetax.tax_base_amount), 0.00) AS net, |
|
||||
coalesce(sum(movetax.balance), 0.00) AS tax |
|
||||
FROM |
|
||||
account_tax_group AS taxgroup |
|
||||
INNER JOIN account_tax AS tax |
|
||||
ON tax.tax_group_id = taxgroup.id |
|
||||
INNER JOIN account_move_line AS movetax |
|
||||
ON movetax.tax_line_id = tax.id |
|
||||
INNER JOIN account_move AS move |
|
||||
ON move.id = movetax.move_id |
|
||||
WHERE taxgroup.id is not null AND movetax.tax_exigible |
|
||||
AND move.company_id = %s AND move.date >= %s |
|
||||
AND move.date <= %s AND move.state = 'posted' |
|
||||
GROUP BY taxgroup.id |
|
||||
ORDER BY code, taxgroup.name |
|
||||
) |
|
||||
INSERT INTO |
|
||||
report_vat_report_taxtag |
|
||||
( |
|
||||
report_id, |
|
||||
create_uid, |
|
||||
create_date, |
|
||||
taxgroup_id, |
|
||||
code, |
|
||||
name, |
|
||||
net, tax |
|
||||
) |
|
||||
SELECT |
|
||||
%s AS report_id, |
|
||||
%s AS create_uid, |
|
||||
NOW() AS create_date, |
|
||||
groups.id, |
|
||||
groups.code, |
|
||||
groups.name, |
|
||||
abs(groups.net), |
|
||||
abs(groups.tax) |
|
||||
FROM |
|
||||
taxgroups groups |
|
||||
""" |
|
||||
query_inject_taxgroups_params = (self.company_id.id, self.date_from, |
|
||||
self.date_to, self.id, self.env.uid) |
|
||||
self.env.cr.execute(query_inject_taxgroups, |
|
||||
query_inject_taxgroups_params) |
|
||||
|
|
||||
def _inject_tax_taxtags_values(self): |
|
||||
""" Inject report values for report_vat_report_tax. """ |
|
||||
# pylint: disable=sql-injection |
|
||||
query_inject_tax = """ |
|
||||
WITH |
|
||||
taxtags_tax AS |
|
||||
( |
|
||||
SELECT |
|
||||
tag.id AS report_tax_id, ' ' AS code, |
|
||||
tax.name, tax.id, |
|
||||
coalesce(sum(movetax.tax_base_amount), 0.00) AS net, |
|
||||
coalesce(sum(movetax.balance), 0.00) AS tax |
|
||||
FROM |
|
||||
report_vat_report_taxtag AS tag |
|
||||
INNER JOIN account_tax_account_tag AS taxtag |
|
||||
ON tag.taxtag_id = taxtag.account_account_tag_id |
|
||||
INNER JOIN account_tax AS tax |
|
||||
ON tax.id = taxtag.account_tax_id |
|
||||
INNER JOIN account_move_line AS movetax |
|
||||
ON movetax.tax_line_id = tax.id |
|
||||
INNER JOIN account_move AS move |
|
||||
ON move.id = movetax.move_id |
|
||||
WHERE tag.id is not null AND movetax.tax_exigible |
|
||||
AND tag.report_id = %s AND move.company_id = %s |
|
||||
AND move.date >= %s AND move.date <= %s |
|
||||
AND move.state = 'posted' |
|
||||
GROUP BY tag.id, tax.id |
|
||||
ORDER BY tax.name |
|
||||
) |
|
||||
INSERT INTO |
|
||||
report_vat_report_tax |
|
||||
( |
|
||||
report_tax_id, |
|
||||
create_uid, |
|
||||
create_date, |
|
||||
tax_id, |
|
||||
name, |
|
||||
net, |
|
||||
tax |
|
||||
) |
|
||||
SELECT |
|
||||
tt.report_tax_id, |
|
||||
%s AS create_uid, |
|
||||
NOW() AS create_date, |
|
||||
tt.id, |
|
||||
tt.name, |
|
||||
abs(tt.net), |
|
||||
abs(tt.tax) |
|
||||
FROM |
|
||||
taxtags_tax tt |
|
||||
""" |
|
||||
query_inject_tax_params = (self.id, self.company_id.id, self.date_from, |
|
||||
self.date_to, self.env.uid) |
|
||||
self.env.cr.execute(query_inject_tax, query_inject_tax_params) |
|
||||
|
|
||||
def _inject_tax_taxgroups_values(self): |
|
||||
""" Inject report values for report_vat_report_tax. """ |
|
||||
# pylint: disable=sql-injection |
|
||||
query_inject_tax = """ |
|
||||
WITH |
|
||||
taxtags_tax AS |
|
||||
( |
|
||||
SELECT |
|
||||
taxtag.id AS report_tax_id, ' ' AS code, |
|
||||
tax.name, tax.id, |
|
||||
coalesce(sum(movetax.tax_base_amount), 0.00) AS net, |
|
||||
coalesce(sum(movetax.balance), 0.00) AS tax |
|
||||
FROM |
|
||||
report_vat_report_taxtag AS taxtag |
|
||||
INNER JOIN account_tax AS tax |
|
||||
ON tax.tax_group_id = taxtag.taxgroup_id |
|
||||
INNER JOIN account_move_line AS movetax |
|
||||
ON movetax.tax_line_id = tax.id |
|
||||
INNER JOIN account_move AS move |
|
||||
ON move.id = movetax.move_id |
|
||||
WHERE taxtag.id is not null AND movetax.tax_exigible |
|
||||
AND taxtag.report_id = %s AND move.company_id = %s |
|
||||
AND move.date >= %s AND move.date <= %s |
|
||||
AND move.state = 'posted' |
|
||||
GROUP BY taxtag.id, tax.id |
|
||||
ORDER BY tax.name |
|
||||
) |
|
||||
INSERT INTO |
|
||||
report_vat_report_tax |
|
||||
( |
|
||||
report_tax_id, |
|
||||
create_uid, |
|
||||
create_date, |
|
||||
tax_id, |
|
||||
name, |
|
||||
net, |
|
||||
tax |
|
||||
) |
|
||||
SELECT |
|
||||
tt.report_tax_id, |
|
||||
%s AS create_uid, |
|
||||
NOW() AS create_date, |
|
||||
tt.id, |
|
||||
tt.name, |
|
||||
abs(tt.net), |
|
||||
abs(tt.tax) |
|
||||
FROM |
|
||||
taxtags_tax tt |
|
||||
""" |
|
||||
query_inject_tax_params = (self.id, self.company_id.id, self.date_from, |
|
||||
self.date_to, self.env.uid) |
|
||||
self.env.cr.execute(query_inject_tax, query_inject_tax_params) |
|
||||
|
@api.multi |
||||
|
def _get_report_values(self, docids, data): |
||||
|
wizard_id = data['wizard_id'] |
||||
|
company = self.env['res.company'].browse(data['company_id']) |
||||
|
company_id = data['company_id'] |
||||
|
date_from = data['date_from'] |
||||
|
date_to = data['date_to'] |
||||
|
based_on = data['based_on'] |
||||
|
tax_detail = data['tax_detail'] |
||||
|
vat_report_data, tax_data = self._get_vat_report_data( |
||||
|
company_id, date_from, date_to) |
||||
|
if based_on == 'taxgroups': |
||||
|
vat_report = self._get_vat_report_group_data( |
||||
|
vat_report_data, tax_data, tax_detail) |
||||
|
else: |
||||
|
vat_report = self._get_vat_report_tag_data( |
||||
|
vat_report_data, tax_data, tax_detail) |
||||
|
return { |
||||
|
'doc_ids': [wizard_id], |
||||
|
'doc_model': 'open.items.report.wizard', |
||||
|
'docs': self.env['open.items.report.wizard'].browse(wizard_id), |
||||
|
'company_name': company.display_name, |
||||
|
'currency_name': company.currency_id.name, |
||||
|
'date_to': data['date_to'], |
||||
|
'date_from': data['date_from'], |
||||
|
'based_on': data['based_on'], |
||||
|
'tax_detail': data['tax_detail'], |
||||
|
'vat_report': vat_report, |
||||
|
} |
@ -1,399 +0,0 @@ |
|||||
# Author: Julien Coux |
|
||||
# Copyright 2016 Camptocamp SA |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
|
|
||||
import logging |
|
||||
|
|
||||
from odoo.tests import common |
|
||||
from odoo.tools import test_reports |
|
||||
|
|
||||
_logger = logging.getLogger(__name__) |
|
||||
|
|
||||
|
|
||||
class AbstractTest(common.TransactionCase): |
|
||||
"""Common technical tests for all reports.""" |
|
||||
at_install = False |
|
||||
post_install = True |
|
||||
|
|
||||
accounts = {} |
|
||||
|
|
||||
def with_context(self, *args, **kwargs): |
|
||||
context = dict(args[0] if args else self.env.context, **kwargs) |
|
||||
self.env = self.env(context=context) |
|
||||
return self |
|
||||
|
|
||||
def _chart_template_create(self): |
|
||||
transfer_account_id = self.env['account.account.template'].create({ |
|
||||
'code': '000', |
|
||||
'name': 'Liquidity Transfers', |
|
||||
'reconcile': True, |
|
||||
'user_type_id': self.ref( |
|
||||
"account.data_account_type_current_assets"), |
|
||||
}) |
|
||||
self.chart = self.env['account.chart.template'].create({ |
|
||||
'name': 'Test COA', |
|
||||
'code_digits': 4, |
|
||||
'bank_account_code_prefix': 1014, |
|
||||
'cash_account_code_prefix': 1014, |
|
||||
'currency_id': self.ref('base.USD'), |
|
||||
'transfer_account_code_prefix': '000', |
|
||||
}) |
|
||||
transfer_account_id.update({ |
|
||||
'chart_template_id': self.chart.id, |
|
||||
}) |
|
||||
self.env['ir.model.data'].create({ |
|
||||
'res_id': transfer_account_id.id, |
|
||||
'model': transfer_account_id._name, |
|
||||
'name': 'Liquidity Transfers', |
|
||||
}) |
|
||||
act = self.env['account.account.template'].create({ |
|
||||
'code': '001', |
|
||||
'name': 'Expenses', |
|
||||
'user_type_id': self.ref("account.data_account_type_expenses"), |
|
||||
'chart_template_id': self.chart.id, |
|
||||
'reconcile': True, |
|
||||
}) |
|
||||
self.env['ir.model.data'].create({ |
|
||||
'res_id': act.id, |
|
||||
'model': act._name, |
|
||||
'name': 'expenses', |
|
||||
}) |
|
||||
act = self.env['account.account.template'].create({ |
|
||||
'code': '002', |
|
||||
'name': 'Product Sales', |
|
||||
'user_type_id': self.ref("account.data_account_type_revenue"), |
|
||||
'chart_template_id': self.chart.id, |
|
||||
'reconcile': True, |
|
||||
}) |
|
||||
self.env['ir.model.data'].create({ |
|
||||
'res_id': act.id, |
|
||||
'model': act._name, |
|
||||
'name': 'sales', |
|
||||
}) |
|
||||
act = self.env['account.account.template'].create({ |
|
||||
'code': '003', |
|
||||
'name': 'Account Receivable', |
|
||||
'user_type_id': self.ref("account.data_account_type_receivable"), |
|
||||
'chart_template_id': self.chart.id, |
|
||||
'reconcile': True, |
|
||||
}) |
|
||||
self.env['ir.model.data'].create({ |
|
||||
'res_id': act.id, |
|
||||
'model': act._name, |
|
||||
'name': 'receivable', |
|
||||
}) |
|
||||
act = self.env['account.account.template'].create({ |
|
||||
'code': '004', |
|
||||
'name': 'Account Payable', |
|
||||
'user_type_id': self.ref("account.data_account_type_payable"), |
|
||||
'chart_template_id': self.chart.id, |
|
||||
'reconcile': True, |
|
||||
}) |
|
||||
self.env['ir.model.data'].create({ |
|
||||
'res_id': act.id, |
|
||||
'model': act._name, |
|
||||
'name': 'payable', |
|
||||
}) |
|
||||
|
|
||||
def _add_chart_of_accounts(self): |
|
||||
self.company = self.env['res.company'].create({ |
|
||||
'name': 'Spanish test company', |
|
||||
}) |
|
||||
self.env.ref('base.group_multi_company').write({ |
|
||||
'users': [(4, self.env.uid)], |
|
||||
}) |
|
||||
self.env.user.write({ |
|
||||
'company_ids': [(4, self.company.id)], |
|
||||
'company_id': self.company.id, |
|
||||
}) |
|
||||
self.with_context( |
|
||||
company_id=self.company.id, force_company=self.company.id) |
|
||||
self.chart.try_loading_for_current_company() |
|
||||
self.revenue = self.env['account.account'].search( |
|
||||
[('user_type_id', '=', self.ref( |
|
||||
"account.data_account_type_revenue"))], limit=1) |
|
||||
self.expense = self.env['account.account'].search( |
|
||||
[('user_type_id', '=', self.ref( |
|
||||
"account.data_account_type_expenses"))], limit=1) |
|
||||
self.receivable = self.env['account.account'].search( |
|
||||
[('user_type_id', '=', self.ref( |
|
||||
"account.data_account_type_receivable"))], limit=1) |
|
||||
self.payable = self.env['account.account'].search( |
|
||||
[('user_type_id', '=', self.ref( |
|
||||
"account.data_account_type_payable"))], limit=1) |
|
||||
return True |
|
||||
|
|
||||
def _journals_create(self): |
|
||||
self.journal_sale = self.env['account.journal'].create({ |
|
||||
'company_id': self.company.id, |
|
||||
'name': 'Test journal for sale', |
|
||||
'type': 'sale', |
|
||||
'code': 'TSALE', |
|
||||
'default_debit_account_id': self.revenue.id, |
|
||||
'default_credit_account_id': self.revenue.id, |
|
||||
}) |
|
||||
self.journal_purchase = self.env['account.journal'].create({ |
|
||||
'company_id': self.company.id, |
|
||||
'name': 'Test journal for purchase', |
|
||||
'type': 'purchase', |
|
||||
'code': 'TPUR', |
|
||||
'default_debit_account_id': self.expense.id, |
|
||||
'default_credit_account_id': self.expense.id, |
|
||||
}) |
|
||||
return True |
|
||||
|
|
||||
def _invoice_create(self): |
|
||||
self.partner = self.env['res.partner'].create({ |
|
||||
'name': 'Test partner', |
|
||||
'company_id': self.company.id, |
|
||||
'property_account_receivable_id': self.receivable.id, |
|
||||
'property_account_payable_id': self.payable.id, |
|
||||
}) |
|
||||
|
|
||||
# customer invoice |
|
||||
customer_invoice_lines = [(0, False, { |
|
||||
'name': 'Test description #1', |
|
||||
'account_id': self.revenue.id, |
|
||||
'quantity': 1.0, |
|
||||
'price_unit': 100.0, |
|
||||
}), (0, False, { |
|
||||
'name': 'Test description #2', |
|
||||
'account_id': self.revenue.id, |
|
||||
'quantity': 2.0, |
|
||||
'price_unit': 25.0, |
|
||||
})] |
|
||||
self.invoice_out = self.env['account.invoice'].create({ |
|
||||
'partner_id': self.partner.id, |
|
||||
'type': 'out_invoice', |
|
||||
'invoice_line_ids': customer_invoice_lines, |
|
||||
'account_id': self.partner.property_account_receivable_id.id, |
|
||||
'journal_id': self.journal_sale.id, |
|
||||
}) |
|
||||
self.invoice_out.action_invoice_open() |
|
||||
|
|
||||
# vendor bill |
|
||||
vendor_invoice_lines = [(0, False, { |
|
||||
'name': 'Test description #1', |
|
||||
'account_id': self.revenue.id, |
|
||||
'quantity': 1.0, |
|
||||
'price_unit': 100.0, |
|
||||
}), (0, False, { |
|
||||
'name': 'Test description #2', |
|
||||
'account_id': self.revenue.id, |
|
||||
'quantity': 2.0, |
|
||||
'price_unit': 25.0, |
|
||||
})] |
|
||||
self.invoice_in = self.env['account.invoice'].create({ |
|
||||
'partner_id': self.partner.id, |
|
||||
'type': 'in_invoice', |
|
||||
'invoice_line_ids': vendor_invoice_lines, |
|
||||
'account_id': self.partner.property_account_payable_id.id, |
|
||||
'journal_id': self.journal_purchase.id, |
|
||||
}) |
|
||||
self.invoice_in.action_invoice_open() |
|
||||
|
|
||||
def setUp(self): |
|
||||
super(AbstractTest, self).setUp() |
|
||||
|
|
||||
self.with_context() |
|
||||
self._chart_template_create() |
|
||||
self._add_chart_of_accounts() |
|
||||
self._journals_create() |
|
||||
self._invoice_create() |
|
||||
|
|
||||
self.model = self._getReportModel() |
|
||||
|
|
||||
self.qweb_report_name = self._getQwebReportName() |
|
||||
self.xlsx_report_name = self._getXlsxReportName() |
|
||||
self.xlsx_action_name = self._getXlsxReportActionName() |
|
||||
|
|
||||
self.report_title = self._getReportTitle() |
|
||||
|
|
||||
self.base_filters = self._getBaseFilters() |
|
||||
self.additional_filters = self._getAdditionalFiltersToBeTested() |
|
||||
|
|
||||
self.report = self.model.create(self.base_filters) |
|
||||
self.report.compute_data_for_report() |
|
||||
|
|
||||
def test_html(self): |
|
||||
test_reports.try_report(self.env.cr, self.env.uid, |
|
||||
self.qweb_report_name, |
|
||||
[self.report.id], |
|
||||
report_type='qweb-html') |
|
||||
|
|
||||
def test_qweb(self): |
|
||||
test_reports.try_report(self.env.cr, self.env.uid, |
|
||||
self.qweb_report_name, |
|
||||
[self.report.id], |
|
||||
report_type='qweb-pdf') |
|
||||
|
|
||||
def test_xlsx(self): |
|
||||
test_reports.try_report(self.env.cr, self.env.uid, |
|
||||
self.xlsx_report_name, |
|
||||
[self.report.id], |
|
||||
report_type='xlsx') |
|
||||
|
|
||||
def test_print(self): |
|
||||
self.report.print_report('qweb') |
|
||||
self.report.print_report('xlsx') |
|
||||
|
|
||||
def test_02_generation_report_html(self): |
|
||||
"""Check if report HTML is correctly generated""" |
|
||||
|
|
||||
# Check if returned report action is correct |
|
||||
report_type = 'qweb-html' |
|
||||
report_action = self.report.print_report(report_type) |
|
||||
self.assertDictContainsSubset( |
|
||||
{ |
|
||||
'type': 'ir.actions.report', |
|
||||
'report_name': self.qweb_report_name, |
|
||||
'report_type': 'qweb-html', |
|
||||
}, |
|
||||
report_action |
|
||||
) |
|
||||
|
|
||||
# Check if report template is correct |
|
||||
report = self.env['ir.actions.report'].search( |
|
||||
[('report_name', '=', self.qweb_report_name), |
|
||||
('report_type', '=', report_type)], limit=1) |
|
||||
self.assertEqual(report.report_type, 'qweb-html') |
|
||||
|
|
||||
rep = report.render(self.report.ids, {}) |
|
||||
|
|
||||
self.assertTrue(self.report_title.encode('utf8') in rep[0]) |
|
||||
self.assertTrue( |
|
||||
self.report.account_ids[0].name.encode('utf8') in rep[0] |
|
||||
) |
|
||||
|
|
||||
def test_04_compute_data(self): |
|
||||
"""Check that the SQL queries work with all filters options""" |
|
||||
|
|
||||
for filters in [{}] + self.additional_filters: |
|
||||
current_filter = self.base_filters.copy() |
|
||||
current_filter.update(filters) |
|
||||
|
|
||||
report = self.model.create(current_filter) |
|
||||
report.compute_data_for_report() |
|
||||
|
|
||||
self.assertGreaterEqual(len(report.account_ids), 1) |
|
||||
|
|
||||
# Same filters with only one account |
|
||||
current_filter = self.base_filters.copy() |
|
||||
current_filter.update(filters) |
|
||||
report_accounts = report.account_ids.filtered('account_id') |
|
||||
current_filter.update({ |
|
||||
'filter_account_ids': |
|
||||
[(6, 0, report_accounts[0].account_id.ids)], |
|
||||
}) |
|
||||
|
|
||||
report2 = self.model.create(current_filter) |
|
||||
report2.compute_data_for_report() |
|
||||
|
|
||||
self.assertEqual(len(report2.account_ids), 1) |
|
||||
self.assertEqual(report2.account_ids.name, |
|
||||
report_accounts[0].name) |
|
||||
|
|
||||
if self._partner_test_is_possible(filters): |
|
||||
# Same filters with only one partner |
|
||||
report_partner_ids = report.account_ids.mapped('partner_ids') |
|
||||
partner_ids = report_partner_ids.mapped('partner_id') |
|
||||
|
|
||||
current_filter = self.base_filters.copy() |
|
||||
current_filter.update(filters) |
|
||||
current_filter.update({ |
|
||||
'filter_partner_ids': [(6, 0, partner_ids[0].ids)], |
|
||||
}) |
|
||||
|
|
||||
report3 = self.model.create(current_filter) |
|
||||
report3.compute_data_for_report() |
|
||||
|
|
||||
self.assertGreaterEqual(len(report3.account_ids), 1) |
|
||||
|
|
||||
report_partner_ids3 = report3.account_ids.mapped('partner_ids') |
|
||||
partner_ids3 = report_partner_ids3.mapped('partner_id') |
|
||||
|
|
||||
self.assertEqual(len(partner_ids3), 1) |
|
||||
self.assertEqual( |
|
||||
partner_ids3.name, |
|
||||
partner_ids[0].name |
|
||||
) |
|
||||
|
|
||||
# Same filters with only one partner and one account |
|
||||
report_partner_ids = report3.account_ids.mapped('partner_ids') |
|
||||
report_account_id = report_partner_ids.filtered( |
|
||||
lambda p: p.partner_id |
|
||||
)[0].report_account_id |
|
||||
|
|
||||
current_filter = self.base_filters.copy() |
|
||||
current_filter.update(filters) |
|
||||
current_filter.update({ |
|
||||
'filter_account_ids': |
|
||||
[(6, 0, report_account_id.account_id.ids)], |
|
||||
'filter_partner_ids': [(6, 0, partner_ids[0].ids)], |
|
||||
}) |
|
||||
|
|
||||
report4 = self.model.create(current_filter) |
|
||||
report4.compute_data_for_report() |
|
||||
|
|
||||
self.assertEqual(len(report4.account_ids), 1) |
|
||||
self.assertEqual(report4.account_ids.name, |
|
||||
report_account_id.account_id.name) |
|
||||
|
|
||||
report_partner_ids4 = report4.account_ids.mapped('partner_ids') |
|
||||
partner_ids4 = report_partner_ids4.mapped('partner_id') |
|
||||
|
|
||||
self.assertEqual(len(partner_ids4), 1) |
|
||||
self.assertEqual( |
|
||||
partner_ids4.name, |
|
||||
partner_ids[0].name |
|
||||
) |
|
||||
|
|
||||
def _partner_test_is_possible(self, filters): |
|
||||
""" |
|
||||
:return: |
|
||||
a boolean to indicate if partner test is possible |
|
||||
with current filters |
|
||||
""" |
|
||||
return True |
|
||||
|
|
||||
def _getReportModel(self): |
|
||||
""" |
|
||||
:return: the report model name |
|
||||
""" |
|
||||
raise NotImplementedError() |
|
||||
|
|
||||
def _getQwebReportName(self): |
|
||||
""" |
|
||||
:return: the qweb report name |
|
||||
""" |
|
||||
raise NotImplementedError() |
|
||||
|
|
||||
def _getXlsxReportName(self): |
|
||||
""" |
|
||||
:return: the xlsx report name |
|
||||
""" |
|
||||
raise NotImplementedError() |
|
||||
|
|
||||
def _getXlsxReportActionName(self): |
|
||||
""" |
|
||||
:return: the xlsx report action name |
|
||||
""" |
|
||||
raise NotImplementedError() |
|
||||
|
|
||||
def _getReportTitle(self): |
|
||||
""" |
|
||||
:return: the report title displayed into the report |
|
||||
""" |
|
||||
raise NotImplementedError() |
|
||||
|
|
||||
def _getBaseFilters(self): |
|
||||
""" |
|
||||
:return: the minimum required filters to generate report |
|
||||
""" |
|
||||
raise NotImplementedError() |
|
||||
|
|
||||
def _getAdditionalFiltersToBeTested(self): |
|
||||
""" |
|
||||
:return: the additional filters to generate report variants |
|
||||
""" |
|
||||
raise NotImplementedError() |
|
@ -1,78 +0,0 @@ |
|||||
# Copyright 2018 Forest and Biomass Romania |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
|
|
||||
import logging |
|
||||
from . import abstract_test |
|
||||
|
|
||||
_logger = logging.getLogger(__name__) |
|
||||
|
|
||||
|
|
||||
class AbstractTestForeignCurrency(abstract_test.AbstractTest): |
|
||||
"""Common technical tests for all reports.""" |
|
||||
|
|
||||
def _chart_template_create(self): |
|
||||
super(AbstractTestForeignCurrency, self)._chart_template_create() |
|
||||
# Account for foreign payments |
|
||||
self.account_type_other = self.env['account.account.type'].create( |
|
||||
{'name': 'foreign expenses', |
|
||||
'type': 'other', |
|
||||
}) |
|
||||
act = self.env['account.account.template'].create({ |
|
||||
'code': '0012', |
|
||||
'name': 'Foreign Expenses', |
|
||||
'user_type_id': self.account_type_other.id, |
|
||||
'chart_template_id': self.chart.id, |
|
||||
'currency_id': self.env.ref('base.EUR').id, |
|
||||
}) |
|
||||
self.env['ir.model.data'].create({ |
|
||||
'res_id': act.id, |
|
||||
'model': act._name, |
|
||||
'name': 'foreign expenses', |
|
||||
}) |
|
||||
return True |
|
||||
|
|
||||
def _add_chart_of_accounts(self): |
|
||||
super(AbstractTestForeignCurrency, self)._add_chart_of_accounts() |
|
||||
self.foreign_expense = self.env['account.account'].search( |
|
||||
[('currency_id', '=', self.env.ref('base.EUR').id)], limit=1) |
|
||||
self.foreign_currency_id = self.foreign_expense.currency_id |
|
||||
return True |
|
||||
|
|
||||
def _journals_create(self): |
|
||||
super(AbstractTestForeignCurrency, self)._journals_create() |
|
||||
self.journal_foreign_purchases = self.env['account.journal'].create({ |
|
||||
'company_id': self.company.id, |
|
||||
'name': 'Test journal for purchase', |
|
||||
'type': 'purchase', |
|
||||
'code': 'TFORPUR', |
|
||||
'default_debit_account_id': self.foreign_expense.id, |
|
||||
'default_credit_account_id': self.foreign_expense.id, |
|
||||
'currency_id': self.foreign_currency_id.id, |
|
||||
}) |
|
||||
return True |
|
||||
|
|
||||
def _invoice_create(self): |
|
||||
super(AbstractTestForeignCurrency, self)._invoice_create() |
|
||||
# vendor bill foreign currency |
|
||||
foreign_vendor_invoice_lines = [(0, False, { |
|
||||
'name': 'Test description #1', |
|
||||
'account_id': self.revenue.id, |
|
||||
'quantity': 1.0, |
|
||||
'price_unit': 100.0, |
|
||||
'currency_id': self.foreign_currency_id.id, |
|
||||
}), (0, False, { |
|
||||
'name': 'Test description #2', |
|
||||
'account_id': self.revenue.id, |
|
||||
'quantity': 2.0, |
|
||||
'price_unit': 25.0, |
|
||||
'currency_id': self.foreign_currency_id.id, |
|
||||
})] |
|
||||
self.foreign_invoice_in = self.env['account.invoice'].create({ |
|
||||
'partner_id': self.partner.id, |
|
||||
'type': 'in_invoice', |
|
||||
'invoice_line_ids': foreign_vendor_invoice_lines, |
|
||||
'account_id': self.partner.property_account_payable_id.id, |
|
||||
'journal_id': self.journal_foreign_purchases.id, |
|
||||
}) |
|
||||
self.foreign_invoice_in.action_invoice_open() |
|
||||
return True |
|
@ -1,75 +0,0 @@ |
|||||
# Copyright 2018 Forest and Biomass Romania |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
|
|
||||
import logging |
|
||||
from odoo.tests.common import TransactionCase |
|
||||
from odoo.tools import test_reports |
|
||||
|
|
||||
_logger = logging.getLogger(__name__) |
|
||||
|
|
||||
|
|
||||
class AbstractTest(TransactionCase): |
|
||||
"""Common technical tests for all reports.""" |
|
||||
|
|
||||
def setUp(cls): |
|
||||
super(AbstractTest, cls).setUp() |
|
||||
|
|
||||
cls.model = cls._getReportModel() |
|
||||
|
|
||||
cls.qweb_report_name = cls._getQwebReportName() |
|
||||
cls.xlsx_report_name = cls._getXlsxReportName() |
|
||||
cls.xlsx_action_name = cls._getXlsxReportActionName() |
|
||||
|
|
||||
cls.report_title = cls._getReportTitle() |
|
||||
|
|
||||
cls.base_filters = cls._getBaseFilters() |
|
||||
|
|
||||
cls.report = cls.model.create(cls.base_filters) |
|
||||
cls.report.compute_data_for_report() |
|
||||
|
|
||||
def test_html(self): |
|
||||
test_reports.try_report(self.env.cr, self.env.uid, |
|
||||
self.qweb_report_name, |
|
||||
[self.report.id], |
|
||||
report_type='qweb-html') |
|
||||
|
|
||||
def test_qweb(self): |
|
||||
test_reports.try_report(self.env.cr, self.env.uid, |
|
||||
self.qweb_report_name, |
|
||||
[self.report.id], |
|
||||
report_type='qweb-pdf') |
|
||||
|
|
||||
def test_xlsx(self): |
|
||||
test_reports.try_report(self.env.cr, self.env.uid, |
|
||||
self.xlsx_report_name, |
|
||||
[self.report.id], |
|
||||
report_type='xlsx') |
|
||||
|
|
||||
def test_print(self): |
|
||||
self.report.print_report('qweb') |
|
||||
self.report.print_report('xlsx') |
|
||||
|
|
||||
def test_generation_report_html(self): |
|
||||
"""Check if report HTML is correctly generated""" |
|
||||
|
|
||||
# Check if returned report action is correct |
|
||||
report_type = 'qweb-html' |
|
||||
report_action = self.report.print_report(report_type) |
|
||||
self.assertDictContainsSubset( |
|
||||
{ |
|
||||
'type': 'ir.actions.report', |
|
||||
'report_name': self.qweb_report_name, |
|
||||
'report_type': 'qweb-html', |
|
||||
}, |
|
||||
report_action |
|
||||
) |
|
||||
|
|
||||
# Check if report template is correct |
|
||||
report = self.env['ir.actions.report'].search( |
|
||||
[('report_name', '=', self.qweb_report_name), |
|
||||
('report_type', '=', report_type)], limit=1) |
|
||||
self.assertEqual(report.report_type, 'qweb-html') |
|
||||
|
|
||||
rep = report.render(self.report.ids, {}) |
|
||||
|
|
||||
self.assertTrue(self.report_title.encode('utf8') in rep[0]) |
|
@ -1,41 +0,0 @@ |
|||||
# Author: Julien Coux |
|
||||
# Copyright 2016 Camptocamp SA |
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|
||||
|
|
||||
from datetime import date |
|
||||
from . import abstract_test |
|
||||
|
|
||||
|
|
||||
class TestAgedPartnerBalance(abstract_test.AbstractTest): |
|
||||
""" |
|
||||
Technical tests for Aged Partner Balance Report. |
|
||||
""" |
|
||||
|
|
||||
def _getReportModel(self): |
|
||||
return self.env['report_aged_partner_balance'] |
|
||||
|
|
||||
def _getQwebReportName(self): |
|
||||
return 'account_financial_report.report_aged_partner_balance_qweb' |
|
||||
|
|
||||
def _getXlsxReportName(self): |
|
||||
return 'a_f_r.report_aged_partner_balance_xlsx' |
|
||||
|
|
||||
def _getXlsxReportActionName(self): |
|
||||
return 'account_financial_report.' \ |
|
||||
'action_report_aged_partner_balance_xlsx' |
|
||||
|
|
||||
def _getReportTitle(self): |
|
||||
return 'Odoo' |
|
||||
|
|
||||
def _getBaseFilters(self): |
|
||||
return { |
|
||||
'date_at': date(date.today().year, 12, 31), |
|
||||
'company_id': self.company.id, |
|
||||
} |
|
||||
|
|
||||
def _getAdditionalFiltersToBeTested(self): |
|
||||
return [ |
|
||||
{'only_posted_moves': True}, |
|
||||
{'show_move_line_details': True}, |
|
||||
{'only_posted_moves': True, 'show_move_line_details': True}, |
|
||||
] |
|
@ -0,0 +1,2 @@ |
|||||
|
natsort |
||||
|
pandas |
Write
Preview
Loading…
Cancel
Save
Reference in new issue