# -*- coding: utf-8 -*- import os import logging import time import smtplib from datetime import datetime, date from django.contrib.auth.models import User from django.core.exceptions import ObjectDoesNotExist from django.db.models import Sum, Count from django.template.loader import get_template from django.template.context import Context from django.core.mail import send_mail from celery.task import task from django.utils import translation from django.utils.translation import ugettext_lazy as _l, ugettext as _ from comun.csv_unicode import fichero_unicode, unicode_csv_reader from comun.models import Error, CargaMasiva, Comercio, \ BienesComerciadosPrincipales, Pais, \ CodigoArmonizado, PaisesPrincipales from carga.models import ComercioExteriorNexo from comun.procesar_csv import ValidadorColumna, Expresion, ValidadorConjunto, ColumnaCSV, ConjuntoCSV, FlujoCSV, ErrorCSV from comun.utilidades import dictfetchall from comun.constantes import IMPORTACIONES, EXPORTACIONES, CMASIVA_MAX_SEC, \ EXPR_REG_ENTERO, EXPR_REG_CODIGO_ARANCELARIO, EXPR_REG_CIIU, \ EXPR_REG_PAIS, EXPR_REG_DECIMAL, EXPR_REG_STRING_150, \ EXPR_REG_ANYO, EXPR_REG_FECHA, EXPR_REG_MES, \ FLUJO_COMERCIAL_PRODUCCION_NACIONAL, FLUJO_COMERCIAL_COMERCIO_EXTERIOR, \ COMERCIO_EXTERIOR_INTRAALBA, COMERCIO_EXTERIOR_EXTRAALBA from django.conf import settings from django.db import connection, transaction logger = logging.getLogger("carga.procesarcsv") def enviar_email(correo, plantilla, titulo, variables): try: t = get_template(plantilla) c = Context(variables) send_mail(titulo, t.render(c), settings.EMAIL_FROM, [correo], fail_silently=False) except smtplib.SMTPException as e: logger.fatal('El correo no pudo ser enviado: smtpException ' + e) except Exception as e: logger.fatal('El correo no pudo ser enviado: ' + e) def prepare_carga_masiva(username, pais, flujo_comercial, mes, anyo): usuario = User.objects.get(username=username) try: proceso_carga_masiva = CargaMasiva.objects.get(usuario=usuario, pais=pais, flujo_comercial=flujo_comercial, mes=mes, anyo=anyo, procesando=True) if (datetime.now() - proceso_carga_masiva.fecha).seconds >= CMASIVA_MAX_SEC: proceso_carga_masiva.fecha = datetime.now() proceso_carga_masiva.procesando = False proceso_carga_masiva.save() carga_masiva = CargaMasiva(usuario=usuario, fecha=datetime.now(), pais=pais, flujo_comercial=flujo_comercial, mes=mes, anyo=anyo, procesando=True) carga_masiva.save() return usuario, False, carga_masiva else: return usuario, True, proceso_carga_masiva except ObjectDoesNotExist: carga_masiva = CargaMasiva(usuario=usuario, fecha=datetime.now(), pais=pais, flujo_comercial=flujo_comercial, mes=mes, anyo=anyo, procesando=True) carga_masiva.save() return usuario, False, carga_masiva def identificar_bienes_principales(cantidad): """ Algoritmo para identificar los bienes principales con relacion a dentro del flujo de comercio registrado """ comercio_exterior = [COMERCIO_EXTERIOR_INTRAALBA, COMERCIO_EXTERIOR_EXTRAALBA] flujo = [IMPORTACIONES, EXPORTACIONES] querys = {} cursor = connection.cursor() querys[COMERCIO_EXTERIOR_INTRAALBA] = """ SELECT * FROM (SELECT DISTINCT(codigo_armonizado_id) as codigo_armonizado, pais_id as pais, SUM(monto) as valor, anyo, rank() OVER (PARTITION BY anyo ORDER BY SUM(monto) DESC) as rango_monto FROM public.comun_comercio WHERE flujo_comercial = %s and pais_id in (SELECT pais_id FROM comun_pais WHERE anyo_inclusion > 0) GROUP BY pais_id, codigo_armonizado_id, anyo ORDER BY codigo_armonizado, rango_monto) as principales WHERE principales.rango_monto < %s; """ querys[COMERCIO_EXTERIOR_EXTRAALBA] = """ SELECT * FROM (SELECT DISTINCT(codigo_armonizado_id) as codigo_armonizado, pais_id as pais, SUM(monto) as valor, anyo, rank() OVER (PARTITION BY anyo ORDER BY SUM(monto) DESC) as rango_monto FROM public.comun_comercio WHERE flujo_comercial = %s and pais_id in (SELECT pais_id FROM comun_pais WHERE not anyo_inclusion > 0) GROUP BY pais_id, codigo_armonizado_id, anyo ORDER BY codigo_armonizado, rango_monto) as principales WHERE principales.rango_monto < %s; """ with transaction.commit_on_success(): try: cursor.execute("DELETE FROM comun_bienescomerciadosprincipales;") transaction.commit_unless_managed() for item_comercio_exterior in comercio_exterior: for item_flujo in flujo: cursor.execute(querys[item_comercio_exterior], [item_flujo, cantidad + 1]) filas = dictfetchall(cursor) bien_principal = BienesComerciadosPrincipales() for fila in filas: bien_principal.flujo_comercial = item_flujo bien_principal.comercio_exterior = item_comercio_exterior bien_principal.codigo_armonizado = CodigoArmonizado.objects.get(id = fila['codigo_armonizado']) bien_principal.pais = Pais.objects.get(id = fila['pais']) bien_principal.valor = fila['valor'] bien_principal.anyo = fila['anyo'] bien_principal.save() bien_principal = BienesComerciadosPrincipales() except Exception as e: logger.fatal('Exception ejecutando la carga de Bienes Principales: %s' % e) transaction.rollback() raise e def identificar_paises_principales(cantidad): """ Algoritmo para identificar los paises principales con relacion a dentro del flujo de comercio registrado """ comercio_exterior = [COMERCIO_EXTERIOR_INTRAALBA, COMERCIO_EXTERIOR_EXTRAALBA] flujo = [IMPORTACIONES, EXPORTACIONES] querys = {} cursor = connection.cursor() querys[COMERCIO_EXTERIOR_INTRAALBA] = """ SELECT * FROM (SELECT DISTINCT(pais_id) as pais, pais_relacion_id as pais_relacion, SUM(monto) as valor, anyo, rank() OVER (PARTITION BY anyo ORDER BY SUM(monto) DESC) FROM public.comun_comercio WHERE flujo_comercial = %s and pais_id in (SELECT pais_id FROM comun_pais WHERE anyo_inclusion > 0) GROUP BY pais_id, pais_relacion_id, anyo ORDER BY anyo, rank) as principales WHERE principales.rank < %s; """ querys[COMERCIO_EXTERIOR_EXTRAALBA] = """ SELECT * FROM (SELECT DISTINCT(pais_id) as pais, pais_relacion_id as pais_relacion, SUM(monto) as valor, anyo, rank() OVER (PARTITION BY anyo ORDER BY SUM(monto) DESC) FROM public.comun_comercio WHERE flujo_comercial = %s and pais_id in (SELECT pais_id FROM comun_pais WHERE not anyo_inclusion > 0) GROUP BY pais_id, pais_relacion_id, anyo ORDER BY anyo, rank) as principales WHERE principales.rank < %s; """ with transaction.commit_on_success(): try: cursor.execute("DELETE FROM comun_paisesprincipales;") transaction.commit_unless_managed() for item_comercio_exterior in comercio_exterior: for item_flujo in flujo: cursor.execute(querys[item_comercio_exterior], [item_flujo, cantidad + 1]) filas = dictfetchall(cursor) pais_principal = PaisesPrincipales() for fila in filas: pais_principal.flujo_comercial = item_flujo pais_principal.comercio_exterior = item_comercio_exterior pais_principal.pais = Pais.objects.get(id = fila['pais']) pais_principal.pais_relacion = Pais.objects.get(id = fila['pais_relacion']) pais_principal.valor = fila['valor'] pais_principal.anyo = fila['anyo'] pais_principal.save() pais_principal = PaisesPrincipales() except Exception as e: logger.fatal('Exception ejecutando la carga de Paises Principales: %s' % e) transaction.rollback() raise e @task def cargar_comercio_exterior(nombre_usuario, pais, anyo, mes, archivo): usuario, procesando, carga_masiva = prepare_carga_masiva(nombre_usuario, pais, FLUJO_COMERCIAL_COMERCIO_EXTERIOR, mes, anyo) variables = {'pais': _(pais), 'mes': mes, 'anyo': anyo} cur_language = translation.get_language() plantilla = 'carga/%s/notificacion_comercio_exterior.mail' % cur_language if procesando: variables['errores_csv'] = [_('archivo_procesando')] enviar_email(usuario.email, plantilla, _('titulo_correo_comercio_exterior'), variables) return None else: parametros = {'pais': pais, 'mes': mes, 'anyo': anyo} nexo = ComercioExteriorNexo(parametros) columnas = [] indice = 0 validador = ValidadorColumna(EXPR_REG_ENTERO, 'error_campo_no_entero') columnas.append(ColumnaCSV(indice, 'flujo_comercial', validador)) indice += 1 validador = ValidadorColumna(EXPR_REG_CODIGO_ARANCELARIO, 'error_campo_no_entero') columnas.append(ColumnaCSV(indice, 'codigo_armonizado', validador)) """ indice += 1 validador = ValidadorColumna(EXPR_REG_CIIU, _('error_campo_no_entero')) columnas.append(ColumnaCSV(indice, 'ciiu', validador)) """ indice += 1 validador = ValidadorColumna(EXPR_REG_PAIS, 'error_formato_pais') columna_pais_relacion = ColumnaCSV(indice, 'pais_relacion', validador) columnas.append(columna_pais_relacion) """ indice += 1 validador = ValidadorColumna(EXPR_REG_STRING_150, _('error_longitud_string')) columnas.append(ColumnaCSV(indice, 'identificacion_tributaria', validador)) indice += 1 validador = ValidadorColumna(EXPR_REG_STRING_150, _('error_longitud_string')) columnas.append(ColumnaCSV(indice, 'nombre_unidad_economica', validador)) """ indice += 1 validador = ValidadorColumna(EXPR_REG_STRING_150, 'error_longitud_string') columnas.append(ColumnaCSV(indice, 'unidad_medida', validador)) indice += 1 validador = ValidadorColumna(EXPR_REG_ENTERO, 'error_campo_no_entero') columnas.append(ColumnaCSV(indice, 'cantidad', validador)) indice += 1 validador = ValidadorColumna(EXPR_REG_DECIMAL, 'error_campo_no_decimal') columnas.append(ColumnaCSV(indice, 'monto', validador)) conjuntos = [] validador = ValidadorConjunto(Expresion.DISTINTO, 'error_pais_relacion') conjuntos.append(ConjuntoCSV(columna_pais_relacion.indice, pais, validador, segundo_es_valor = True)) csv_flujo = FlujoCSV() try: csv_flujo.cargar_fichero(archivo, columnas, nexo, conjuntos) except Exception: logger.critical('Error cargando el archivo') error = ErrorCSV(fila = None, columna = None, error = 'error_cargando_archivo') csv_flujo.errores_csv.append(error) csv_flujo.errores_trans.append(_('error_cargando_archivo')) variables['errores_csv'] = csv_flujo.errores_trans enviar_email(usuario.email, plantilla, _('titulo_correo_comercio_exterior'), variables) return None finally: if len(csv_flujo.errores_csv) > 0: for error_csv in csv_flujo.errores_csv: error = Error() error.carga_masiva = carga_masiva error.fila = error_csv.fila error.columna = error_csv.columna error.error = error_csv.error error.save() carga_masiva.errores = True variables['errores_csv'] = csv_flujo.errores_trans else: carga_masiva.errores = False try: identificar_bienes_principales(settings.NUMERO_MAXIMO_REGISTROS_FICHAS_PRINCIPALES) identificar_paises_principales(settings.NUMERO_MAXIMO_REGISTROS_FICHAS_PRINCIPALES) except Exception as e: error = ErrorCSV(fila = None, columna = None, error = 'error_actualizando_fichas') csv_flujo.errores_csv.append(error) csv_flujo.errores_trans.append(_('error_actualizando_fichas')) variables['errores_csv'] = csv_flujo.errores_trans enviar_email(usuario.email, plantilla, _('titulo_correo_comercio_exterior'), variables) carga_masiva.procesando = False carga_masiva.save() enviar_email(usuario.email, plantilla, _('titulo_correo_comercio_exterior'), variables) return 0 @task def cargar_produccion_nacional(nombre_usuario, pais, anyo, mes, archivo): """ Tarea para cargar la produccion nacional de un pais """ usuario, procesando, carga_masiva = prepare_carga_masiva(nombre_usuario, pais, FLUJO_COMERCIAL_PRODUCCION_NACIONAL, mes, anyo) variables = {'pais': pais, 'mes': mes, 'anyo': anyo} cur_language = translation.get_language() plantilla = 'carga/%s/notificacion_comercio_exterior.mail' % cur_language if procesando: variables['errores_csv'] = [_('archivo_procesando')] enviar_email(usuario.email, plantilla, _('titulo_correo_produccion_nacional'), variables) return None else: parametros = {'pais': pais, 'mes': mes, 'anyo': anyo, 'flujo': FLUJO_COMERCIAL_PRODUCCION_NACIONAL} nexo = ComercioExteriorNexo(parametros) columnas = [] indice = 0 validador = ValidadorColumna(EXPR_REG_CODIGO_ARANCELARIO, _('error_campo_no_entero')) columnas.append(ColumnaCSV(indice, 'codigo_armonizado', validador)) indice += 1 validador = ValidadorColumna(EXPR_REG_CIIU, _('error_campo_no_entero')) columnas.append(ColumnaCSV(indice, 'ciiu', validador)) indice += 1 validador = ValidadorColumna(EXPR_REG_STRING_150, _('error_longitud_string')) columnas.append(ColumnaCSV(indice, 'identificacion_tributaria', validador)) indice += 1 validador = ValidadorColumna(EXPR_REG_STRING_150, _('error_longitud_string')) columnas.append(ColumnaCSV(indice, 'nombre_unidad_economica', validador)) indice += 1 validador = ValidadorColumna(EXPR_REG_STRING_150, _('error_longitud_string')) columnas.append(ColumnaCSV(indice, 'unidad_medida', validador)) indice += 1 validador = ValidadorColumna(EXPR_REG_ENTERO, _('error_campo_no_entero')) columnas.append(ColumnaCSV(indice, 'cantidad', validador)) indice += 1 validador = ValidadorColumna(EXPR_REG_DECIMAL, _('error_campo_no_decimal')) columnas.append(ColumnaCSV(indice, 'monto', validador)) csv_flujo = FlujoCSV() try: csv_flujo.cargar_fichero(archivo, columnas, nexo) except Exception: logger.critical('Error cargando el archivo') csv_flujo.errores_csv.append(_('error_cargando_archivo')) variables['errores_csv'] = csv_flujo.errores_csv enviar_email(usuario.email, plantilla, _('titulo_correo_produccion_nacional'), variables) return None finally: if len(csv_flujo.errores_csv) > 0: for error in csv_flujo.errores_csv: error_csv = ErrorCSV() error_csv.carga_masiva = carga_masiva error_csv.error = error error_csv.save() carga_masiva.errores_csv = True variables['errores_csv'] = csv_flujo.errores_csv else: carga_masiva.errores_csv = False carga_masiva.procesando = False carga_masiva.save() enviar_email(usuario.email, plantilla, _('titulo_correo_produccion_nacional'), variables) return 0