Browse Source

Completa campos faltantes na migração + novo log

Fix #1796

Incidentalmente agora mostra estrutura do legado no log de ocorrências
Fix #1794
pull/1847/head
Marcio Mazza 7 years ago
parent
commit
bc28f2e6ae
  1. 1
      sapl/base/legacy.yaml
  2. 1
      sapl/comissoes/legacy.yaml
  3. 377
      sapl/legacy/migracao_dados.py
  4. 5
      sapl/legacy/scripts/exporta_zope/exporta_zope.py
  5. 2
      sapl/legacy/scripts/migra_um_db.sh
  6. 96
      sapl/legacy/test_renames.py
  7. 9
      sapl/materia/legacy.yaml
  8. 10
      sapl/materia/models.py
  9. 1
      sapl/norma/legacy.yaml
  10. 4
      sapl/parlamentares/legacy.yaml
  11. 1
      sapl/protocoloadm/legacy.yaml
  12. 1
      sapl/sessao/legacy.yaml
  13. 3
      sapl/sessao/models.py

1
sapl/base/legacy.yaml

@ -5,4 +5,3 @@ Autor:
nome: nom_autor
cargo: des_cargo
tipo: tip_autor
username: col_username

1
sapl/comissoes/legacy.yaml

@ -25,7 +25,6 @@ Comissao:
telefone_secretaria: num_tel_secretaria
tipo: tip_comissao
unidade_deliberativa: ind_unid_deliberativa
ativa:
Periodo (PeriodoCompComissao):
data_fim: dat_fim_periodo

377
sapl/legacy/migracao_dados.py

