diff --git a/.env.example b/.env.example index 06def96..ab40d49 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,2 @@ URL_PRIMEIRO_BANCO=seubanco_legado -URL_SEGUNDO_BANCO=seunovobanco +URL_SEGUNDO_BANCO=seunovobanco \ No newline at end of file diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index 19339c2..6a4e873 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -63,7 +63,7 @@ jobs: - name: Executa dataload Python env: - FULL_URL: postgresql+psycopg2://acta_test:acta_test@localhost:5432/acta_test + URL_SEGUNDO_BANCO: postgresql+psycopg2://acta_test:acta_test@localhost:5432/acta_test run: papermill python/dataload.ipynb /tmp/dataload-output.ipynb diff --git a/.github/workflows/deploy-producao.yml b/.github/workflows/deploy-producao.yml index c507572..4ff670b 100644 --- a/.github/workflows/deploy-producao.yml +++ b/.github/workflows/deploy-producao.yml @@ -47,11 +47,11 @@ jobs: - name: Executa dataload Python em produção env: - FULL_URL: ${{ secrets.NEON_PROD_DATABASE_URL }} + URL_SEGUNDO_BANCO: ${{ secrets.NEON_PROD_DATABASE_URL }} run: papermill python/dataload.ipynb /tmp/dataload-output.ipynb - name: Executa RPA em produção env: - FULL_URL: ${{ secrets.URL_SEGUNDO_BANCO }} + URL_SEGUNDO_BANCO: ${{ secrets.NEON_PROD_DATABASE_URL }} URL_PRIMEIRO_BANCO: ${{ secrets.PRIMEIRO_DATABASE_URL }} - run: papermill python/rpa.py /tmp/rpa-output.py \ No newline at end of file + run: python python/rpa.py \ No newline at end of file diff --git a/README.md b/README.md index 8c7c24c..4d52254 100644 --- a/README.md +++ b/README.md @@ -60,16 +60,14 @@ python -m pip install -r .\python\requirements.txt As conexões são informadas por variáveis de ambiente: ```env -FULL_URL=postgresql+psycopg2://usuario:senha@localhost:5432/acta -URL_PRIMEIRO_BANCO=postgresql+psycopg2://usuario:senha@localhost:5432/acta_primeiro URL_SEGUNDO_BANCO=postgresql+psycopg2://usuario:senha@localhost:5432/acta +URL_PRIMEIRO_BANCO=postgresql+psycopg2://usuario:senha@localhost:5432/acta_primeiro ``` | Variável | Uso | | --- | --- | -| `FULL_URL` | Conexão SQLAlchemy usada pelo `dataload.ipynb` | +| `URL_SEGUNDO_BANCO` | Banco do segundo ano normalizado usado pelo `dataload.ipynb` e como destino do RPA | | `URL_PRIMEIRO_BANCO` | [Banco do primeiro ano](https://github.com/AppActa/acta-primeiro/blob/main/src/main/resources/sql/script_banco.sql) usado como origem da migração | -| `URL_SEGUNDO_BANCO` | Banco do segundo ano normalizado usado como destino da migração | Nunca versione senhas ou URLs reais de conexão. O [`.env.example`](.env.example) contém apenas valores de referência. @@ -100,7 +98,7 @@ Get-ChildItem .\sql -Filter *.sql | O notebook cria empresas, pessoas e registros relacionados ao ciclo PDCA, mantendo as dependências entre as tabelas: ```powershell -$env:FULL_URL = "postgresql+psycopg2://usuario:senha@localhost:5432/acta" +$env:URL_SEGUNDO_BANCO = "postgresql+psycopg2://usuario:senha@localhost:5432/acta" python -m papermill .\python\dataload.ipynb "$env:TEMP\acta-dataload-output.ipynb" --log-output ``` diff --git a/python/dataload.ipynb b/python/dataload.ipynb index 7bf4cea..d22b14f 100644 --- a/python/dataload.ipynb +++ b/python/dataload.ipynb @@ -20,6 +20,7 @@ "from faker import Faker\n", "import pandas as pd\n", "from sqlalchemy import create_engine, text\n", + "from sqlalchemy.dialects.postgresql import UUID\n", "from re import sub\n", "from unicodedata import normalize\n", "from string import ascii_lowercase\n", @@ -41,7 +42,7 @@ "# capturando variáveis de ambiente\n", "load_dotenv()\n", "\n", - "DATABASE_URL = os.getenv(\"FULL_URL\")\n", + "DATABASE_URL = os.getenv(\"URL_SEGUNDO_BANCO\")\n", "engine = create_engine(DATABASE_URL)\n", "faker = Faker(\"pt_BR\")" ] @@ -743,7 +744,12 @@ " try:\n", " with engine.begin() as conn:\n", " conn.execute(text(\"SET LOCAL app.current_user_id = '0'\"))\n", - " df.to_sql(name = tabela, schema = schema, con = conn, if_exists = 'append', index = False)\n", + " dtype = None\n", + " if (schema, tabela) == ('pdca', 'ciclo'):\n", + " dtype = {'id_ishikawa_mongo': UUID(as_uuid=True)}\n", + " elif (schema, tabela) == ('pdca', 'causa_raiz'):\n", + " dtype = {'id_5_porques_mongo': UUID(as_uuid=True)}\n", + " df.to_sql(name = tabela, schema = schema, con = conn, if_exists = 'append', index = False, dtype = dtype)\n", "\n", " # arrumando geração automática de ids inseridos manualmente\n", " conn.execute(text(\"SELECT setval(pg_get_serial_sequence('pdca.plano_acao', 'id'), :v)\"), {'v': id_plano_acao - 1})\n", diff --git a/sql/003_functions_triggers_procedures.sql b/sql/003_functions_triggers_procedures.sql index 1126313..f699591 100644 --- a/sql/003_functions_triggers_procedures.sql +++ b/sql/003_functions_triggers_procedures.sql @@ -57,8 +57,8 @@ CREATE OR REPLACE FUNCTION auditoria.fn_log_status() RETURNS TRIGGER AS $$ DECLARE usuario BIGINT; + registro_id BIGINT; BEGIN - IF OLD.status IS DISTINCT FROM NEW.status THEN BEGIN @@ -70,9 +70,15 @@ BEGIN IF usuario IS NULL THEN RAISE EXCEPTION 'Usuário não recebido pelo backend'; END IF; + -- usuario_treinamento usa chave composta e não possui coluna id + IF TG_TABLE_NAME = 'usuario_treinamento' THEN + registro_id := NEW.id_treinamento; + ELSE + registro_id := NEW.id; + END IF; INSERT INTO auditoria.log_status (id_usuario, id_registro, tabela, status_anterior, status_atual, data_log) VALUES ( - usuario, NEW.id, TG_TABLE_NAME, OLD.status, NEW.status, NOW()); + usuario, registro_id, TG_TABLE_NAME, OLD.status, NEW.status, NOW()); END IF; RETURN NEW; @@ -581,7 +587,7 @@ BEGIN RAISE EXCEPTION 'Convite não pode ser criado para usuário já ativado'; END IF; - UPDATE pdca.convite_usuario SET status = 'EXPIRADO' + UPDATE public.convite_usuario SET status = 'EXPIRADO' WHERE id_usuario = NEW.id_usuario AND status = 'PENDENTE' AND expira_em <= NOW(); @@ -890,4 +896,4 @@ BEGIN UPDATE pdca.tarefa SET status = 'EM_ANDAMENTO', data_fim_prevista = novo_prazo, data_fim_real = NULL, atualizado_em = CURRENT_TIMESTAMP WHERE id = tarefa_id; END; -$$; +$$; \ No newline at end of file