1
# -*- coding: utf-8 -*-
2
# -*- encoding: utf-8 -*-
3
##############################################################################
5
# OpenERP - Export format BOE model 347 engine
6
# Copyright (C) 2009 Asr Oss. All Rights Reserved
9
# This program is free software: you can redistribute it and/or modify
10
# it under the terms of the GNU General Public License as published by
11
# the Free Software Foundation, either version 3 of the License, or
12
# (at your option) any later version.
14
# This program is distributed in the hope that it will be useful,
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
# GNU General Public License for more details.
19
# You should have received a copy of the GNU General Public License
20
# along with this program. If not, see <http://www.gnu.org/licenses/>.
22
##############################################################################
25
Export format BOE model 347 engine wizards
27
__author__ = """Alejandro Sanchez Ramirez Asr Oss - alejandro@asr-oss.com
28
Borja López Soilán (Pexego) - borjals@pexego.es"""
31
from tools.translate import _
38
############################################################################
40
############################################################################
42
def _formatString(text, length, fill=' ', align='<'):
44
Formats the string into a fixed length ASCII (iso-8859-1) record.
47
'Todos los campos alfanuméricos y alfabéticos se presentarán alineados a la izquierda y
48
rellenos de blancos por la derecha, en mayúsculas sin caracteres especiales, y sin vocales acentuadas.
49
Para los caracteres específicos del idioma se utilizará la codificación ISO-8859-1. De esta
50
forma la letra “Ñ” tendrá el valor ASCII 209 (Hex. D1) y la “Ç”(cedilla mayúscula) el valor ASCII
52
(http://www.boe.es/boe/dias/2008/10/23/pdfs/A42154-42190.pdf)
55
# Turn text (probably unicode) into an ASCII (iso-8859-1) string
57
if isinstance(text, (unicode)):
58
ascii_string = text.encode('iso-8859-1', 'ignore')
60
ascii_string = str(text or '')
61
# Cut the string if it is too long
62
if len(ascii_string) > length:
63
ascii_string = ascii_string[:length]
65
#ascii_string = '{0:{1}{2}{3}s}'.format(ascii_string, fill, align, length) #for python >= 2.6
67
ascii_string = str(ascii_string) + (length-len(str(ascii_string)))*fill
69
ascii_string = (length-len(str(ascii_string)))*fill + str(ascii_string)
71
assert False, _('Wrong aling option. It should be < or >')
73
ascii_string = ascii_string.upper()
77
replacements = [('Á', 'A'), ('É', 'E'), ('Í', 'I'), ('Ó', 'O'), ('Ú', 'U')]
78
for orig, repl in replacements:
79
ascii_string.replace(orig, repl)
81
assert len(ascii_string) == length, \
82
_("The formated string must match the given length")
86
def _formatNumber(number, int_length, dec_length=0, include_sign=False):
88
Formats the number into a fixed length ASCII (iso-8859-1) record.
90
'Todos los campos numéricos se presentarán alineados a la derecha
91
y rellenos a ceros por la izquierda sin signos y sin empaquetar.'
92
(http://www.boe.es/boe/dias/2008/10/23/pdfs/A42154-42190.pdf)
95
# Separate the number parts (-55.23 => int_part=55, dec_part=0.23, sign='N')
99
_number = float(number)
100
int_part = int(_number)
101
dec_part = int((_number % 1)*100)
102
sign = _number > 0 and ' ' or 'N'
110
#ascii_string += '{0:0>{1}}'.format(int_part, int_length) #for python >= 2.6
111
ascii_string += '%.*d' % (int_length, int_part)
113
#ascii_string += '{0:0<{1}}'.format(dec_part, dec_length) #for python >= 2.6
114
ascii_string += str(dec_part)+(dec_length-len(str(dec_part)))*'0'
116
assert len(ascii_string) == (include_sign and 1 or 0) + int_length + dec_length, \
117
_("The formated string must match the given length")
121
def _formatBoolean(value, yes='X', no=' '):
123
Formats a boolean value into a fixed length ASCII (iso-8859-1) record.
125
return value and yes or no
128
############################################################################
130
############################################################################
132
class wizard_export_boe(wizard.interface):
134
Wizard to export the 347 model report in BOE format.
137
############################################################################
139
############################################################################
141
_init_form = """<?xml version="1.0" encoding="utf-8"?>
142
<form string="Export 347 in BOE format" colspan="4" width="400">
143
<label string="This wizard will export the 347 report data to a BOE format file." colspan="4"/>
144
<label string="" colspan="4"/>
145
<label string="You may afterwards import this file into the AEAT help program." colspan="4"/>
148
_done_form = """<?xml version="1.0" encoding="utf-8"?>
149
<form string="347 report exported in BOE format" colspan="4" width="400">
150
<label string="The report file has been sucessfully generated." colspan="4"/>
151
<label string="" colspan="4"/>
152
<field name="file_name" nolabel="1"/>
153
<field name="file" filename="file_name" nolabel="1"/>
154
<label string="" colspan="4"/>
155
<label string="You may now verify, print or upload the exported file using the AEAT help program available at:" colspan="4"/>
156
<field name="aeat_program_download_url" widget="url" nolabel="1" colspan="4"/>
160
'file' : { 'string': 'Exported file', 'type':'binary', 'readonly':True },
161
'file_name': {'string': 'Exported file', 'type': 'char', 'size': 64, 'readonly':True},
162
'aeat_program_download_url' : {'string': 'AEAT URL', 'type': 'char', 'size': 255 },
165
############################################################################
167
############################################################################
169
def _get_formated_declaration_record(self, report):
171
Returns a type 1, declaration/company, formated record.
173
Format of the record:
174
Tipo registro 1 – Registro de declarante:
175
Posiciones Descripción
177
2-4 Modelo Declaración
179
9-17 NIF del declarante
180
18-57 Apellidos y nombre o razón social del declarante
182
59-67 Teléfono contacto
183
68-107 Apellidos y nombre contacto
184
108-120 Número identificativo de la declaración
185
121-122 Declaración complementaria o substitutiva
186
123-135 Número identificativo de la declaración anterior
187
136-144 Número total de personas y entidades
188
145-159 Importe total de las operaciones
189
160-168 Número total de inmuebles
190
169-183 Importe total de las operaciones de arrendamiento
192
391-399 NIF del representante legal
194
488-500 Sello electrónico
198
text += '1' # Tipo de Registro
199
text += '347' # Modelo Declaración
200
text += _formatString(report.fiscalyear_id.code, 4) # Ejercicio
201
text += _formatString(report.company_vat, 9) # NIF del declarante
202
text += _formatString(report.company_id.name, 40) # Apellidos y nombre o razón social del declarante
203
text += _formatString(report.support_type, 1) # Tipo de soporte
204
text += _formatString(report.contact_phone, 9) # Persona de contacto (Teléfono)
205
text += _formatString(report.contact_name, 40) # Persona de contacto (Apellidos y nombre)
206
text += _formatNumber(report.number, 13) # Número identificativo de la declaración
207
text += _formatString(report.type, 2) # Declaración complementaria o substitutiva
208
text += _formatNumber(report.previous_number, 13) # Número identificativo de la declaración anterior
209
text += _formatNumber(report.total_partner_records, 9) # Número total de personas y entidades
210
text += _formatNumber(report.total_amount, 13, 2) # Importe total de las operaciones
211
text += _formatNumber(report.total_real_state_records, 9) # Número total de inmuebles
212
text += _formatNumber(report.total_real_state_amount, 13, 2) # Importe total de las operaciones de arrendamiento
213
text += 207*' ' # Blancos
214
text += _formatString(report.representative_vat, 9) # NIF del representante legal
215
text += 88*' ' # Blancos
216
text += 13*' ' # Sello electrónico
218
assert len(text) == 502, _("The type 1 record must be 502 characters long")
221
def _get_formated_partner_record(self, report, partner_record):
223
Returns a type 2, partner, formated record
225
Format of the record:
226
Tipo de Registro 2 – Registro de declarado
227
Posiciones Descripción
229
2-4 Modelo Declaración
231
9-17 NIF del declarante
232
18-26 NIF del declarado
233
27-35 NIF del representante legal
234
36-75 Apellidos y nombre, razón social o denominación del declarado
236
77-80 Código provincia/país
238
82 Clave de operación
239
83-97 Importe de las operaciones
240
98 Operación de seguro
241
99 Arrendamiento local negocio
242
100-114 Importe percibido en metálico
243
115-129 Importe percibido por transmisiones de inmuebles sujetas a IVA
245
488-500 Sello electrónico
249
text += '2' # Tipo de Registro
250
text += '347' # Modelo Declaración
251
text += _formatString(report.fiscalyear_id.code, 4) # Ejercicio
252
text += _formatString(report.company_vat, 9) # NIF del declarante
253
text += _formatString(partner_record.partner_vat, 9) # NIF del declarado
254
text += _formatString(partner_record.representative_vat, 9) # NIF del representante legal
255
text += _formatString(partner_record.partner_id.name, 40) # Apellidos y nombre, razón social o denominación del declarado
256
text += 'D' # Tipo de hoja: Constante ‘D’.
257
text += _formatNumber(partner_record.partner_state_code, 2) # Código provincia
258
text += _formatString(partner_record.partner_country_code, 2) # Código país
259
text += ' ' # Blancos
260
text += _formatString(partner_record.operation_key, 1) # Clave de operación
261
text += _formatNumber(partner_record.amount, 13, 2) # Importe de las operaciones
262
text += _formatBoolean(partner_record.insurance_operation) # Operación de seguro
263
text += _formatBoolean(partner_record.bussiness_real_state_rent) # Arrendamiento local negocio
264
text += _formatNumber(partner_record.cash_amount, 13, 2) # Importe percibido en metálico
265
text += _formatNumber(partner_record.real_state_transmissions_amount, 13, 2) # Importe percibido por transmisiones de inmuebles sujetas a IVA
266
text += 371*' ' # Blancos
267
text += '\r\n' # Sello electrónico
269
assert len(text) == 502, _("The type 2-D record (partner) must be 502 characters long")
272
def _get_formated_real_state_record(self, report, partner_record):
274
Returns a type 2, real state, formated record
276
Format of the record:
277
Tipo de Registro 2 – Registro de inmueble
278
Posiciones Descripción
280
2-4 Modelo Declaración
282
9-17 NIF del declarante
283
18-26 NIF del arrendatario
284
27-35 NIF del representante legal
285
36-75 Apellidos y nombre, razón social o denominación del declarado
288
100-114 Importe de la operación
289
115 Situación del inmueble
290
116-140 Referencia catastral
291
141-333 Dirección y datos del inmueble
293
146–195 NOMBRE VÍA PUBLICA
294
196–198 TIPO DE NUMERACIÓN
295
199–203 NUMERO DE CASA
296
204-206 CALIFICADOR DEL NUMERO
300
216–218 PLANTA O PISO
303
262–291 LOCALIDAD O POBLACIÓN.
305
322–326 CODIGO DE MUNICIPIO
306
327-328 CODIGO PROVINCIA
307
329-333 CODIGO POSTAL
312
text += '2' # Tipo de Registro
313
text += '347' # Modelo Declaración
314
text += _formatNumber(report.fiscalyear_id.code, 4) # Ejercicio
315
text += _formatString(report.company_vat, 9) # NIF del declarante
316
text += _formatString(partner_record.partner_vat, 9) # NIF del declarado
317
text += _formatString(partner_record.representative_vat, 9) # NIF del representante legal
318
text += _formatString(partner_record.partner_id.name, 40) # Apellidos y nombre, razón social o denominación del declarado
319
text += 'I' # Tipo de hoja: Constante ‘I’.
320
text += 23*'' # Blancos
321
text += _formatNumber(partner_record.real_state_amount, 13, 2) # Importe de las operaciones
322
text += _formatNumber(partner_record.real_state_situation, 1) # Situación del inmueble
323
text += _formatString(partner_record.real_state_reference, 25) # Referencia catastral
324
text += _formatString(partner_record.real_state_address_type, 5) # TIPO DE VÍA
325
text += _formatString(partner_record.real_state_address, 50) # NOMBRE VÍA PUBLICA
326
text += _formatString(partner_record.real_state_number_type, 3) # TIPO DE NUMERACIÓN
327
text += _formatString(partner_record.real_state_number, 5) # NUMERO DE CASA
328
text += _formatString(partner_record.real_state_number_calification, 3) # CALIFICADOR DEL NUMERO
329
text += _formatString(partner_record.real_state_block, 3) # BLOQUE
330
text += _formatString(partner_record.real_state_portal, 3) # PORTAL
331
text += _formatString(partner_record.real_state_stairway, 3) # ESCALERA
332
text += _formatString(partner_record.real_state_floor, 3) # PLANTA O PISO
333
text += _formatString(partner_record.real_state_door, 3) # PUERTA
334
text += _formatString(partner_record.real_state_complement, 40) # COMPLEMENTO
335
text += _formatString(partner_record.real_state_city, 30) # LOCALIDAD O POBLACIÓN
336
text += _formatString(partner_record.real_state_township, 30) # MUNICIPIO
337
text += _formatString(partner_record.real_state_township_code, 5) # CODIGO DE MUNICIPIO
338
text += _formatString(partner_record.real_state_state_code, 2) # CODIGO PROVINCIA
339
text += _formatString(partner_record.real_state_postal_code, 5) # CODIGO POSTAL
340
text += 167*' ' # Blancos
341
text += '\r\n' # Sello electrónico
343
assert len(text) == 502, _("The type 2-I record (real state) must be 502 characters long")
347
def _export_boe_file(self, cr, uid, data, context):
349
Action that exports the data into a BOE formated text file.
352
pool = pooler.get_pool(cr.dbname)
353
report = pool.get('l10n.es.aeat.mod347.report').browse(cr, uid, data['id'], context=context)
357
# Add the header record
358
file_contents += self._get_formated_declaration_record(report)
361
# Add the partner records
363
for partner_record in report.partner_record_ids:
364
file_contents += self._get_formated_partner_record(report, partner_record)
367
# Add the real state records
369
for real_state_record in report.real_state_record_ids:
370
file_contents += self._get_formated_real_state_record(report, real_state_record)
373
# Generate the file and save as attachment
375
file = base64.encodestring(file_contents)
376
file_name = _('347_report_%s.txt') % time.strftime(_('%Y-%m-%d'))
377
pool.get('ir.attachment').create(cr, uid, {
378
'name': _('347 report %s') % time.strftime(_('%Y-%m-%d')),
380
'datas_fname': file_name,
381
'res_model': 'l10n.es.aeat.mod347.report',
382
'res_id': data['id'],
390
'file_name': file_name,
391
'aeat_program_download_url': "http://www.aeat.es/wps/portal/ProgramaAyuda?channel=e5b22fc8ebd4f010VgnVCM1000004ef01e0a____&ver=L&site=56d8237c0bc1ff00VgnVCM100000d7005a80____"
394
############################################################################
396
############################################################################
401
'result': {'type':'form', 'arch': _init_form, 'fields': {}, 'state':[('end', 'Cancel', 'gtk-cancel', True), ('export', 'Export', 'gtk-apply', True)]}
404
'actions': [_export_boe_file],
405
'result': {'type': 'form', 'arch': _done_form, 'fields': _done_fields, 'state':[('end','Done', 'gtk-ok', True)]}
409
wizard_export_boe('l10n_es_aeat_mod347.wizard_export_boe')