Skip to content

Commit

Permalink
[IMP] l10n_ar_txt_mendoza: TXT Mendoza
Browse files Browse the repository at this point in the history
Tarea: 38394
  • Loading branch information
pablohmontenegro committed Oct 28, 2024
1 parent b3cec2c commit 63439b1
Show file tree
Hide file tree
Showing 16 changed files with 522 additions and 20 deletions.
26 changes: 6 additions & 20 deletions l10n_ar_account_tax_settlement/models/account_journal.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError, RedirectWarning
from odoo.exceptions import ValidationError
from odoo.tools.float_utils import float_round
# from odoo.tools.misc import formatLang
# from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
Expand Down Expand Up @@ -853,9 +853,8 @@ def iibb_aplicado_sircar_files_values(self, move_lines):
line_nbr = 1
for line in move_lines.filtered('payment_id'):
alicuot_line = line.tax_line_id.get_partner_alicuot(
line.partner_id, line.date) if not line.tax_line_id.withholding_type == 'code' else line.payment_id.alicuota_mendoza * 100

if not type(alicuot_line, float) and not alicuot_line:
line.partner_id, line.date)
if not alicuot_line:
raise ValidationError(_(
'No hay alicuota configurada en el partner '
'"%s" (id: %s)') % (
Expand Down Expand Up @@ -894,31 +893,18 @@ def iibb_aplicado_sircar_files_values(self, move_lines):

# 8 alicuota de la retencion
content.append(format_amount(
alicuot_line.alicuota_retencion if not type(alicuot_line, float) else alicuot_line, 6, 2, '.'))
alicuot_line.alicuota_retencion, 6, 2, '.'))

# 9 Monto retenido
content.append(format_amount(-line.balance, 12, 2, '.'))

# 10 Tipo de Régimen de Percepción
# (código correspondiente según tabla definida por la jurisdicción)
if not type(alicuot_line, float) and not alicuot_line.regimen_retencion:
if not alicuot_line.regimen_retencion:
raise ValidationError(_(
'No hay regimen de retencion configurado para la alícuota'
' del partner %s') % line.partner_id.name)
elif not line.tax_line_id.codigo_regimen:
raise RedirectWarning(
message=_("El impuesto '%s' not tiene código de regimen en solapa 'Opciones avanzadas' campo 'Codigo de regimen'.", line.tax_line_id.name),
action={
'type': 'ir.actions.act_window',
'res_model': 'account.tax',
'views': [(False, 'form')],
'res_id': line.tax_line_id.id,
'name': _('Tax'),
'view_mode': 'form',
},
button_text=_('Editar Impuesto'),
)
content.append(alicuot_line.regimen_retencion if not type(alicuot_line, float) else line.tax_line_id.codigo_regimen)
content.append(alicuot_line.regimen_retencion)

# 11 Jurisdicción: código en Convenio Multilateral de la
# jurisdicción a la cual está presentando la DDJJ
Expand Down
2 changes: 2 additions & 0 deletions l10n_ar_txt_mendoza/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import models
from . import wizard
19 changes: 19 additions & 0 deletions l10n_ar_txt_mendoza/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
'name': 'TXT Mendoza',
'version': "16.0.1.0.0",
'category': 'Accounting',
'author': 'ADHOC SA',
'depends': [
'l10n_ar_account_tax_settlement',
'l10n_ar_account_withholding',
],
'data': [
'views/account_move_views.xml',
'views/afip_activity_view.xml',
'views/account_payment_view.xml',
'wizard/res_config_settings_views.xml',
],
'installable': True,
'auto_install': False,
'application': True,
}
6 changes: 6 additions & 0 deletions l10n_ar_txt_mendoza/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from . import account_move
from . import afip_activity
from . import res_company
from . import account_payment_group
from . import account_payment
from . import account_journal
252 changes: 252 additions & 0 deletions l10n_ar_txt_mendoza/models/account_journal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
from odoo import models, fields, _
from odoo.exceptions import ValidationError, RedirectWarning
import re

