169 lines
7.2 KiB
Python
169 lines
7.2 KiB
Python
from datetime import date
|
|
|
|
from lxml import etree
|
|
from stdnum.sk import vat as sk_vat
|
|
|
|
from odoo import fields, models
|
|
from odoo.tools import date_utils, float_round, street_split
|
|
|
|
|
|
class SlovakTaxReportCustomHandler(models.AbstractModel):
|
|
"""
|
|
Generate the VAT report for the Slovakia.
|
|
Generated using as a reference the documentation at
|
|
https://www.financnasprava.sk/sk/podnikatelia/dane/dan-z-pridanej-hodnoty/danove-priznanie
|
|
"""
|
|
_name = 'l10n_sk.tax.report.handler'
|
|
_inherit = 'account.tax.report.handler'
|
|
_description = 'Slovak Tax Report Custom Handler'
|
|
|
|
_BODY_FIELD_MAP = [
|
|
('r01', 'sk_01', 'base'), ('r01a', 'sk_01a', 'base'),
|
|
('r02', 'sk_01', 'vat'), ('r02a', 'sk_01a', 'vat'),
|
|
('r03', 'sk_03', 'base'), ('r04', 'sk_03', 'vat'),
|
|
('r05', 'sk_05', 'base'), ('r05a', 'sk_05a', 'base'),
|
|
('r06', 'sk_05', 'vat'), ('r06a', 'sk_05a', 'vat'),
|
|
('r07', 'sk_07', 'base'), ('r08', 'sk_07', 'vat'),
|
|
('r09', 'sk_09', 'base'), ('r09a', 'sk_09a', 'base'), ('r09b', 'sk_09b', 'base'),
|
|
('r10', 'sk_09', 'vat'), ('r10a', 'sk_09a', 'vat'), ('r10b', 'sk_09b', 'vat'),
|
|
('r11', 'sk_11', 'base'), ('r11a', 'sk_11a', 'base'), ('r11b', 'sk_11b', 'base'),
|
|
('r11c', 'sk_11c', 'base'), ('r11d', 'sk_11d', 'base'), ('r11e', 'sk_11e', 'base'),
|
|
('r12', 'sk_11', 'vat'), ('r12a', 'sk_11a', 'vat'), ('r12b', 'sk_11b', 'vat'),
|
|
('r12c', 'sk_11c', 'vat'), ('r12d', 'sk_11d', 'vat'), ('r12e', 'sk_11e', 'vat'),
|
|
('r13', 'sk_13', 'base'), ('r14', 'sk_14', 'base'), ('r15', 'sk_15', 'base'),
|
|
('r16', 'sk_16', 'vat'), ('r17', 'sk_17', 'vat'),
|
|
('r18', 'sk_18_total', 'vat'), ('r18a', 'sk_18a_total', 'vat'), ('r19', 'sk_19_total', 'vat'),
|
|
('r20', 'sk_20', 'vat'), ('r20a', 'sk_20a', 'vat'), ('r21', 'sk_21', 'vat'),
|
|
('r22', 'sk_22', 'vat'), ('r22a', 'sk_22a', 'vat'), ('r23', 'sk_23', 'vat'),
|
|
('r23a', 'sk_23a', 'vat'), ('r23b', 'sk_23b', 'vat'), ('r23c', 'sk_23c', 'vat'),
|
|
('r24', 'sk_24', 'base'), ('r25', 'sk_24', 'vat'),
|
|
('r26', 'sk_26', 'base'), ('r27', 'sk_26', 'vat'),
|
|
('r28', 'sk_28', 'vat'), ('r29', 'sk_29', 'vat'),
|
|
('r30', 'sk_30', 'vat'), ('r31', 'sk_31', 'vat'),
|
|
('r32', 'sk_32', 'vat'),
|
|
('r33', 'sk_33', 'vat'), ('r34', 'sk_34', 'vat'), ('r35', 'sk_35', 'vat'),
|
|
('r36', 'sk_36', 'vat'), ('r37', 'sk_37', 'vat'),
|
|
]
|
|
|
|
def _custom_options_initializer(self, report, options, previous_options):
|
|
super()._custom_options_initializer(report, options, previous_options=previous_options)
|
|
|
|
options.setdefault('buttons', []).append({
|
|
'name': self.env._('XML'),
|
|
'sequence': 30,
|
|
'action': 'export_file',
|
|
'action_param': 'export_to_xml',
|
|
'file_export_type': self.env._('XML'),
|
|
})
|
|
|
|
def export_to_xml(self, options):
|
|
report = self.env['account.report'].browse(options['report_id'])
|
|
sender_company = report._get_sender_company_for_export(options)
|
|
|
|
data = {
|
|
'xml_values': self._l10n_sk_get_xml_values(report, options, sender_company),
|
|
}
|
|
|
|
xml_content = self.env['ir.qweb']._render('l10n_sk_reports.sk_vat_report_template', values=data)
|
|
tree = etree.fromstring(xml_content)
|
|
formatted_xml = etree.tostring(tree, pretty_print=True, xml_declaration=True, encoding='UTF-8')
|
|
|
|
return {
|
|
'file_name': report.get_default_report_filename(options, 'xml'),
|
|
'file_content': formatted_xml,
|
|
'file_type': 'xml',
|
|
}
|
|
|
|
def _l10n_sk_get_report_line_values(self, report, options):
|
|
report_options = report.get_options(previous_options={**options, 'export_mode': 'file'})
|
|
values = {}
|
|
for line in report._get_lines(report_options):
|
|
code = line.get('code')
|
|
if not code or not code.startswith('sk_'):
|
|
continue
|
|
|
|
expression_values = {
|
|
column.get('expression_label'): column.get('no_format')
|
|
for column in line.get('columns', [])
|
|
}
|
|
values[code] = {
|
|
'base': float_round(expression_values.get('base') or 0, precision_digits=2),
|
|
'vat': float_round(expression_values.get('vat') or 0, precision_digits=2),
|
|
}
|
|
|
|
return values
|
|
|
|
def _l10n_sk_compute_tax_period(self, date_from, date_to):
|
|
month_value = ''
|
|
quarter_value = ''
|
|
quarter_start, quarter_end = date_utils.get_quarter(date_from)
|
|
|
|
if date_from.year == date_to.year and date_from.month == date_to.month:
|
|
month_value = str(date_to.month)
|
|
elif date_from == quarter_start and date_to == quarter_end:
|
|
quarter_value = str(date_utils.get_quarter_number(date_to))
|
|
|
|
return {
|
|
'mesiac': month_value,
|
|
'stvrtrok': quarter_value,
|
|
'rok': str(date_to.year),
|
|
}
|
|
|
|
def _l10n_sk_get_body_values(self, report_values):
|
|
def _format_decimal(value):
|
|
rounded = float_round(value or 0, precision_digits=2)
|
|
return f"{rounded:.2f}"
|
|
|
|
values = {
|
|
xml_field: _format_decimal(report_values.get(report_code, {}).get(label, 0))
|
|
for xml_field, report_code, label in self._BODY_FIELD_MAP
|
|
}
|
|
values['splneniePodmienok'] = '0'
|
|
return values
|
|
|
|
def _l10n_sk_get_header_values(self, company):
|
|
partner = company.partner_id
|
|
split_address = street_split(partner.street or '')
|
|
|
|
company_name_lines = [line for line in (company.name or '').split('\n') if line][:4] or ['']
|
|
partner_phone = partner.phone or company.phone or ''
|
|
partner_email = partner.email or company.email or ''
|
|
|
|
return {
|
|
'kodStatu': 'SK',
|
|
'cislo': company.company_registry or '',
|
|
'dic': sk_vat.compact(company.vat or ''),
|
|
'danovyUrad': '',
|
|
'nevzniklaPov': '0',
|
|
'rdp': '1',
|
|
'odp': '0',
|
|
'ddp': '0',
|
|
'datumZisteniaDdp': '',
|
|
'platitel': '1',
|
|
'registrovana': '0',
|
|
'inaPovinna': '0',
|
|
'zdanitelna': '1',
|
|
'zastupca': '0',
|
|
'zastupca69aa': '0',
|
|
'meno_riadky': company_name_lines,
|
|
'ulica': split_address['street_name'] or '',
|
|
'cislo_adresy': split_address['street_number'] or '',
|
|
'psc': partner.zip or '',
|
|
'obec': partner.city or '',
|
|
'telefon': partner_phone,
|
|
'email': partner_email,
|
|
'menoPriezvisko': partner.name or '',
|
|
'telefon_oos': partner_phone,
|
|
'email_oos': partner_email,
|
|
'datumVyhlasenia': date.today().strftime('%d.%m.%Y'),
|
|
}
|
|
|
|
def _l10n_sk_get_xml_values(self, report, options, company):
|
|
date_from = fields.Date.to_date(options['date']['date_from'])
|
|
date_to = fields.Date.to_date(options['date']['date_to'])
|
|
report_values = self._l10n_sk_get_report_line_values(report, options)
|
|
xml_values = self._l10n_sk_get_body_values(report_values)
|
|
xml_values.update(self._l10n_sk_get_header_values(company))
|
|
xml_values.update(self._l10n_sk_compute_tax_period(date_from, date_to))
|
|
return xml_values
|