Browse Source

Registra ocorrências de migração em arquivo

pull/1751/merge
Marcio Mazza 7 years ago
parent
commit
c50a30ebf3
  1. 163
      sapl/legacy/migracao_dados.py

163
sapl/legacy/migracao_dados.py

@ -1,5 +1,5 @@
import os
import re import re
from collections import defaultdict
from datetime import date from datetime import date
from functools import lru_cache, partial from functools import lru_cache, partial
from itertools import groupby from itertools import groupby
@ -15,7 +15,7 @@ from django.contrib.auth.models import Group
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.db import connections, transaction from django.db import connections, transaction
from django.db.models import Count, Max, Q from django.db.models import Max, Q
from django.db.models.base import ModelBase from django.db.models.base import ModelBase
from pytz import timezone from pytz import timezone
from unipath import Path from unipath import Path
@ -110,16 +110,30 @@ def get_renames():
def info(msg): def info(msg):
print('INFO: ' + msg) print('INFO: ' + msg)
ocorrencias = defaultdict(list)
def warn(msg):
print('CUIDADO! ' + msg) def warn(tipo, msg, dados):
ocorrencias[tipo].append(dados)
print('CUIDADO! ' + msg.format(**dados))
class ForeignKeyFaltando(ObjectDoesNotExist): class ForeignKeyFaltando(ObjectDoesNotExist):
'Uma FK aponta para um registro inexistente' 'Uma FK aponta para um registro inexistente'
def __init__(self, msg=''): def __init__(self, field, value, label):
self.msg = msg self.field = field
self.value = value
self.label = label
msg = 'FK [{field}] não encontrada para o valor {value} (em {model} / {label})' # noqa
@property
def dados(self):
return {'field': self.field.name,
'value': self.value,
'model': self.field.model.__name__,
'label': self.label}
@lru_cache() @lru_cache()
@ -128,7 +142,7 @@ def _get_all_ids_from_model(model):
return set(model.objects.values_list('id', flat=True)) return set(model.objects.values_list('id', flat=True))
def get_fk_related(field, value, label=None): def get_fk_related(field, value, label='---'):
if value is None and field.null: if value is None and field.null:
return None return None
@ -139,9 +153,7 @@ def get_fk_related(field, value, label=None):
# consideramos zeros como nulos, se não está entre os ids anteriores # consideramos zeros como nulos, se não está entre os ids anteriores
return None return None
else: else:
msg = 'FK [%s] não encontrada para o valor %s (em %s %s)' % ( raise ForeignKeyFaltando(field=field, value=value, label=label)
field.name, value, field.model.__name__, label or '---')
raise ForeignKeyFaltando(msg)
def exec_sql(sql, db='default'): def exec_sql(sql, db='default'):
@ -609,6 +621,7 @@ def get_pk_legado(tabela):
DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand() DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand()
PATH_TABELA_TIMEZONES = DIR_DADOS_MIGRACAO.child('tabela_timezones.yaml') PATH_TABELA_TIMEZONES = DIR_DADOS_MIGRACAO.child('tabela_timezones.yaml')
DIR_RESULTADOS = DIR_DADOS_MIGRACAO.child('resultados')
class DataMigrator: class DataMigrator:
@ -618,8 +631,8 @@ class DataMigrator:
self.choice_valida = {} self.choice_valida = {}
# configura timezone de migração # configura timezone de migração
nome_legado = DATABASES['legacy']['NAME'] self.nome_banco_legado = DATABASES['legacy']['NAME']
match = re.match('sapl_cm_(.*)', nome_legado) match = re.match('sapl_cm_(.*)', self.nome_banco_legado)
sigla_casa = match.group(1) sigla_casa = match.group(1)
with open(PATH_TABELA_TIMEZONES, 'r') as arq: with open(PATH_TABELA_TIMEZONES, 'r') as arq:
tabela_timezones = yaml.load(arq) tabela_timezones = yaml.load(arq)
@ -641,7 +654,7 @@ class DataMigrator:
if field_type == 'ForeignKey': if field_type == 'ForeignKey':
# not necessarily a model # not necessarily a model
if hasattr(old, '_meta') and old._meta.pk.name != 'id': if hasattr(old, '_meta') and old._meta.pk.name != 'id':
label = old.pk label = 'pk = {}'.format(old.pk)
else: else:
label = '-- SEM PK --' label = '-- SEM PK --'
fk_field_name = '{}_id'.format(field.name) fk_field_name = '{}_id'.format(field.name)
@ -694,7 +707,18 @@ class DataMigrator:
fill_vinculo_norma_juridica() fill_vinculo_norma_juridica()
fill_dados_basicos() fill_dados_basicos()
info('Começando migração: %s...' % obj) info('Começando migração: %s...' % obj)
self._do_migrate(obj) try:
ocorrencias.clear()
dir_ocorrencias = DIR_RESULTADOS.child(date.today().isoformat())
dir_ocorrencias.mkdir(parents=True)
self._do_migrate(obj)
finally:
# grava ocorrências
arq_ocorrencias = dir_ocorrencias.child(
self.nome_banco_legado + '.yaml')
with open(arq_ocorrencias, 'w') as arq:
yaml.safe_dump(dict(ocorrencias), arq, allow_unicode=True)
info('Ocorrências salvas em\n {}'.format(arq_ocorrencias))
# recria tipos de autor padrão que não foram criados pela migração # recria tipos de autor padrão que não foram criados pela migração
cria_models_tipo_autor() cria_models_tipo_autor()
@ -772,7 +796,7 @@ class DataMigrator:
# tentamos preencher uma FK e o ojeto relacionado # tentamos preencher uma FK e o ojeto relacionado
# não existe # não existe
# então este é um objeo órfão: simplesmente ignoramos # então este é um objeo órfão: simplesmente ignoramos
warn(e.msg) warn('fk', e.msg, e.dados)
continue continue
else: else:
if get_id_do_legado: if get_id_do_legado:
@ -841,10 +865,15 @@ pois não existe protocolo no sistema com este número no ano {ano_original}.
nota = nota.strip().format(num_protocolo=old.num_protocolo, nota = nota.strip().format(num_protocolo=old.num_protocolo,
ano_original=ano_original, ano_original=ano_original,
ano_novo=ano_novo) ano_novo=ano_novo)
warn('PROTOCOLO ENCONTRADO APENAS PARA O ANO SEGUINTE!!!!! ' msg = 'PROTOCOLO ENCONTRADO APENAS PARA O ANO SEGUINTE!!!!! '\
'DocumentoAdministrativo: {}, numero_protocolo: {}, ' 'DocumentoAdministrativo: {cod_documento}, '\
'ano doc adm: {}'.format( 'numero_protocolo: {num_protocolo}, '\
old.cod_documento, old.num_protocolo, ano_original)) 'ano doc adm: {ano_original}'
warn('protocolo_ano_seguinte', msg,
{'cod_documento': old.cod_documento,
'num_protocolo': old.num_protocolo,
'ano_original': ano_original,
'nota': nota})
else: else:
nota = NOTA_DOCADM + ''' nota = NOTA_DOCADM + '''
Não existe no sistema nenhum protocolo com estes dados Não existe no sistema nenhum protocolo com estes dados
@ -852,9 +881,12 @@ e portanto nenhum protocolo foi vinculado a este documento.'''
nota = nota.format( nota = nota.format(
num_protocolo=old.num_protocolo, num_protocolo=old.num_protocolo,
ano_original=ano_original) ano_original=ano_original)
warn('Protocolo {} faltando ' msg = 'Protocolo {num_protocolo} faltando (referenciado ' \
'(referenciado no documento administrativo {})'.format( 'no documento administrativo {cod_documento})'
old.num_protocolo, old.cod_documento)) warn('protocolo_faltando', msg,
{'num_protocolo': old.num_protocolo,
'cod_documento': old.cod_documento,
'nota': nota})
if protocolo: if protocolo:
assert len(protocolo) == 1, 'mais de um protocolo encontrado' assert len(protocolo) == 1, 'mais de um protocolo encontrado'
[new.protocolo] = protocolo [new.protocolo] = protocolo
@ -883,18 +915,10 @@ def adjust_ordemdia_antes_salvar(new, old):
if old.num_ordem is None: if old.num_ordem is None:
new.numero_ordem = 999999999 new.numero_ordem = 999999999
warn('ordem_dia_num_ordem_nulo',
'OrdemDia de PK {pk} tinha numero ordem nulo. '
def adjust_ordemdia_depois_salvar(new, old): 'O valor %s foi colocado no lugar.' % new.numero_ordem,
if old.num_ordem is None and new.numero_ordem == 999999999: {'pk': old.pk})
with reversion.create_revision():
problema = 'OrdemDia de PK %s tinha seu valor de numero ordem' \
' nulo.' % old.pk
descricao = 'O valor %s foi colocado no lugar.' % new.numero_ordem
warn(problema + ' => ' + descricao)
save_relation(obj=new, problema=problema,
descricao=descricao, eh_stub=False)
reversion.set_comment('OrdemDia sem número da ordem.')
def adjust_parlamentar(new, old): def adjust_parlamentar(new, old):
@ -904,7 +928,10 @@ def adjust_parlamentar(new, old):
# but data includes null values # but data includes null values
# => transform None to False # => transform None to False
if value is None: if value is None:
warn('nulo convertido para falso') warn('unidade_deliberativa_nulo_p_false',
'nulo convertido para falso na unidade_deliberativa '
'do parlamentar {pk_parlamentar}',
{'pk_parlamentar': old.cod_parlamentar})
new.unidade_deliberativa = False new.unidade_deliberativa = False
# migra município de residência # migra município de residência
if old.cod_localidade_resid: if old.cod_localidade_resid:
@ -950,19 +977,12 @@ def adjust_normarelacionada(new, old):
def adjust_protocolo_antes_salvar(new, old): def adjust_protocolo_antes_salvar(new, old):
if old.num_protocolo is None: if new.numero is None:
new.numero = old.cod_protocolo new.numero = old.cod_protocolo
warn('num_protocolo_nulo',
'Número do protocolo de PK {cod_protocolo} era nulo '
def adjust_protocolo_depois_salvar(new, old): 'e foi alterado para sua pk ({cod_protocolo})',
if old.num_protocolo is None: {'cod_protocolo': old.cod_protocolo})
with reversion.create_revision():
problema = 'Número do protocolo de PK %s é nulo' % new.pk
descricao = 'Número do protocolo alterado para %s!' % new.numero
warn(problema + ' => ' + descricao)
save_relation(obj=new, problema=problema,
descricao=descricao, eh_stub=False)
reversion.set_comment('Número de protocolo teve que ser alterado')
def adjust_registrovotacao_antes_salvar(new, old): def adjust_registrovotacao_antes_salvar(new, old):
@ -982,20 +1002,22 @@ def adjust_tipoafastamento(new, old):
new.indicador = 'A' new.indicador = 'A'
MODEL_TIPO_MATERIA_OU_DOCUMENTO = {'M': TipoMateriaLegislativa,
'D': TipoDocumento}
def adjust_tipoproposicao(new, old): def adjust_tipoproposicao(new, old):
if old.ind_mat_ou_doc == 'M': "Aponta para o tipo relacionado de matéria ou documento"
tipo_materia = TipoMateriaLegislativa.objects.filter( value = old.tip_mat_ou_doc
pk=old.tip_mat_ou_doc) model_tipo = MODEL_TIPO_MATERIA_OU_DOCUMENTO[old.ind_mat_ou_doc]
if tipo_materia: tipo = model_tipo.objects.filter(pk=value)
new.tipo_conteudo_related = tipo_materia[0] if tipo:
else: new.tipo_conteudo_related = tipo[0]
raise ForeignKeyFaltando else:
elif old.ind_mat_ou_doc == 'D': raise ForeignKeyFaltando(
tipo_documento = TipoDocumento.objects.filter(pk=old.tip_mat_ou_doc) field=TipoProposicao.tipo_conteudo_related,
if tipo_documento: value=(model_tipo.__name__, value),
new.tipo_conteudo_related = tipo_documento[0] label='ind_mat_ou_doc = {}'.format(old.ind_mat_ou_doc))
else:
raise ForeignKeyFaltando
def adjust_statustramitacao(new, old): def adjust_statustramitacao(new, old):
@ -1057,9 +1079,12 @@ def vincula_autor(new, old, model_relacionado, campo_relacionado, campo_nome):
new.autor_related = model_relacionado.objects.get(pk=pk_rel) new.autor_related = model_relacionado.objects.get(pk=pk_rel)
except ObjectDoesNotExist: except ObjectDoesNotExist:
# ignoramos o autor órfão # ignoramos o autor órfão
nome_model_relacionado = model_relacionado._meta.model.__name__
raise ForeignKeyFaltando( raise ForeignKeyFaltando(
'{} [pk={}] inexistente para autor'.format( field=Autor.autor_related,
model_relacionado._meta.verbose_name, pk_rel)) value=(nome_model_relacionado, pk_rel),
label='{} [pk={}] inexistente para autor'.format(
nome_model_relacionado, pk_rel))
else: else:
new.nome = getattr(new.autor_related, campo_nome) new.nome = getattr(new.autor_related, campo_nome)
return True return True
@ -1124,20 +1149,6 @@ AJUSTE_ANTES_SALVAR = {
AJUSTE_DEPOIS_SALVAR = { AJUSTE_DEPOIS_SALVAR = {
NormaJuridica: adjust_normajuridica_depois_salvar, NormaJuridica: adjust_normajuridica_depois_salvar,
OrdemDia: adjust_ordemdia_depois_salvar,
Protocolo: adjust_protocolo_depois_salvar,
} }
# CHECKS #################################################################### # CHECKS ####################################################################
def get_ind_excluido(new):
model_legado = legacy_app.get_model(type(new).__name__)
old = model_legado.objects.get(**{model_legado._meta.pk.name: new.id})
return getattr(old, 'ind_excluido', False)
def check_app_no_ind_excluido(app):
for model in app.models.values():
assert not any(get_ind_excluido(new) for new in model.objects.all())
print('OK!')

Loading…
Cancel
Save