source: ecoalba/apps/carga/tasks.py @ 47c62bb

Last change on this file since 47c62bb was 47c62bb, checked in by jbecerra <jbecerra@…>, 10 years ago

Ajustes en convenios

  • Property mode set to 100644
File size: 16.9 KB
Line 
1# -*- coding: utf-8 -*-
2import os
3import logging
4import time
5import smtplib
6from datetime import datetime, date
7from django.contrib.auth.models import User
8from django.core.exceptions import ObjectDoesNotExist
9from django.db.models import Sum, Count
10from django.template.loader import get_template
11from django.template.context import Context
12from django.core.mail import send_mail
13from celery.task import task
14from django.utils import translation
15from django.utils.translation import ugettext_lazy as _l, ugettext as _
16from comun.csv_unicode import fichero_unicode, unicode_csv_reader
17from comun.models import Error, CargaMasiva, Comercio, \
18                        BienesComerciadosPrincipales, Pais, \
19                        CodigoArmonizado, PaisesPrincipales
20from carga.models import ComercioExteriorNexo
21from comun.procesar_csv import ValidadorColumna, Expresion, ValidadorConjunto, ColumnaCSV, ConjuntoCSV, FlujoCSV, ErrorCSV
22from comun.utilidades import dictfetchall
23from comun.constantes import IMPORTACIONES, EXPORTACIONES, CMASIVA_MAX_SEC, \
24                            EXPR_REG_ENTERO, EXPR_REG_CODIGO_ARANCELARIO, EXPR_REG_CIIU, \
25                            EXPR_REG_PAIS, EXPR_REG_DECIMAL, EXPR_REG_STRING_150, \
26                            EXPR_REG_ANYO, EXPR_REG_FECHA, EXPR_REG_MES, \
27                            FLUJO_COMERCIAL_PRODUCCION_NACIONAL, FLUJO_COMERCIAL_COMERCIO_EXTERIOR, \
28                            COMERCIO_EXTERIOR_INTRAALBA, COMERCIO_EXTERIOR_EXTRAALBA
29from django.conf import settings
30from django.db import connection, transaction
31                                   
32
33logger = logging.getLogger("carga.procesarcsv")
34
35def enviar_email(correo, plantilla, titulo, variables):
36    try:
37        t = get_template(plantilla)
38        c = Context(variables)
39       
40        send_mail(titulo, t.render(c), settings.EMAIL_FROM, [correo], fail_silently=False)
41    except smtplib.SMTPException as e:
42        logger.fatal('El correo no pudo ser enviado: smtpException ' + e)
43    except Exception as e:
44        logger.fatal('El correo no pudo ser enviado: ' + e)
45
46def prepare_carga_masiva(username, pais, flujo_comercial, mes, anyo):
47
48    usuario = User.objects.get(username=username)
49   
50    try:
51        proceso_carga_masiva = CargaMasiva.objects.get(usuario=usuario, pais=pais, flujo_comercial=flujo_comercial, mes=mes, anyo=anyo, procesando=True)
52       
53        if (datetime.now() - proceso_carga_masiva.fecha).seconds >= CMASIVA_MAX_SEC:
54            proceso_carga_masiva.fecha = datetime.now()
55            proceso_carga_masiva.procesando = False
56            proceso_carga_masiva.save()
57           
58            carga_masiva = CargaMasiva(usuario=usuario, fecha=datetime.now(), pais=pais, flujo_comercial=flujo_comercial, mes=mes, anyo=anyo, procesando=True)
59            carga_masiva.save()
60       
61            return usuario, False, carga_masiva
62        else:
63            return usuario, True, proceso_carga_masiva
64    except ObjectDoesNotExist:
65        carga_masiva = CargaMasiva(usuario=usuario, fecha=datetime.now(), pais=pais, flujo_comercial=flujo_comercial, mes=mes, anyo=anyo, procesando=True)
66        carga_masiva.save()
67       
68        return usuario, False, carga_masiva
69
70def identificar_bienes_principales(cantidad):
71    """
72    Algoritmo para identificar los bienes principales con relacion a <pais> dentro del flujo de comercio registrado
73    """
74    comercio_exterior = [COMERCIO_EXTERIOR_INTRAALBA, COMERCIO_EXTERIOR_EXTRAALBA]
75    flujo = [IMPORTACIONES, EXPORTACIONES]
76    querys = {}
77    cursor = connection.cursor()
78   
79    querys[COMERCIO_EXTERIOR_INTRAALBA] = """
80    SELECT * FROM
81     (SELECT
82      DISTINCT(codigo_armonizado_id) as codigo_armonizado,
83      pais_id as pais,
84      SUM(monto) as valor,
85      anyo,
86      rank() OVER (PARTITION BY anyo ORDER BY SUM(monto) DESC) as rango_monto
87    FROM
88      public.comun_comercio
89    WHERE
90      flujo_comercial = %s and
91      pais_id in (SELECT pais_id FROM comun_pais WHERE anyo_inclusion > 0)
92    GROUP BY
93      pais_id,
94      codigo_armonizado_id,
95      anyo
96    ORDER BY codigo_armonizado, rango_monto) as principales
97    WHERE
98      principales.rango_monto < %s;
99    """
100   
101    querys[COMERCIO_EXTERIOR_EXTRAALBA] = """
102    SELECT * FROM
103     (SELECT
104      DISTINCT(codigo_armonizado_id) as codigo_armonizado,
105      pais_id as pais,
106      SUM(monto) as valor,
107      anyo,
108      rank() OVER (PARTITION BY anyo ORDER BY SUM(monto) DESC) as rango_monto
109    FROM
110      public.comun_comercio
111    WHERE
112      flujo_comercial = %s and
113      pais_id in (SELECT pais_id FROM comun_pais WHERE not anyo_inclusion > 0)
114    GROUP BY
115      pais_id,
116      codigo_armonizado_id,
117      anyo
118    ORDER BY codigo_armonizado, rango_monto) as principales
119    WHERE
120      principales.rango_monto < %s;
121    """
122   
123    with transaction.commit_on_success():
124   
125        try:
126            cursor.execute("DELETE FROM comun_bienescomerciadosprincipales;")
127            transaction.commit_unless_managed()
128           
129            for item_comercio_exterior in comercio_exterior:
130                for item_flujo in flujo:
131                    cursor.execute(querys[item_comercio_exterior], [item_flujo, cantidad + 1])
132                    filas = dictfetchall(cursor)
133                   
134                    bien_principal = BienesComerciadosPrincipales()
135                    for fila in filas:
136                        bien_principal.flujo_comercial = item_flujo
137                        bien_principal.comercio_exterior = item_comercio_exterior
138                        bien_principal.codigo_armonizado = CodigoArmonizado.objects.get(id = fila['codigo_armonizado'])
139                        bien_principal.pais = Pais.objects.get(id = fila['pais'])
140                        bien_principal.valor = fila['valor']
141                        bien_principal.anyo = fila['anyo']
142                       
143                        bien_principal.save()
144                        bien_principal = BienesComerciadosPrincipales()
145        except Exception as e:
146            logger.fatal('Exception ejecutando la carga de Bienes Principales: %s' % e)
147            transaction.rollback()
148           
149            raise e
150
151def identificar_paises_principales(cantidad):
152    """
153    Algoritmo para identificar los paises principales con relacion a <pais> dentro del flujo de comercio registrado
154    """
155    comercio_exterior = [COMERCIO_EXTERIOR_INTRAALBA, COMERCIO_EXTERIOR_EXTRAALBA]
156    flujo = [IMPORTACIONES, EXPORTACIONES]
157    querys = {}
158    cursor = connection.cursor()
159   
160    querys[COMERCIO_EXTERIOR_INTRAALBA] = """
161    SELECT * FROM
162     (SELECT
163      DISTINCT(pais_id) as pais,
164      pais_relacion_id as pais_relacion,
165      SUM(monto) as valor,
166      anyo,
167      rank() OVER (PARTITION BY anyo ORDER BY SUM(monto) DESC)
168    FROM
169      public.comun_comercio
170    WHERE
171      flujo_comercial = %s and
172      pais_id in (SELECT pais_id FROM comun_pais WHERE anyo_inclusion > 0)
173    GROUP BY
174      pais_id,
175      pais_relacion_id,
176      anyo
177    ORDER BY anyo, rank) as principales
178    WHERE
179      principales.rank < %s;
180    """
181   
182    querys[COMERCIO_EXTERIOR_EXTRAALBA] = """
183    SELECT * FROM
184     (SELECT
185      DISTINCT(pais_id) as pais,
186      pais_relacion_id as pais_relacion,
187      SUM(monto) as valor,
188      anyo,
189      rank() OVER (PARTITION BY anyo ORDER BY SUM(monto) DESC)
190    FROM
191      public.comun_comercio
192    WHERE
193      flujo_comercial = %s and
194      pais_id in (SELECT pais_id FROM comun_pais WHERE not anyo_inclusion > 0)
195    GROUP BY
196      pais_id,
197      pais_relacion_id,
198      anyo
199    ORDER BY anyo, rank) as principales
200    WHERE
201      principales.rank < %s;
202    """
203    with transaction.commit_on_success():
204   
205        try:
206            cursor.execute("DELETE FROM comun_paisesprincipales;")
207            transaction.commit_unless_managed()
208           
209            for item_comercio_exterior in comercio_exterior:
210                for item_flujo in flujo:
211                    cursor.execute(querys[item_comercio_exterior], [item_flujo, cantidad + 1])
212                    filas = dictfetchall(cursor)
213                   
214                    pais_principal = PaisesPrincipales()
215                    for fila in filas:
216                        pais_principal.flujo_comercial = item_flujo
217                        pais_principal.comercio_exterior = item_comercio_exterior
218                        pais_principal.pais = Pais.objects.get(id = fila['pais'])
219                        pais_principal.pais_relacion = Pais.objects.get(id = fila['pais_relacion'])
220                        pais_principal.valor = fila['valor']
221                        pais_principal.anyo = fila['anyo']
222                       
223                        pais_principal.save()
224                        pais_principal = PaisesPrincipales()
225        except Exception as e:
226            logger.fatal('Exception ejecutando la carga de Paises Principales: %s' % e)
227            transaction.rollback()
228           
229            raise e
230
231@task
232def cargar_comercio_exterior(nombre_usuario, pais, anyo, mes, archivo):
233    usuario, procesando, carga_masiva = prepare_carga_masiva(nombre_usuario, pais, FLUJO_COMERCIAL_COMERCIO_EXTERIOR, mes, anyo)
234   
235    variables = {'pais': _(pais), 'mes': mes, 'anyo': anyo}
236    cur_language = translation.get_language()
237    plantilla = 'carga/%s/notificacion_comercio_exterior.mail' % cur_language
238   
239    if procesando:
240        variables['errores_csv'] = [_('archivo_procesando')]
241        enviar_email(usuario.email, plantilla, _('titulo_correo_comercio_exterior'), variables)
242        return None
243    else:
244        parametros = {'pais': pais, 'mes': mes, 'anyo': anyo}
245       
246        nexo = ComercioExteriorNexo(parametros)
247       
248        columnas = []
249        indice = 0
250       
251        validador = ValidadorColumna(EXPR_REG_ENTERO, 'error_campo_no_entero')
252        columnas.append(ColumnaCSV(indice, 'flujo_comercial', validador))
253       
254        indice += 1
255        validador = ValidadorColumna(EXPR_REG_CODIGO_ARANCELARIO, 'error_campo_no_entero')
256        columnas.append(ColumnaCSV(indice, 'codigo_armonizado', validador))
257        """
258        indice += 1
259        validador = ValidadorColumna(EXPR_REG_CIIU, _('error_campo_no_entero'))
260        columnas.append(ColumnaCSV(indice, 'ciiu', validador))
261        """
262        indice += 1
263        validador = ValidadorColumna(EXPR_REG_PAIS, 'error_formato_pais')
264        columna_pais_relacion = ColumnaCSV(indice, 'pais_relacion', validador)
265        columnas.append(columna_pais_relacion)
266        """
267        indice += 1
268        validador = ValidadorColumna(EXPR_REG_STRING_150, _('error_longitud_string'))
269        columnas.append(ColumnaCSV(indice, 'identificacion_tributaria', validador))
270       
271        indice += 1
272        validador = ValidadorColumna(EXPR_REG_STRING_150, _('error_longitud_string'))
273        columnas.append(ColumnaCSV(indice, 'nombre_unidad_economica', validador))
274        """
275        indice += 1
276        validador = ValidadorColumna(EXPR_REG_STRING_150, 'error_longitud_string')
277        columnas.append(ColumnaCSV(indice, 'unidad_medida', validador))
278       
279        indice += 1
280        validador = ValidadorColumna(EXPR_REG_ENTERO, 'error_campo_no_entero')
281        columnas.append(ColumnaCSV(indice, 'cantidad', validador))
282       
283        indice += 1
284        validador = ValidadorColumna(EXPR_REG_DECIMAL, 'error_campo_no_decimal')
285        columnas.append(ColumnaCSV(indice, 'monto', validador))
286       
287        conjuntos = []
288       
289        validador = ValidadorConjunto(Expresion.DISTINTO, 'error_pais_relacion')
290        conjuntos.append(ConjuntoCSV(columna_pais_relacion.indice, pais, validador, segundo_es_valor = True))
291       
292        csv_flujo = FlujoCSV()
293        try:
294            csv_flujo.cargar_fichero(archivo, columnas, nexo, conjuntos)
295        except Exception:
296            logger.critical('Error cargando el archivo')
297           
298            error = ErrorCSV(fila = None, columna = None, error = 'error_cargando_archivo')
299            csv_flujo.errores_csv.append(error)
300            csv_flujo.errores_trans.append(_('error_cargando_archivo'))
301           
302            variables['errores_csv'] = csv_flujo.errores_trans
303            enviar_email(usuario.email, plantilla, _('titulo_correo_comercio_exterior'), variables)
304           
305            return None
306        finally:
307            if len(csv_flujo.errores_csv) > 0:
308                for error_csv in csv_flujo.errores_csv:
309                    error = Error()
310                    error.carga_masiva = carga_masiva
311                    error.fila = error_csv.fila
312                    error.columna = error_csv.columna
313                    error.error = error_csv.error
314                    error.save()
315                   
316                carga_masiva.errores = True
317               
318                variables['errores_csv'] = csv_flujo.errores_trans
319            else:
320                carga_masiva.errores = False
321               
322                try:
323                    identificar_bienes_principales(settings.NUMERO_MAXIMO_REGISTROS_FICHAS_PRINCIPALES)
324                    identificar_paises_principales(settings.NUMERO_MAXIMO_REGISTROS_FICHAS_PRINCIPALES)
325                except Exception as e:
326                    error = ErrorCSV(fila = None, columna = None, error = 'error_actualizando_fichas')
327                    csv_flujo.errores_csv.append(error)
328                    csv_flujo.errores_trans.append(_('error_actualizando_fichas'))
329           
330                    variables['errores_csv'] = csv_flujo.errores_trans
331                    enviar_email(usuario.email, plantilla, _('titulo_correo_comercio_exterior'), variables)
332           
333            carga_masiva.procesando = False
334            carga_masiva.save()
335           
336            enviar_email(usuario.email, plantilla, _('titulo_correo_comercio_exterior'), variables)
337    return 0
338   
339@task
340def cargar_produccion_nacional(nombre_usuario, pais, anyo, mes, archivo):
341    """
342    Tarea para cargar la produccion nacional de un pais
343    """
344    usuario, procesando, carga_masiva = prepare_carga_masiva(nombre_usuario, pais, FLUJO_COMERCIAL_PRODUCCION_NACIONAL, mes, anyo)
345   
346    variables = {'pais': pais, 'mes': mes, 'anyo': anyo}
347    cur_language = translation.get_language()
348    plantilla = 'carga/%s/notificacion_comercio_exterior.mail' % cur_language
349   
350    if procesando:
351        variables['errores_csv'] = [_('archivo_procesando')]
352        enviar_email(usuario.email, plantilla, _('titulo_correo_produccion_nacional'), variables)
353        return None
354    else:
355        parametros = {'pais': pais, 'mes': mes, 'anyo': anyo, 'flujo': FLUJO_COMERCIAL_PRODUCCION_NACIONAL}
356       
357        nexo = ComercioExteriorNexo(parametros)
358       
359        columnas = []
360        indice = 0
361       
362        validador = ValidadorColumna(EXPR_REG_CODIGO_ARANCELARIO, _('error_campo_no_entero'))
363        columnas.append(ColumnaCSV(indice, 'codigo_armonizado', validador))
364       
365        indice += 1
366        validador = ValidadorColumna(EXPR_REG_CIIU, _('error_campo_no_entero'))
367        columnas.append(ColumnaCSV(indice, 'ciiu', validador))
368       
369        indice += 1
370        validador = ValidadorColumna(EXPR_REG_STRING_150, _('error_longitud_string'))
371        columnas.append(ColumnaCSV(indice, 'identificacion_tributaria', validador))
372       
373        indice += 1
374        validador = ValidadorColumna(EXPR_REG_STRING_150, _('error_longitud_string'))
375        columnas.append(ColumnaCSV(indice, 'nombre_unidad_economica', validador))
376       
377        indice += 1
378        validador = ValidadorColumna(EXPR_REG_STRING_150, _('error_longitud_string'))
379        columnas.append(ColumnaCSV(indice, 'unidad_medida', validador))
380       
381        indice += 1
382        validador = ValidadorColumna(EXPR_REG_ENTERO, _('error_campo_no_entero'))
383        columnas.append(ColumnaCSV(indice, 'cantidad', validador))
384       
385        indice += 1
386        validador = ValidadorColumna(EXPR_REG_DECIMAL, _('error_campo_no_decimal'))
387        columnas.append(ColumnaCSV(indice, 'monto', validador))
388       
389        csv_flujo = FlujoCSV()
390        try:
391            csv_flujo.cargar_fichero(archivo, columnas, nexo)
392        except Exception:
393            logger.critical('Error cargando el archivo')
394            csv_flujo.errores_csv.append(_('error_cargando_archivo'))
395           
396            variables['errores_csv'] = csv_flujo.errores_csv
397            enviar_email(usuario.email, plantilla, _('titulo_correo_produccion_nacional'), variables)
398           
399            return None
400        finally:
401            if len(csv_flujo.errores_csv) > 0:
402                for error in csv_flujo.errores_csv:
403                    error_csv = ErrorCSV()
404                    error_csv.carga_masiva = carga_masiva
405                    error_csv.error = error
406                   
407                    error_csv.save()
408                   
409                carga_masiva.errores_csv = True
410               
411                variables['errores_csv'] = csv_flujo.errores_csv
412            else:
413                carga_masiva.errores_csv = False
414           
415            carga_masiva.procesando = False
416            carga_masiva.save()
417           
418            enviar_email(usuario.email, plantilla, _('titulo_correo_produccion_nacional'), variables)
419    return 0
Note: See TracBrowser for help on using the repository browser.