Skip to content

Commit 1f61f76

Browse files
[IMP] l10n_ar_txt_tucuman: new module
closes #541 Tarea: 38200 X-original-commit: c7b5853 Signed-off-by: Katherine Zaoral <kz@adhoc.com.ar> Signed-off-by: pablohmontenegro <pam@adhoc.com.ar>
1 parent 3d54b42 commit 1f61f76

File tree

6 files changed

+224
-0
lines changed

6 files changed

+224
-0
lines changed

l10n_ar_txt_tucuman/README.rst

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
.. |company| replace:: ADHOC SA
2+
3+
.. |company_logo| image:: https://raw.githubusercontent.com/ingadhoc/maintainer-tools/master/resources/adhoc-logo.png
4+
:alt: ADHOC SA
5+
:target: https://www.adhoc.com.ar
6+
7+
.. |icon| image:: https://raw.githubusercontent.com/ingadhoc/maintainer-tools/master/resources/adhoc-icon.png
8+
9+
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.png
10+
:target: https://www.gnu.org/licenses/agpl
11+
:alt: License: AGPL-3
12+
13+
===========================
14+
Tax Settlements For Tucuman
15+
===========================
16+
17+
Este módulo imlementa:
18+
19+
* Descargar TXT Tucuman de retenciones y percepciones aplicadas.
20+
21+
22+
Installation
23+
============
24+
25+
To install this module, you need to:
26+
27+
#. Only need to install the module
28+
29+
Configuration
30+
=============
31+
32+
To configure this module, you need to:
33+
34+
#. Nothing to configure
35+
36+
Usage
37+
=====
38+
39+
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
40+
:alt: Try me on Runbot
41+
:target: http://runbot.adhoc.com.ar/
42+
43+
Credits
44+
=======
45+
46+
Images
47+
------
48+
49+
* |company| |icon|
50+
51+
Contributors
52+
------------
53+
54+
Maintainer
55+
----------
56+
57+
|company_logo|
58+
59+
This module is maintained by the |company|.
60+
61+
To contribute to this module, please visit https://www.adhoc.com.ar.

l10n_ar_txt_tucuman/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import models

