@ -1,9 +1,14 @@
#-*- coding: utf-8 -*-
#-*- coding: utf-8 -*-
import re
import re
import requests
from datetime import datetime , date
from datetime import datetime , date
from django . db import models
from django . db import models
from django . db . models import Q
from django . core . mail import send_mail
from django . core . urlresolvers import reverse
from django . utils . translation import ugettext as _
from django . utils . translation import ugettext as _
from sigi . apps . utils import SearchField
from sigi . apps . utils import SearchField , to_ascii
from sigi . apps . casas . models import Orgao
from sigi . apps . servidores . models import Servidor , Servico
from sigi . apps . servidores . models import Servidor , Servico
class Projeto ( models . Model ) :
class Projeto ( models . Model ) :
@ -360,3 +365,383 @@ class Tramitacao(models.Model):
if self . observacao :
if self . observacao :
result = result + u " ( %s ) " % ( self . observacao )
result = result + u " ( %s ) " % ( self . observacao )
return unicode ( result ) # XXX is this unicode(...) really necessary???
return unicode ( result ) # XXX is this unicode(...) really necessary???
class Gescon ( models . Model ) :
url_gescon = models . URLField (
_ ( u " Webservice Gescon " ) ,
default = ( u " https://adm.senado.gov.br/gestao-contratos/api/contratos "
u " /busca?especie= {s} " ) ,
help_text = _ ( u " Informe o ponto de consulta do webservice do Gescon, "
u " inclusive com a querystring. No ponto onde deve ser "
u " inserida a sigla da subespecie do contrato, use a "
u " marcação {s} .<br/><strong>Por exemplo:</strong> "
u " https://adm.senado.gov.br/gestao-contratos/api/contratos "
u " /busca?especie=<strong> {s} </strong> " )
)
subespecies = models . TextField (
_ ( u " Subespécies " ) ,
default = u " AC=ACT \n PI=PI \n CN=PML \n TA=PML " ,
help_text = _ ( u " Informe as siglas das subespécies de contratos que "
u " devem ser pesquisados no Gescon com a sigla "
u " correspondente do projeto no SIGI. Coloque um par de "
u " siglas por linha, no formato SIGLA_GESTON=SIGLA_SIGI. "
u " As siglas não encontradas serão ignoradas. " )
)
palavras = models . TextField (
_ ( u " Palavras de filtro " ) ,
default = u " ILB \n INTERLEGIS " ,
help_text = _ ( u " Palavras que devem aparecer no campo OBJETO dos dados do "
u " Gescon para identificar se o contrato pertence ao ILB. "
u " <ul><li>Informe uma palavra por linha.</li> "
u " <li>Ocorrendo qualquer uma das palavras, o contrato será "
u " importado.</li></ul> " )
)
email = models . EmailField (
_ ( u " E-mail " ) ,
help_text = _ ( u " Caixa de e-mail para onde o relatório diário de "
u " importação será enviado. " )
)
ultima_importacao = models . TextField (
_ ( u " Resultado da última importação " ) ,
blank = True
)
class Meta :
verbose_name = _ ( u " Configuração do Gescon " )
verbose_name_plural = _ ( u " Configurações do Gescon " )
def __unicode__ ( self ) :
return self . url_gescon
def save ( self , * args , * * kwargs ) :
self . pk = 1 # Highlander (singleton pattern)
return super ( Gescon , self ) . save ( * args , * * kwargs )
def delete ( self , * args , * * kwargs ) :
pass # Highlander is immortal
def add_message ( self , msg , save = False ) :
self . ultima_importacao + = msg + " \n "
if save :
self . save ( )
self . email_report ( )
def email_report ( self ) :
if self . email :
send_mail (
subject = _ ( u " Relatório de importação GESCON " ) ,
message = self . ultima_importacao ,
recipient_list = self . email ,
fail_silently = True
)
else :
self . ultima_importacao + = _ (
u " \n \n *Não foi definida uma caixa de e-mail nas configurações "
u " do Gescon* "
)
self . save ( )
def importa_contratos ( self ) :
self . ultima_importacao = " "
self . add_message (
_ ( u " Importação iniciada em { : %d / % m/ % Y % H: % M: % S} \n "
u " ========================================== \n " ) . format (
datetime . now ( )
)
)
if self . palavras == " " :
self . add_message ( _ ( u " Nenhuma palavra de pesquisa definida - "
u " processo abortado. " ) , True )
return
if self . subespecies == " " :
self . add_message ( _ ( u " Nenhuma subespécie definida - processo "
u " abortado. " ) , True )
return
if " {s} " not in self . url_gescon :
self . add_message (
_ (
u " Falta a marcação {s} na URL para indicar o local onde "
u " inserir a sigla da subespécia na consulta ao webservice "
u " - processo abortado. "
) ,
True
)
return
palavras = self . palavras . split ( )
subespecies = { tuple ( s . split ( " = " ) ) for s in self . subespecies . split ( ) }
for sigla_gescon , sigla_sigi in subespecies :
self . add_message ( _ ( u " \n Importando subespécie {s} " . format (
s = sigla_gescon ) ) )
url = self . url_gescon . format ( s = sigla_gescon )
projeto = Projeto . objects . get ( sigla = sigla_sigi )
try :
response = requests . get ( url )
except Exception as e :
self . add_message (
_ ( u " \t Erro ao acessar {url} : {errmsg} " ) . format (
url = url ,
errmsg = str ( e )
)
)
continue
if not response . ok :
self . add_message (
_ ( u " \t Erro ao acessar {url} : {reason} " ) . format (
url = url ,
reason = response . reason
)
)
continue
if not ' application/json ' in response . headers . get ( ' Content-Type ' ) :
self . add_message ( _ ( u " \t Resultado da consulta à {url} não "
u " retornou dados em formato json " ) . format (
url = url
)
)
continue
contratos = response . json ( )
# Pegar só os contratos que possuem alguma das palavras-chave
nossos = [ c for c in contratos
if any ( palavra in c [ ' objeto ' ] for palavra in palavras ) ]
self . add_message (
_ ( u " \t {count} contratos encontrados no Gescon " ) . format (
count = len ( nossos )
)
)
novos = 0
erros = 0
verificados = 0
atualizados = 0
for contrato in nossos :
numero = contrato [ ' numero ' ] . zfill ( 8 )
numero = " {} / {} " . format ( numero [ : 4 ] , numero [ 4 : ] )
sigad = contrato [ ' processo ' ] . zfill ( 17 )
sigad = " {} . {} / {} - {} " . format ( sigad [ : 5 ] , sigad [ 5 : 11 ] ,
sigad [ 11 : 15 ] , sigad [ 15 : ] )
if contrato [ ' cnpjCpfFornecedor ' ] :
cnpj = contrato [ ' cnpjCpfFornecedor ' ] . zfill ( 14 )
cnpj = " {} . {} . {} / {} - {} " . format ( cnpj [ : 2 ] , cnpj [ 2 : 5 ] ,
cnpj [ 5 : 8 ] , cnpj [ 8 : 12 ] ,
cnpj [ 12 : ] )
else :
cnpj = None
if contrato [ ' nomeFornecedor ' ] :
nome = contrato [ ' nomeFornecedor ' ]
nome = nome . replace ( u ' VEREADORES DE ' , ' ' )
nome = nome . split ( ' - ' ) [ 0 ]
nome = nome . split ( ' / ' ) [ 0 ]
nome = nome . strip ( )
nome = nome . replace ( " " , " " )
nome = to_ascii ( nome )
else :
nome = None
if ( cnpj is None ) and ( nome is None ) :
self . add_message (
_ ( u " \t O contrato {numero} no Gescon não informa o CNPJ "
u " nem o nome do órgão. " ) . format ( numero = numero )
)
erros + = 1
continue
orgao = None
if cnpj is not None :
try :
orgao = Orgao . objects . get ( cnpj = cnpj )
except (
Orgao . DoesNotExist ,
Orgao . MultipleObjectsReturned ) as e :
orgao = None
pass
if ( orgao is None ) and ( nome is not None ) :
try :
orgao = Orgao . objects . get ( search_text__iexact = nome )
except (
Orgao . DoesNotExist ,
Orgao . MultipleObjectsReturned ) as e :
orgao = None
pass
if orgao is None :
self . add_message (
_ ( u " \t Órgão não encontrado no SIGI ou mais de um órgão "
u " encontrado com o mesmo CNPJ ou nome. Favor "
u " regularizar o cadastro: CNPJ: {cnpj} , "
u " Nome: {nome} " . format (
cnpj = contrato [ ' cnpjCpfFornecedor ' ] ,
nome = contrato [ ' nomeFornecedor ' ]
)
)
)
erros + = 1
continue
# O mais seguro é o NUP sigad
convenios = Convenio . objects . filter ( num_processo_sf = sigad )
chk = convenios . count ( )
if chk == 0 :
# NUP não encontrado, talvez exista apenas com o número
# do GESCON
convenios = Convenio . objects . filter (
Q ( num_convenio = numero ) |
Q ( num_processo_sf = numero )
)
chk = convenios . count ( )
if chk == 0 :
convenio = Convenio (
casa_legislativa = orgao ,
projeto = projeto ,
num_processo_sf = sigad ,
num_convenio = numero ,
data_sigi = date . today ( ) ,
data_sigad = contrato [ ' assinatura ' ] ,
observacao = contrato [ ' objeto ' ] ,
data_retorno_assinatura = contrato [ ' inicioVigencia ' ] ,
data_termino_vigencia = contrato [ ' terminoVigencia ' ] ,
data_pub_diario = contrato [ ' publicacao ' ]
)
convenio . save ( )
novos + = 1
elif chk == 1 :
convenio = convenios . get ( )
if convenio . casa_legislativa != orgao :
self . add_message (
_ ( u " \t O órgao no convênio {url} diverge do que "
u " consta no Gescon ( {cnpj} , {nome} ) " ) . format (
url = reverse ( ' admin: %s _ %s _change ' % (
convenio . _meta . app_label ,
convenio . _meta . model_name ) ,
args = [ convenio . id ] ) ,
cnpj = cnpj ,
nome = contrato [ ' nomeFornecedor ' ]
)
)
erros + = 1
continue
if convenio . num_processo_sf != sigad :
sigi_nums = filter (
type ( convenio . num_processo_sf ) . isdigit ,
convenio . num_processo_sf
) . zfill ( 17 )
gesc_nums = filter ( type ( sigad ) . isdigit , sigad ) . zfill ( 17 )
if ( sigi_nums == gesc_nums or
convenio . num_processo_sf == " " ) :
# Número SIGAD incorreto no SIGI, podemos corrigir
convenio . num_processso_sf = sigad
convenio . save ( )
else :
self . add_message (
_ ( u " \t O contrato Gescon nº {numero} corresponde "
u " ao convênio SIGI {url} , mas o NUP sigad "
u " diverge (Gescon: {sigad_gescon} , "
u " SIGI: {sigad_sigi} ) " ) . format (
numero = numero ,
url = reverse ( ' admin: %s _ %s _change ' % (
convenio . _meta . app_label ,
convenio . _meta . model_name ) ,
args = [ convenio . id ] ) ,
sigad_gescon = sigad ,
sigad_sigi = convenio . num_processo_sf
)
)
erros + = 1
continue
if convenio . num_convenio != numero :
sigi_nums = filter ( type ( convenio . num_convenio ) . isdigit ,
convenio . num_convenio ) . zfill ( 8 )
gesc_nums = filter ( type ( numero ) . isdigit ,
numero ) . zfill ( 8 )
if ( sigi_nums == gesc_nums or
convenio . num_convenio == " " ) :
# Número gescon errado no SIGI mas podemos corrigir
convenio . num_convenio = numero
else :
self . add_message (
_ ( u " \t O contrato Gescon ID {id} corresponde ao "
u " convênio SIGI {url} , mas o número do convênio "
u " diverge (Gescon: {numero_gescon} , SIGI: "
u " {numero_sigi} ) " ) . format (
id = contrato [ ' id ' ] ,
url = reverse ( ' admin: %s _ %s _change ' % (
convenio . _meta . app_label ,
convenio . _meta . model_name ) ,
args = [ convenio . id ]
) ,
numero_gescon = numero ,
numero_sigi = convenio . num_convenio
)
)
erros + = 1
continue
if contrato [ ' objeto ' ] not in convenio . observacao :
convenio . observacao + = " \n " + contrato [ ' objeto ' ]
convenio . data_sigad = contrato [ ' assinatura ' ]
convenio . data_retorno_assinatura = contrato [ ' inicioVigencia ' ]
convenio . data_termino_vigencia = contrato [ ' terminoVigencia ' ]
convenio . data_pub_diario = contrato [ ' publicacao ' ]
try :
convenio . save ( )
except Exception :
import ipdb ; ipdb . set_trace ( )
print contrato
raise
atualizados + = 1
verificados + = 1
else :
self . add_message ( _ ( u " \t Existem {count} convênios no SIGI "
u " que correspondem ao mesmo contrato no "
u " Gescon (contrato {numero} , sigad "
u " {sigad} ) " ) . format (
count = chk ,
numero = numero ,
sigad = sigad
)
)
erros + = 1
continue
self . add_message (
_ ( u " \t {novos} novos convenios adicionados ao SIGI, "
u " {atualizados} atualizados, {verificados} confirmados e "
u " {erros} reportados com erro. " ) . format (
novos = novos ,
atualizados = atualizados ,
verificados = verificados ,
erros = erros
)
)
self . save ( )
@classmethod
def load ( cls ) :
obj , created = cls . objects . get_or_create ( pk = 1 )
return obj