ASER_TECH
Como os dados chegam do OpenEdge ao SQL Server, como as tabelas se ligam entre si, quando cada sincronismo corre e o que fazer quando algo falha.
ASER_TECH · compatibilidade 150 · collation Latin1_General_CI_AS · recovery model FULL. Estrutura lida dos catálogos sys.* (só SELECTs). Os horários vêm dos scripts do repositório, não do Agendador de Tarefas do servidor.Mapa do modelo
As tabelas agrupadas por área de negócio e as ligações principais. Clica numa tabela para abrir a ficha com todas as colunas.
Fluxo de dados
Cada sincronismo lê o OpenEdge, valida em staging e grava no SQL Server. Os incrementais guardam o ponto onde ficaram num marcador.
PUB.* (referencia, cobro, garantia…)importar_*.pyLê full ou delta por datas; valida chaves, tipos e comprimentos em stagingOE_*SyncAvança só quando os dados ficam confirmados; preview e rollback não o mexemCadeia operacional: 7 etapas em série
oe_cadeia_operacional sobre toda a sequência
✓ Cada etapa faz commit próprio: uma falha não desfaz as anteriores
Fora da cadeia: catálogos, localizações, referências, preços, stocks e clientes
Horários: um dia típico
Hora local do servidor. São as definições dos scripts agendar_*.ps1, não uma leitura das tarefas instaladas.
| Grupo | Full | Incremental | Instalador | Notas |
|---|---|---|---|---|
| Cadeia operacional | Diário 02:00 | 08:05–22:05, a cada 5 min | agendar_cadeia_operacional.ps1 | 7 etapas; garantias/veículos sempre full. Inclui veículos, devoluções e conta corrente. |
| Referências | Diário 03:00 | 08:00–19:00, a cada hora | agendar_referencias.ps1 | 12 incrementais/dia |
| PVPs | Diário 03:00 | 08:03–19:03, a cada hora | agendar_pvps.ps1 | 12 incrementais/dia |
| Catálogos (8 tabelas) | Diário 05:00 | — | agendar_full_auxiliares.ps1 | Tarefa «OE Catalogos - full» |
| Localizações | Diário 05:00 | — | agendar_full_auxiliares.ps1 | «OE Localizacoes - full», independente dos catálogos |
| Stocks | Diário 05:30 | 08:00–19:00, a cada 10 min | agendar_stocks.ps1 | 67 incrementais previstos/dia |
| Clientes | 08:30–19:30, a cada 30 min | — | agendar_clientes.ps1 | 23 leituras full/dia |
| Garantias (tarefa independente) | Seg–sáb 08:15–19:15, a cada hora | — | agendar_garantias.ps1 | 12 full/dia, além das garantias da cadeia |
| Rappel de vendas | Seg–sáb 08:20–19:20, a cada hora | — | agendar_rappel.ps1 | Cálculo completo a partir do OE; 12 execuções/dia |
MultipleInstances=IgnoreNew, limite de 12 h, conta S4U. Se a execução anterior ainda estiver a correr, o disparo seguinte é ignorado, por isso «previsto» não é «garantido». Uma execução pode terminar depois do fim da janela. As tarefas das 03:00 e das 05:00 são independentes e podem sobrepor-se.
Agendadores antigos substituídos pela cadeia
| Grupo | Full antigo | Incremental antigo | Script |
|---|---|---|---|
| Encomendas | Dom 16:00 cab. / 16:02 linhas | 08:05–22:05 / 08:07–22:07, 5 min | agendar_encomendas.ps1 |
| Ptelin | Dom 16:07 | 08:09–22:09, 5 min | agendar_ptelin.ps1 |
| Documentos | Dom 16:09 / linhas 16:11 (parametrizável) | 08:11–22:11 / 08:13–22:13, 5 min | agendar_documentos.ps1 |
O instalador da cadeia espera que estas tarefas terminem e depois remove-as. Não as voltar a instalar em paralelo. Os scripts ficam no repositório só como referência.
Sincronismos
Uma ficha por tabela de destino: de onde vem, como é identificada cada linha, como se lê o delta e o que acontece aos registos que desaparecem da origem.
Regras que afetam os resultados
reporte-lin (empresa, ano, série/contador, número). Linhas e cabeçalho são eliminados numa transação. Uma ausência na origem, por si só, não é tratada como eliminação.fac-alm-c1.fillerUPD identifica os anulados. Remove linhas antes do cabeçalho. A importação EFC remove apenas as suas devoluções.loativo = 0 quando fecbaja é NULL e 1 quando existe baixa. Não inverter, apesar do nome da coluna.Relações
Há três níveis de confiança: as FKs impostas pelo SQL, as ligações que os importadores calculam e as relações de domínio que existem só por código.
① FKs declaradas: ativas, validadas, sem CASCADE
inId_CabinIdFK_Cli_EncomendasLin_Cab_ID
inDocumento_Numero + teContadorinDocumento_Numero + teContadorFK_Pdc_EncomendasLin_Cab
inid + Innumero_garantiainid + innumero_garantiaFK_Cli_garantia_veiculo_Garantias
DELETE/UPDATE: NO_ACTION. Numa FK composta, componentes NULL não garantem que o pai exista.
② Ligações calculadas pelos importadores
③ Relações de domínio (por código, não verificadas nos dados)
| De | Para | Campos | Atenção |
|---|
Tabelas e colunas
As 33 tabelas, com todas as colunas, chaves, índices e restrições. Pesquisa por tabela, coluna, tipo ou campo de origem. «Sem mapeamento» não significa que a coluna não seja usada: pode ser preenchida pela aplicação.
Marcadores e objetos auxiliares
Fotografia de 28/10/2026, 11:57, não estado em tempo real. ultima_inicio é o ponto de partida do próximo delta.
OE_DocumentoLinhaSync tem uma entrada para documentos e outra para devoluções: cada uma tem o seu próprio ponto de leitura.
dbo.OE_LinhasGlobaisId
Fornece IDs comuns a Cli_EncomendasLin e Cli_Ptelin, para que inid_encomenda seja inequívoco quando lido com inPteCar.
Após INSERT/UPDATE, cada tabela verifica (com applock) que o ID não está a ser usado na outra. Os importadores usam IDENTITY_INSERT e lock transacional. Não existem views, procedures nem funções.
TR_Cli_EncomendasLin_IdGlobal
CREATE TRIGGER [dbo].[TR_Cli_EncomendasLin_IdGlobal] ON [dbo].[Cli_EncomendasLin]
AFTER INSERT, UPDATE AS
BEGIN
SET NOCOUNT ON;
IF NOT EXISTS (SELECT 1 FROM inserted) RETURN;
DECLARE @r int;
EXEC @r=sys.sp_getapplock @Resource=N'oe_ids_ptelin_encomendas:dbo',
@LockMode='Exclusive', @LockOwner='Transaction', @LockTimeout=300000;
IF @r<0 THROW 51001, 'Nao foi possivel validar o ID global.', 1;
IF EXISTS (SELECT 1 FROM inserted i JOIN [dbo].[Cli_Ptelin] o WITH (UPDLOCK,HOLDLOCK) ON o.inId=i.inId)
THROW 51002, 'ID ja utilizado na outra tabela: Ptelin/EncomendasLin.', 1;
ENDTR_Cli_Ptelin_IdGlobal
CREATE TRIGGER [dbo].[TR_Cli_Ptelin_IdGlobal] ON [dbo].[Cli_Ptelin]
AFTER INSERT, UPDATE AS
BEGIN
SET NOCOUNT ON;
IF NOT EXISTS (SELECT 1 FROM inserted) RETURN;
DECLARE @r int;
EXEC @r=sys.sp_getapplock @Resource=N'oe_ids_ptelin_encomendas:dbo',
@LockMode='Exclusive', @LockOwner='Transaction', @LockTimeout=300000;
IF @r<0 THROW 51001, 'Nao foi possivel validar o ID global.', 1;
IF EXISTS (SELECT 1 FROM inserted i JOIN [dbo].[Cli_EncomendasLin] o WITH (UPDLOCK,HOLDLOCK) ON o.inId=i.inId)
THROW 51002, 'ID ja utilizado na outra tabela: Ptelin/EncomendasLin.', 1;
ENDOperação e manutenção
Ativar os horários no servidor
- Atualizar o projeto a partir de
asertech_sync, preservando o.envdo servidor. Instalarrequirements.txtse necessário. Ficheiros alterados a 28/10:executar_cadeia_operacional.py,executar_devolucoes.py,executar_conta_corrente.py,importar_conta_corrente.py,conta_corrente_estado.py,agendar_cadeia_operacional.ps1. - Validar a definição sem instalar (PowerShell como administrador):
.\agendar_cadeia_operacional.ps1 -ValidateOnly
- Se ainda não houver marcador das devoluções na base de destino:
python executar_devolucoes.py --mode full
- Registar a cadeia (full 02:00, incremental 08:05–22:05):
.\agendar_cadeia_operacional.ps1 -Force
Não é só leitura: verifica ligações e colunas e prepara os IDs comuns. - Confirmar o que ficou instalado:
Get-ScheduledTask -TaskName 'OE Cadeia Operacional*' | Select-Object TaskName, State, Triggers Get-ScheduledTask -TaskName 'OE Cadeia Operacional*' | Get-ScheduledTaskInfo
A primeira conta corrente sem marcador faz full automaticamente; os restantes incrementais precisam da sua carga inicial.
Executar e diagnosticar
# Cadeia completa python executar_cadeia_operacional.py --mode full python executar_cadeia_operacional.py --mode incremental # Etapas isoladas python executar_devolucoes.py --mode incremental python executar_conta_corrente.py --mode incremental python executar_conta_corrente.py --mode incremental --preview python importar_conta_corrente.py --check # Auxiliares python executar_full_auxiliares.py --tipo catalogos python executar_full_auxiliares.py --tipo localizacoes # Rappel de vendas python executar_rappel.py --preview python executar_rappel.py
Use os executar_*: chamar importar_*.py diretamente não deixa log no monitor. Alguns importadores preparam estrutura mesmo com --check/--preview.
Logs e monitor
.\iniciar_monitor.ps1
# Abrir http://127.0.0.1:8088
logs/cadeia_operacional mostra a ordem, os resultados e as interrupções. Há uma pasta por grupo (referencias, pvps, stocks, catalogos, localizacoes, clientes, encomendas, ptelin, documentos, devolucoes, garantias, garantia_veiculo, conta_corrente, rappel).
O monitor lê logs e tarefas do Windows, não as bases. Atualiza a cada 30 s (tarefas em cache 60 s). «Sem fecho» pode ser execução ativa ou interrompida; «sem logs» não é sucesso. -BindAddress 0.0.0.0 só em rede interna de confiança (não tem login).
Recuperação após falha
- Ver primeiro o log da cadeia e depois o log da etapa que falhou.
- Resolver o erro de chave, conversão, truncagem ou bloqueio antes de repetir.
- Para corrigir atrasos, correr o full apropriado e verificar o resultado.
- Manter ligações e credenciais só no
.env. As tarefas S4U precisam de autenticação SQL, não Trusted Connection.
- Apagar marcadores ou renumerar IDs.
- Correr às cegas
preparar_ids_linhas_globais.py,preparar_*.sqlou--prepare-schema, porque alteram a estrutura. - Reinstalar os agendadores antigos de encomendas, Ptelin ou documentos.
- Esperar que uma falha desfaça etapas anteriores, porque os commits já feitos ficam.
Pontos de atenção
Fontes, alcance e versão
sys.tables, sys.columns, sys.types, sys.identity_columns, sys.default_constraints, sys.computed_columns, sys.indexes, sys.index_columns, sys.foreign_keys, sys.foreign_key_columns, sys.check_constraints, sys.objects, sys.sql_modules, sys.sequences e configuração da base. Estado: tabelas OE_*Sync. Não foram exportados registos comerciais nem pessoais.
Código local do commit
abe86c2, consultado a 28/10/2026; horários dos ficheiros agendar_*.ps1. Um script existir não quer dizer que a tarefa esteja instalada no servidor. As relações de domínio estão assinaladas como não verificadas.