l10n_ar_txt_tucuman/__manifest__.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
'name': 'Txt Tucuman',
3+
'version': "17.0.1.0.0",
4+
'category': 'Accounting',
5+
'website': 'www.adhoc.com.ar',
6+
'license': 'LGPL-3',
7+
'depends': [
8+
'l10n_ar_account_tax_settlement',
9+
],
10+
'data': [
11+
],
12+
'demo': [
13+
],
14+
'installable': False,
15+
'auto_install': False,
16+
'application': False,
17+
}
836 KB
Binary file not shown.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import account_journal
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
from odoo import models, fields, _
2+
from odoo.exceptions import UserError
3+
4+
5+
class AccountJournal(models.Model):
6+
_inherit = 'account.journal'
7+
8+
settlement_tax = fields.Selection(selection_add=[
9+
('iibb_tucuman', 'TXT Retenciones/Percepciones Tucuman')
10+
])
11+
12+
def iibb_tucuman_files_values(self, move_lines):
13+
""" Implementado segun especificación indicada en tarea 38200.
14+
Ver especificación también en l10n_ar_txt_tucuman/doc/MRETPER6R2.pdf a partir de la página 12. """
15+
self.ensure_one()
16+
17+
# VALIDACIONES
18+
self._iibb_tucuman_validations(move_lines)
19+
20+
# ELABORACIÓN DE ARCHIVOS TXT
21+
lines = move_lines.sorted(key=lambda r: (r.date, r.id))
22+
return [{
23+
'txt_filename': 'DATOS.txt',
24+
'txt_content': self._iibb_tucuman_datos_txt_file(lines),
25+
},
26+
{'txt_filename': 'RETPER.txt',
27+
'txt_content': self._iibb_tucuman_retper_txt_file(lines),
28+
},
29+
{'txt_filename': 'NCFACT.TXT',
30+
'txt_content': self._iibb_tucuman_ncfact_txt_file(lines.filtered(lambda x: x.move_type == 'out_refund')),
31+
}]
32+
33+
def _iibb_tucuman_validations(self, move_lines):
34+
""" Validaciones para el archivo TXT Retenciones/Percepciones Tucuman. Si no hay errores este método no
35+
devuelve nada, de lo contrario se lanzará mensaje de error que corresponda indicando lo que el usuario debe
36+
corregir para poder generar el archivo. """
37+
if nc_without_reversed_entry_id := move_lines.filtered(lambda x: x.move_type == 'out_refund'
38+
and not x.move_id.reversed_entry_id):
39+
raise UserError(_("Algunos comprobantes rectificativos no contienen información de que "
40+
"comprobante original están revirtiendo: %s") %
41+
(", ".join(nc_without_reversed_entry_id.mapped('move_id.name'))))
42+
if moves_without_street_city_state := move_lines.filtered(lambda x: not x.partner_id.street or
43+
not x.partner_id.city or
44+
not x.partner_id.state_id or not x.partner_id.zip):
45+
raise UserError(_("Algunos comprobantes no contienen información acerca de la calle/ciudad/provincia/cod "
46+
"postal del contacto: %s") %
47+
(", ".join(moves_without_street_city_state.mapped('move_id.name'))))
48+
move_lines_with_five_digits_pos = move_lines.filtered(
49+
lambda x: x.move_id._l10n_ar_get_document_number_parts(
50+
x.move_id.l10n_latam_document_number,
51+
x.l10n_latam_document_type_id.code
52+
)['point_of_sale'] > 9999 # Verificar si el punto de venta es mayor a 9999
53+
)
54+
if move_lines_with_five_digits_pos:
55+
raise UserError(_("Algunos comprobantes tienen punto de venta de 5 dígitos y deben tener de 4 dígitos para "
56+
"poder generar el archivo txt de retenciones y percepciones de Tucuman: %s") %
57+
(", ".join(move_lines_with_five_digits_pos.mapped('move_id.name'))))
58+
percepciones = move_lines.filtered(lambda x: x.move_id.is_invoice())
59+
if percepciones and len(percepciones) != len(move_lines):
60+
raise UserError(_("Debe generar archivos para TXT Tucuman por separado para retenciones por un lado y "
61+
"percepciones por otro."))
62+
63+
def _iibb_tucuman_datos_txt_file(self, lines):
64+
""" Devuelve contenido del archivo DATOS.TXT Tucuman. """
65+
content_datos = ''
66+
for line in lines:
67+
is_perception = line.move_id.is_invoice()
68+
# 1, FECHA, longitud: 8. Formato AAAAMMDD
69+
content_datos += fields.Date.from_string(line.date).strftime('%Y%m%d')
70+
# 2, TIPODOC, longitud: 2
71+
content_datos += line.partner_id.l10n_latam_identification_type_id.l10n_ar_afip_code
72+
# 3, DOCUMENTO, longitud: 11
73+
content_datos += line.partner_id.l10n_ar_vat
74+
# 4, TIPO COMP, longitud: 2
75+
# 99 para retenciones por el ejemplo que pasó en el archivo adjunto el cliente en la tarea 38200
76+
content_datos += line.move_id.l10n_latam_document_type_id.code.zfill(2) if is_perception else '99'
77+
# 5, LETRA, longitud: 1
78+
content_datos += line.move_id.l10n_latam_document_type_id.l10n_ar_letter if is_perception else ' '
79+
# 6, COD. LUGAR EMISION, longitud: 4
80+
document_number_parts = line.move_id._l10n_ar_get_document_number_parts(
81+
line.move_id.l10n_latam_document_number, line.l10n_latam_document_type_id.code)
82+
content_datos += str(document_number_parts['point_of_sale']).zfill(4)
83+
# 7, NUMERO, longitud: 8
84+
content_datos += str(document_number_parts['invoice_number']).zfill(8)
85+
# 8, BASE_CALCULO, longitud: 15,2
86+
content_datos += '%015.2f' % (line.tax_base_amount if is_perception else line.payment_id.withholding_base_amount)
87+
# 9, PORCENTAJE/ALICUOTA, longitud: 6,3
88+
partner_alicuot = line.tax_line_id.get_partner_alicuot(line.partner_id, line.date)
89+
if is_perception:
90+
content_datos += '%06.3f' % partner_alicuot.alicuota_percepcion
91+
else:
92+
content_datos += '%06.3f' % partner_alicuot.alicuota_retencion
93+
# 10, MONTO_RET/PER, longitud: 15,2
94+
content_datos += '%015.2f' % abs(line.balance)
95+
content_datos += '\r\n'
96+
return content_datos
97+
98+
def _iibb_tucuman_retper_txt_file(self, lines):
99+
""" Devuelve contenido del archivo RETPER.TXT Tucuman. """
100+
content_retper = ''
101+
for line in lines:
102+
# 1, TIPODOC, longitud: 2
103+
content_retper += line.partner_id.l10n_latam_identification_type_id.l10n_ar_afip_code
104+
# 2, DOCUMENTO, longitud: 11
105+
content_retper += line.partner_id.l10n_ar_vat
106+
# 3, NOMBRE, longitud: 40
107+
content_retper += line.partner_id.name[:40].ljust(40)
108+
# 4, DOMICILIO, longitud: 40
109+
content_retper += line.partner_id.street[:40].ljust(40)
110+
# 5, Nro, longitud: 5
111+
# Hacemos '9' * 5 por el ejemplo que pasó en el archivo adjunto el cliente en la tarea
112+
content_retper += '9' * 5
113+
# 6, LOCALIDAD, longitud: 15
114+
content_retper += line.partner_id.city[:15].ljust(15)
115+
# 7, PROVINCIA, longitud: 15
116+
content_retper += line.partner_id.state_id.name[:15].ljust(15)
117+
# 8, NO USADO, longitud 11
118+
content_retper += ' ' * 11
119+
# 9, C. POSTAL, longitud: 8
120+
content_retper += '%8s' % line.partner_id.zip
121+
content_retper += '\r\n'
122+
return content_retper
123+
124+
def _iibb_tucuman_ncfact_txt_file(self, lines):
125+
""" Devuelve contenido del archivo NCFACT.TXT Tucuman. """
126+
content_ncfact = ''
127+
for line in lines:
128+
nc_document_number_parts = line.move_id._l10n_ar_get_document_number_parts(
129+
line.move_id.l10n_latam_document_number, line.l10n_latam_document_type_id.code)
130+
# 1, COD. LUGAR EMISION NC, longitud: 4
131+
content_ncfact += str(nc_document_number_parts['point_of_sale']).zfill(4)
132+
# 2, NUMERO NV, longitud: 8
133+
content_ncfact += str(nc_document_number_parts['invoice_number']).zfill(8)
134+
# 3, COD LUGAR EMISION FAC, longitud: 4
135+
document_number_parts = line.move_id._l10n_ar_get_document_number_parts(
136+
line.move_id.reversed_entry_id.l10n_latam_document_number,
137+
line.move_id.reversed_entry_id.l10n_latam_document_type_id.code)
138+
content_ncfact += str(document_number_parts['point_of_sale']).zfill(4)
139+
# 4, NUMERO FAC, longitud: 8
140+
content_ncfact += str(document_number_parts['invoice_number']).zfill(8)
141+
# 5, TIPO FAC, longitud: 2
142+
content_ncfact += line.move_id.reversed_entry_id.l10n_latam_document_type_id.code.zfill(2)
143+
content_ncfact += '\r\n'
144+
return content_ncfact

0 commit comments

Comments
 (0)