#########
# helpers
#########


def format_amount(amount, padding=15, decimals=2, sep=""):
if amount < 0:
template = "-{:0>%dd}" % (padding - 1 - len(sep))
else:
template = "{:0>%dd}" % (padding - len(sep))
res = template.format(
int(round(abs(amount) * 10**decimals, decimals)))
if sep:
res = "{0}{1}{2}".format(res[:-decimals], sep, res[-decimals:])
return res


def get_line_tax_base(move_line):
return sum(move_line.move_id.line_ids.filtered(
lambda x: move_line.tax_line_id in x.tax_ids).mapped(
'balance'))


def get_pos_and_number(full_number):
"""
Para un numero nos fijamos si hay '-', si hay:
* mas de 1, entonces devolvemos error
* 1, entonces devolvemos las partes (solo parte númerica)
* 0, entonces devolvemos '0' y parte númerica del número que se pasó
"""
args = full_number.split('-')
if len(args) == 1:
# si no hay '-' tomamos punto de venta 0
return ('0', re.sub('[^0-9]', '', args[0]))
else:
return re.sub('[^0-9]', '', args[0]), re.sub('[^0-9]', '', ''.join(args[1:]))


class AccountJournal(models.Model):
_inherit = 'account.journal'

def iibb_aplicado_sircar_files_values(self, move_lines):
""" Especificacion en /doc/sircar, solicitado en ticket 62526. Método heredado de https://github.com/ingadhoc/odoo-argentina-ee/blob/16.0/l10n_ar_account_tax_settlement/models/account_journal.py#L840
"""
self.ensure_one()
ret = ''
perc = ''

for line in move_lines.filtered(
lambda x: not x.payment_id and not x.move_id):
raise ValidationError(_(
'Hay lineas a liquidar que no estan enlazadas a pagos ni '
'facturas lo cual es requerido para generar el TXT'))

line_nbr = 1
for line in move_lines.filtered('payment_id'):
alicuot_line = line.tax_line_id.get_partner_alicuot(
line.partner_id, line.date) if not line.tax_line_id.withholding_type == 'code' else line.payment_id.alicuota_mendoza * 100

if not isinstance(alicuot_line, float) and not alicuot_line:
raise ValidationError(_(
'No hay alicuota configurada en el partner '
'"%s" (id: %s)') % (
line.partner_id.name, line.partner_id.id))

payment = line.payment_id
internal_type = line.l10n_latam_document_type_id.internal_type

# 1 Número de Renglón (único por archivo)
content = []
content.append('%05d' % line_nbr)

# 2 Origen del Comprobante
content.append('1')

# 3 Tipo del Comprobante
if payment.payment_type == 'outbound':
content.append('1')
else:
content.append('2')

# 4 Número del comprobante
content.append('%012d' % int(
re.sub('[^0-9]', '', line.payment_id.withholding_number or '')))

# 5 Cuit del contribuyene
content.append(line.partner_id.ensure_vat())

# 6 Fecha de la percepción
content.append(
fields.Date.from_string(line.date).strftime('%d/%m/%Y'))

# 7 Monto sujeto a percepción
content.append(format_amount(
payment.withholdable_base_amount, 12, 2, '.'))

# 8 alicuota de la retencion
content.append(format_amount(
alicuot_line.alicuota_retencion if not isinstance(alicuot_line, float) else alicuot_line, 6, 2, '.'))

# 9 Monto retenido
content.append(format_amount(-line.balance, 12, 2, '.'))

# 10 Tipo de Régimen de Percepción
# (código correspondiente según tabla definida por la jurisdicción)
if not isinstance(alicuot_line, float) and not alicuot_line.regimen_retencion:
raise ValidationError(_(
'No hay regimen de retencion configurado para la alícuota'
' del partner %s') % line.partner_id.name)
elif not line.tax_line_id.codigo_regimen:
raise RedirectWarning(
message=_("El impuesto '%s' not tiene código de regimen en solapa 'Opciones avanzadas' campo 'Codigo de regimen'.", line.tax_line_id.name),
action={
'type': 'ir.actions.act_window',
'res_model': 'account.tax',
'views': [(False, 'form')],
'res_id': line.tax_line_id.id,
'name': _('Tax'),
'view_mode': 'form',
},
button_text=_('Editar Impuesto'),
)
content.append(alicuot_line.regimen_retencion if not isinstance(alicuot_line, float) else line.tax_line_id.codigo_regimen)