@ -1,31 +1,32 @@
import re
from collections import defaultdict
import traceback
from collections import OrderedDict, defaultdict, namedtuple
from datetime import date
from functools import lru_cache, partial
from itertools import groupby
from operator import xor
from subprocess import PIPE, call
import pkg_resources
import pytz
import reversion
import yaml
from django.apps import apps
from django.apps.config import AppConfig
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ObjectDoesNotExist
from django.db import connections, transaction
from django.db.models import Max, Q
from django.db.models.base import ModelBase
from pytz import timezone
from unipath import Path
from sapl.base.models import AppConfig as AppConf
from sapl.base.models import Autor, TipoAutor, cria_models_tipo_autor
from sapl.comissoes.models import Comissao, Composicao, Participacao
from sapl.legacy.models import NormaJuridica as OldNormaJuridica
from sapl.legacy.models import TipoNumeracaoProtocolo
from sapl.materia.models import (AcompanhamentoMateria, Proposicao,
StatusTramitacao, TipoDocumento,
from sapl.materia.models import (AcompanhamentoMateria, MateriaLegislativa,
Proposicao, StatusTramitacao, TipoDocumento,
TipoMateriaLegislativa, TipoProposicao,
Tramitacao)
from sapl.norma.models import (AssuntoNorma, NormaJuridica, NormaRelacionada,
@ -68,8 +69,6 @@ for a1, s1 in name_sets:
else:
assert not s1.intersection(s2)
legacy_app = apps.get_app_config('legacy')
# RENAMES ###################################################################
@ -108,6 +107,51 @@ def get_renames():
return field_renames, model_renames
field_renames, model_renames = get_renames()
legacy_app = apps.get_app_config('legacy')
models_novos_para_antigos = {
model: legacy_app.get_model(model_renames.get(model, model.__name__))
for model in field_renames}
models_novos_para_antigos[Composicao] = models_novos_para_antigos[Participacao]
content_types = {model: ContentType.objects.get(
app_label=model._meta.app_label, model=model._meta.model_name)
for model in field_renames}
campos_novos_para_antigos = {
model._meta.get_field(nome_novo): nome_antigo
for model, renames in field_renames.items()
for nome_novo, nome_antigo in renames.items()}
# campos de Composicao (de Comissao)
for nome_novo, nome_antigo in (('comissao', 'cod_comissao'),
('periodo', 'cod_periodo_comp')):
campos_novos_para_antigos[
Composicao._meta.get_field(nome_novo)] = nome_antigo
# campos virtuais de Proposicao para funcionar com get_fk_related
class CampoVirtual(namedtuple('CampoVirtual', 'model related_model')):
null = True
CAMPOS_VIRTUAIS_PROPOSICAO = {
TipoMateriaLegislativa: CampoVirtual(Proposicao, MateriaLegislativa),
TipoDocumento: CampoVirtual(Proposicao, DocumentoAdministrativo)
}
for campo_virtual in CAMPOS_VIRTUAIS_PROPOSICAO.values():
campos_novos_para_antigos[campo_virtual] = 'cod_mat_ou_doc'
# campos virtuais de Autor para funcionar com get_fk_related
CAMPOS_VIRTUAIS_AUTOR = {related: CampoVirtual(Autor, related)
for related in (Parlamentar, Comissao, Partido)}
for related, campo_antigo in [(Parlamentar, 'cod_parlamentar'),
(Comissao, 'cod_comissao'),
(Partido, 'cod_partido')]:
campo_virtual = CAMPOS_VIRTUAIS_AUTOR[related]
campos_novos_para_antigos[campo_virtual] = campo_antigo
# MIGRATION #################################################################
@ -122,22 +166,48 @@ def warn(tipo, msg, dados):
print('CUIDADO! ' + msg.format(**dados))
@lru_cache()
def get_pk_legado(tabela):
if tabela == 'despacho_inicial':
# adaptação para deleção correta no mysql ao final de migrar_model
# acompanha o agrupamento de despacho_inicial feito em iter_sql_records
return 'cod_materia', 'cod_comissao'
res = exec_legado(
'show index from {} WHERE Key_name = "PRIMARY"'.format(tabela))
return [r[4] for r in res]
@lru_cache()
def get_estrutura_legado(model):
model_legado = models_novos_para_antigos[model]
tabela_legado = model_legado._meta.db_table
campos_pk_legado = get_pk_legado(tabela_legado)
return model_legado, tabela_legado, campos_pk_legado
class ForeignKeyFaltando(ObjectDoesNotExist):
'Uma FK aponta para um registro inexistente'
def __init__(self, field, value, label):
def __init__(self, field, valor, old):
self.field = field
self.value = value
self.label = label
self.valor = valor
self.old = old
msg = 'FK [{field}] não encontrada para o valor {value} (em {model} / {label})' # noqa
msg = 'FK não encontrada para [{campo} = {valor}] (em {tabela} / pk = {pk})' # noqa
@property
def dados(self):
return {'field': self.field.name,
'value': self.value,
'model': self.field.model.__name__,
'label': self.label}
campo = campos_novos_para_antigos[self.field]
_, tabela, campos_pk = get_estrutura_legado(self.field.model)
pk = {c: getattr(self.old, c) for c in campos_pk}
sql = 'select * from {} where {}'.format(
tabela,
' and '.join(['{} = {}'.format(k, v) for k, v in pk.items()]))
return OrderedDict((('campo', campo),
('valor', self.valor),
('tabela', tabela),
('pk', pk),
('sql', sql)))
@lru_cache()
@ -146,18 +216,17 @@ def _get_all_ids_from_model(model):
return set(model.objects.values_list('id', flat=True))
def get_fk_related(field, value, label='---'):
if value is None and field.null:
def get_fk_related(field, old):
valor = getattr(old, campos_novos_para_antigos[field])
if valor is None and field.null:
return None
# if field.related_model.objects.filter(id=value).exists():
if value in _get_all_ids_from_model(field.related_model):
return value
elif value == 0 and field.null:
if valor in _get_all_ids_from_model(field.related_model):
return valor
elif valor == 0 and field.null:
# consideramos zeros como nulos, se não está entre os ids anteriores
return None
else:
raise ForeignKeyFaltando(field=field, value=value, label=label)
raise ForeignKeyFaltando(field=field, valor=valor, old=old)
def exec_sql(sql, db='default'):
@ -552,9 +621,21 @@ relatoria | tip_fim_relatoria = NULL | tip_fim_relatoria = 0
anula_tipos_origem_externa_invalidos()
def iter_sql_records(sql):
class Record:
pass
def iter_sql_records(tabela):
if tabela == 'despacho_inicial':
sql = ''' select cod_materia, cod_comissao from despacho_inicial
where ind_excluido <> 1
group by cod_materia, cod_comissao
order by cod_materia, min(num_ordem)
'''
else:
sql = 'select * from ' + tabela
if existe_coluna_no_legado(tabela, 'ind_excluido'):
sql += ' where ind_excluido <> 1'
cursor = exec_legado(sql)
fieldnames = [name[0] for name in cursor.description]
for row in cursor.fetchall():
@ -624,52 +705,40 @@ def reinicia_sequence(model, id):
sequence_name, id))
def get_pk_legado(tabela):
res = exec_legado(
'show index from {} WHERE Key_name = "PRIMARY"'.format(tabela))
return [r[4] for r in res]
DIR_DADOS_MIGRACAO = Path('~/migracao_sapl/').expand()
PATH_TABELA_TIMEZONES = DIR_DADOS_MIGRACAO.child('tabela_timezones.yaml')
DIR_RESULTADOS = DIR_DADOS_MIGRACAO.child('resultados')
class DataMigrator:
def dict_representer(dumper, data):
return dumper.represent_dict(data.items())
yaml.add_representer(OrderedDict, dict_representer)
def __init__(self):
self.field_renames, self.model_renames = get_renames()
self.choice_valida = {}
# configura timezone de migração
self.nome_banco_legado = DATABASES['legacy']['NAME']
match = re.match('sapl_cm_(.*)', self.nome_banco_legado)
nome_banco_legado = DATABASES['legacy']['NAME']
match = re.match('sapl_cm_(.*)', nome_banco_legado)
sigla_casa = match.group(1)
with open(PATH_TABELA_TIMEZONES, 'r') as arq:
tabela_timezones = yaml.load(arq)
municipio, uf, nome_timezone = tabela_timezones[sigla_casa]
if nome_timezone:
self.timezone = timezone(nome_timezone)
timezone = pytz.timezone(nome_timezone)
else:
self.timezone = get_timezone(municipio, uf)
timezone = get_timezone(municipio, uf)
def populate_renamed_fields(self, new, old):
renames = self.field_renames[type(new)]
def populate_renamed_fields(new, old):
renames = field_renames[type(new)]
for field in new._meta.fields:
old_field_name = renames.get(field.name)
field_type = field.get_internal_type()
if old_field_name:
old_value = getattr(old, old_field_name)
field_type = field.get_internal_type()
if field_type == 'ForeignKey':
# not necessarily a model
if hasattr(old, '_meta') and old._meta.pk.name != 'id':
label = 'pk = {}'.format(old.pk)
else:
label = '-- SEM PK --'
fk_field_name = '{}_id'.format(field.name)
value = get_fk_related(field, old_value, label)
value = get_fk_related(field, old)
setattr(new, fk_field_name, value)
else:
value = getattr(old, old_field_name)
@ -685,15 +754,14 @@ class DataMigrator:
return (field_type == tipo
and value and not value.tzinfo)
if campo_tempo_sem_timezone('DateTimeField'):
value = self.timezone.localize(value)
value = timezone.localize(value)
if campo_tempo_sem_timezone('TimeField'):
value = value.replace(tzinfo=self.timezone)
value = value.replace(tzinfo=timezone)
setattr(new, field.name, value)
def migrar(self, obj=appconfs, interativo=True):
# warning: model/app migration order is of utmost importance
def migrar_dados(interativo=True):
uniformiza_banco()
# excluindo database antigo.
@ -717,59 +785,60 @@ class DataMigrator:
fill_vinculo_norma_juridica()
fill_dados_basicos()
info('Começando migração: %s...' % obj)
info('Começando migração: ...')
try:
ocorrencias.clear()
dir_ocorrencias = DIR_RESULTADOS.child(date.today().isoformat())
dir_ocorrencias.mkdir(parents=True)
self._do_migrate(obj)
migrar_todos_os_models()
except Exception as e:
ocorrencias['traceback'] = str(traceback.format_exc())
raise e
finally:
# grava ocorrências
arq_ocorrencias = dir_ocorrencias.child(
self.nome_banco_legado + '.yaml')
nome_banco_legado + '.yaml')
with open(arq_ocorrencias, 'w') as arq:
yaml.safe_dump(dict(ocorrencias), arq, allow_unicode=True)
dump = yaml.dump(dict(ocorrencias), allow_unicode=True)
arq.write(dump.replace('\n- ', '\n\n- '))
info('Ocorrências salvas em\n {}'.format(arq_ocorrencias))
# recria tipos de autor padrão que não foram criados pela migração
cria_models_tipo_autor()
def _do_migrate(self, obj):
if isinstance(obj, AppConfig):
models = [model for model in obj.models.values()
if model in self.field_renames]
if obj.label == 'materia':
def move_para_depois_de(lista, movido, referencias):
indice_inicial = lista.index(movido)
lista.remove(movido)
indice_apos_refs = max(lista.index(r) for r in referencias) + 1
lista.insert(max(indice_inicial, indice_apos_refs), movido)
return lista
def migrar_todos_os_models():
models = [model for app in appconfs for model in app.models.values()
if model in field_renames]
# Devido à referência TipoProposicao.tipo_conteudo_related
# a migração de TipoProposicao precisa ser feita
# após TipoMateriaLegislativa e TipoDocumento
# (porém antes de Proposicao)
models.remove(TipoProposicao)
pos_tipo_proposicao = max(
models.index(TipoMateriaLegislativa),
models.index(TipoDocumento)) + 1
models.insert(pos_tipo_proposicao, TipoProposicao)
move_para_depois_de(models, TipoProposicao,
[TipoMateriaLegislativa, TipoDocumento])
assert models.index(TipoProposicao) < models.index(Proposicao)
move_para_depois_de(models, Proposicao,
[MateriaLegislativa, DocumentoAdministrativo])
for model in models:
migrar_model(model)
self._do_migrate(models)
elif isinstance(obj, ModelBase):
self.migrate_model(obj)
elif hasattr(obj, '__iter__'):
for item in obj:
self._do_migrate(item)
else:
raise TypeError(
'Parameter must be a Model, AppConfig or a sequence of them')
def migrate_model(self, model):
def migrar_model(model):
print('Migrando %s...' % model.__name__)
nome_model = self.model_renames.get(model, model.__name__)
model_legado = legacy_app.get_model(nome_model)
tabela_legado = model_legado._meta.db_table
campos_pk = get_pk_legado(tabela_legado)
model_legado, tabela_legado, campos_pk_legado = \
get_estrutura_legado(model)
if len(campos_pk) == 1:
if len(campos_pk_legado) == 1:
# a pk no legado tem um único campo
nome_pk = model_legado._meta.pk.name
if 'ind_excluido' in {f.name for f in model_legado._meta.fields}:
@ -784,11 +853,7 @@ class DataMigrator:
return getattr(old, nome_pk)
else:
# a pk no legado tem mais de um campo
sql = 'select * from ' + tabela_legado
if existe_coluna_no_legado(tabela_legado, 'ind_excluido'):
sql += ' where ind_excluido != 1'
old_records = iter_sql_records(sql)
old_records = iter_sql_records(tabela_legado)
get_id_do_legado = None
ajuste_antes_salvar = AJUSTE_ANTES_SALVAR.get(model)
@ -796,11 +861,12 @@ class DataMigrator:
# convert old records to new ones
with transaction.atomic():
novos = []
sql_delete_legado = ''
for old in old_records:
new = model()
try:
self.populate_renamed_fields(new, old)
populate_renamed_fields(new, old)
if ajuste_antes_salvar:
ajuste_antes_salvar(new, old)
except ForeignKeyFaltando as e:
@ -812,12 +878,9 @@ class DataMigrator:
else:
if get_id_do_legado:
new.id = get_id_do_legado(old)
# validação do model
new.clean()
# salva novo registro
with reversion.create_revision():
new.save()
reversion.set_comment('Objeto criado pela migração')
new.clean() # valida model
novos.append(new) # guarda para salvar
# acumula deleção do registro no legado
sql_delete_legado += 'delete from {} where {};\n'.format(
@ -825,10 +888,15 @@ class DataMigrator:
' and '.join(
'{} = "{}"'.format(campo,
getattr(old, campo))
for campo in campos_pk))
for campo in campos_pk_legado))
# salva novos registros
with reversion.create_revision():
model.objects.bulk_create(novos)
reversion.set_comment('Objetos criados pela migração')
if ajuste_depois_salvar:
ajuste_depois_salvar(new, old)
ajuste_depois_salvar()
# se configuramos ids explicitamente devemos reiniciar a sequence
if get_id_do_legado:
@ -840,11 +908,6 @@ class DataMigrator:
exec_legado(sql_delete_legado)
def migrar_dados(obj=appconfs, interativo=True):
dm = DataMigrator()
dm.migrar(obj, interativo)
# MIGRATION_ADJUSTMENTS #####################################################
def adjust_acompanhamentomateria(new, old):
@ -954,37 +1017,19 @@ def adjust_parlamentar(new, old):
def adjust_participacao(new, old):
composicao = Composicao()
composicao.comissao_id, composicao.periodo_id = [
get_fk_related(Composicao._meta.get_field(name),
value,
'composicao_comissao.cod_comp_comissao = {}'.format(
old.pk
))
for name, value in (('comissao', old.cod_comissao),
('periodo', old.cod_periodo_comp))]
# check if there is already an "equal" one in the db
already_created = Composicao.objects.filter(
comissao=composicao.comissao, periodo=composicao.periodo)
if already_created:
assert len(already_created) == 1 # we must never have made 2 copies
[composicao] = already_created
else:
comissao_id, periodo_id = [
get_fk_related(Composicao._meta.get_field(name), old)
for name in ('comissao', 'periodo')]
with reversion.create_revision():
composicao.save()
composicao, _ = Composicao.objects.get_or_create(
comissao_id=comissao_id, periodo_id=periodo_id)
reversion.set_comment('Objeto criado pela migração')
new.composicao = composicao
def adjust_proposicao_antes_salvar(new, old):
if new.data_envio:
new.ano = new.data_envio.year
def adjust_normarelacionada(new, old):
tipo = TipoVinculoNormaJuridica.objects.filter(sigla=old.tip_vinculo)
assert len(tipo) == 1
new.tipo_vinculo = tipo[0]
new.tipo_vinculo = TipoVinculoNormaJuridica.objects.get(
sigla=old.tip_vinculo)
def adjust_protocolo_antes_salvar(new, old):
@ -1009,18 +1054,21 @@ def adjust_registrovotacao_antes_salvar(new, old):
def adjust_tipoafastamento(new, old):
if old.ind_afastamento == 1:
assert xor(old.ind_afastamento, old.ind_fim_mandato)
if old.ind_afastamento:
new.indicador = 'A'
elif old.ind_fim_mandato:
new.indicador = 'F'
MODEL_TIPO_MATERIA_OU_DOCUMENTO = {'M': TipoMateriaLegislativa,
TIPO_MATERIA_OU_TIPO_DOCUMENTO = {'M': TipoMateriaLegislativa,
'D': TipoDocumento}
def adjust_tipoproposicao(new, old):
"Aponta para o tipo relacionado de matéria ou documento"
value = old.tip_mat_ou_doc
model_tipo = MODEL_TIPO_MATERIA_OU_DOCUMENTO[old.ind_mat_ou_doc]
model_tipo = TIPO_MATERIA_OU_TIPO_DOCUMENTO[old.ind_mat_ou_doc]
tipo = model_tipo.objects.filter(pk=value)
if tipo:
new.tipo_conteudo_related = tipo[0]
@ -1028,7 +1076,17 @@ def adjust_tipoproposicao(new, old):
raise ForeignKeyFaltando(
field=TipoProposicao.tipo_conteudo_related,
value=(model_tipo.__name__, value),
label='ind_mat_ou_doc = {}'.format(old.ind_mat_ou_doc))
label={'ind_mat_ou_doc': old.ind_mat_ou_doc})
def adjust_proposicao_antes_salvar(new, old):
if new.data_envio:
new.ano = new.data_envio.year
if old.cod_mat_ou_doc:
tipo_mat_ou_doc = type(new.tipo.tipo_conteudo_related)
campo_virtual = CAMPOS_VIRTUAIS_PROPOSICAO[tipo_mat_ou_doc]
new.content_type = content_types[campo_virtual.related_model]
new.object_id = get_fk_related(campo_virtual, old)
def adjust_statustramitacao(new, old):
@ -1067,47 +1125,40 @@ def adjust_normajuridica_antes_salvar(new, old):
new.esfera_federacao = ''
def adjust_normajuridica_depois_salvar(new, old):
def adjust_normajuridica_depois_salvar():
# Ajusta relação M2M
ligacao = NormaJuridica.assuntos.through
if not old.cod_assunto: # it can be null or empty
return
# lista de pks separadas por vírgulas (ignorando strings vazias)
lista_pks_assunto = [int(pk) for pk in old.cod_assunto.split(',') if pk]
assuntos_migrados, normas_migradas = [
set(model.objects.values_list('id', flat=True))
for model in [AssuntoNorma, NormaJuridica]]
for pk_assunto in lista_pks_assunto:
try:
new.assuntos.add(AssuntoNorma.objects.get(pk=pk_assunto))
except ObjectDoesNotExist:
pass # ignora assuntos inexistentes
def filtra_assuntos_migrados(cod_assunto):
return [a for a in map(int, cod_assunto.split(','))
if a in assuntos_migrados]
norma_para_assuntos = [
(norma, filtra_assuntos_migrados(cod_assunto))
for norma, cod_assunto in OldNormaJuridica.objects.filter(
pk__in=normas_migradas).values_list('pk', 'cod_assunto')]
def vincula_autor(new, old, model_relacionado, campo_relacionado, campo_nome):
pk_rel = getattr(old, campo_relacionado)
if pk_rel:
try:
new.autor_related = model_relacionado.objects.get(pk=pk_rel)
except ObjectDoesNotExist:
# ignoramos o autor órfão
nome_model_relacionado = model_relacionado._meta.model.__name__
raise ForeignKeyFaltando(
field=Autor.autor_related,
value=(nome_model_relacionado, pk_rel),
label='{} [pk={}] inexistente para autor'.format(
nome_model_relacionado, pk_rel))
else:
new.nome = getattr(new.autor_related, campo_nome)
return True
ligacao.objects.bulk_create(
ligacao(normajuridica_id=norma, assuntonorma_id=assunto)
for norma, assuntos in norma_para_assuntos
for assunto in assuntos)
def adjust_autor(new, old):
for args in [
# essa ordem é importante
(Parlamentar, 'cod_parlamentar', 'nome_parlamentar'),
(Comissao, 'cod_comissao', 'nome'),
(Partido, 'cod_partido', 'nome')]:
if vincula_autor(new, old, *args):
# vincula autor com o objeto relacionado, tentando os três campos antigos
# o primeiro campo preenchido será usado, podendo lançar ForeignKeyFaltando
for model_relacionado, campo_nome in [(Parlamentar, 'nome_parlamentar'),
(Comissao, 'nome'),
(Partido, 'nome')]:
field = CAMPOS_VIRTUAIS_AUTOR[model_relacionado]
fk_encontrada = get_fk_related(field, old)
if fk_encontrada:
new.autor_related = model_relacionado.objects.get(id=fk_encontrada)
new.nome = getattr(new.autor_related, campo_nome)
break
if old.col_username:

