168 lines
7.0 KiB
Python
168 lines
7.0 KiB
Python
from odoo import fields, models
|
|
from odoo.tools import float_round, SQL
|
|
|
|
|
|
class L10nBgReportsTaxReportHandler(models.AbstractModel):
|
|
_name = 'l10n_bg_reports.tax.report.handler'
|
|
_inherit = ['account.tax.report.handler']
|
|
_description = 'Tax report handler for Bulgaria'
|
|
|
|
TAX_TAGS_PER_TYPE_IN_ORDER = {
|
|
'purchase': ['30', '31', '41', '32', '42'],
|
|
'sale': ['11', '21', '12', '22', '13', '23', '24', '14', '15', '16', '17', '18', '19'],
|
|
}
|
|
|
|
FILE_NAME_PER_TYPE = {
|
|
'purchase': 'POKUPKI.txt',
|
|
'sale': 'PRODAGBI.txt',
|
|
}
|
|
|
|
def _get_file_name(self, ledger_type):
|
|
assert ledger_type in {'purchase', 'sale'}
|
|
|
|
return self.FILE_NAME_PER_TYPE[ledger_type]
|
|
|
|
def _custom_options_initializer(self, report, options, previous_options):
|
|
super()._custom_options_initializer(report, options, previous_options=previous_options)
|
|
|
|
options.setdefault('buttons', []).extend([{
|
|
'name': self._get_file_name(ledger_type),
|
|
'sequence': 15,
|
|
'action': 'export_file',
|
|
'action_param': f'export_{ledger_type}_report_to_txt',
|
|
'file_export_type': 'TXT',
|
|
} for ledger_type in ('purchase', 'sale')])
|
|
|
|
def _get_ledger_data(self, options, ledger_type):
|
|
assert ledger_type in {'purchase', 'sale'}
|
|
|
|
def build_result(query_res_line, tax_tags):
|
|
result = {
|
|
'vat': self.env.company.vat,
|
|
'date': fields.Date.to_date(options['date']['date_from']).strftime('%Y%m'),
|
|
'branch_code': query_res_line['branch_code'],
|
|
'serial_number': query_res_line['serial_number'],
|
|
'document_type': query_res_line['document_type'],
|
|
'document_name': query_res_line['document_name'],
|
|
'document_date': query_res_line['document_date'],
|
|
'partner_vat': query_res_line['partner_vat'],
|
|
'partner_name': query_res_line['partner_name'],
|
|
'product_type': query_res_line['label'][0][:30].replace('\n', ' '),
|
|
'exemption_reason': query_res_line['exemption_reason'],
|
|
'total_base': 0,
|
|
'total_tax': 0,
|
|
}
|
|
|
|
for tax_tag, amount, is_tax_line in zip(query_res_line['tax_tag'], query_res_line['amount_currency'], query_res_line['is_tax_line']):
|
|
if ledger_type == 'sale':
|
|
result['total_tax' if is_tax_line else 'total_base'] += amount
|
|
|
|
tax = tax_tags[tax_tag].name
|
|
|
|
if tax in self.TAX_TAGS_PER_TYPE_IN_ORDER[ledger_type]:
|
|
result[f'tax_{tax}'] = result.get(f'tax_{tax}', 0) + amount
|
|
|
|
return result
|
|
|
|
self.env.flush_all()
|
|
|
|
report = self.env['account.report'].browse(options['report_id'])
|
|
|
|
query_params = report._get_report_query(options, 'strict_range')
|
|
|
|
tax_tags_names = tuple(self.TAX_TAGS_PER_TYPE_IN_ORDER[ledger_type])
|
|
tax_tags = self.env['account.account.tag'].search([
|
|
('name', 'in', tax_tags_names),
|
|
('country_id.code', '=', 'BG'),
|
|
]).grouped('id')
|
|
|
|
query = SQL("""
|
|
SELECT
|
|
row_number() over (ORDER BY account_move.sequence_number DESC) AS serial_number,
|
|
account_move.l10n_bg_document_type AS document_type,
|
|
account_move.name AS document_name,
|
|
account_move.invoice_date AS document_date,
|
|
company_id.l10n_bg_branch_code as branch_code,
|
|
partner.vat AS partner_vat,
|
|
partner.name AS partner_name,
|
|
array_agg(account_move_line.name) AS label,
|
|
array_agg(tag.id ORDER BY tag.id) AS tax_tag,
|
|
account_move.l10n_bg_exemption_reason AS exemption_reason,
|
|
array_agg(CASE WHEN account_move_line.tax_line_id IS NOT NULL THEN TRUE ELSE FALSE END) AS is_tax_line,
|
|
array_agg(ABS(account_move_line.amount_currency)) AS amount_currency
|
|
FROM
|
|
%(table_references)s
|
|
%(currency_table_join)s
|
|
JOIN account_move ON account_move.id = account_move_line.move_id
|
|
LEFT JOIN res_partner partner ON partner.id = account_move_line.partner_id
|
|
LEFT JOIN res_company company_id ON company_id.id = account_move.company_id
|
|
LEFT JOIN account_account_tag_account_move_line_rel aa_tag_aml_rel ON aa_tag_aml_rel.account_move_line_id = account_move_line.id
|
|
LEFT JOIN account_account_tag tag ON aa_tag_aml_rel.account_account_tag_id = tag.id
|
|
WHERE
|
|
%(search_conditions)s
|
|
AND account_move.move_type IN %(move_types)s
|
|
AND tag.id = ANY(%(tag_ids)s)
|
|
GROUP BY account_move.id, partner.id, company_id.id
|
|
ORDER BY serial_number
|
|
""",
|
|
table_references=query_params.from_clause,
|
|
currency_table_join=report._currency_table_aml_join(options),
|
|
search_conditions=query_params.where_clause,
|
|
move_types=('in_invoice', 'in_refund', 'in_receipt') if ledger_type == 'purchase' else ('out_invoice', 'out_refund', 'out_receipt'),
|
|
tag_ids=list(tax_tags.keys()),
|
|
)
|
|
|
|
self.env.cr.execute(query)
|
|
|
|
data = []
|
|
|
|
for query_res in self.env.cr.dictfetchall():
|
|
data.append(build_result(query_res, tax_tags))
|
|
|
|
return data
|
|
|
|
def _export_report_to_txt(self, options, ledger_type):
|
|
assert ledger_type in {'purchase', 'sale'}
|
|
|
|
ledger_data = self._get_ledger_data(options, ledger_type)
|
|
file_content = []
|
|
|
|
for line in ledger_data:
|
|
line_content = (
|
|
f"{line['vat']:15}"
|
|
f"{line['date']}"
|
|
f"{line['branch_code']:0>4}"
|
|
f"{line['serial_number']:15}"
|
|
f"{line['document_type']:2}"
|
|
f"{line['document_name']:20}"
|
|
f"{line['document_date'].strftime('%d/%m/%Y')}"
|
|
f"{line['partner_vat'] or '':15}"
|
|
f"{line['partner_name'].replace(' ', '-'):50}"
|
|
f"{(line['product_type'] or '')[:30].replace(' ', '-'):30}"
|
|
)
|
|
|
|
if ledger_type == 'sale':
|
|
line_content += (
|
|
f"{float_round(line['total_base'], precision_digits=1) or '':>15}"
|
|
f"{float_round(line['total_tax'], precision_digits=1) or '':>15}"
|
|
)
|
|
|
|
for tag in self.TAX_TAGS_PER_TYPE_IN_ORDER[ledger_type]:
|
|
line_content += f"{line.get(f'tax_{tag}', ''):>15}"
|
|
|
|
line_content += f"{(line['exemption_reason'] or ''):2}"
|
|
|
|
file_content.append(line_content)
|
|
|
|
return {
|
|
'file_name': self._get_file_name(ledger_type),
|
|
'file_content': '\n'.join(file_content).encode(),
|
|
'file_type': 'txt',
|
|
}
|
|
|
|
def export_purchase_report_to_txt(self, options):
|
|
return self._export_report_to_txt(options, 'purchase')
|
|
|
|
def export_sale_report_to_txt(self, options):
|
|
return self._export_report_to_txt(options, 'sale')
|