# 11 Jurisdicción: código en Convenio Multilateral de la
# jurisdicción a la cual está presentando la DDJJ
if not line.tax_line_id.jurisdiction_code:
raise ValidationError(_(
'No hay etiqueta de jurisdicción configurada!'))

content.append(line.tax_line_id.jurisdiction_code)

# Tipo registro 2. Provincia Cordoba
if line.tax_line_id.jurisdiction_code in ['904', '914']:

# 12 Tipo de Operación (1-Efectuada, 2-Anulada, 3-Omitida)
content.append('2' if internal_type == 'credit_note' else '1')

# 13 Fecha de Emisión de Constancia (en formato dd/mm/aaaa)
content.append(fields.Date.from_string(line.date).strftime('%d/%m/%Y'))

# 14 Número de Constancia - Numeric(14)
content.append('%014s' % int(re.sub('[^0-9]', '', payment.withholding_number or '0')[:14]))

# 15 Número de Constancia original (sólo para las Anulaciones –ver códigos por jur-) - Numeric(14)
original_invoice = line.move_id._found_related_invoice() or line.move_id
content.append('%014d' % int(re.sub('[^0-9]', '', original_invoice.document_number or ''))
if internal_type == 'credit_note' else '%014d' % 0)

ret += ','.join(content) + '\r\n'
line_nbr += 1

line_nbr = 1
for line in move_lines.filtered(lambda x: x.move_id.is_invoice()):
alicuot_line = line.tax_line_id.get_partner_alicuot(
line.partner_id, line.date)
if not alicuot_line:
raise ValidationError(_(
'No hay alicuota configurada en el partner '
'"%s" (id: %s)') % (
line.partner_id.name, line.partner_id.id))


# 1 Número de Renglón (único por archivo)
content = []
content.append('%05d' % line_nbr)

letter = line.l10n_latam_document_type_id.l10n_ar_letter

# 2 Tipo de comprobante
internal_type = line.l10n_latam_document_type_id.internal_type
if internal_type == 'invoice':
tipo_comprobante = letter == 'E' and 5 or 1
elif internal_type == 'credit_note':
tipo_comprobante = letter == 'E' and 106 or 102
elif internal_type == 'debit_note':
tipo_comprobante = letter == 'E' and 6 or 2
elif line.move_id.type == 'out_invoice':
tipo_comprobante = 20
elif line.move_id.type == 'out_refund':
tipo_comprobante = 120
else:
raise ValidationError(_('Tipo de comprobante no reconocido'))
content.append('%03d' % tipo_comprobante)

# 3 Letra del comprobante
content.append(line.l10n_latam_document_type_id.l10n_ar_letter)

# 4 Número del comprobante
content.append('%012d' % int(
re.sub('[^0-9]', '', line.move_id.l10n_latam_document_number or '')))

# 5 Cuit del contribuyene
content.append(line.partner_id.ensure_vat())

# 6 Fecha de la percepción
content.append(
fields.Date.from_string(line.date).strftime('%d/%m/%Y'))

# 7 Monto sujeto a percepción
content.append(format_amount(-get_line_tax_base(line), 12, 2, '.'))

# 8 alicuota de la percepcion
content.append(format_amount(
alicuot_line.alicuota_percepcion, 6, 2, '.'))

# 9 Monto percibido
content.append(format_amount(-line.balance, 12, 2, '.'))

