1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/account_intrastat/models/account_intrastat_report.py
2024-12-10 09:04:09 +07:00

679 lines
34 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from psycopg2.sql import SQL, Literal, Identifier
from itertools import zip_longest
from odoo import api, models, _
from odoo.tools import get_lang, OrderedSet
from odoo.tools.float_utils import float_repr, float_round
from odoo.tools.misc import format_date
_merchandise_export_code = {
'BE': '29',
'FR': '21',
'NL': '7',
}
_merchandise_import_code = {
'BE': '19',
'FR': '11',
'NL': '6',
}
_unknown_country_code = {
'BE': 'QU',
'NL': 'QV',
}
_qn_unknown_individual_vat_country_codes = ('FI', 'SE', 'SK', 'DE', 'AT')
errors = ('expired_trans', 'premature_trans', 'missing_trans', 'expired_comm', 'premature_comm', 'missing_comm', 'missing_unit', 'missing_weight')
REPORT_LINE_ID_KEYS = ['type', 'transaction_code', 'commodity_code', 'intrastat_product_origin_country_code', 'partner_vat', 'country_code', 'incoterm_code', 'transport_code', 'invoice_currency_id', 'region_code']
class IntrastatReportCustomHandler(models.AbstractModel):
_name = 'account.intrastat.report.handler'
_inherit = 'account.report.custom.handler'
_description = 'Intrastat Report Custom Handler'
def _get_custom_display_config(self):
return {
'components': {
'AccountReportFilters': 'account_intrastat.IntrastatReportFilters',
},
}
def _dynamic_lines_generator(self, report, options, all_column_groups_expression_totals=None, warnings=None):
if options.get('intrastat_grouped'):
# dict of the form {move_id: {column_group_key: {expression_label: value}}}
move_info_dict = {}
# dict of the form {column_group_key: {expression_label: value}}
total_values_dict = {}
# Build query
query_list = []
full_query_params = []
for column_group_key, column_group_options in report._split_options_per_column_group(options).items():
query, params = self._build_query_group(column_group_options, column_group_key)
query_list.append(query)
full_query_params += params
full_query = SQL(" UNION ALL ").join(query_list)
self._cr.execute(full_query, full_query_params)
results = self._cr.dictfetchall()
# Fill dictionaries
for res in results:
line_id = self._get_report_line_id(report, res)
column_group_key = res['column_group_key']
current_move_info = move_info_dict.setdefault(line_id, {'name': self._get_move_info_name(res)})
current_move_info[column_group_key] = res
# We add the value to the total (for total line)
total_values_dict.setdefault(column_group_key, {'value': 0})
total_values_dict[column_group_key]['value'] += res['value']
# Create lines
lines = []
for move_id, move_info in move_info_dict.items():
line = self._create_report_line(options, move_info, move_id, ['value'], warnings=warnings)
lines.append((0, line))
# Create total line if only one type of invoice is selected
if options.get('intrastat_total_line'):
total_line = self._create_report_total_line(options, total_values_dict)
lines.append((0, total_line))
else:
lines = [(0, line) for line in self._get_lines(options)]
return lines
def _get_move_info_name(self, move_info):
# Some values are necessary for the id generation but not in the name, we removed region_code because a condition handles it after
keys = OrderedSet(REPORT_LINE_ID_KEYS) - OrderedSet(['incoterm_code', 'transport_code', 'invoice_currency_id', 'region_code'])
name = " - ".join(str(move_info[key]) for key in keys)
if self._show_region_code():
name += f" - {move_info['region_code']}"
return name
def _get_report_line_id(self, report, move_info):
move_values = []
for key in REPORT_LINE_ID_KEYS:
if key == 'intrastat_product_origin_country_code' and move_info.get(key) == 'XU':
# Special case for the United Kingdom where the code is XU instead of GB,
# to avoid issue when we fetch children lines, we set to GB in the line id.
move_values.append('GB')
else:
move_values.append(str(move_info.get(key)))
return report._get_generic_line_id('account.move', None, markup=",".join(move_values))
def _custom_options_initializer(self, report, options, previous_options=None):
super()._custom_options_initializer(report, options, previous_options=previous_options)
previous_options = previous_options or {}
# Filter only partners with VAT
options['intrastat_with_vat'] = previous_options.get('intrastat_with_vat', False)
options['intrastat_grouped'] = previous_options.get('intrastat_grouped', False)
# Filter types of invoices
default_type = [
{'name': _('Arrival'), 'selected': False, 'id': 'arrival'},
{'name': _('Dispatch'), 'selected': False, 'id': 'dispatch'},
]
options['intrastat_type'] = previous_options.get('intrastat_type', default_type)
options['country_format'] = previous_options.get('country_format')
options['commodity_flow'] = previous_options.get('commodity_flow')
# Filter the domain based on the types of invoice selected
include_arrivals, include_dispatches = self._determine_inclusion(options)
invoice_types = []
if include_arrivals:
invoice_types += ['in_invoice', 'out_refund']
if include_dispatches:
invoice_types += ['out_invoice', 'in_refund']
# When only one type is selected, we can display a total line
options['intrastat_total_line'] = include_arrivals != include_dispatches
options.setdefault('forced_domain', []).append(('move_id.move_type', 'in', invoice_types))
# Filter report type (extended form)
options['intrastat_extended'] = previous_options.get('intrastat_extended', True)
# 2 columns are conditional and should only appear when rendering the extended intrastat report
# Some countries don't use the region code column; we hide it for them.
excluded_columns = set()
if not options['intrastat_extended']:
excluded_columns |= {'transport_code', 'incoterm_code'}
if not self._show_region_code():
excluded_columns.add('region_code')
new_columns = []
for col in options['columns']:
if col['expression_label'] not in excluded_columns:
new_columns.append(col)
# Replace country names by codes if necessary (for file exports)
if options.get('country_format') == 'code':
if col['expression_label'] == 'country_name':
col['expression_label'] = 'country_code'
elif col['expression_label'] == 'intrastat_product_origin_country_name':
col['expression_label'] = 'intrastat_product_origin_country_code'
options['columns'] = new_columns
# Only pick Sale/Purchase journals (+ divider)
report._init_options_journals(options, previous_options=previous_options, additional_journals_domain=[('type', 'in', ('sale', 'purchase'))])
# When printing the report to xlsx, we want to use country codes instead of names
xlsx_button_option = next(button_opt for button_opt in options['buttons'] if button_opt.get('action_param') == 'export_to_xlsx')
xlsx_button_option['action_param'] = 'export_to_xlsx'
options['ignore_totals_below_sections'] = True
@api.model
def _determine_inclusion(self, options):
include_arrivals = options['intrastat_type'][0]['selected']
include_dispatches = options['intrastat_type'][1]['selected']
if not include_arrivals and not include_dispatches:
include_arrivals = include_dispatches = True
return include_arrivals, include_dispatches
####################################################
# OVERRIDES
####################################################
def _show_region_code(self):
"""Return a bool indicating if the region code is to be displayed for the country concerned in this localisation."""
# TO OVERRIDE
return True
####################################################
# OPTIONS: INIT
####################################################
def export_to_xlsx(self, options, response=None):
# We need to regenerate the options to make sure we hide the country name columns as expected.
report = self.env['account.report'].browse(options['report_id'])
new_options = report.get_options(previous_options={**options, 'country_format': 'code', 'commodity_flow': 'code'})
return report.export_to_xlsx(new_options, response=response)
####################################################
# REPORT LINES: CORE
####################################################
@api.model
def _create_report_line(self, options, line_vals, line_id, number_values, warnings=None):
""" Create a standard (non-total) line for the report
:param options: report options
:param line_vals: values necessary for the line
:param line_id: id of the line
:param number_values: list of expression labels that need to have the 'number' class
"""
report = self.env['account.report'].browse(options['report_id'])
columns = []
uom_precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
for column in options['columns']:
expression_label = column['expression_label']
value = line_vals.get(column['column_group_key'], {}).get(expression_label, None)
if value:
if options.get('commodity_flow') != 'code' and column['expression_label'] == 'system':
value = f"{value} ({line_vals.get(column['column_group_key'], {}).get('type', False)})"
elif column['expression_label'] == 'supplementary_units':
value = float_repr(float_round(value, precision_digits=uom_precision), precision_digits=uom_precision)
columns.append(report._build_column_dict(value, column, options=options))
if warnings is not None:
for column_group in options['column_groups']:
for warning_code in errors:
if line_vals.get(column_group) and any(line_vals[column_group].get(warning_code)):
warning_params = warnings.setdefault(
f'account_intrastat.intrastat_warning_{warning_code}',
{'ids': [], 'alert_type': 'warning'}
)
warning_params['ids'].extend(aml_id for aml_id in line_vals[column_group][warning_code] if aml_id is not None)
unfold_all = self._context.get('print_mode') or options.get('unfold_all')
return {
'id': line_id,
'name': line_vals['name'],
'columns': columns,
'unfoldable': True,
'unfolded': unfold_all or line_id in options.get('unfolded_lines'),
'expand_function': '_report_expand_unfoldable_line_intrastat_line',
'level': 1,
'class': 'account_intrastat_line_name',
}
def _report_expand_unfoldable_line_intrastat_line(self, line_dict_id, groupby, options, progress, offset, unfold_all_batch_data=None):
options['account_report'] = self.env['account.report'].browse(options['report_id'])
lines = self._get_lines(options, line_dict_id)
return {
'lines': lines,
'offset_increment': len(lines),
'has_more': self._has_more_lines(options['account_report'], len(lines)),
}
def _get_lines(self, options, parent_line=None):
""" This functions gets every line (account.move.line) that matches the selected options. """
report = self.env['account.report'].browse(options['report_id'])
expanded_line_options = None
if parent_line:
expanded_line_options = self._get_markup_info_from_intrastat_id(parent_line)
queries = []
full_query_params = []
for column_group_key, column_group_options in report._split_options_per_column_group(options).items():
query, params, = self._prepare_query(column_group_options, column_group_key, expanded_line_options)
queries.append(query)
full_query_params += params
full_query = SQL(" UNION ALL ").join(queries)
self._cr.execute(full_query, full_query_params)
raw_intrastat_lines = self._cr.dictfetchall()
raw_intrastat_lines = self._fill_missing_values(raw_intrastat_lines)
lines = []
for raw_intrastat_line in raw_intrastat_lines:
if self._has_more_lines(report, len(lines)):
# Enough elements loaded. Only the one due to the +1 in the limit passed when computing aml_results is left.
# This element won't generate a line now, but we use it to know that we'll need to add a load_more line.
break
lines.append(self._get_aml_line(report, parent_line, options, raw_intrastat_line))
return lines
def _has_more_lines(self, report, treated_results_count):
limit_to_load = report.load_more_limit + 1 if report.load_more_limit and not self._context.get('print_mode') else None
return limit_to_load and treated_results_count == report.load_more_limit
def _get_aml_line(self, report, parent_line_id, options, aml_data):
line_columns = []
for column in options['columns']:
col_expr_label = column['expression_label']
col_value = aml_data.get(col_expr_label)
if col_expr_label == 'system' and options.get('commodity_flow') != 'code':
col_value = f"{col_value} ({aml_data['type']})"
# if several columns with same name but different group key (i.e. with period comparison),
# then ensure that None is set as value for the non-corresponding columns.
col_value = col_value if column.get('column_group_key') == aml_data.get('column_group_key') else None
new_column = report._build_column_dict(col_value, column, options=options)
line_columns.append(new_column)
return {
'id': report._get_generic_line_id('account.move.line', aml_data['id'], parent_line_id=parent_line_id),
'caret_options': 'account.move.line',
'parent_id': parent_line_id,
'name': aml_data['name'],
'columns': line_columns,
'level': 3,
}
@api.model
def _create_report_total_line(self, options, total_vals):
""" Create a total line for the report
:param options: report options
:param total_vals: total values dict
"""
report = self.env['account.report'].browse(options['report_id'])
columns = []
for column in options['columns']:
value = total_vals.get(column['column_group_key'], {}).get(column['expression_label'])
columns.append(report._build_column_dict(value, column, options=options))
return {
'id': report._get_generic_line_id(None, None, markup='total'),
'name': _('Total'),
'level': 1,
'columns': columns,
}
####################################################
# REPORT LINES: QUERY
####################################################
@api.model
def _prepare_query(self, options, column_group_key=None, expanded_line_options=None):
query_blocks, where_params = self._build_query(options, column_group_key, expanded_line_options) # pylint: disable=sql-injection
query = SQL("({select} {from} {where} {order})").format(**query_blocks)
return query, where_params
@api.model
def _build_query(self, options, column_group_key=None, expanded_line_options=None):
# pylint: disable=sql-injection
def format_where_params(option_key, comparison_value=('None',)):
if expanded_line_options[option_key] not in comparison_value:
return expanded_line_options[option_key]
return None
domain = None
if expanded_line_options:
Move = self.env['account.move']
move_types = Move.get_outbound_types(include_receipts=False) if expanded_line_options['type'] == 'Arrival' else Move.get_inbound_types(include_receipts=False)
domain = [('move_id.move_type', 'in', move_types)]
# triangular use cases are handled by letting the intrastat_country_id editable on
# invoices. Modifying or emptying it allow to alter the intrastat declaration
# accordingly to specs (https://www.nbb.be/doc/dq/f_pdf_ex/intra2017fr.pdf (§ 4.x))
report = self.env['account.report'].browse(options['report_id'])
tables, where_clause, where_params = report._query_get(options, 'strict_range', domain=domain)
tables = SQL(tables)
where_clause = SQL(where_clause)
import_merchandise_code = _merchandise_import_code.get(self.env.company.country_id.code, '29')
export_merchandise_code = _merchandise_export_code.get(self.env.company.country_id.code, '19')
unknown_individual_vat = 'QN999999999999' if self.env.company.country_id.code in _qn_unknown_individual_vat_country_codes else 'QV999999999999'
unknown_country_code = _unknown_country_code.get(self.env.company.country_id.code, 'QV')
weight_category_id = self.env['ir.model.data']._xmlid_to_res_id('uom.product_uom_categ_kgm')
currency_table_query = SQL(report._get_query_currency_table(options))
select = SQL("""
SELECT
%s AS column_group_key,
row_number() over () AS sequence,
CASE WHEN account_move.move_type IN ('in_invoice', 'out_refund') THEN %s ELSE %s END AS system,
country.code AS country_code,
COALESCE(country.name->>{user_lang}, country.name->>'en_US') AS country_name,
company_country.code AS comp_country_code,
transaction.code AS transaction_code,
company_region.code AS region_code,
comp_partner.vat as company_vat,
code.code AS commodity_code,
account_move_line.id AS id,
prodt.id AS template_id,
prodt.categ_id AS category_id,
account_move_line.product_uom_id AS uom_id,
inv_line_uom.category_id AS uom_category_id,
account_move.id AS invoice_id,
account_move_line.id as move_line_id,
account_move.currency_id AS invoice_currency_id,
account_move.name,
COALESCE(account_move.date, account_move.invoice_date) AS invoice_date,
account_move.move_type AS invoice_type,
COALESCE(inv_incoterm.code, comp_incoterm.code) AS incoterm_code,
COALESCE(inv_transport.code, comp_transport.code) AS transport_code,
CASE WHEN account_move.move_type IN ('in_invoice', 'out_refund') THEN 'Arrival' ELSE 'Dispatch' END AS type,
ROUND(
COALESCE(prod.weight, 0) * account_move_line.quantity / (
CASE WHEN inv_line_uom.category_id IS NULL OR inv_line_uom.category_id = prod_uom.category_id
THEN inv_line_uom.factor ELSE 1 END
) * (
CASE WHEN prod_uom.uom_type <> 'reference'
THEN prod_uom.factor ELSE 1 END
),
SCALE(ref_weight_uom.rounding)
) AS weight,
account_move_line.quantity / (
CASE WHEN inv_line_uom.category_id IS NULL OR inv_line_uom.category_id = prod_uom.category_id
THEN inv_line_uom.factor ELSE 1 END
) AS quantity,
CASE WHEN code.supplementary_unit IS NOT NULL and prod.intrastat_supplementary_unit_amount != 0
THEN ROUND(CAST(
prod.intrastat_supplementary_unit_amount * (
account_move_line.quantity / (
CASE WHEN inv_line_uom.category_id IS NULL OR inv_line_uom.category_id = prod_uom.category_id
THEN inv_line_uom.factor ELSE 1 END
)) AS numeric), 2)
ELSE NULL END AS supplementary_units,
account_move_line.quantity AS line_quantity,
-- We double sign the balance to make sure that we keep consistency between invoice/bill and the intrastat report
-- Example: An invoice selling 10 items (but one is free 10 - 1), in the intrastat report we'll have 2 lines
-- One for 10 items minus one for the free item
SIGN(account_move_line.quantity) * SIGN(account_move_line.price_unit) * ABS(ROUND(account_move_line.balance * currency_table.rate, currency_table.precision)) AS value,
CASE WHEN product_country.code = 'GB' THEN 'XU' ELSE COALESCE(product_country.code, %s) END AS intrastat_product_origin_country_code,
COALESCE(product_country.name->>{user_lang}, product_country.name->>'en_US') AS intrastat_product_origin_country_name,
CASE WHEN partner.vat IS NOT NULL THEN partner.vat
WHEN partner.vat IS NULL AND partner.is_company IS FALSE THEN %s
ELSE 'QV999999999999'
END AS partner_vat,
transaction.expiry_date <= account_move.invoice_date AS expired_trans,
transaction.start_date > account_move.invoice_date AS premature_trans,
transaction.id IS NULL AS missing_trans,
code.expiry_date <= account_move.invoice_date AS expired_comm,
code.start_date > account_move.invoice_date AS premature_comm,
code.id IS NULL as missing_comm,
COALESCE(prod.intrastat_supplementary_unit_amount, 0) = 0 AND code.supplementary_unit IS NOT NULL as missing_unit,
COALESCE(prod.weight, 0) = 0 AND code.supplementary_unit IS NULL AS missing_weight,
prod.id AS product_id,
prodt.categ_id AS template_categ,
prodt.description as goods_description
""").format(user_lang=Literal(self.env.user.lang or get_lang(self.env).code))
from_ = SQL("""
FROM
{tables}
JOIN {currency_table_query} ON currency_table.company_id = account_move_line.company_id
JOIN account_move ON account_move.id = account_move_line.move_id
LEFT JOIN account_intrastat_code transaction ON account_move_line.intrastat_transaction_id = transaction.id
LEFT JOIN res_company company ON account_move.company_id = company.id
LEFT JOIN account_intrastat_code company_region ON company.intrastat_region_id = company_region.id
LEFT JOIN res_partner partner ON account_move_line.partner_id = partner.id
LEFT JOIN res_partner comp_partner ON company.partner_id = comp_partner.id
LEFT JOIN res_country country ON account_move.intrastat_country_id = country.id
LEFT JOIN res_country company_country ON comp_partner.country_id = company_country.id
INNER JOIN product_product prod ON account_move_line.product_id = prod.id
LEFT JOIN product_template prodt ON prod.product_tmpl_id = prodt.id
LEFT JOIN account_intrastat_code code ON code.id = prod.intrastat_code_id
LEFT JOIN uom_uom inv_line_uom ON account_move_line.product_uom_id = inv_line_uom.id
LEFT JOIN uom_uom prod_uom ON prodt.uom_id = prod_uom.id
LEFT JOIN account_incoterms inv_incoterm ON account_move.invoice_incoterm_id = inv_incoterm.id
LEFT JOIN account_incoterms comp_incoterm ON company.incoterm_id = comp_incoterm.id
LEFT JOIN account_intrastat_code inv_transport ON account_move.intrastat_transport_mode_id = inv_transport.id
LEFT JOIN account_intrastat_code comp_transport ON company.intrastat_transport_mode_id = comp_transport.id
LEFT JOIN res_country product_country ON product_country.id = account_move_line.intrastat_product_origin_country_id
LEFT JOIN res_country partner_country ON partner.country_id = partner_country.id AND partner_country.intrastat IS TRUE
LEFT JOIN uom_uom ref_weight_uom on ref_weight_uom.category_id = %s and ref_weight_uom.uom_type = 'reference'
""").format(tables=tables, currency_table_query=currency_table_query)
where = SQL("""
WHERE
{where_clause}
AND account_move_line.display_type = 'product'
AND (account_move_line.price_subtotal != 0 OR account_move_line.price_unit * account_move_line.quantity != 0)
AND company_country.id != country.id
AND country.intrastat = TRUE AND (country.code != 'GB' OR account_move.date < '2021-01-01')
AND prodt.type != 'service'
AND ref_weight_uom.active
""").format(where_clause=where_clause)
if expanded_line_options:
# When expanding the grouped lines, we only want to add the ones that matches the parent country code, currency and commodity code
where_values = {
'country.code': format_where_params('country_code'),
'code.code': format_where_params('commodity_code'),
'product_country.code': format_where_params('intrastat_product_origin_country_code', comparison_value=('QV', 'QU')),
'transaction.code': format_where_params('transaction_code'),
'company_region.code': format_where_params('region_code'),
'partner.vat': format_where_params('partner_vat', comparison_value=('QV999999999999', 'QN999999999999')),
'account_move.currency_id': format_where_params('invoice_currency_id'),
}
for key, value in where_values.items():
where += SQL(" AND {key} IS NOT DISTINCT FROM %s").format(key=Identifier(*key.split('.')))
where_params.append(value)
where += SQL(" AND COALESCE(inv_incoterm.code, comp_incoterm.code) IS NOT DISTINCT FROM %s")
where_params.append(format_where_params('incoterm_code'))
where += SQL(" AND COALESCE(inv_transport.code, comp_transport.code) IS NOT DISTINCT FROM %s")
where_params.append(format_where_params('transport_code'))
if options['intrastat_with_vat']:
where += SQL(" AND partner.vat IS NOT NULL ")
order = SQL("ORDER BY account_move.invoice_date DESC, account_move_line.id")
query = {
'select': select,
'from': from_,
'where': where,
'order': order,
}
query_params = [
column_group_key,
import_merchandise_code,
export_merchandise_code,
unknown_country_code,
unknown_individual_vat,
weight_category_id,
*where_params,
]
return query, query_params
@api.model
def _build_query_group(self, options, column_group_key=None):
""" This is the query to have the line grouped by country, currency and commodity code. """
inner_query, params = self._prepare_query(options, column_group_key)
query = SQL("""
SELECT %s AS column_group_key,
intrastat_lines.system as system,
intrastat_lines.type as type,
intrastat_lines.country_code AS country_code,
intrastat_lines.transaction_code as transaction_code,
intrastat_lines.transport_code as transport_code,
intrastat_lines.region_code as region_code,
intrastat_lines.commodity_code AS commodity_code,
intrastat_lines.country_name as country_name,
intrastat_lines.partner_vat as partner_vat,
intrastat_lines.incoterm_code as incoterm_code,
intrastat_lines.intrastat_product_origin_country_name as intrastat_product_origin_country_name,
intrastat_lines.intrastat_product_origin_country_code as intrastat_product_origin_country_code,
intrastat_lines.invoice_currency_id as invoice_currency_id,
ARRAY_AGG(CASE WHEN intrastat_lines.expired_trans IS TRUE THEN intrastat_lines.move_line_id END) as expired_trans,
ARRAY_AGG(CASE WHEN intrastat_lines.premature_trans IS TRUE THEN intrastat_lines.move_line_id END) as premature_trans,
ARRAY_AGG(CASE WHEN intrastat_lines.missing_trans IS TRUE THEN intrastat_lines.move_line_id END) as missing_trans,
ARRAY_AGG(CASE WHEN intrastat_lines.expired_comm IS TRUE THEN intrastat_lines.product_id END) as expired_comm,
ARRAY_AGG(CASE WHEN intrastat_lines.premature_comm IS TRUE THEN intrastat_lines.product_id END) as premature_comm,
ARRAY_AGG(CASE WHEN intrastat_lines.missing_comm IS TRUE THEN intrastat_lines.product_id END) as missing_comm,
ARRAY_AGG(CASE WHEN intrastat_lines.missing_unit IS TRUE THEN intrastat_lines.product_id END) as missing_unit,
ARRAY_AGG(CASE WHEN intrastat_lines.missing_weight IS TRUE THEN intrastat_lines.product_id END) as missing_weight,
SUM(intrastat_lines.value) as value,
SUM(intrastat_lines.weight) as weight,
SUM(intrastat_lines.supplementary_units) as supplementary_units
FROM ({}) intrastat_lines
INNER JOIN account_move ON account_move.id = intrastat_lines.invoice_id
GROUP BY system, type, country_code, transaction_code, transport_code, region_code, commodity_code, country_name, partner_vat,
incoterm_code,intrastat_product_origin_country_code, intrastat_product_origin_country_name, invoice_currency_id
""").format(inner_query)
params = [
column_group_key,
*params,
]
return query, params
####################################################
# REPORT LINES: HELPERS
####################################################
@api.model
def _fill_missing_values(self, vals_list):
""" Template method to be overidden to retrieve complex data
:param vals_list: A dictionary created by the dictfetchall method.
"""
return vals_list
def _get_markup_info_from_intrastat_id(self, line_id):
""" This function gets necessary info present in the generic report line id.
This information are related to REPORT_LINE_ID_KEYS.
:param line_id: A generic report line id
:return: A dictionary containing as key all the values in REPORT_LINE_ID_KEYS
and as value what we found in the generic report line id. If we don't
have a related value, we fill it with 'None'.
"""
markup = self.env['account.report']._get_markup(line_id)
line = markup.split(',')
return {
key: value
for key, value in zip_longest(REPORT_LINE_ID_KEYS, line, fillvalue='None')
}
####################################################
# ACTIONS
####################################################
def action_invalid_code_moves(self, options, params):
return {
'type': 'ir.actions.act_window',
'name': _('Invalid transaction intrastat code entries.'),
'res_model': 'account.move.line',
'views': [(
self.env.ref('account_intrastat.account_move_line_tree_view_account_intrastat_transaction_codes').id,
'list',
), (False, 'form')],
'domain': [('id', 'in', params['ids'])],
'context': {
'create': False,
'delete': False,
'expand': True,
},
}
def action_invalid_code_products(self, options, params):
return {
'type': 'ir.actions.act_window',
'name': _('Invalid commodity intrastat code products.'),
'res_model': 'product.product',
'views': [(
self.env.ref('account_intrastat.product_product_tree_view_account_intrastat').id,
'list',
), (False, 'form')],
'domain': [('id', 'in', params['ids'])],
'context': {
'create': False,
'delete': False,
'expand': True,
},
}
def action_undefined_units_products(self, options, params):
return {
'type': 'ir.actions.act_window',
'name': _('Undefined supplementary unit products.'),
'res_model': 'product.product',
'views': [(
self.env.ref('account_intrastat.product_product_tree_view_account_intrastat_supplementary_unit').id,
'list',
), (False, 'form')],
'domain': [('id', 'in', params['ids'])],
'context': {
'create': False,
'delete': False,
'expand': True,
},
}
def action_undefined_weight_products(self, options, params):
return {
'type': 'ir.actions.act_window',
'name': _('Undefined weight products.'),
'res_model': 'product.product',
'views': [(
self.env.ref('account_intrastat.product_product_tree_view_account_intrastat_weight').id,
'list',
), (False, 'form')],
'domain': [('id', 'in', params['ids'])],
'context': {
'create': False,
'delete': False,
'expand': True,
},
}