5
sapl/legacy/scripts/exporta_zope/exporta_zope.py

@ -14,7 +14,6 @@ from functools import partial
import magic
import yaml
import ZODB.DB
import ZODB.FileStorage
from ZODB.broken import Broken
@ -191,7 +190,9 @@ def read_sde(element):
]
if meta_type != 'Script (Python)':
# ignoramos os scrips python de eventos dos templates
yield id, read_sde(obj)
yield {'id': id,
'meta_type': meta_type,
'dados': read_sde(obj)}
data = dict(read_properties())
children = list(read_children())

2
sapl/legacy/scripts/migra_um_db.sh

@ -39,7 +39,7 @@ if [ $# -ge 2 ]; then
echo "--- MIGRACAO ---" | tee -a $LOG
echo >> $LOG
DATABASE_NAME=$1 ./manage.py migracao_25_31 --force --settings sapl.legacy_migration_settings 2>&1 | tee -a $LOG
DATABASE_NAME=$1 ./manage.py migracao_25_31 --force --dados --settings sapl.legacy_migration_settings 2>&1 | tee -a $LOG
echo >> $LOG
else
echo "USO:"

96
sapl/legacy/test_renames.py

@ -1,29 +1,76 @@
import sapl.comissoes
import sapl.materia
import sapl.norma
import sapl.sessao
from django.contrib.contenttypes.fields import GenericForeignKey
from sapl.base.models import AppConfig, Autor, CasaLegislativa, TipoAutor
from sapl.comissoes.models import \
DocumentoAcessorio as DocumentoAcessorioComissoes
from sapl.comissoes.models import Comissao, Composicao, Participacao, Reuniao
from sapl.materia.models import (AcompanhamentoMateria, DocumentoAcessorio,
MateriaLegislativa, Proposicao,
TipoMateriaLegislativa, TipoProposicao,
Tramitacao)
from sapl.norma.models import (NormaJuridica, NormaRelacionada,
TipoVinculoNormaJuridica)
from sapl.parlamentares.models import (Frente, Mandato, Parlamentar, Partido,
TipoAfastamento, Votante)
from sapl.protocoloadm.models import DocumentoAdministrativo
from sapl.sessao.models import (Bancada, Bloco, CargoBancada,
ExpedienteMateria, Orador, OradorExpediente,
OrdemDia, RegistroVotacao, ResumoOrdenacao,
SessaoPlenaria, TipoResultadoVotacao,
VotoParlamentar)
from .migracao_dados import appconfs, get_renames, legacy_app
RENAMING_IGNORED_MODELS = [
sapl.comissoes.models.Composicao,
sapl.norma.models.AssuntoNormaRelationship,
Votante, Frente, Bancada, CargoBancada, Bloco, # parlamentares
Composicao, Reuniao, DocumentoAcessorioComissoes, # commissoes
AppConfig, CasaLegislativa, # base
ResumoOrdenacao, # sessao
TipoVinculoNormaJuridica, # norma
# FIXME retirar daqui depois que a issue #218 for resolvida!!!!!!!
sapl.sessao.models.AcompanharMateria,
]
RENAMING_IGNORED_FIELDS = [
(sapl.comissoes.models.Participacao, {'composicao'}),
(sapl.materia.models.Proposicao, {'documento'}),
(sapl.materia.models.TipoProposicao, {'tipo_documento'}),
(sapl.materia.models.Tramitacao, {'ultima'}),
(sapl.sessao.models.SessaoPlenaria, {'finalizada',
'upload_pauta',
(TipoAfastamento, {'indicador'}),
(Participacao, {'composicao'}),
(Proposicao, {
'ano', 'content_type', 'object_id', 'conteudo_gerado_related',
'status', 'hash_code', 'texto_original'}),
(TipoProposicao, {
'object_id', 'content_type', 'tipo_conteudo_related', 'perfis',
# não estou entendendo como esses campos são enumerados,
# mas eles não fazem parte da migração
# 'tipomaterialegislativa_set', 'tipodocumento_set',
}),
(Tramitacao, {'ultima'}),
(SessaoPlenaria, {'finalizada', 'iniciada', 'painel_aberto', 'interativa',
'upload_ata',
'iniciada'}),
(sapl.sessao.models.ExpedienteMateria, {'votacao_aberta'}),
(sapl.sessao.models.OrdemDia, {'votacao_aberta'}),
'upload_anexo',
'upload_pauta'}),
(ExpedienteMateria, {'votacao_aberta'}),
(OrdemDia, {'votacao_aberta'}),
(NormaJuridica, {'texto_integral', 'data_ultima_atualizacao', 'assuntos'}),
(Parlamentar, {
'uf_residencia', 'municipio_residencia', 'cropping', 'fotografia'}),
(Partido, {'logo_partido'}),
(MateriaLegislativa, {
'autores', 'anexadas', 'data_ultima_atualizacao', 'texto_original'}),
(DocumentoAdministrativo, {'protocolo', 'texto_integral'}),
(Mandato, {'titular', 'data_fim_mandato', 'data_inicio_mandato'}),
(TipoMateriaLegislativa, {'sequencia_numeracao'}),
(TipoAutor, {'content_type'}),
(TipoResultadoVotacao, {'natureza'}),
(RegistroVotacao, {'ordem', 'expediente'}),
(DocumentoAcessorio, {'arquivo', 'data_ultima_atualizacao'}),
(OradorExpediente, {'upload_anexo', 'observacao'}),
(Orador, {'upload_anexo', 'observacao'}),
(VotoParlamentar, {'user', 'ip', 'expediente', 'data_hora', 'ordem'}),
(NormaRelacionada, {'tipo_vinculo'}),
(AcompanhamentoMateria, {'confirmado', 'data_cadastro', 'usuario'}),
(Autor, {'user', 'content_type', 'object_id', 'autor_related'}),
(Comissao, {'ativa'}),
]
@ -31,7 +78,9 @@ def test_get_renames():
field_renames, model_renames = get_renames()
all_models = {m for ac in appconfs for m in ac.get_models()}
for model in all_models:
field_names = {f.name for f in model._meta.fields if f.name != 'id'}
field_names = {f.name for f in model._meta.get_fields()
if f.name != 'id'
and (f.concrete or isinstance(f, GenericForeignKey))}
if model not in field_renames:
# check ignored models in renaming
assert model in RENAMING_IGNORED_MODELS
@ -46,11 +95,12 @@ def test_get_renames():
match_msg_template % ('new', 'current')
# ignored fields are explicitly listed
missing_in_renames = field_names - renamed
if missing_in_renames:
assert (model, missing_in_renames) in \
RENAMING_IGNORED_FIELDS, \
'Field(s) missing in renames but not explicitly listed'
missing = field_names - renamed
if missing:
assert (model, missing) in RENAMING_IGNORED_FIELDS, \
'Campos faltando na renomeação,' \
'mas não listados explicitamente: ({}, {})'.format(
model.__name__, missing)
# all old names correspond to a legacy field
legacy_model = legacy_app.get_model(

9
sapl/materia/legacy.yaml

@ -58,9 +58,8 @@ AssuntoMateria:
dispositivo: des_dispositivo
DespachoInicial:
comissao: cod_comissao
materia: cod_materia
numero_ordem: num_ordem
comissao: cod_comissao
TipoDocumento:
descricao: des_tipo_documento
@ -112,10 +111,6 @@ Parecer:
TipoProposicao:
descricao: des_tipo_proposicao
materia_ou_documento: ind_mat_ou_doc
modelo: nom_modelo
tipo_documento:
tipo_materia:
Proposicao:
autor: cod_autor
@ -124,7 +119,7 @@ Proposicao:
data_recebimento: dat_recebimento
descricao: txt_descricao
justificativa_devolucao: txt_justif_devolucao
materia: cod_mat_ou_doc
materia_de_vinculo: cod_materia
numero_proposicao: num_proposicao
tipo: tip_proposicao

10
sapl/materia/models.py

@ -40,9 +40,6 @@ class TipoProposicao(models.Model):
error_messages={
'unique': _('Já existe um Tipo de Proposição com esta descrição.')
})
# FIXME - para a rotina de migração - estes campos mudaram
# retire o comentário quando resolver
content_type = models.ForeignKey(ContentType, default=None,
on_delete=models.PROTECT,
verbose_name=_('Definição de Tipo'))
@ -378,9 +375,6 @@ class AssuntoMateria(models.Model):
@reversion.register()
class DespachoInicial(models.Model):
# TODO M2M?
# TODO Despachos não são necessáriamente comissoes, podem ser outros
# órgãos, ex: procuradorias
materia = models.ForeignKey(MateriaLegislativa, on_delete=models.CASCADE)
comissao = models.ForeignKey(Comissao, on_delete=models.CASCADE)
@ -692,16 +686,12 @@ class Proposicao(models.Model):
texto_articulado = GenericRelation(
TextoArticulado, related_query_name='texto_articulado')
# FIXME - para a rotina de migração - este campo mudou
# retire o comentário quando resolver
materia_de_vinculo = models.ForeignKey(
MateriaLegislativa, blank=True, null=True,
on_delete=models.CASCADE,
verbose_name=_('Matéria anexadora'),
related_name=_('proposicao_set'))
# FIXME - para a rotina de migração - estes campos mudaram
# retire o comentário quando resolver
content_type = models.ForeignKey(
ContentType, default=None, blank=True, null=True,
verbose_name=_('Tipo de Material Gerado'))

1
sapl/norma/legacy.yaml

@ -9,7 +9,6 @@ TipoNormaJuridica:
NormaJuridica:
ano: ano_norma
assunto: cod_assunto
complemento: ind_complemento
data: dat_norma
data_publicacao: dat_publicacao

4
sapl/parlamentares/legacy.yaml

@ -38,7 +38,6 @@ Parlamentar:
ativo: ind_ativo
biografia: txt_biografia
cep_residencia: num_cep_resid
cod_casa: cod_casa
cpf: num_cpf
data_nascimento: dat_nascimento
email: end_email
@ -58,7 +57,6 @@ Parlamentar:
telefone: num_tel_parlamentar
telefone_residencia: num_tel_resid
titulo_eleitor: num_tit_eleitor
unidade_deliberativa: ind_unid_deliberativa
TipoDependente:
descricao: des_tipo_dependente
@ -80,10 +78,8 @@ Filiacao:
partido: cod_partido
TipoAfastamento:
afastamento: ind_afastamento
descricao: des_afastamento
dispositivo: des_dispositivo
fim_mandato: ind_fim_mandato
Mandato:
coligacao: cod_coligacao

1
sapl/protocoloadm/legacy.yaml

@ -11,7 +11,6 @@ DocumentoAdministrativo:
dias_prazo: num_dias_prazo
interessado: txt_interessado
numero: num_documento
numero_protocolo: num_protocolo
observacao: txt_observacao
tipo: tip_documento
tramitacao: ind_tramitacao

1
sapl/sessao/legacy.yaml

@ -52,7 +52,6 @@ OradorExpediente (OradoresExpediente): {}
OrdemDia: {}
PresencaOrdemDia (OrdemDiaPresenca):
data_ordem: dat_ordem
parlamentar: cod_parlamentar
sessao_plenaria: cod_sessao_plen

3
sapl/sessao/models.py

@ -436,7 +436,8 @@ class RegistroVotacao(models.Model):
if not xor(bool(self.ordem), bool(self.expediente)):
raise ValidationError(
'RegistroVotacao deve ter exatamente um dos campos '
'ordem ou expediente deve estar preenchido')
'ordem ou expediente preenchido. Ambos estão preenchidos: '
'{}, {}'. format(self.ordem, self.expediente))
@reversion.register()

Loading…
Cancel
Save