Initial commit: L10N_Americas packages

This commit is contained in:
Ernad Husremovic 2025-08-29 15:20:52 +02:00
commit 12b27ce151
714 changed files with 79328 additions and 0 deletions

View file

@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import account_chart_template
from . import account_move
from . import account_move_line
from . import account_tax
from . import l10n_latam_document_type
from . import res_company
from . import res_country
from . import res_currency
from . import res_partner
from . import res_partner_bank
from . import uom_uom

View file

@ -0,0 +1,15 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models
from odoo.http import request
class AccountChartTemplate(models.Model):
_inherit = 'account.chart.template'
def _load(self, company):
""" Set tax calculation rounding method required in Chilean localization"""
res = super()._load(company)
if company.account_fiscal_country_id.code == 'CL':
company.write({'tax_calculation_rounding_method': 'round_globally'})
return res

View file

@ -0,0 +1,280 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.exceptions import ValidationError
from odoo import models, fields, api, _
from odoo.tools.misc import formatLang
from odoo.tools.float_utils import float_repr, float_round
SII_VAT = '60805000-0'
class AccountMove(models.Model):
_inherit = "account.move"
partner_id_vat = fields.Char(related='partner_id.vat', string='VAT No')
l10n_latam_internal_type = fields.Selection(
related='l10n_latam_document_type_id.internal_type', string='L10n Latam Internal Type')
def _get_l10n_latam_documents_domain(self):
self.ensure_one()
if self.journal_id.company_id.account_fiscal_country_id != self.env.ref('base.cl') or not \
self.journal_id.l10n_latam_use_documents:
return super()._get_l10n_latam_documents_domain()
if self.journal_id.type == 'sale':
domain = [('country_id.code', '=', 'CL')]
if self.move_type in ['in_invoice', 'out_invoice']:
domain += [('internal_type', 'in', ['invoice', 'debit_note', 'invoice_in'])]
elif self.move_type in ['in_refund', 'out_refund']:
domain += [('internal_type', '=', 'credit_note')]
if self.company_id.partner_id.l10n_cl_sii_taxpayer_type == '1':
domain += [('code', '!=', '71')] # Companies with VAT Affected doesn't have "Boleta de honorarios Electrónica"
return domain
if self.move_type == 'in_refund':
internal_types_domain = ('internal_type', '=', 'credit_note')
else:
internal_types_domain = ('internal_type', 'in', ['invoice', 'debit_note', 'invoice_in'])
domain = [
('country_id.code', '=', 'CL'),
internal_types_domain,
]
if self.partner_id.l10n_cl_sii_taxpayer_type == '1' and self.partner_id_vat != '60805000-0':
domain += [('code', 'not in', ['39', '70', '71', '914', '911'])]
elif self.partner_id.l10n_cl_sii_taxpayer_type == '1' and self.partner_id_vat == '60805000-0':
domain += [('code', 'not in', ['39', '70', '71'])]
elif self.partner_id.l10n_cl_sii_taxpayer_type == '2':
domain += [('code', '=', '71')]
elif self.partner_id.l10n_cl_sii_taxpayer_type == '3':
domain += [('code', 'in', ['35', '38', '39', '41', '56', '61'])]
elif self.partner_id.country_id.code != 'CL' or self.partner_id.l10n_cl_sii_taxpayer_type == '4':
domain += [('code', '=', '46')]
else:
domain += [('code', 'in', [])]
return domain
def _check_document_types_post(self):
for rec in self.filtered(
lambda r: r.company_id.account_fiscal_country_id.code == "CL" and
r.journal_id.type in ['sale', 'purchase']):
tax_payer_type = rec.partner_id.l10n_cl_sii_taxpayer_type
vat = rec.partner_id.vat
country_id = rec.partner_id.country_id
latam_document_type_code = rec.l10n_latam_document_type_id.code
if (rec.journal_id.type == 'purchase' and tax_payer_type == '4' and country_id.code != 'CL' and
latam_document_type_code == '61' and
'46' in rec.l10n_cl_reference_ids.mapped('l10n_cl_reference_doc_type_selection')):
continue
if (not tax_payer_type or not vat) and (country_id.code == "CL" and latam_document_type_code
and latam_document_type_code not in ['35', '38', '39', '41']):
raise ValidationError(_('Tax payer type and vat number are mandatory for this type of '
'document. Please set the current tax payer type of this customer'))
if rec.journal_id.type == 'sale' and rec.journal_id.l10n_latam_use_documents:
if country_id.code != "CL":
if not ((tax_payer_type == '4' and latam_document_type_code in ['110', '111', '112']) or (
tax_payer_type == '3' and latam_document_type_code in ['39', '41', '61', '56'])):
raise ValidationError(_(
'Document types for foreign customers must be export type (codes 110, 111 or 112) or you should define the customer as an end consumer and use receipts (codes 39 or 41)'))
if rec.journal_id.type == 'purchase' and rec.journal_id.l10n_latam_use_documents:
if vat != SII_VAT and latam_document_type_code == '914':
raise ValidationError(_('The DIN document is intended to be used only with RUT 60805000-0'
' (Tesorería General de La República)'))
if not tax_payer_type or not vat:
if country_id.code == "CL" and latam_document_type_code not in [
'35', '38', '39', '41']:
raise ValidationError(_('Tax payer type and vat number are mandatory for this type of '
'document. Please set the current tax payer type of this supplier'))
if tax_payer_type == '2' and latam_document_type_code not in ['70', '71', '56', '61']:
raise ValidationError(_('The tax payer type of this supplier is incorrect for the selected type'
' of document.'))
if tax_payer_type in ['1', '3']:
if latam_document_type_code in ['70', '71']:
raise ValidationError(_('The tax payer type of this supplier is not entitled to deliver '
'fees documents'))
if latam_document_type_code in ['110', '111', '112']:
raise ValidationError(_('The tax payer type of this supplier is not entitled to deliver '
'imports documents'))
if (tax_payer_type == '4' or country_id.code != "CL") and latam_document_type_code != '46':
raise ValidationError(_('You need a journal without the use of documents for foreign '
'suppliers'))
@api.onchange('journal_id')
def _l10n_cl_onchange_journal(self):
if self.company_id.country_id.code == 'CL':
self.l10n_latam_document_type_id = False
def _post(self, soft=True):
self._check_document_types_post()
return super()._post(soft)
def _l10n_cl_get_formatted_sequence(self, number=0):
return '%s %06d' % (self.l10n_latam_document_type_id.doc_code_prefix, 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 6 padding number """
if self.journal_id.l10n_latam_use_documents and self.company_id.account_fiscal_country_id.code == "CL":
if self.l10n_latam_document_type_id:
return self._l10n_cl_get_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.company_id.account_fiscal_country_id.code == "CL" and self.l10n_latam_use_documents:
where_string = where_string.replace('journal_id = %(journal_id)s AND', '')
where_string += ' AND l10n_latam_document_type_id = %(l10n_latam_document_type_id)s AND ' \
'company_id = %(company_id)s AND move_type IN %(move_type)s'
param['company_id'] = self.company_id.id or False
param['l10n_latam_document_type_id'] = self.l10n_latam_document_type_id.id or 0
param['move_type'] = (('in_invoice', 'in_refund') if
self.l10n_latam_document_type_id._is_doc_type_vendor() else ('out_invoice', 'out_refund'))
return where_string, param
def _get_name_invoice_report(self):
self.ensure_one()
if self.l10n_latam_use_documents and self.company_id.account_fiscal_country_id.code == 'CL':
return 'l10n_cl.report_invoice_document'
return super()._get_name_invoice_report()
def _format_lang_totals(self, value, currency):
return formatLang(self.env, value, currency_obj=currency)
def _l10n_cl_get_invoice_totals_for_report(self):
self.ensure_one()
include_sii = self._l10n_cl_include_sii()
base_lines = self.line_ids.filtered(lambda x: x.display_type == 'product')
tax_lines = self.line_ids.filtered(lambda x: x.display_type == 'tax')
base_line_vals_list = [x._convert_to_tax_base_line_dict() for x in base_lines]
if include_sii:
for vals in base_line_vals_list:
vals['taxes'] = vals['taxes'].flatten_taxes_hierarchy().filtered(lambda tax: tax.l10n_cl_sii_code != 14)
tax_line_vals_list = [x._convert_to_tax_line_dict() for x in tax_lines]
if include_sii:
tax_line_vals_list = [x for x in tax_line_vals_list if x['tax_repartition_line'].tax_id.l10n_cl_sii_code != 14]
tax_totals = self.env['account.tax']._prepare_tax_totals(
base_line_vals_list,
self.currency_id,
tax_lines=tax_line_vals_list,
)
if include_sii:
tax_totals['amount_total'] = self.amount_total
tax_totals['amount_untaxed'] = self.currency_id.round(
tax_totals['amount_total'] - sum([x['tax_amount'] for x in tax_line_vals_list if 'tax_amount' in x]))
tax_totals['formatted_amount_total'] = formatLang(self.env, tax_totals['amount_total'], currency_obj=self.currency_id)
tax_totals['formatted_amount_untaxed'] = formatLang(self.env, tax_totals['amount_untaxed'], currency_obj=self.currency_id)
if tax_totals['subtotals']:
tax_totals['subtotals'][0]['formatted_amount'] = tax_totals['formatted_amount_untaxed']
return tax_totals
def _l10n_cl_include_sii(self):
self.ensure_one()
return self.l10n_latam_document_type_id.code in ['39', '41', '110', '111', '112', '34']
def _is_manual_document_number(self):
if self.journal_id.company_id.country_id.code == 'CL':
return self.journal_id.type == 'purchase' and not self.l10n_latam_document_type_id._is_doc_type_vendor()
return super()._is_manual_document_number()
def _l10n_cl_get_amounts(self):
"""
This method is used to calculate the amount and taxes required in the Chilean localization electronic documents.
"""
self.ensure_one()
global_discounts = self.invoice_line_ids.filtered(lambda x: x.price_subtotal < 0)
export = self.l10n_latam_document_type_id._is_doc_type_export()
main_currency = self.company_id.currency_id if not export else self.currency_id
key_main_currency = 'amount_currency' if export else 'balance'
sign_main_currency = -1 if self.move_type == 'out_invoice' else 1
currency_round_main_currency = self.currency_id if export else self.company_id.currency_id
currency_round_other_currency = self.company_id.currency_id if export else self.currency_id
total_amount_main_currency = currency_round_main_currency.round(self.amount_total) if export \
else (currency_round_main_currency.round(abs(self.amount_total_signed)))
other_currency = self.currency_id != self.company_id.currency_id
values = {
'main_currency': main_currency,
'vat_amount': 0,
'subtotal_amount_taxable': 0,
'subtotal_amount_exempt': 0, 'total_amount': total_amount_main_currency,
'main_currency_round': currency_round_main_currency.decimal_places,
'main_currency_name': self._l10n_cl_normalize_currency_name(
currency_round_main_currency.name) if export else False
}
vat_percent = 0
if other_currency:
key_other_currency = 'balance' if export else 'amount_currency'
values['second_currency'] = {
'subtotal_amount_taxable': 0,
'subtotal_amount_exempt': 0,
'vat_amount': 0,
'total_amount': currency_round_other_currency.round(abs(self.amount_total_signed)) \
if export else currency_round_other_currency.round(self.amount_total),
'round_currency': currency_round_other_currency.decimal_places,
'name': self._l10n_cl_normalize_currency_name(currency_round_other_currency.name),
'rate': round(abs(self.amount_total_signed) / self.amount_total, 4),
}
for line in self.line_ids:
if line.tax_line_id and line.tax_line_id.l10n_cl_sii_code == 14:
values['vat_amount'] += line[key_main_currency] * sign_main_currency
if other_currency:
values['second_currency']['vat_amount'] += line[key_other_currency] * sign_main_currency # amount_currency behaves as balance
vat_percent = line.tax_line_id.amount if line.tax_line_id.amount > vat_percent else vat_percent
if line.display_type == 'product':
if line.tax_ids.filtered(lambda x: x.l10n_cl_sii_code == 14):
values['subtotal_amount_taxable'] += line[key_main_currency] * sign_main_currency
if other_currency:
values['second_currency']['subtotal_amount_taxable'] += line[key_other_currency] * sign_main_currency
elif not line.tax_ids:
values['subtotal_amount_exempt'] += line[key_main_currency] * sign_main_currency
if other_currency:
values['second_currency']['subtotal_amount_exempt'] += line[key_other_currency] * sign_main_currency
values['global_discounts'] = []
for gd in global_discounts:
main_value = currency_round_main_currency.round(abs(gd.price_subtotal)) if \
(not other_currency and not export) or (other_currency and export) else \
currency_round_main_currency.round(abs(gd.balance))
second_value = currency_round_other_currency.round(abs(gd.balance)) if other_currency and export else \
currency_round_other_currency.round(abs(gd.price_subtotal))
values['global_discounts'].append(
{
'name': gd.name,
'global_discount_main_value': main_value,
'global_discount_second_value': second_value if second_value != main_value else False,
'tax_ids': gd.tax_ids,
}
)
values['vat_percent'] = '%.2f' % vat_percent if vat_percent > 0 else False
return values
def _l10n_cl_get_withholdings(self):
"""
This method calculates the section of withholding taxes, or 'other' taxes for the Chilean electronic invoices.
These taxes are not VAT taxes in general; they are special taxes (for example, alcohol or sugar-added beverages,
withholdings for meat processing, fuel, etc.
The taxes codes used are included here:
[15, 17, 18, 19, 24, 25, 26, 27, 271]
http://www.sii.cl/declaraciones_juradas/ddjj_3327_3328/cod_otros_imp_retenc.pdf
The need of the tax is not just the amount, but the code of the tax, the percentage amount and the amount
:return:
"""
self.ensure_one()
tax = [{'tax_code': line.tax_line_id.l10n_cl_sii_code,
'tax_name': line.tax_line_id.name,
'tax_base': abs(sum(self.invoice_line_ids.filtered(
lambda x: line.tax_line_id.l10n_cl_sii_code in x.tax_ids.mapped('l10n_cl_sii_code')).mapped(
'balance'))),
'tax_percent': abs(line.tax_line_id.amount),
'tax_amount_currency': self.currency_id.round(abs(line.amount_currency)),
'tax_amount': self.currency_id.round(abs(line.balance))} for line in self.line_ids.filtered(
lambda x: x.tax_group_id.id in [
self.env.ref('l10n_cl.tax_group_ila').id, self.env.ref('l10n_cl.tax_group_retenciones').id])]
return tax
def _float_repr_float_round(self, value, decimal_places):
return float_repr(float_round(value, decimal_places), decimal_places)

View file

@ -0,0 +1,127 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models
from odoo.tools.float_utils import float_repr
class AccountMoveLine(models.Model):
_inherit = 'account.move.line'
def _l10n_cl_prices_and_taxes(self):
""" this method is preserved here to allow compatibility with old templates,
Nevertheless it will be deprecated in future versions, since it had been replaced by
the method _l10n_cl_get_line_amounts, which is the same method used to calculate
the values for the XML (DTE) file
"""
self.ensure_one()
invoice = self.move_id
included_taxes = self.tax_ids.filtered(lambda x: x.l10n_cl_sii_code == 14) if self.move_id._l10n_cl_include_sii() else self.tax_ids
if not included_taxes:
price_unit = self.tax_ids.with_context(round=False).compute_all(
self.price_unit, invoice.currency_id, 1.0, self.product_id, invoice.partner_id)
price_unit = price_unit['total_excluded']
price_subtotal = self.price_subtotal
else:
price_unit = included_taxes.compute_all(
self.price_unit, invoice.currency_id, 1.0, self.product_id, invoice.partner_id)['total_included']
price = self.price_unit * (1 - (self.discount or 0.0) / 100.0)
price_subtotal = included_taxes.compute_all(
price, invoice.currency_id, self.quantity, self.product_id, invoice.partner_id)['total_included']
price_net = price_unit * (1 - (self.discount or 0.0) / 100.0)
return {
'price_unit': price_unit,
'price_subtotal': price_subtotal,
'price_net': price_net
}
def _l10n_cl_get_line_amounts(self):
"""
This method is used to calculate the amount and taxes of the lines required in the Chilean localization
electronic documents.
"""
# If in this fix we should check for boletas, we have the following cases, and how this affects the xml
# for facturas and boletas:
# 1. local invoice in same currency tax not included in price
# 2. local invoice in same currency tax included in price (there is difference of -1 peso in amount_untaxed
# and +1 peso in vat tax amount. The lines are OK
# 3. local invoice in different currency tax not included in price
# 4. local invoice in different currency tax include in price -> this is the most problematic case because
# 5. foreign invoice in different currency (without tax)
if self.display_type != 'product':
return {
'price_subtotal': 0,
}
line_sign = self.price_subtotal / abs(self.price_subtotal) if self.price_subtotal else 0
domestic_invoice_other_currency = self.move_id.currency_id != self.move_id.company_id.currency_id and not \
self.move_id.l10n_latam_document_type_id._is_doc_type_export()
export = self.move_id.l10n_latam_document_type_id._is_doc_type_export()
if not export:
# This is to manage case 1, 2, 3 and 4
# cases 1 and 2: domestic invoice in same currency and cases 3 and 4 with other currency
main_currency = self.move_id.company_id.currency_id
main_currency_field = 'balance'
second_currency_field = 'price_subtotal'
second_currency = self.currency_id
main_currency_rate = 1
second_currency_rate = abs(self.move_id.amount_total_signed) / self.move_id.amount_total if self.move_id.amount_total else 1
inverse_rate = second_currency_rate if domestic_invoice_other_currency else main_currency_rate
else:
# This is to manage case 5 (export docs)
main_currency = self.currency_id
second_currency = self.move_id.company_id.currency_id
main_currency_field = 'price_subtotal'
second_currency_field = 'balance'
inverse_rate = abs(self.move_id.amount_total_signed) / self.move_id.amount_total if self.move_id.amount_total else 1
price_subtotal = abs(self[main_currency_field]) * line_sign
if self.quantity and self.discount != 100.0:
price_unit = (price_subtotal / abs(self.quantity)) / (1 - self.discount / 100)
if self.move_id.l10n_latam_document_type_id._is_doc_type_electronic_ticket():
price_item_document = (self.price_total / abs(self.quantity)) / (1 - self.discount / 100)
price_line_document = self.price_total
else:
price_item_document = price_unit
price_line_document = price_subtotal
else:
price_item_document = price_line_document = 0.0
price_unit = self.price_unit
if self.discount == 100:
price_before_discount = price_unit * self.quantity
else:
price_before_discount = price_subtotal / (1 - self.discount / 100)
discount_amount = price_before_discount * self.discount / 100
values = {
'decimal_places': main_currency.decimal_places,
'price_item': round(price_unit, 6),
'price_item_document': round(price_item_document, 2),
'price_line_document': price_line_document,
'total_discount': main_currency.round(discount_amount),
'price_subtotal': main_currency.round(price_subtotal),
'exempt': bool(not self.tax_ids),
'main_currency': main_currency,
}
if domestic_invoice_other_currency or export:
price_subtotal_second = abs(self[second_currency_field]) * line_sign
if self.quantity and self.discount != 100.0:
price_unit_second = (price_subtotal_second / abs(self.quantity)) / (1 - self.discount / 100)
else:
price_unit_second = self.price_unit
discount_amount_second = price_unit_second * self.quantity - price_subtotal_second
values['second_currency'] = {
'price': second_currency.round(price_unit_second),
'currency_name': self.move_id._format_length(second_currency.name, 3),
'conversion_rate': round(inverse_rate, 4),
'amount_discount': second_currency.round(discount_amount_second),
'total_amount': second_currency.round(price_subtotal_second),
'round_currency': second_currency.decimal_places,
}
values['line_description'] = '%s (%s: %s @ %s)' % (
self.name,
values['second_currency']['currency_name'],
float_repr(values['second_currency']['price'], values['second_currency']['round_currency']),
self.move_id._float_repr_float_round(values['second_currency']['conversion_rate'], values['second_currency']['round_currency']),
) if values.get('second_currency') and not self.l10n_latam_document_type_id._is_doc_type_export() else self.name
return values

View file

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
class AccountTax(models.Model):
_name = 'account.tax'
_inherit = 'account.tax'
l10n_cl_sii_code = fields.Integer('SII Code', group_operator=False)
class AccountTaxTemplate(models.Model):
_name = 'account.tax.template'
_inherit = 'account.tax.template'
l10n_cl_sii_code = fields.Integer('SII Code')
def _get_tax_vals(self, company, tax_template_to_tax):
self.ensure_one()
vals = super(AccountTaxTemplate, self)._get_tax_vals(company, tax_template_to_tax)
vals.update({
'l10n_cl_sii_code': self.l10n_cl_sii_code,
})
if self.tax_group_id:
vals['tax_group_id'] = self.tax_group_id.id
return vals

View file

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, fields
class L10nLatamDocumentType(models.Model):
_inherit = 'l10n_latam.document.type'
internal_type = fields.Selection(
selection_add=[
('invoice', 'Invoices'),
('invoice_in', 'Purchase Invoices'),
('debit_note', 'Debit Notes'),
('credit_note', 'Credit Notes'),
('receipt_invoice', 'Receipt Invoice'),
('stock_picking', 'Stock Delivery'),
],
)
l10n_cl_active = fields.Boolean(
'Active in localization', help='This boolean enables document to be included on invoicing')
def _format_document_number(self, document_number):
""" Make validation of Import Dispatch Number
* making validations on the document_number. If it is wrong it should raise an exception
* format the document_number against a pattern and return it
"""
self.ensure_one()
if self.country_id.code != "CL":
return super()._format_document_number(document_number)
if not document_number:
return False
return document_number.zfill(6)
def _is_doc_type_vendor(self):
return self.code == '46'
def _is_doc_type_export(self):
return self.code in ['110', '111', '112'] and self.country_id.code == 'CL'
def _is_doc_type_electronic_ticket(self):
return self.code in ['39', '41'] and self.country_id.code == 'CL'

View file

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, fields
class ResCompany(models.Model):
_inherit = "res.company"
l10n_cl_activity_description = fields.Char(
string='Company Activity Description', related='partner_id.l10n_cl_activity_description', readonly=False)
def _localization_use_documents(self):
""" Chilean localization use documents """
self.ensure_one()
return self.account_fiscal_country_id.code == "CL" or super()._localization_use_documents()

View file

@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
class ResPartner(models.Model):
_name = 'res.country'
_inherit = 'res.country'
l10n_cl_customs_code = fields.Char('Customs Code')
l10n_cl_customs_name = fields.Char('Customs Name')
l10n_cl_customs_abbreviation = fields.Char('Customs Abbreviation')

View file

@ -0,0 +1,10 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import _, api, fields, models
class ResCurrency(models.Model):
_name = "res.currency"
_inherit = "res.currency"
l10n_cl_currency_code = fields.Char('Currency Code')
l10n_cl_short_name = fields.Char('Short Name')

View file

@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import stdnum
from odoo import _, api, fields, models
from odoo.exceptions import UserError, ValidationError
class ResPartner(models.Model):
_name = 'res.partner'
_inherit = 'res.partner'
_sii_taxpayer_types = [
('1', _('VAT Affected (1st Category)')),
('2', _('Fees Receipt Issuer (2nd category)')),
('3', _('End Consumer')),
('4', _('Foreigner')),
]
l10n_cl_sii_taxpayer_type = fields.Selection(
_sii_taxpayer_types, 'Taxpayer Type', index='btree_not_null',
help='1 - VAT Affected (1st Category) (Most of the cases)\n'
'2 - Fees Receipt Issuer (Applies to suppliers who issue fees receipt)\n'
'3 - End consumer (only receipts)\n'
'4 - Foreigner')
l10n_cl_activity_description = fields.Char(string='Activity Description')
@api.model
def _commercial_fields(self):
return super()._commercial_fields() + ['l10n_cl_sii_taxpayer_type']
def _format_vat_cl(self, values):
identification_types = [self.env.ref('l10n_latam_base.it_vat').id, self.env.ref('l10n_cl.it_RUT').id,
self.env.ref('l10n_cl.it_RUN').id]
country = self.env["res.country"].browse(values.get('country_id'))
identification_type = self.env['l10n_latam.identification.type'].browse(
values.get('l10n_latam_identification_type_id')
)
partner_country_is_chile = country.code == "CL" or identification_type.country_id.code == "CL"
if partner_country_is_chile and \
values.get('l10n_latam_identification_type_id') in identification_types and values.get('vat') and\
stdnum.util.get_cc_module('cl', 'vat').is_valid(values['vat']):
return stdnum.util.get_cc_module('cl', 'vat').format(values['vat']).replace('.', '').replace(
'CL', '').upper()
else:
return values['vat']
def _format_dotted_vat_cl(self, vat):
vat_l = vat.split('-')
n_vat, n_dv = vat_l[0], vat_l[1]
return '%s-%s' % (format(int(n_vat), ',d').replace(',', '.'), n_dv)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if vals.get('vat'):
vals['vat'] = self._format_vat_cl(vals)
return super().create(vals_list)
def write(self, values):
if any(field in values for field in ['vat', 'l10n_latam_identification_type_id', 'country_id']):
for record in self:
vat_values = {
'vat': values.get('vat', record.vat),
'l10n_latam_identification_type_id': values.get(
'l10n_latam_identification_type_id', record.l10n_latam_identification_type_id.id),
'country_id': values.get('country_id', record.country_id.id)
}
values['vat'] = self._format_vat_cl(vat_values)
return super().write(values)

View file

@ -0,0 +1,9 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models
class ResBank(models.Model):
_name = 'res.bank'
_inherit = 'res.bank'
l10n_cl_sbif_code = fields.Char('Cod. SBIF', size=10)

View file

@ -0,0 +1,9 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import fields, models, api, _
class UomUom(models.Model):
_inherit = 'uom.uom'
l10n_cl_sii_code = fields.Char('SII Code')