mirror of
https://github.com/bringout/oca-ocb-l10n_americas.git
synced 2026-04-26 06:52:01 +02:00
Initial commit: L10N_Americas packages
This commit is contained in:
commit
12b27ce151
714 changed files with 79328 additions and 0 deletions
12
odoo-bringout-oca-ocb-l10n_ec/l10n_ec/models/__init__.py
Normal file
12
odoo-bringout-oca-ocb-l10n_ec/l10n_ec/models/__init__.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import res_partner
|
||||
from . import l10n_ec_sri_payment
|
||||
from . import l10n_latam_document_type
|
||||
from . import account_move
|
||||
from . import account_tax
|
||||
from . import account_tax_group
|
||||
from . import res_company
|
||||
from . import account_journal
|
||||
from . import account_chart_template
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import models
|
||||
|
||||
|
||||
class AccountChartTemplate(models.Model):
|
||||
_inherit = "account.chart.template"
|
||||
|
||||
def _get_account_from_template(self, companies, template):
|
||||
if template:
|
||||
return self.env['account.account'].search([('company_id', 'in', companies.ids), ('code', '=', template.code)])
|
||||
return self.env['account.account']
|
||||
|
||||
def _load(self, company):
|
||||
# EXTENDS account to setup taxes groups accounts configuration
|
||||
res = super()._load(company)
|
||||
self._l10n_ec_configure_ecuadorian_tax_groups_accounts(company)
|
||||
return res
|
||||
|
||||
def _l10n_ec_configure_ecuadorian_tax_groups_accounts(self, companies):
|
||||
'''
|
||||
Set tax groups accounts for automatic closing entry in 103 and 104 reports
|
||||
The structure of the variable with the list of accounts by tax group:
|
||||
('<tax_group_record_id>', '<payable_account_code>', '<receivable_account_code>')
|
||||
'''
|
||||
_TAX_GROUPS_ACCOUNTS_LIST = [
|
||||
('tax_group_vat_05', '21070102', '11050202'),
|
||||
('tax_group_vat_08', '21070102', '11050202'),
|
||||
('tax_group_vat_12', '21070102', '11050202'),
|
||||
('tax_group_vat_13', '21070102', '11050202'),
|
||||
('tax_group_vat14', '21070102', '11050202'),
|
||||
('tax_group_vat_15', '21070102', '11050202'),
|
||||
('tax_group_vat0', '21070102', '11050202'),
|
||||
('tax_group_vat_not_charged', '21070102', '11050202'),
|
||||
('tax_group_vat_exempt', '21070102', '11050202'),
|
||||
('tax_group_ice', '21070104', '21070104'),
|
||||
('tax_group_irbpnr', '21070105', '21070105'),
|
||||
('tax_group_withhold_vat_sale', '21070102', '11050203'),
|
||||
('tax_group_withhold_vat_purchase', '21070102', '11050203'),
|
||||
('tax_group_withhold_income_sale', '21070103', '11050201'),
|
||||
('tax_group_withhold_income_purchase', '21070103', '11050201'),
|
||||
('tax_group_outflows', '21070106', '11050205'),
|
||||
('tax_group_others', '21070106', '11050205'),
|
||||
]
|
||||
for tax_group_xml_id, payable_account_code, receivable_account_code in _TAX_GROUPS_ACCOUNTS_LIST:
|
||||
for company in companies.filtered(lambda company: company.account_fiscal_country_id.code == 'EC' and
|
||||
company.chart_template_id == self.env.ref('l10n_ec.l10n_ec_ifrs')):
|
||||
# search accounts
|
||||
AccountObject = self.env['account.account']
|
||||
company_domain = [('company_id', '=', company.id)]
|
||||
payable_account_id = AccountObject.search([('code', '=', payable_account_code)] + company_domain)
|
||||
receivable_account_id = AccountObject.search([('code', '=', receivable_account_code)] + company_domain)
|
||||
# set accounts in tax groups by company
|
||||
self.env.ref(f'l10n_ec.{tax_group_xml_id}').with_company(company).property_tax_payable_account_id = payable_account_id
|
||||
self.env.ref(f'l10n_ec.{tax_group_xml_id}').with_company(company).property_tax_receivable_account_id = receivable_account_id
|
||||
|
||||
def _prepare_all_journals(self, acc_template_ref, company, journals_dict=None):
|
||||
res = super()._prepare_all_journals(acc_template_ref, company, journals_dict=journals_dict)
|
||||
if company.account_fiscal_country_id.code == 'EC':
|
||||
for journal_values in res:
|
||||
if journal_values.get('type') == 'sale':
|
||||
journal_values.update({
|
||||
'name': f"001-001 {journal_values['name']}",
|
||||
'l10n_ec_entity': '001',
|
||||
'l10n_ec_emission': '001',
|
||||
'l10n_ec_emission_address_id': company.partner_id.id,
|
||||
})
|
||||
sale_account = acc_template_ref.get(self.env.ref('l10n_ec.ec410101', raise_if_not_found=False))
|
||||
if sale_account:
|
||||
journal_values['default_account_id'] = sale_account.id
|
||||
if journal_values.get('type') == 'purchase':
|
||||
purchase_account = acc_template_ref.get(self.env.ref('l10n_ec.ec52022816', raise_if_not_found=False))
|
||||
if purchase_account:
|
||||
journal_values['default_account_id'] = purchase_account.id
|
||||
return res
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class AccountJournal(models.Model):
|
||||
_inherit = "account.journal"
|
||||
|
||||
l10n_ec_require_emission = fields.Boolean(
|
||||
string='Require Emission',
|
||||
compute='_compute_l10n_ec_require_emission',
|
||||
help='True if an entity and emission point must be set on the journal'
|
||||
)
|
||||
l10n_ec_entity = fields.Char(string="Emission Entity", size=3, copy=False)
|
||||
l10n_ec_emission = fields.Char(string="Emission Point", size=3, copy=False)
|
||||
l10n_ec_emission_address_id = fields.Many2one(
|
||||
comodel_name="res.partner",
|
||||
string="Emission address",
|
||||
domain="['|', ('id', '=', company_partner_id), '&', ('id', 'child_of', company_partner_id), ('type', '!=', 'contact')]",
|
||||
)
|
||||
|
||||
@api.depends('type', 'country_code', 'l10n_latam_use_documents')
|
||||
def _compute_l10n_ec_require_emission(self):
|
||||
for journal in self:
|
||||
journal.l10n_ec_require_emission = journal.type == 'sale' and journal.country_code == 'EC' and journal.l10n_latam_use_documents
|
||||
|
||||
# NOTE: Removed in master as it has no use
|
||||
l10n_ec_emission_type = fields.Selection(
|
||||
string="Emission type",
|
||||
selection=[
|
||||
("pre_printed", "Pre Printed"),
|
||||
("auto_printer", "Auto Printer"),
|
||||
("electronic", "Electronic"),
|
||||
],
|
||||
default="electronic",
|
||||
)
|
||||
210
odoo-bringout-oca-ocb-l10n_ec/l10n_ec/models/account_move.py
Normal file
210
odoo-bringout-oca-ocb-l10n_ec/l10n_ec/models/account_move.py
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.addons.l10n_ec.models.res_partner import PartnerIdTypeEc
|
||||
from odoo import fields, models, api
|
||||
|
||||
_DOCUMENTS_MAPPING = {
|
||||
"01": [
|
||||
'ec_dt_01',
|
||||
'ec_dt_02',
|
||||
'ec_dt_04',
|
||||
'ec_dt_05',
|
||||
'ec_dt_08',
|
||||
'ec_dt_09',
|
||||
'ec_dt_11',
|
||||
'ec_dt_12',
|
||||
'ec_dt_16',
|
||||
'ec_dt_20',
|
||||
'ec_dt_21',
|
||||
'ec_dt_41',
|
||||
'ec_dt_42',
|
||||
'ec_dt_43',
|
||||
'ec_dt_45',
|
||||
'ec_dt_47',
|
||||
'ec_dt_48'
|
||||
],
|
||||
"02": [
|
||||
'ec_dt_03',
|
||||
'ec_dt_04',
|
||||
'ec_dt_05',
|
||||
'ec_dt_09',
|
||||
'ec_dt_19',
|
||||
'ec_dt_41',
|
||||
'ec_dt_294',
|
||||
'ec_dt_344'
|
||||
],
|
||||
"03": [
|
||||
'ec_dt_03',
|
||||
'ec_dt_04',
|
||||
'ec_dt_05',
|
||||
'ec_dt_09',
|
||||
'ec_dt_15',
|
||||
'ec_dt_19',
|
||||
'ec_dt_41',
|
||||
'ec_dt_45',
|
||||
'ec_dt_294',
|
||||
'ec_dt_344'
|
||||
],
|
||||
"04": [
|
||||
'ec_dt_01',
|
||||
'ec_dt_04',
|
||||
'ec_dt_05',
|
||||
'ec_dt_41',
|
||||
'ec_dt_44',
|
||||
'ec_dt_47',
|
||||
'ec_dt_48',
|
||||
'ec_dt_49',
|
||||
'ec_dt_50',
|
||||
'ec_dt_51',
|
||||
'ec_dt_52',
|
||||
'ec_dt_370',
|
||||
'ec_dt_371',
|
||||
'ec_dt_372',
|
||||
'ec_dt_373'
|
||||
],
|
||||
"05": [
|
||||
'ec_dt_01',
|
||||
'ec_dt_04',
|
||||
'ec_dt_05',
|
||||
'ec_dt_41',
|
||||
'ec_dt_44',
|
||||
'ec_dt_47',
|
||||
'ec_dt_48',
|
||||
'ec_dt_370',
|
||||
'ec_dt_371',
|
||||
'ec_dt_372',
|
||||
'ec_dt_373'
|
||||
],
|
||||
"06": [
|
||||
'ec_dt_01',
|
||||
'ec_dt_04',
|
||||
'ec_dt_05',
|
||||
'ec_dt_41',
|
||||
'ec_dt_44',
|
||||
'ec_dt_47',
|
||||
'ec_dt_48',
|
||||
'ec_dt_370',
|
||||
'ec_dt_371',
|
||||
'ec_dt_372',
|
||||
'ec_dt_373'
|
||||
],
|
||||
"07": [
|
||||
'ec_dt_01',
|
||||
'ec_dt_04',
|
||||
'ec_dt_05',
|
||||
],
|
||||
"09": [
|
||||
'ec_dt_01',
|
||||
'ec_dt_04',
|
||||
'ec_dt_05',
|
||||
'ec_dt_15',
|
||||
'ec_dt_16',
|
||||
'ec_dt_41',
|
||||
'ec_dt_47',
|
||||
'ec_dt_48',
|
||||
],
|
||||
"20": [
|
||||
'ec_dt_01',
|
||||
'ec_dt_04',
|
||||
'ec_dt_05',
|
||||
'ec_dt_15',
|
||||
'ec_dt_16',
|
||||
'ec_dt_41',
|
||||
'ec_dt_47',
|
||||
'ec_dt_48'
|
||||
],
|
||||
"21": [
|
||||
'ec_dt_01',
|
||||
'ec_dt_04',
|
||||
'ec_dt_05',
|
||||
'ec_dt_15',
|
||||
'ec_dt_16',
|
||||
'ec_dt_41',
|
||||
'ec_dt_47',
|
||||
'ec_dt_48'
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
class AccountMove(models.Model):
|
||||
_inherit = "account.move"
|
||||
|
||||
l10n_ec_sri_payment_id = fields.Many2one(
|
||||
comodel_name="l10n_ec.sri.payment",
|
||||
string="Payment Method (SRI)",
|
||||
)
|
||||
|
||||
# NOTE: For backward compatibility, removed in master
|
||||
def _get_l10n_ec_identification_type(self):
|
||||
return PartnerIdTypeEc.get_ats_code_for_partner(self.partner_id, self.move_type)
|
||||
|
||||
@api.model
|
||||
def _get_l10n_ec_documents_allowed(self, identification_code):
|
||||
documents_allowed = self.env['l10n_latam.document.type']
|
||||
for document_ref in _DOCUMENTS_MAPPING.get(identification_code.value, []):
|
||||
document_allowed = self.env.ref('l10n_ec.%s' % document_ref, False)
|
||||
if document_allowed:
|
||||
documents_allowed |= document_allowed
|
||||
return documents_allowed
|
||||
|
||||
def _get_l10n_latam_documents_domain(self):
|
||||
self.ensure_one()
|
||||
domain = super()._get_l10n_latam_documents_domain()
|
||||
if self.country_code == 'EC' and self.journal_id.l10n_latam_use_documents:
|
||||
if self.debit_origin_id: # show/hide the debit note document type
|
||||
domain.extend([('internal_type', '=', 'debit_note')])
|
||||
elif self.move_type in ('out_invoice', 'in_invoice'):
|
||||
domain.extend([('internal_type', '=', 'invoice')])
|
||||
allowed_documents = self._get_l10n_ec_documents_allowed(PartnerIdTypeEc.get_ats_code_for_partner(self.partner_id, self.move_type))
|
||||
domain.extend([('id', 'in', allowed_documents.ids)])
|
||||
return domain
|
||||
|
||||
def _get_ec_formatted_sequence(self, number=0):
|
||||
return "%s %s-%s-%09d" % (
|
||||
self.l10n_latam_document_type_id.doc_code_prefix,
|
||||
self.journal_id.l10n_ec_entity,
|
||||
self.journal_id.l10n_ec_emission,
|
||||
number,
|
||||
)
|
||||
|
||||
def _get_starting_sequence(self):
|
||||
"""If use documents then will create a new starting sequence using the document type code prefix and the
|
||||
journal document number with a 8 padding number"""
|
||||
if (
|
||||
self.journal_id.l10n_latam_use_documents
|
||||
and self.company_id.country_id.code == "EC"
|
||||
):
|
||||
if self.l10n_latam_document_type_id:
|
||||
return self._get_ec_formatted_sequence()
|
||||
return super()._get_starting_sequence()
|
||||
|
||||
def _get_last_sequence_domain(self, relaxed=False):
|
||||
where_string, param = super(AccountMove, self)._get_last_sequence_domain(relaxed)
|
||||
if self.country_code == "EC" and self.l10n_latam_use_documents:
|
||||
internal_type = self.l10n_latam_document_type_id.internal_type
|
||||
document_types = self.env['l10n_latam.document.type'].search([
|
||||
('internal_type', '=', internal_type),
|
||||
('country_id.code', '=', 'EC'),
|
||||
])
|
||||
if document_types:
|
||||
where_string += """
|
||||
AND l10n_latam_document_type_id in %(l10n_latam_document_type_id)s
|
||||
"""
|
||||
param["l10n_latam_document_type_id"] = tuple(document_types.ids)
|
||||
return where_string, param
|
||||
|
||||
def _skip_format_document_number(self):
|
||||
"""
|
||||
If a Credit Note is created from a Vendor Bill and the partner_id != "EC",
|
||||
we want to allow the user to allocate any number without following the EC format.
|
||||
"""
|
||||
self.ensure_one()
|
||||
if self.country_code == 'EC':
|
||||
return (
|
||||
self.l10n_latam_document_type_id.internal_type in ('credit_note', 'debit_note')
|
||||
and self.partner_id.country_code != "EC"
|
||||
and self.move_type == 'in_refund'
|
||||
and self.journal_id.type == 'purchase'
|
||||
)
|
||||
super()._skip_format_document_number()
|
||||
53
odoo-bringout-oca-ocb-l10n_ec/l10n_ec/models/account_tax.py
Normal file
53
odoo-bringout-oca-ocb-l10n_ec/l10n_ec/models/account_tax.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class AccountTax(models.Model):
|
||||
|
||||
_inherit = "account.tax"
|
||||
|
||||
l10n_ec_code_base = fields.Char(
|
||||
string="Code base",
|
||||
help="Tax declaration code of the base amount prior to the calculation of the tax",
|
||||
)
|
||||
l10n_ec_code_applied = fields.Char(
|
||||
string="Code applied",
|
||||
help="Tax declaration code of the resulting amount after the calculation of the tax",
|
||||
)
|
||||
l10n_ec_code_ats = fields.Char(
|
||||
string="Code ATS",
|
||||
help="Tax Identification Code for the Simplified Transactional Annex",
|
||||
)
|
||||
|
||||
|
||||
class AccountTaxTemplate(models.Model):
|
||||
|
||||
_inherit = "account.tax.template"
|
||||
|
||||
def _get_tax_vals(self, company, tax_template_to_tax):
|
||||
vals = super(AccountTaxTemplate, self)._get_tax_vals(
|
||||
company, tax_template_to_tax
|
||||
)
|
||||
vals.update(
|
||||
{
|
||||
"l10n_ec_code_base": self.l10n_ec_code_base,
|
||||
"l10n_ec_code_applied": self.l10n_ec_code_applied,
|
||||
"l10n_ec_code_ats": self.l10n_ec_code_ats,
|
||||
}
|
||||
)
|
||||
return vals
|
||||
|
||||
l10n_ec_code_base = fields.Char(
|
||||
string="Code base",
|
||||
help="Tax declaration code of the base amount prior to the calculation of the tax",
|
||||
)
|
||||
l10n_ec_code_applied = fields.Char(
|
||||
string="Code applied",
|
||||
help="Tax declaration code of the resulting amount after the calculation of the tax",
|
||||
)
|
||||
l10n_ec_code_ats = fields.Char(
|
||||
string="Code ATS",
|
||||
help="Tax Identification Code for the Simplified Transactional Annex",
|
||||
)
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
_TYPE_EC = [
|
||||
("vat05", "VAT 5%"),
|
||||
("vat08", "VAT 8%"),
|
||||
("vat12", "VAT 12%"),
|
||||
("vat13", "VAT 13%"),
|
||||
("vat14", "VAT 14%"),
|
||||
("vat15", "VAT 15%"),
|
||||
("zero_vat", "VAT 0%"),
|
||||
("not_charged_vat", "VAT Not Charged"),
|
||||
("exempt_vat", "VAT Exempt"),
|
||||
("ice", "Special Consumptions Tax (ICE)"),
|
||||
("irbpnr", "Plastic Bottles (IRBPNR)"),
|
||||
("withhold_vat_sale", "VAT Withhold on Sales"),
|
||||
("withhold_vat_purchase", "VAT Withhold on Purchases"),
|
||||
("withhold_income_sale", "Profit Withhold on Sales"),
|
||||
("withhold_income_purchase", "Profit Withhold on Purchases"),
|
||||
("outflows_tax", "Exchange Outflows"),
|
||||
("other", "Others"),
|
||||
("withhold_vat", "VAT Withhold (Deprecated)"), # removed in master
|
||||
("withhold_income_tax", "Profit Withhold (Deprecated)"), # removed in master
|
||||
]
|
||||
|
||||
|
||||
class AccountTaxGroup(models.Model):
|
||||
_inherit = "account.tax.group"
|
||||
|
||||
l10n_ec_type = fields.Selection(
|
||||
_TYPE_EC, string="Type Ecuadorian Tax", help="Ecuadorian taxes subtype"
|
||||
)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class SriPayment(models.Model):
|
||||
|
||||
_name = "l10n_ec.sri.payment"
|
||||
_description = "SRI Payment Method"
|
||||
|
||||
name = fields.Char("Name")
|
||||
code = fields.Char("Code")
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
import re
|
||||
|
||||
|
||||
class L10nLatamDocumentType(models.Model):
|
||||
_inherit = "l10n_latam.document.type"
|
||||
|
||||
internal_type = fields.Selection(
|
||||
selection_add=[
|
||||
("purchase_liquidation", "Purchase Liquidation"),
|
||||
("withhold", "Withhold"),
|
||||
]
|
||||
)
|
||||
|
||||
l10n_ec_check_format = fields.Boolean(
|
||||
string="Check Number Format EC", default=False
|
||||
)
|
||||
|
||||
def _format_document_number(self, document_number):
|
||||
self.ensure_one()
|
||||
if self.country_id != self.env.ref("base.ec"):
|
||||
return super()._format_document_number(document_number)
|
||||
if not document_number:
|
||||
return False
|
||||
if self.l10n_ec_check_format:
|
||||
document_number = re.sub(r'\s+', "", document_number) # remove any whitespace
|
||||
num_match = re.match(r'(\d{1,3})-(\d{1,3})-(\d{1,9})', document_number)
|
||||
if num_match:
|
||||
# Fill each number group with zeroes (3, 3 and 9 respectively)
|
||||
document_number = "-".join([n.zfill(3 if i < 2 else 9) for i, n in enumerate(num_match.groups())])
|
||||
else:
|
||||
raise UserError(
|
||||
_(u"Ecuadorian Document %s must be like 001-001-123456789")
|
||||
% (self.display_name)
|
||||
)
|
||||
|
||||
return document_number
|
||||
10
odoo-bringout-oca-ocb-l10n_ec/l10n_ec/models/res_company.py
Normal file
10
odoo-bringout-oca-ocb-l10n_ec/l10n_ec/models/res_company.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
from odoo import models
|
||||
|
||||
|
||||
class ResCompany(models.Model):
|
||||
|
||||
_inherit = "res.company"
|
||||
|
||||
def _localization_use_documents(self):
|
||||
self.ensure_one()
|
||||
return self.account_fiscal_country_id.code == "EC" or super(ResCompany, self)._localization_use_documents()
|
||||
124
odoo-bringout-oca-ocb-l10n_ec/l10n_ec/models/res_partner.py
Normal file
124
odoo-bringout-oca-ocb-l10n_ec/l10n_ec/models/res_partner.py
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import enum
|
||||
import stdnum
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
def verify_final_consumer(vat):
|
||||
return vat == '9' * 13 # final consumer is identified with 9999999999999
|
||||
|
||||
|
||||
class PartnerIdTypeEc(enum.Enum):
|
||||
"""
|
||||
Ecuadorian partner identification type/code for ATS and SRI.
|
||||
"""
|
||||
|
||||
IN_RUC = '01'
|
||||
IN_CEDULA = '02'
|
||||
IN_PASSPORT = '03'
|
||||
OUT_RUC = '04'
|
||||
OUT_CEDULA = '05'
|
||||
OUT_PASSPORT = '06'
|
||||
FINAL_CONSUMER = '07'
|
||||
FOREIGN = '08'
|
||||
|
||||
@classmethod
|
||||
def get_ats_code_for_partner(cls, partner, move_type):
|
||||
"""
|
||||
Returns ID code for move and partner based on subset of Table 2 of SRI's ATS specification
|
||||
"""
|
||||
partner_id_type = partner._l10n_ec_get_identification_type()
|
||||
if move_type.startswith('in_'):
|
||||
if partner_id_type == 'ruc': # includes final consumer
|
||||
return cls.IN_RUC
|
||||
elif partner_id_type == 'cedula':
|
||||
return cls.IN_CEDULA
|
||||
elif partner_id_type in ['foreign', 'passport']:
|
||||
return cls.IN_PASSPORT
|
||||
elif move_type.startswith('out_'):
|
||||
if partner_id_type == 'ruc': # includes final consumer
|
||||
return cls.OUT_RUC
|
||||
elif partner_id_type == 'cedula':
|
||||
return cls.OUT_CEDULA
|
||||
elif partner_id_type in ['foreign', 'passport']:
|
||||
return cls.OUT_PASSPORT
|
||||
|
||||
|
||||
class ResPartner(models.Model):
|
||||
|
||||
_inherit = "res.partner"
|
||||
|
||||
l10n_ec_vat_validation = fields.Char(
|
||||
string="VAT Error message validation",
|
||||
compute="_compute_l10n_ec_vat_validation",
|
||||
help="Error message when validating the Ecuadorian VAT",
|
||||
)
|
||||
|
||||
@api.constrains("vat", "country_id", "l10n_latam_identification_type_id")
|
||||
def check_vat(self):
|
||||
it_ruc = self.env.ref("l10n_ec.ec_ruc", False)
|
||||
it_dni = self.env.ref("l10n_ec.ec_dni", False)
|
||||
ecuadorian_partners = self.filtered(
|
||||
lambda x: x.country_id == self.env.ref("base.ec")
|
||||
)
|
||||
for partner in ecuadorian_partners:
|
||||
if partner.vat:
|
||||
if partner.l10n_latam_identification_type_id.id in (
|
||||
it_ruc.id,
|
||||
it_dni.id,
|
||||
):
|
||||
if partner.l10n_latam_identification_type_id.id == it_dni.id and len(partner.vat) != 10:
|
||||
raise ValidationError(_('If your identification type is %s, it must be 10 digits')
|
||||
% it_dni.display_name)
|
||||
if partner.l10n_latam_identification_type_id.id == it_ruc.id and len(partner.vat) != 13:
|
||||
raise ValidationError(_('If your identification type is %s, it must be 13 digits')
|
||||
% it_ruc.display_name)
|
||||
return super(ResPartner, self - ecuadorian_partners).check_vat()
|
||||
|
||||
@api.depends("vat", "country_id", "l10n_latam_identification_type_id")
|
||||
def _compute_l10n_ec_vat_validation(self):
|
||||
it_ruc = self.env.ref("l10n_ec.ec_ruc", False)
|
||||
it_dni = self.env.ref("l10n_ec.ec_dni", False)
|
||||
ruc = stdnum.util.get_cc_module("ec", "ruc")
|
||||
ci = stdnum.util.get_cc_module("ec", "ci")
|
||||
for partner in self:
|
||||
partner.l10n_ec_vat_validation = False
|
||||
if partner and partner.l10n_latam_identification_type_id in (it_ruc, it_dni) and partner.vat:
|
||||
final_consumer = verify_final_consumer(partner.vat)
|
||||
if not final_consumer:
|
||||
if partner.l10n_latam_identification_type_id.id == it_dni.id and not ci.is_valid(partner.vat):
|
||||
partner.l10n_ec_vat_validation = _("The VAT %s seems to be invalid as the tenth digit doesn't comply with the validation algorithm "
|
||||
"(could be an old VAT number)") % partner.vat
|
||||
if partner.l10n_latam_identification_type_id.id == it_ruc.id and not ruc.is_valid(partner.vat):
|
||||
partner.l10n_ec_vat_validation = _("The VAT %s seems to be invalid as the tenth digit doesn't comply with the validation algorithm "
|
||||
"(SRI has stated that this validation is not required anymore for some VAT numbers)") % partner.vat
|
||||
|
||||
def _l10n_ec_get_identification_type(self):
|
||||
"""Maps Odoo identification types to Ecuadorian ones.
|
||||
Useful for document type domains, electronic documents, ats, others.
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
id_types_by_xmlid = {
|
||||
'l10n_ec.ec_dni': 'cedula', # DNI
|
||||
'l10n_ec.ec_ruc': 'ruc', # RUC
|
||||
'l10n_ec.ec_passport': 'ec_passport', # EC passport
|
||||
'l10n_latam_base.it_pass': 'passport', # Passport
|
||||
'l10n_latam_base.it_fid': 'foreign', # Foreign ID
|
||||
'l10n_latam_base.it_vat': 'foreign',
|
||||
}
|
||||
|
||||
# This method is orm-cached, which makes it more efficient in loops than get_external_id()
|
||||
xmlid_by_res_id = {
|
||||
self.env['ir.model.data']._xmlid_to_res_model_res_id(xmlid, raise_if_not_found=True)[1]: xmlid
|
||||
for xmlid in id_types_by_xmlid
|
||||
}
|
||||
|
||||
id_type_xmlid = xmlid_by_res_id.get(self.l10n_latam_identification_type_id.id)
|
||||
if id_type_xmlid in id_types_by_xmlid:
|
||||
return id_types_by_xmlid[id_type_xmlid]
|
||||
|
||||
if self.l10n_latam_identification_type_id.country_id.code != 'EC':
|
||||
return 'foreign'
|
||||
Loading…
Add table
Add a link
Reference in a new issue