l10n_eu_oss/wizard/l10n_eu_oss_wizard.py
# -*- encoding: utf-8 -*-
# Copyright 2021 Valentin Vinagre <valentin.vinagre@sygel.es>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import _, fields, models, api
from openerp.exceptions import Warning
class L10nEuOssWizard(models.TransientModel):
_name = "l10n.eu.oss.wizard"
_description = "l10n.eu.oss.wizard"
def _get_default_company_id(self):
return self.env.user.company_id.id
def _get_eu_res_country_group(self):
eu_group = self.env.ref("base.europe", raise_if_not_found=False)
if not eu_group:
raise Warning(
_(
"The Europe country group cannot be found. "
"Please update the base module."
)
)
return eu_group
def _default_fiscal_position_id(self):
user = self.env.user
eu_country_group = self._get_eu_res_country_group()
return self.env["account.fiscal.position"].search(
[
("company_id", "=", user.company_id.id),
("vat_required", "=", True),
("country_group_id", "=", eu_country_group.id),
],
limit=1,
)
def _default_done_country_ids(self):
user = self.env.user
eu_country_group = self._get_eu_res_country_group()
return (
eu_country_group.country_ids
- self._default_todo_country_ids()
- user.company_id.country_id
)
def _default_todo_country_ids(self):
user = self.env.user
eu_country_group = self._get_eu_res_country_group()
eu_fiscal = self.env["account.fiscal.position"].search(
[
("country_id", "in", eu_country_group.country_ids.ids),
("vat_required", "=", False),
("auto_apply", "=", True),
("company_id", "=", user.company_id.id),
("fiscal_position_type", "=", "b2c"),
]
)
return (
eu_country_group.country_ids
- eu_fiscal.mapped("country_id")
- user.company_id.country_id
)
company_id = fields.Many2one(
"res.company", string="Company", required=True, default=_get_default_company_id
)
done_country_ids = fields.Many2many(
"res.country",
"l10n_eu_oss_country_rel_done",
default=_default_done_country_ids,
string="Already Supported",
)
todo_country_ids = fields.Many2many(
"res.country",
"l10n_eu_oss_country_rel_todo",
default=_default_todo_country_ids,
string="EU Customers From",
required=True,
)
price_include_tax = fields.Boolean(string="Price Include Tax", default=False)
general_tax = fields.Many2one(
comodel_name="account.tax", string="General Tax", required=True
)
reduced_tax = fields.Many2one(comodel_name="account.tax", string="Reduced Tax",)
superreduced_tax = fields.Many2one(
comodel_name="account.tax", string="Super Reduced Tax",
)
second_superreduced_tax = fields.Many2one(
comodel_name="account.tax", string="Second Super Reduced Tax"
)
def _upgrade_tax_code(self, country_id, rate, code_type, company):
account_tax_code = self.env["account.tax.code"]
rate_str = str(rate).replace(".", '')
code_name = 'OSSEU{}{}{}'.format(country_id.code, code_type, rate_str)
account_tax_code = account_tax_code.search([
('code', '=', code_name),
('oss_country_id', '=', country_id.id),
('company_id', '=', company.id),
], limit=1)
if not account_tax_code:
account_tax_code = account_tax_code.create({
"code": code_name,
"name": _(
"OSS for EU to %(country_name)s: %(type)s %(rate)s"
) % {
"country_name": country_id.name,
"type": code_type,
"rate": rate_str,
},
"sign": 1,
"oss_country_id": country_id.id,
"company_id": company.id,
})
return account_tax_code
def _prepare_tax_vals(self, country_id, tax_id, rate):
self.ensure_one()
company = self.company_id
code_bi = self._upgrade_tax_code(country_id, rate, 'TB', company)
code_c = self._upgrade_tax_code(country_id, rate, 'C', company)
return {
"name": _("OSS for EU to %(country_name)s: %(rate)s") % {
"country_name": country_id.name, "rate": rate
},
"amount": rate,
"type": tax_id.type,
"account_collected_id": tax_id.account_collected_id.id,
"account_paid_id": tax_id.account_paid_id.id,
"type_tax_use": "sale",
"description": "EU-OSS-VAT-{}-{}".format(country_id.code, rate),
"oss_country_id": country_id.id,
"company_id": self.company_id.id,
"price_include": self.price_include_tax,
"base_code_id": code_bi.id,
"base_sign": 1,
"tax_code_id": code_c.id,
"tax_sign": 1,
"ref_base_code_id": code_bi.id,
"ref_base_sign": -1,
"ref_tax_code_id": code_c.id,
"ref_tax_sign": -1,
"sequence": 1000,
}
def generate_dict_taxes(self, selected_taxes, oss_rate_id):
dict_taxes = {}
# delete emptys values
oss_rate_id = [i for i in oss_rate_id if i != 0.0]
for idx, value in enumerate(selected_taxes):
dict_taxes[value] = oss_rate_id[
idx if idx < len(oss_rate_id) else len(oss_rate_id) - 1
]
return dict_taxes
def _prepare_fiscal_position_vals(self, country, taxes_data):
fiscal_pos_name = _("Intra-EU B2C in %(country_name)s") % {
"country_name": country.name
}
fiscal_pos_name += " (EU-OSS-%s)" % country.code
return {
"name": fiscal_pos_name,
"company_id": self.company_id.id,
"vat_required": False,
"auto_apply": True,
"country_id": country.id,
"fiscal_position_type": "b2c",
"tax_ids": [(0, 0, tax_data) for tax_data in taxes_data],
}
def update_fpos(self, fpos_id, taxes_data):
fpos_id.mapped("tax_ids").filtered(
lambda x: x.tax_dest_id.oss_country_id
).unlink()
fpos_id.write({"tax_ids": [(0, 0, tax_data) for tax_data in taxes_data]})
@api.multi
def generate_eu_oss_taxes(self):
oss_rate = self.env["oss.tax.rate"]
account_tax = self.env["account.tax"]
selected_taxes = []
fpos_obj = self.env["account.fiscal.position"]
# Get the taxes configured in the wizard
if self.general_tax:
selected_taxes.append(self.general_tax)
if self.reduced_tax:
selected_taxes.append(self.reduced_tax)
if self.superreduced_tax:
selected_taxes.append(self.superreduced_tax)
if self.second_superreduced_tax:
selected_taxes.append(self.second_superreduced_tax)
for country in self.todo_country_ids:
oss_rate_id = oss_rate.search([("oss_country_id", "=", country.id)])
taxes_data = []
# Create taxes dict to create
dict_taxes = self.generate_dict_taxes(
selected_taxes, oss_rate_id.get_rates_list()
)
# Create and search taxes
last_rate = None
tax_dest_id = None
for tax, rate in dict_taxes.items():
if last_rate != rate:
tax_dest_id = self.env["account.tax"].search(
[
("amount", "=", rate),
("type_tax_use", "=", "sale"),
("oss_country_id", "=", country.id),
("company_id", "=", self.company_id.id),
],
limit=1,
)
if not tax_dest_id:
tax_dest_id = account_tax.create(
self._prepare_tax_vals(country, tax, rate)
)
taxes_data.append({"tax_src_id": tax.id, "tax_dest_id": tax_dest_id.id})
last_rate = rate
# Create a fiscal position for the country
fpos = self.env["account.fiscal.position"].search(
[
("country_id", "=", country.id),
("vat_required", "=", False),
("auto_apply", "=", True),
("company_id", "=", self.company_id.id),
("fiscal_position_type", "=", "b2c"),
]
)
if not fpos:
data_fiscal = self._prepare_fiscal_position_vals(country, taxes_data)
fpos_obj.create(data_fiscal)
else:
self.update_fpos(fpos, taxes_data)
return {"type": "ir.actions.act_window_close"}