# 10 Tipo de Régimen de Percepción
# (código correspondiente según tabla definida por la jurisdicción)
if not alicuot_line.regimen_percepcion:
raise ValidationError(_(
'No hay regimen de percepcion configurado para la alícuota'
' del partner %s') % line.partner_id.name)
content.append(alicuot_line.regimen_percepcion)

# 11 Jurisdicción: código en Convenio Multilateral de la
# jurisdicción a la cual está presentando la DDJJ
if not line.tax_line_id.jurisdiction_code:
raise ValidationError(_(
'No hay etiqueta de jurisdicción configurada!'))

content.append(line.tax_line_id.jurisdiction_code)

# Tipo registro 2. Provincia Cordoba
if line.tax_line_id.jurisdiction_code in ['904', '914']:

# 12 Tipo de Operación (1-Efectuada, 2-Anulada, 3-Omitida, 4-Informativa)
content.append('2' if internal_type == 'credit_note' else '1')

# 13 Número de Constancia original (sólo para 2-Anulaciones) Alfanumérico (14) - ejemplo 1A002311312221
content.append(self._get_perception_original_invoice_number(line)
if internal_type == 'credit_note' else '%014d' % 0)

perc += ','.join(content) + '\r\n'
line_nbr += 1

return [
{
'txt_filename': 'Perc IIBB Aplicadas para SIRCAR.txt',
'txt_content': perc,
},
{
'txt_filename': 'Ret IIBB Aplicadas para SIRCAR.txt',
'txt_content': ret,
}]

15 changes: 15 additions & 0 deletions l10n_ar_txt_mendoza/models/account_move.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from odoo import models, fields, api


class AccountMove(models.Model):
_inherit = 'account.move'

actividades_padron = fields.Many2many(
'afip.activity',
related='partner_id.actividades_padron',
)
activities_mendoza_ids = fields.Many2many(
comodel_name='afip.activity',
string="Activities in Mendoza",
domain="[('id', 'in', actividades_padron)]"
)
8 changes: 8 additions & 0 deletions l10n_ar_txt_mendoza/models/account_payment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from odoo import models, fields, api


class AccountPayment(models.Model):

_inherit = "account.payment"

alicuota_mendoza = fields.Float(store=True, readonly=True)
32 changes: 32 additions & 0 deletions l10n_ar_txt_mendoza/models/account_payment_group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
from odoo import models, api, fields, _
from odoo.exceptions import ValidationError


class AccountPaymentGroup(models.Model):

_inherit = "account.payment.group"

# IMPORTANTE: alicuota_mendoza se guarda al momento de correr el código python del impuesto 'Retención IIBB Mendoza Aplicada' --> payment.write({'alicuota_mendoza': alicuota}). Ver por interfaz.
alicuota_mendoza = fields.Float(help="Guardamos la alícuota para el txt de mendoza.", readonly=True)

def compute_withholdings(self):
"""Para el cálculo de retenciones automáticas de aplicadas de Mendoza siempre tiene que haber una factura vinculada al payment group."""
tax_group_mendoza_id = self.env.ref('l10n_ar_ux.tax_group_retencion_iibb_za').id
retencion_mdza_aplicada = self.env['account.tax'].with_context(type=None).search([
('type_tax_use', '=', self.partner_type),
('company_id', '=', self.company_id.id),
('tax_group_id', '=', tax_group_mendoza_id),
], limit=1)
if retencion_mdza_aplicada and not self.to_pay_move_line_ids:
raise ValidationError('No puede calcular retenciones automáticas de aplicadas de Mendoza si no seleccionó una factura para pagar')
else:
super().compute_withholdings()

# Agregamos la alícuota de mendoza al payment (es necesario para generar el txt iibb_aplicado_sircar_files_values)
payment_mendoza = self.payment_ids.filtered(lambda x: x.tax_withholding_id.tax_group_id.id == tax_group_mendoza_id and x.tax_withholding_id.withholding_type == 'code' and x.state == 'draft')
if payment_mendoza:
payment_mendoza.alicuota_mendoza = self.alicuota_mendoza
Loading

0 comments on commit 63439b1

Please sign in to comment.