Browse Source
Update links in report, add account group file, update trial balance with hierarchy.
Update links in report, add account group file, update trial balance with hierarchy.
Update indentation, remove empty lines from header. Update test. Update pylint. Remove company_id on computing accounts, since account.group is not a company based model, filtering accounts is done on trial balance report. Update account variables. Improve condition in padding on accounts. Add option to print hierarchy based on defined accounts/computed accounts. Add VAT report, hierarchy from tax tags ans taxes. Fix pylint, xlsx report generation header. Update code to select code_prefix or name. Update code to select code_prefix or name. Update code to select code_prefix or name. Fix domain in base amounts in vat report. Change trial balance code_prefix or name. Update trail balance, add tests for vat report. Update pylint, amounts as monetary, many2one option on generation excels. Update pulint. Add VAT Report in readme. Add VAT Report in readme. Update array_agg. Update array_agg. Update array_agg. Add option in VAT Report to be printed on Tax Tags - Tax Groups. Add widget to hierarchy_on on trial balance.pull/559/head
Fekete Mihai
7 years ago
committed by
Pedro M. Baeza
44 changed files with 2739 additions and 347 deletions
-
2account_financial_report/README.rst
-
6account_financial_report/__manifest__.py
-
7account_financial_report/menuitems.xml
-
6account_financial_report/models/__init__.py
-
1account_financial_report/models/account.py
-
48account_financial_report/models/account_group.py
-
3account_financial_report/report/__init__.py
-
5account_financial_report/report/abstract_report_xlsx.py
-
2account_financial_report/report/aged_partner_balance.py
-
5account_financial_report/report/aged_partner_balance_xlsx.py
-
13account_financial_report/report/general_ledger.py
-
7account_financial_report/report/general_ledger_xlsx.py
-
8account_financial_report/report/open_items.py
-
8account_financial_report/report/open_items_xlsx.py
-
300account_financial_report/report/templates/aged_partner_balance.xml
-
239account_financial_report/report/templates/general_ledger.xml
-
38account_financial_report/report/templates/open_items.xml
-
333account_financial_report/report/templates/trial_balance.xml
-
169account_financial_report/report/templates/vat_report.xml
-
261account_financial_report/report/trial_balance.py
-
5account_financial_report/report/trial_balance_xlsx.py
-
351account_financial_report/report/vat_report.py
-
51account_financial_report/report/vat_report_xlsx.py
-
32account_financial_report/reports.xml
-
8account_financial_report/static/src/js/account_financial_report_backend.js
-
19account_financial_report/static/src/js/account_financial_report_widgets.js
-
2account_financial_report/tests/__init__.py
-
4account_financial_report/tests/abstract_test.py
-
75account_financial_report/tests/abstract_test_tax_report.py
-
1account_financial_report/tests/test_aged_partner_balance.py
-
4account_financial_report/tests/test_general_ledger.py
-
1account_financial_report/tests/test_open_items.py
-
440account_financial_report/tests/test_trial_balance.py
-
288account_financial_report/tests/test_vat_report.py
-
28account_financial_report/view/account_view.xml
-
6account_financial_report/view/report_template.xml
-
2account_financial_report/view/report_trial_balance.xml
-
9account_financial_report/view/report_vat_report.xml
-
6account_financial_report/wizard/__init__.py
-
1account_financial_report/wizard/open_items_wizard.py
-
9account_financial_report/wizard/trial_balance_wizard.py
-
1account_financial_report/wizard/trial_balance_wizard_view.xml
-
80account_financial_report/wizard/vat_report_wizard.py
-
44account_financial_report/wizard/vat_report_wizard_view.xml
@ -1,6 +1,2 @@ |
|||
|
|||
# Author: Damien Crier |
|||
# Copyright 2016 Camptocamp SA |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from . import account |
|||
from . import account_group |
@ -0,0 +1,48 @@ |
|||
# © 2018 Forest and Biomass Romania SA |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class AccountGroup(models.Model): |
|||
_inherit = 'account.group' |
|||
|
|||
group_child_ids = fields.One2many( |
|||
comodel_name='account.group', |
|||
inverse_name='parent_id', |
|||
string='Child Groups') |
|||
level = fields.Integer( |
|||
string='Level', |
|||
compute='_compute_level', |
|||
store=True) |
|||
account_ids = fields.One2many( |
|||
comodel_name='account.account', |
|||
inverse_name='group_id', |
|||
string="Accounts") |
|||
compute_account_ids = fields.Many2many( |
|||
'account.account', |
|||
compute='_compute_group_accounts', |
|||
string="Accounts", store=True) |
|||
|
|||
@api.multi |
|||
@api.depends('parent_id') |
|||
def _compute_level(self): |
|||
for group in self: |
|||
level = 0 |
|||
new_group = group |
|||
while new_group.parent_id: |
|||
level += 1 |
|||
new_group = new_group.parent_id |
|||
group.level = level |
|||
|
|||
@api.multi |
|||
@api.depends('code_prefix', 'account_ids', 'account_ids.code', |
|||
'group_child_ids', 'group_child_ids.account_ids.code') |
|||
def _compute_group_accounts(self): |
|||
account_obj = self.env['account.account'] |
|||
accounts = account_obj.search([]) |
|||
for group in self: |
|||
prefix = group.code_prefix if group.code_prefix else group.name |
|||
gr_acc = accounts.filtered( |
|||
lambda a: a.code.startswith(prefix)).ids |
|||
group.compute_account_ids = [(6, 0, gr_acc)] |
@ -0,0 +1,169 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
|
|||
<template id="account_financial_report.report_vat_report_qweb"> |
|||
<t t-call="web.html_container"> |
|||
<t t-foreach="docs" t-as="o"> |
|||
<t t-call="account_financial_report.internal_layout" t-lang="user.lang"> |
|||
<t t-call="account_financial_report.report_vat_report_base"/> |
|||
</t> |
|||
</t> |
|||
</t> |
|||
</template> |
|||
|
|||
<template id="account_financial_report.report_vat_report_base"> |
|||
<div class="page data_table"> |
|||
<t t-set="title">VAT Report</t> |
|||
<div class="row"> |
|||
<h4 class="mt0" t-esc="title or 'Odoo Report'"/> |
|||
</div> |
|||
|
|||
|
|||
<!-- Display filters --> |
|||
<t t-call="account_financial_report.report_vat_report_filters"/> |
|||
<div class="page_break"/> |
|||
|
|||
<div class="act_as_table data_table" style="width: 100%;"> |
|||
<!-- Display table headers for lines --> |
|||
<div class="act_as_thead"> |
|||
<div class="act_as_row labels"> |
|||
<!--## code--> |
|||
<div class="act_as_cell first_column" style="width: 5%;">Code</div> |
|||
<!--## name--> |
|||
<div class="act_as_cell" style="width: 65%;">Name</div> |
|||
<!--## net--> |
|||
<div class="act_as_cell" style="width: 15%;">Net</div> |
|||
<!--## tax--> |
|||
<div class="act_as_cell" style="width: 15%;">Tax</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<t t-foreach="o.taxtags_ids" t-as="tag"> |
|||
<div class="act_as_row lines" style="font-weight: bold;"> |
|||
<t t-if="tag.taxtag_id"> |
|||
<t t-set="res_model" t-value="'account.account.tag'"/> |
|||
<t t-set="res_id" t-value="tag.taxtag_id.id"/> |
|||
</t> |
|||
<t t-if="tag.taxgroup_id"> |
|||
<t t-set="res_model" t-value="'account.tax.group'"/> |
|||
<t t-set="res_id" t-value="tag.taxgroup_id.id"/> |
|||
</t> |
|||
<div class="act_as_cell left oe_tooltip_string" style="width: 5%;"> |
|||
<span> |
|||
<a t-att-data-active-id="res_id" |
|||
t-att-data-res-model="res_model" |
|||
class="o_account_financial_reports_web_action" |
|||
t-att-style="style"> |
|||
<t t-att-style="style" t-raw="tag.code"/></a> |
|||
</span> |
|||
</div> |
|||
<div class="act_as_cell left oe_tooltip_string" style="width: 65%;"> |
|||
<span> |
|||
<a t-att-data-active-id="res_id" |
|||
t-att-data-res-model="res_model" |
|||
class="o_account_financial_reports_web_action" |
|||
t-att-style="style"><t t-att-style="style" t-raw="tag.name"/></a> |
|||
</span> |
|||
</div> |
|||
<div class="act_as_cell amount" style="width: 15%;"> |
|||
<t t-set="domain" |
|||
t-value="[('tax_ids', 'in', [tax.tax_id.id for tax in tag.tax_ids]), |
|||
('date', '>=', o.date_from), |
|||
('date', '<=', o.date_to)]"/> |
|||
<span> |
|||
<a t-att-data-domain="domain" |
|||
t-att-data-res-model="'account.move.line'" |
|||
class="o_account_financial_reports_web_action_multi" |
|||
t-att-style="style"> |
|||
<t t-att-style="style" t-raw="tag.net" |
|||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a> |
|||
</span> |
|||
</div> |
|||
<div class="act_as_cell amount" style="width: 15%;"> |
|||
<t t-set="domain" |
|||
t-value="[('tax_line_id', 'in', [tax.tax_id.id for tax in tag.tax_ids]), |
|||
('date', '>=', o.date_from), |
|||
('date', '<=', o.date_to), |
|||
('tax_exigible', '=', True)]"/> |
|||
<span> |
|||
<a t-att-data-domain="domain" |
|||
t-att-data-res-model="'account.move.line'" |
|||
class="o_account_financial_reports_web_action_multi" |
|||
t-att-style="style"> |
|||
<t t-att-style="style" t-raw="tag.tax" |
|||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a> |
|||
</span> |
|||
</div> |
|||
</div> |
|||
<t t-if="o.tax_detail"> |
|||
<t t-foreach="tag.tax_ids" t-as="tax"> |
|||
<t t-set="res_model" t-value="'account.tax'"/> |
|||
<div class="act_as_row lines"> |
|||
<div class="act_as_cell" style="width: 5%;"/> |
|||
<div class="act_as_cell left oe_tooltip_string" style="padding-left: 20px; width: 65%;"> |
|||
<span> |
|||
<a t-att-data-active-id="tax.tax_id.id" |
|||
t-att-data-res-model="res_model" |
|||
class="o_account_financial_reports_web_action" |
|||
t-att-style="style"><t t-att-style="style" t-raw="tax.name"/></a> |
|||
</span> |
|||
</div> |
|||
<div class="act_as_cell amount" style="width: 15%;"> |
|||
<t t-set="domain" |
|||
t-value="[('tax_ids', 'in', tax.tax_id.ids), |
|||
('date', '>=', o.date_from), |
|||
('date', '<=', o.date_to), |
|||
('tax_exigible', '=', True)]"/> |
|||
<span> |
|||
<a t-att-data-domain="domain" |
|||
t-att-data-res-model="'account.move.line'" |
|||
class="o_account_financial_reports_web_action_multi" |
|||
t-att-style="style"> |
|||
<t t-att-style="style" t-raw="tax.net" |
|||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a> |
|||
</span> |
|||
</div> |
|||
<div class="act_as_cell amount" style="width: 15%;"> |
|||
<t t-set="domain" |
|||
t-value="[('tax_line_id', '=', tax.tax_id.id), |
|||
('date', '>=', o.date_from), |
|||
('date', '<=', o.date_to), |
|||
('tax_exigible', '=', True)]"/> |
|||
<span> |
|||
<a t-att-data-domain="domain" |
|||
t-att-data-res-model="'account.move.line'" |
|||
class="o_account_financial_reports_web_action_multi" |
|||
t-att-style="style"> |
|||
<t t-att-style="style" t-raw="tax.tax" |
|||
t-options="{'widget': 'monetary', 'display_currency': res_company.currency_id}"/></a> |
|||
</span> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
</t> |
|||
</t> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<template id="account_financial_report.report_vat_report_filters"> |
|||
<div class="act_as_table data_table" style="width: 100%;"> |
|||
<div class="act_as_row labels"> |
|||
<div class="act_as_cell">Date From</div> |
|||
<div class="act_as_cell">Date To</div> |
|||
<div class="act_as_cell">Based On</div> |
|||
</div> |
|||
<div class="act_as_row"> |
|||
<div class="act_as_cell"> |
|||
<span t-field="o.date_from"/> |
|||
</div> |
|||
<div class="act_as_cell"> |
|||
<span t-field="o.date_to"/> |
|||
</div> |
|||
<div class="act_as_cell"> |
|||
<span t-field="o.based_on"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
</odoo> |
@ -0,0 +1,351 @@ |
|||
# Copyright 2018 Forest and Biomass Romania |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class VATReport(models.TransientModel): |
|||
_name = "report_vat_report" |
|||
""" Here, we just define class fields. |
|||
For methods, go more bottom at this file. |
|||
|
|||
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' |
|||
_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' |
|||
) |
|||
|
|||
|
|||
class VATReportTax(models.TransientModel): |
|||
_name = 'report_vat_report_tax' |
|||
_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 |
|||
) |
|||
|
|||
# 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) |
|||
|
|||
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 |
|||
|
|||
@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 |
|||
) |
|||
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) |
|||
|
|||
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) |
@ -0,0 +1,51 @@ |
|||
# Copyright 2018 Forest and Biomass Romania |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from odoo import _, models |
|||
|
|||
|
|||
class VATReportXslx(models.AbstractModel): |
|||
_name = 'report.a_f_r.report_vat_report_xlsx' |
|||
_inherit = 'report.account_financial_report.abstract_report_xlsx' |
|||
|
|||
def _get_report_name(self): |
|||
return _('VAT Report') |
|||
|
|||
def _get_report_columns(self, report): |
|||
return { |
|||
0: {'header': _('Code'), 'field': 'code', 'width': 5}, |
|||
1: {'header': _('Name'), 'field': 'name', 'width': 100}, |
|||
2: {'header': _('Net'), |
|||
'field': 'net', |
|||
'type': 'amount', |
|||
'width': 14}, |
|||
3: {'header': _('Tax'), |
|||
'field': 'tax', |
|||
'type': 'amount', |
|||
'width': 14}, |
|||
} |
|||
|
|||
def _get_report_filters(self, report): |
|||
return [ |
|||
[_('Date from'), report.date_from], |
|||
[_('Date to'), report.date_to], |
|||
[_('Based on'), report.based_on], |
|||
] |
|||
|
|||
def _get_col_count_filter_name(self): |
|||
return 0 |
|||
|
|||
def _get_col_count_filter_value(self): |
|||
return 2 |
|||
|
|||
def _generate_report_content(self, workbook, report): |
|||
# For each taxtag |
|||
self.write_array_header() |
|||
for taxtag in report.taxtags_ids: |
|||
# Write taxtag line |
|||
self.write_line(taxtag) |
|||
|
|||
# For each tax if detail taxes |
|||
if report.tax_detail: |
|||
for tax in taxtag.tax_ids: |
|||
self.write_line(tax) |
@ -0,0 +1,75 @@ |
|||
# 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]) |
@ -0,0 +1,288 @@ |
|||
# Copyright 2018 Forest and Biomass Romania |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
import time |
|||
|
|||
from odoo.tests import common |
|||
from . import abstract_test_tax_report |
|||
|
|||
|
|||
class TestVAT(abstract_test_tax_report.AbstractTest): |
|||
""" |
|||
Technical tests for VAT Report. |
|||
""" |
|||
|
|||
def _getReportModel(self): |
|||
return self.env['report_vat_report'] |
|||
|
|||
def _getQwebReportName(self): |
|||
return 'account_financial_report.report_vat_report_qweb' |
|||
|
|||
def _getXlsxReportName(self): |
|||
return 'a_f_r.report_vat_report_xlsx' |
|||
|
|||
def _getXlsxReportActionName(self): |
|||
return 'account_financial_report.action_report_vat_report_xlsx' |
|||
|
|||
def _getReportTitle(self): |
|||
return 'Odoo' |
|||
|
|||
def _getBaseFilters(self): |
|||
return { |
|||
'date_from': time.strftime('%Y-01-01'), |
|||
'date_to': time.strftime('%Y-12-31'), |
|||
'company_id': self.env.user.company_id.id |
|||
} |
|||
|
|||
def _getAdditionalFiltersToBeTested(self): |
|||
return [ |
|||
{'based_on': 'taxtags'}, |
|||
{'based_on': 'taxgroups'}, |
|||
{'tax_details': True}, |
|||
{'based_on': 'taxtags', 'tax_details': True}, |
|||
{'based_on': 'taxgroups', 'tax_details': True}, |
|||
] |
|||
|
|||
|
|||
class TestVATReport(common.TransactionCase): |
|||
|
|||
def setUp(self): |
|||
super(TestVATReport, self).setUp() |
|||
self.date_from = time.strftime('%Y-%m-01'), |
|||
self.date_to = time.strftime('%Y-%m-28'), |
|||
self.receivable_account = self.env['account.account'].search([ |
|||
('user_type_id.name', '=', 'Receivable') |
|||
], limit=1) |
|||
self.income_account = self.env['account.account'].search([ |
|||
('user_type_id.name', '=', 'Income') |
|||
], limit=1) |
|||
self.tax_account = self.env['account.account'].search([ |
|||
('user_type_id', |
|||
'=', |
|||
self.env.ref( |
|||
'account.data_account_type_non_current_liabilities').id |
|||
)], limit=1) |
|||
self.bank_journal = self.env['account.journal'].search( |
|||
[('type', '=', 'bank')], limit=1) |
|||
self.tax_tag_01 = self.env['account.account.tag'].create({ |
|||
'name': 'Tag 01', |
|||
'applicability': 'taxes' |
|||
}) |
|||
self.tax_tag_02 = self.env['account.account.tag'].create({ |
|||
'name': 'Tag 02', |
|||
'applicability': 'taxes' |
|||
}) |
|||
self.tax_tag_03 = self.env['account.account.tag'].create({ |
|||
'name': 'Tag 03', |
|||
'applicability': 'taxes' |
|||
}) |
|||
self.tax_group_10 = self.env['account.tax.group'].create({ |
|||
'name': 'Tax 10%', |
|||
'sequence': 1 |
|||
}) |
|||
self.tax_group_20 = self.env['account.tax.group'].create({ |
|||
'name': 'Tax 20%', |
|||
'sequence': 2 |
|||
}) |
|||
self.tax_10 = self.env['account.tax'].create({ |
|||
'name': 'Tax 10.0%', |
|||
'amount': 10.0, |
|||
'amount_type': 'percent', |
|||
'type_tax_use': 'sale', |
|||
'account_id': self.tax_account.id, |
|||
'refund_account_id': self.tax_account.id, |
|||
'tax_group_id': self.tax_group_10.id, |
|||
'tag_ids': [(6, 0, [self.tax_tag_01.id, self.tax_tag_02.id])] |
|||
}) |
|||
self.tax_20 = self.env['account.tax'].create({ |
|||
'sequence': 30, |
|||
'name': 'Tax 20.0%', |
|||
'amount': 20.0, |
|||
'amount_type': 'percent', |
|||
'type_tax_use': 'sale', |
|||
'tax_exigibility': 'on_payment', |
|||
'account_id': self.tax_account.id, |
|||
'refund_account_id': self.tax_account.id, |
|||
'cash_basis_account': self.tax_account.id, |
|||
'tax_group_id': self.tax_group_20.id, |
|||
'tag_ids': [(6, 0, [self.tax_tag_02.id, self.tax_tag_03.id])] |
|||
}) |
|||
|
|||
invoice = self.env['account.invoice'].create({ |
|||
'partner_id': self.env.ref('base.res_partner_2').id, |
|||
'account_id': self.receivable_account.id, |
|||
'date_invoice': time.strftime('%Y-%m-03'), |
|||
'type': 'out_invoice', |
|||
}) |
|||
|
|||
self.env['account.invoice.line'].create({ |
|||
'product_id': self.env.ref('product.product_product_4').id, |
|||
'quantity': 1.0, |
|||
'price_unit': 100.0, |
|||
'invoice_id': invoice.id, |
|||
'name': 'product', |
|||
'account_id': self.income_account.id, |
|||
'invoice_line_tax_ids': [(6, 0, [self.tax_10.id])], |
|||
}) |
|||
invoice.compute_taxes() |
|||
invoice.action_invoice_open() |
|||
|
|||
self.cbinvoice = self.env['account.invoice'].create({ |
|||
'partner_id': self.env.ref('base.res_partner_2').id, |
|||
'account_id': self.receivable_account.id, |
|||
'date_invoice': time.strftime('%Y-%m-05'), |
|||
'type': 'out_invoice', |
|||
}) |
|||
|
|||
self.env['account.invoice.line'].create({ |
|||
'product_id': self.env.ref('product.product_product_4').id, |
|||
'quantity': 1.0, |
|||
'price_unit': 500.0, |
|||
'invoice_id': self.cbinvoice.id, |
|||
'name': 'product', |
|||
'account_id': self.income_account.id, |
|||
'invoice_line_tax_ids': [(6, 0, [self.tax_20.id])], |
|||
}) |
|||
self.cbinvoice.compute_taxes() |
|||
self.cbinvoice.action_invoice_open() |
|||
|
|||
def _get_report_lines(self): |
|||
company = self.env.ref('base.main_company') |
|||
self.cbinvoice.pay_and_reconcile( |
|||
self.bank_journal.id, 300, time.strftime('%Y-%m-10')) |
|||
vat_report = self.env['report_vat_report'].create({ |
|||
'date_from': self.date_from, |
|||
'date_to': self.date_to, |
|||
'company_id': company.id, |
|||
'based_on': 'taxtags', |
|||
'tax_detail': True, |
|||
}) |
|||
vat_report.compute_data_for_report() |
|||
lines = {} |
|||
vat_taxtag_model = self.env['report_vat_report_taxtag'] |
|||
lines['tag_01'] = vat_taxtag_model.search([ |
|||
('report_id', '=', vat_report.id), |
|||
('taxtag_id', '=', self.tax_tag_01.id), |
|||
]) |
|||
lines['tag_02'] = vat_taxtag_model.search([ |
|||
('report_id', '=', vat_report.id), |
|||
('taxtag_id', '=', self.tax_tag_02.id), |
|||
]) |
|||
lines['tag_03'] = vat_taxtag_model.search([ |
|||
('report_id', '=', vat_report.id), |
|||
('taxtag_id', '=', self.tax_tag_03.id), |
|||
]) |
|||
vat_tax_model = self.env['report_vat_report_tax'] |
|||
lines['tax_10'] = vat_tax_model.search([ |
|||
('report_tax_id', '=', lines['tag_02'].id), |
|||
('tax_id', '=', self.tax_10.id), |
|||
]) |
|||
lines['tax_20'] = vat_tax_model.search([ |
|||
('report_tax_id', '=', lines['tag_02'].id), |
|||
('tax_id', '=', self.tax_20.id), |
|||
]) |
|||
vat_report['based_on'] = 'taxgroups' |
|||
vat_report.compute_data_for_report() |
|||
lines['group_10'] = vat_taxtag_model.search([ |
|||
('report_id', '=', vat_report.id), |
|||
('taxgroup_id', '=', self.tax_group_10.id), |
|||
]) |
|||
lines['group_20'] = vat_taxtag_model.search([ |
|||
('report_id', '=', vat_report.id), |
|||
('taxgroup_id', '=', self.tax_group_20.id), |
|||
]) |
|||
vat_tax_model = self.env['report_vat_report_tax'] |
|||
lines['tax_group_10'] = vat_tax_model.search([ |
|||
('report_tax_id', '=', lines['group_10'].id), |
|||
('tax_id', '=', self.tax_10.id), |
|||
]) |
|||
lines['tax_group_20'] = vat_tax_model.search([ |
|||
('report_tax_id', '=', lines['group_20'].id), |
|||
('tax_id', '=', self.tax_20.id), |
|||
]) |
|||
return lines |
|||
|
|||
def test_01_compute(self): |
|||
# Generate the vat lines |
|||
lines = self._get_report_lines() |
|||
|
|||
# Check report based on taxtags |
|||
self.assertEqual(len(lines['tag_01']), 1) |
|||
self.assertEqual(len(lines['tag_02']), 1) |
|||
self.assertEqual(len(lines['tag_03']), 1) |
|||
self.assertEqual(len(lines['tax_10']), 1) |
|||
self.assertEqual(len(lines['tax_20']), 1) |
|||
self.assertEqual(lines['tag_01'].net, 100) |
|||
self.assertEqual(lines['tag_01'].tax, 10) |
|||
self.assertEqual(lines['tag_02'].net, 350) |
|||
self.assertEqual(lines['tag_02'].tax, 60) |
|||
self.assertEqual(lines['tag_03'].net, 250) |
|||
self.assertEqual(lines['tag_03'].tax, 50) |
|||
self.assertEqual(lines['tax_10'].net, 100) |
|||
self.assertEqual(lines['tax_10'].tax, 10) |
|||
self.assertEqual(lines['tax_20'].net, 250) |
|||
self.assertEqual(lines['tax_20'].tax, 50) |
|||
|
|||
# Check report based on taxgroups |
|||
self.assertEqual(len(lines['group_10']), 1) |
|||
self.assertEqual(len(lines['group_20']), 1) |
|||
self.assertEqual(len(lines['tax_group_10']), 1) |
|||
self.assertEqual(len(lines['tax_group_20']), 1) |
|||
self.assertEqual(lines['group_10'].net, 100) |
|||
self.assertEqual(lines['group_10'].tax, 10) |
|||
self.assertEqual(lines['group_20'].net, 250) |
|||
self.assertEqual(lines['group_20'].tax, 50) |
|||
self.assertEqual(lines['tax_group_10'].net, 100) |
|||
self.assertEqual(lines['tax_group_10'].tax, 10) |
|||
self.assertEqual(lines['tax_group_20'].net, 250) |
|||
self.assertEqual(lines['tax_group_20'].tax, 50) |
|||
|
|||
def test_get_report_html(self): |
|||
company = self.env.ref('base.main_company') |
|||
vat_report = self.env['report_vat_report'].create({ |
|||
'date_from': self.date_from, |
|||
'date_to': self.date_to, |
|||
'company_id': company.id, |
|||
'tax_detail': True, |
|||
}) |
|||
vat_report.compute_data_for_report() |
|||
vat_report.get_html(given_context={}) |
|||
|
|||
def test_wizard_date_range(self): |
|||
vat_wizard = self.env['vat.report.wizard'] |
|||
date_range = self.env['date.range'] |
|||
self.type = self.env['date.range.type'].create( |
|||
{'name': 'Month', |
|||
'company_id': False, |
|||
'allow_overlap': False}) |
|||
dt = date_range.create({ |
|||
'name': 'FS2016', |
|||
'date_start': time.strftime('%Y-%m-01'), |
|||
'date_end': time.strftime('%Y-%m-28'), |
|||
'type_id': self.type.id, |
|||
}) |
|||
wizard = vat_wizard.create( |
|||
{'date_range_id': dt.id, |
|||
'date_from': time.strftime('%Y-%m-28'), |
|||
'date_to': time.strftime('%Y-%m-01'), |
|||
'tax_detail': True}) |
|||
wizard.onchange_date_range_id() |
|||
self.assertEqual(wizard.date_from, time.strftime('%Y-%m-01')) |
|||
self.assertEqual(wizard.date_to, time.strftime('%Y-%m-28')) |
|||
wizard._export('qweb-pdf') |
|||
wizard.button_export_html() |
|||
wizard.button_export_pdf() |
|||
wizard.button_export_xlsx() |
|||
wizard = vat_wizard.create( |
|||
{'date_range_id': dt.id, |
|||
'date_from': time.strftime('%Y-%m-28'), |
|||
'date_to': time.strftime('%Y-%m-01'), |
|||
'based_on': 'taxgroups', |
|||
'tax_detail': True}) |
|||
wizard.onchange_date_range_id() |
|||
self.assertEqual(wizard.date_from, time.strftime('%Y-%m-01')) |
|||
self.assertEqual(wizard.date_to, time.strftime('%Y-%m-28')) |
|||
wizard._export('qweb-pdf') |
|||
wizard.button_export_html() |
|||
wizard.button_export_pdf() |
|||
wizard.button_export_xlsx() |
@ -1,9 +1,11 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
|
|||
<template id="report_trial_balance"> |
|||
<div class="o_account_financial_reports_page"> |
|||
<t t-call="account_financial_report.report_buttons"/> |
|||
<t t-call="account_financial_report.report_trial_balance_base"/> |
|||
</div> |
|||
</template> |
|||
|
|||
</odoo> |
@ -0,0 +1,9 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<template id="report_vat_report"> |
|||
<div class="o_account_financial_reports_page"> |
|||
<t t-call="account_financial_report.report_buttons"/> |
|||
<t t-call="account_financial_report.report_vat_report_base"/> |
|||
</div> |
|||
</template> |
|||
</odoo> |
@ -1,9 +1,5 @@ |
|||
|
|||
# Author: Damien Crier |
|||
# Author: Julien Coux |
|||
# Copyright 2016 Camptocamp SA |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
from . import aged_partner_balance_wizard |
|||
from . import general_ledger_wizard |
|||
from . import open_items_wizard |
|||
from . import trial_balance_wizard |
|||
from . import vat_report_wizard |
@ -0,0 +1,80 @@ |
|||
# Copyright 2018 Forest and Biomass Romania |
|||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
|||
|
|||
from odoo import api, fields, models |
|||
from odoo.tools.safe_eval import safe_eval |
|||
from odoo.tools import pycompat |
|||
|
|||
|
|||
class VATReportWizard(models.TransientModel): |
|||
_name = "vat.report.wizard" |
|||
|
|||
company_id = fields.Many2one( |
|||
comodel_name='res.company', |
|||
default=lambda self: self.env.user.company_id, |
|||
string='Company' |
|||
) |
|||
date_range_id = fields.Many2one( |
|||
comodel_name='date.range', |
|||
string='Date range' |
|||
) |
|||
date_from = fields.Date('Start Date', required=True) |
|||
date_to = fields.Date('End Date', required=True) |
|||
based_on = fields.Selection([('taxtags', 'Tax Tags'), |
|||
('taxgroups', 'Tax Groups')], |
|||
string='Based On', |
|||
required=True, |
|||
default='taxtags') |
|||
tax_detail = fields.Boolean('Detail Taxes') |
|||
|
|||
@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 |
|||
|
|||
@api.multi |
|||
def button_export_html(self): |
|||
self.ensure_one() |
|||
action = self.env.ref( |
|||
'account_financial_report.action_report_vat_report') |
|||
vals = action.read()[0] |
|||
context1 = vals.get('context', {}) |
|||
if isinstance(context1, pycompat.string_types): |
|||
context1 = safe_eval(context1) |
|||
model = self.env['report_vat_report'] |
|||
report = model.create(self._prepare_vat_report()) |
|||
report.compute_data_for_report() |
|||
context1['active_id'] = report.id |
|||
context1['active_ids'] = report.ids |
|||
vals['context'] = context1 |
|||
return vals |
|||
|
|||
@api.multi |
|||
def button_export_pdf(self): |
|||
self.ensure_one() |
|||
report_type = 'qweb-pdf' |
|||
return self._export(report_type) |
|||
|
|||
@api.multi |
|||
def button_export_xlsx(self): |
|||
self.ensure_one() |
|||
report_type = 'xlsx' |
|||
return self._export(report_type) |
|||
|
|||
def _prepare_vat_report(self): |
|||
self.ensure_one() |
|||
return { |
|||
'company_id': self.company_id.id, |
|||
'date_from': self.date_from, |
|||
'date_to': self.date_to, |
|||
'based_on': self.based_on, |
|||
'tax_detail': self.tax_detail, |
|||
} |
|||
|
|||
def _export(self, report_type): |
|||
"""Default export is PDF.""" |
|||
model = self.env['report_vat_report'] |
|||
report = model.create(self._prepare_vat_report()) |
|||
report.compute_data_for_report() |
|||
return report.print_report(report_type) |
@ -0,0 +1,44 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
|
|||
<record id="vat_report_wizard" model="ir.ui.view"> |
|||
<field name="name">vat_report_wizard_view</field> |
|||
<field name="model">vat.report.wizard</field> |
|||
<field name="arch" type="xml"> |
|||
<form string="VAT Report Options"> |
|||
<group name="main_info"> |
|||
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/> |
|||
</group> |
|||
<group name="filters"> |
|||
<group name="date_range"> |
|||
<field name="date_range_id" domain="['|',('company_id','=',company_id), ('company_id','=',False)]"/> |
|||
<field name="date_from"/> |
|||
<field name="date_to"/> |
|||
</group> |
|||
<group name="other_filters"> |
|||
<field name="based_on" widget="radio"/> |
|||
<field name="tax_detail"/> |
|||
</group> |
|||
</group> |
|||
<footer> |
|||
<button name="button_export_html" string="View" |
|||
type="object" default_focus="1" class="oe_highlight"/> |
|||
or |
|||
<button name="button_export_pdf" string="Export PDF" type="object"/> |
|||
or |
|||
<button name="button_export_xlsx" string="Export XLSX" type="object"/> |
|||
or |
|||
<button string="Cancel" class="oe_link" special="cancel" /> |
|||
</footer> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
|
|||
<act_window id="action_vat_report_wizard" |
|||
name="VAT Report" |
|||
res_model="vat.report.wizard" |
|||
view_type="form" |
|||
view_mode="form" |
|||
view_id="vat_report_wizard" |
|||
target="new" /> |
|||
</odoo> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue