Ponto de partida
Cinco decisões que estruturam o resto
Dois níveis: Supplier e SupplierEstablishment. Fornecedor é a entidade jurídica, chaveada pela raiz de 8 do CNPJ; estabelecimento é o CNPJ completo de 14, matriz ou filial. Certidão federal, CNDT, regime tributário e quadro societário vivem na raiz. Situação cadastral, inscrição estadual, inscrição municipal, alvará e licença ambiental vivem no estabelecimento — e uma filial pode estar baixada com a matriz ativa.
Isso já está valendo. A IN RFB 2.229/2024 pôs o CNPJ alfanumérico em produção em 31/07/2026 — mês passado. Coluna VARCHAR(14), nunca numérica; os 12 primeiros caracteres aceitam A–Z, os 2 DV continuam numéricos; o DV usa ASCII − 48. A maioria das bibliotecas de validação de CNPJ ainda não implementa isso.
Cotar não exige homologar. Dois estados de relacionamento, no modelo da Oracle: Prospect participa de RFQ e de qualificação mas não recebe pedido; SpendAuthorized transaciona. É a mudança de maior retorno sobre o modelo atual — desbloqueia cotação sem o atrito de exigir dez certidões de quem talvez nem venda.
Documento enviado ≠ verificação feita. São duas entidades. SupplierDocument é o PDF que o fornecedor subiu; SupplierVerification é a consulta que o Nexio fez numa fonte oficial, com carimbo de data, fonte e resultado. Níveis de confiança diferentes, retenções diferentes e telas diferentes.
Dado bancário muda por proposta, nunca por edição. A alteração é escrita numa tabela de proposta e o registro vivo não muda até um segundo aprovador confirmar, vendo o diff. Mesma regra na API e na importação. É o padrão do D365 e é o único controle estrutural contra a fraude de troca de conta.
Fundamentos
Sete princípios
1. O Nexio é dono da identidade e da aptidão; o ERP é dono da obrigação e do pagamento
O cadastro guarda os fatos que sustentam "podemos comprar deste fornecedor, com que risco, e para onde pagamos" — e a evidência dessa decisão. Título a pagar, aging, retenção calculada, conta contábil, DARF, CNAB e escrituração são do ERP. Boa parte dos campos que Oracle, SAP e D365 carregam no fornecedor existe para servir ao módulo financeiro; copiá-los é o erro clássico de quem modela olhando ERP.
2. Certidão vence sozinha; status é derivado
A data de vencimento do documento é a fonte da verdade — o status do processo de homologação nunca a influencia. Isso é explícito na documentação do Ariba e evita o estado impossível "homologação aprovada com certidão vencida".
3. Homologação é por categoria, não global
Homologar "o fornecedor" é o antipadrão. Um fornecedor de serviço de limpeza e um de matéria-prima química exigem evidências diferentes. Ariba escopa qualificação por commodity + região; Oracle organiza áreas de qualificação em rule sets. Requalificação preserva o mesmo escopo da qualificação anterior.
4. Não existe rol legal fechado de documentos no setor privado
Diferente de licitação pública, cada comprador define seu pacote. O Nexio não pode ter lista de documentos codificada: precisa de requisitos configuráveis por tenant × categoria × faixa de risco. Lista fixa perde cliente de setor regulado por não coletar o que ele precisa, e irrita cliente de serviço leve por exigir o que não faz sentido.
5. Sanção pública alerta; não bloqueia sozinha
CEIS, CNEP e CEPIM são sanções em contratação pública. Uma empresa listada não está legalmente impedida de vender para uma empresa privada. No privado esses cadastros são sinal reputacional: geram alerta e decisão registrada. Bloqueio automático produz falso positivo, e o time de compras aprende a ignorar o alerta — que é o pior resultado possível de um controle.
6. CNAE não autoriza atividade
CNAE é classificação estatística e fiscal. Quem autoriza é alvará, licença setorial e conselho de classe. Use CNAE como triagem e como sinal de alerta quando o objeto contratado não guarda relação com nenhum CNAE do fornecedor — nunca como bloqueio duro, que reprova fornecedor legítimo e aprova o irregular que tem o CNAE certo e nenhuma licença.
7. O que o fornecedor declara e o que ele está autorizado a vender são coisas diferentes
As categorias que o fornecedor marca no portal servem para descoberta — montar a lista de convidados de um RFQ. O que ele pode de fato ter comprado é o ItemSupplier e a homologação por categoria. Fundir as duas transforma um campo preenchido pelo próprio fornecedor em controle de compliance.
Modelo
Mapa de entidades
PortalUser.
BankAccountChangeProposal, nunca por update.
Convenção de nomes. O documento é em português; os identificadores são em inglês — entidades, atributos, valores de enum, rotas, permissões e códigos de erro. A exceção são os dados de negócio brasileiros, que ficam como são no mundo real: identificadores fiscais (cnpj, cpf, primaryCnae), nomes de regime tributário (SimplesNacional, LucroReal), siglas de unidade (UN, CX, KG), tipos de certidão e os exemplos de taxonomia — esses são conteúdo, não código.
A decisão central
Fornecedor e estabelecimento
A Oracle separa Supplier (entidade legal global) de Supplier Site (unidade que transaciona, com condição de pagamento, moeda e tolerâncias próprias). Esse modelo não mapeia direto para o Brasil: no Oracle o CNPJ mora no fornecedor e o site não tem identificação fiscal própria — mas aqui cada filial que emite nota tem CNPJ próprio e situação cadastral própria.
Vive na raiz (Supplier) | Vive no estabelecimento |
|---|---|
| Razão social, natureza jurídica, porte, data de abertura | CNPJ completo (14), matriz ou filial |
| CNAE principal e secundários | Situação cadastral e data — uma filial pode estar baixada com a matriz ativa |
| Regime tributário, opção pelo Simples, opção pelo regime regular de IBS/CBS | Inscrição estadual (por UF) e inscrição municipal |
| Quadro societário | Endereço fiscal |
| CND federal, CRF do FGTS, CNDT | Certidão estadual e municipal, alvará, licença ambiental, licenças setoriais |
| Grupo econômico, DUNS, LEI | Capacidade de entrega, contatos operacionais |
Grupo econômico é derivado, não digitado
A raiz de 8 dígitos do CNPJ identifica a entidade jurídica — matriz e filiais a compartilham. Isso dá ao Nexio um recurso que nenhum produto global tem: ao cadastrar um CNPJ cuja raiz já existe na base, sugerir o vínculo automaticamente em vez de deixar nascer um fornecedor duplicado. Para grupos com raízes distintas, existe parentSupplierId autorreferente, no modelo da Oracle e da Coupa.
O que o Nexio não vai construir agora: o "site" comercial
SAP e NetSuite particionam o fornecedor por unidade do comprador (company code, purchasing org, subsidiary). Num SaaS multi-tenant o tenant já é o comprador — replicar isso dentro do tenant só se paga com clientes que tenham várias filiais compradoras de fato. A evidência de que precisa vem quando o ItemSupplier precisar variar por local de entrega, que é o eixo ship-to organization da ASL da Oracle. Até lá, condição de pagamento, moeda e incoterm ficam no estabelecimento.
O tipo de pessoa muda o formulário inteiro
Company | MEI | Individual | RuralProducer | Foreign não é um campo com metade dos outros opcionais: é o seletor que decide quais campos existem, quais certidões são exigidas e quais alertas aparecem. Fornecedor estrangeiro não tem CNPJ, IE, IM, CND, FGTS, CNDT, CNAE nem Simples — forçar esses campos como obrigatórios é o bug mais comum de cadastro multi-país.
Domínio
Campos
Legenda: obrig · cond conforme tipo de pessoa · opc · gerado preenchido por consulta ou cálculo.
Fornecedor — identificação
| Campo | Tipo | Regra | |
|---|---|---|---|
| entityType | enum | obrig | Company | MEI | Individual | RuralProducer | Foreign. Governa a obrigatoriedade de todo o resto. |
| cnpjRoot | char(8) | gerado | Derivado do CNPJ do estabelecimento matriz. Indexado — é a chave de agrupamento de grupo econômico. |
| legalName | string(200) | obrig | Preenchido automaticamente pela consulta ao CNPJ quando disponível. |
| tradeName | string(200) | opc | É por ele que o comprador busca. Indexado na busca full-text. |
| cpf | char(11) | cond | Obrigatório para Individual e RuralProducer. Dado pessoal — ver LGPD. |
| foreignTaxId / taxIdCountry | string(40) / char(2) | cond | Obrigatórios para Foreign. Sem DV nacional — validação por formato do país. ISO 3166. |
| legalNatureCode | string(4) | opc | Código da tabela da Receita. Vem da consulta. |
| companySize | enum | opc | NotInformed | ME | EPP | Other. Notoriamente desatualizado na base da Receita — indicativo, nunca verdade contratual. |
| foundedOn | date | opc | Empresa aberta há poucos meses é sinal de triagem, não de reprovação. |
| primaryCnae / secondaryCnaes | char(7) / char(7)[] | opc | Subclasse CNAE de 7 dígitos. Triagem e sugestão de categoria — nunca habilitação. |
| duns / leiCode | char(9) / char(20) | opc | Identificadores globais, relevantes em fornecedor estrangeiro. |
| parentSupplierId | Guid? | opc | Autorreferência. Grupo econômico com raízes distintas. |
| isOneTimeSupplier | bool | opc | Compra pontual sem homologação plena. Evita poluir a base com fornecedor de uma compra só. |
Fornecedor — tributário
| Campo | Tipo | Regra | |
|---|---|---|---|
| taxRegime | enum | opc | SimplesNacional | MEI | LucroPresumido | LucroReal | TaxExempt | NotApplicable. Obtido dos dados abertos da Receita (tabela do Simples traz opção e datas). |
| optsForRegularIbsCbsRegime | bool? | opc | Campo novo e decisivo. Sob a LC 214/2025, optante do Simples que recolhe IBS/CBS dentro do DAS não permite crédito ao comprador; se optar pelo regime regular, o crédito é integral. Dois orçamentos de mesmo valor bruto podem ter custo líquido diferente por causa disso. Praticamente nenhum cadastro de fornecedor tem esse campo hoje. |
| regularRegimeOptedOn | date? | cond | Obrigatória quando o anterior é verdadeiro — a opção tem data e afeta comparativos retroativos. |
Estabelecimento
| Campo | Tipo | Regra | |
|---|---|---|---|
| cnpj | varchar(14) | obrig | Nunca numérico. Regex ^[A-Z0-9]{12}[0-9]{2}$, gravado sem máscara e em caixa alta. DV por módulo 11 com valor do caractere = ASCII − 48 (assim A–Z valem 17–42). Caso de teste canônico da Receita: 12ABC34501DE → DV 35. Índice único por tenant. |
| establishmentType | enum | gerado | Headquarters quando a ordem é 0001, senão Branch. |
| registrationStatus / registrationStatusOn | enum / date | gerado | 01 Null | 02 Active | 03 Suspended | 04 Unfit | 08 ClosedDown. Só Active deveria homologar. É por estabelecimento, não por raiz. |
| stateRegistrationStatus / stateRegistrationNumber / stateRegistrationUf | enum / string(20) / char(2) | cond | stateRegistrationStatus ∈ {HasRegistration, Exempt, NotApplicable, NotInformed}. É 1:N — o mesmo fornecedor pode ter IE em várias UFs. O erro clássico é uma coluna de texto que recebe "ISENTO" digitado de sete jeitos. |
| municipalRegistration / municipalRegistrationCityCode | string(20) / código IBGE | opc | Necessária para prestador de serviço emitir NFS-e. |
| isPrimary | bool | obrig | Exatamente um por fornecedor. É o padrão em pedidos quando nenhum outro é escolhido. |
| paymentTerms / currency / defaultIncoterm | string(40) / char(3) / char(3) | opc | Termos comerciais negociados. O prazo é do Nexio; o cálculo do vencimento e dos encargos é do ERP. |
| receiptTolerance | obj | opc | Percentuais de over e under delivery, e dias de antecipação e atraso aceitos. Detalhado no documento de Unidade de Medida. |
Armadilha de importação: o Excel converte 3E5… em notação científica e come zeros à esquerda. O importador precisa forçar a coluna de CNPJ como texto. E a API deve expor CNPJ como string desde o dia 1, mesmo enquanto for numérico — trocar tipo em API pública depois é caro.
Domínio
Endereços e contatos
Propósito de endereço é flag, não enum
A Oracle usa AddressPurposeOrderingFlag, AddressPurposeRemitToFlag e AddressPurposeRFQOrBiddingFlag — booleanos independentes. Um endereço pode ser simultaneamente de pedido e de cobrança; um enum "tipo de endereço" obrigaria a cadastrar o mesmo endereço duas vezes. O Nexio usa as mesmas flags mais purposeShipping e fiscal.
Contato tem papel; a Oracle não tem e faz falta
O modelo da Oracle só traz AdministrativeContactFlag e deixa o papel funcional emergir da associação contato×endereço. O Nexio precisa de roles[] — Commercial, Tax, Finance, Technical, Quality, PortalAdmin — porque precisa saber para quem enviar o RFQ e para quem enviar o pedido, que raramente são a mesma pessoa. Exatamente um contato tem isPortalAdmin.
Contato e credencial são entidades separadas
SupplierContact 1:0..1 PortalUser. O contato é dado cadastral e pode existir sem login; o usuário do portal tem status de conta, escopo de acesso e MFA. Fundir os dois faz com que desativar um contato apague um acesso, e vice-versa.
| Entidade | Campos |
|---|---|
| SupplierAddress | label, street, number, complement, district, cityCode (IBGE), state, postalCode, country, landmark, phone, email, purposeHeadquarters, purposeOrdering, purposeShipping, purposeRemitTo, purposeRfq, purposeTax, establishmentId?, status, inactiveOn |
| SupplierContact | firstName, lastName, jobTitle, email, phone, mobile, roles[], addressIds[], establishmentId?, isPortalAdmin, status, inactiveOn |
| PortalUser | contactId, login, accountStatus, dataAccessScope, mfaEnabled, lastAccessOn |
Domínio · FornecedorDocumento
Documentos
Tipo de documento é catálogo configurável por tenant, não enum de código. Campo fixo por tipo (fgtsCertificateUrl, fgtsExpiresOn) não escala e obriga migração para cada novo tipo.
| Campo | Regra |
|---|---|
| documentTypeId | Catálogo do tenant. Cada tipo declara: nível (raiz ou estabelecimento), se tem vencimento, validade padrão, se é exigido por categoria, e a política de vencimento. |
| scope | Supplier ou Establishment — herdado do tipo. |
| number, issuer, issuedOn, expiresOn | Vencimento nulo = documento sem validade (contrato social). |
| fileId | IObjectStorageService, path tenants/{tid}/suppliers/{sid}/docs/{uuid}.{ext}, URL pré-assinada com TTL de 1h. |
| status | gerado Valid | Expiring | Expired | Waived — derivado da data, com janela de "a vencer" configurável. Nunca gravado à mão. |
| confirmedBy / confirmedOn | Quem, do lado do comprador, conferiu o documento. Diferente de quem subiu. |
| waivedBy / waiverReason | Dispensa é decisão registrada, não campo em branco. |
Catálogo-semente de tipos, com o nível certo
| Documento | Emissor | Validade | Nível |
|---|---|---|---|
| Contrato / estatuto social | Junta comercial | sem validade | raiz |
| CND / CPEN federal | RFB + PGFN (conjunta) | 180 dias | raiz |
| CRF do FGTS | Caixa Econômica Federal | 30 dias — a mais curta do pacote, porque o recolhimento é mensal | raiz |
| CNDT | Justiça do Trabalho / TST | 180 dias | raiz |
| Certidão estadual | SEFAZ / PGE da UF | 30 a 180 dias, varia | estabelecimento |
| Certidão municipal | Prefeitura | 30 a 90 dias, varia | estabelecimento |
| Falência / recuperação judicial | Cartório distribuidor da comarca | 30 a 180 dias · paga | estabelecimento |
| Alvará de funcionamento | Prefeitura | geralmente anual | estabelecimento |
| Licença ambiental (LP/LI/LO) | Órgão estadual ou IBAMA | anos, por licença | estabelecimento |
| Licenças setoriais (ANVISA AFE, MAPA, ANTT, ANP) | Órgão setorial | varia | estabelecimento · por categoria |
| ISO 9001 / 14001 / 45001 | Organismo acreditado | ciclo de 3 anos | estabelecimento |
| Apólices (RC geral, RC profissional, performance bond) | Seguradora | vigência da apólice | raiz · por categoria |
| Código de conduta assinado | o próprio tenant | configurável | raiz |
Documento vencido não deve apagar o fornecedor do mapa. Nenhum dos produtos pesquisados bloqueia automaticamente o cadastro ao vencer um documento — o padrão real é sinalizar e rotear para decisão humana. No Nexio, a política é por tipo de documento e graduada: avisar, exigir justificativa na aprovação do pedido, ou bloquear a emissão de novo pedido. Bloqueio silencioso trava a operação e gera o workaround clássico — o comprador cadastra um fornecedor duplicado para contornar, o que alimenta o problema da antiduplicidade.
Domínio · FornecedorVerificacao
Verificações em fonte oficial
Entidade append-only: cada consulta gera um registro novo, com fonte, data, resultado e evidência. Sem a data da consulta, a flag é inauditável — o par flag + fonte + data é o que a Oracle faz com OnOFACListFlag e OFACSources.
| Fonte | O que devolve | Automatizável | Uso |
|---|---|---|---|
| Receita — CNPJ | Razão social, fantasia, endereço, CNAEs, porte, situação, sócios | Sim | Autopreenchimento no cadastro e revalidação periódica da situação |
| Receita — Simples/MEI | Opção e datas | Sim (dados abertos) | Regime tributário |
| Portal da Transparência — CEIS, CNEP, CEPIM, acordos de leniência | Sanções por CPF/CNPJ | Sim — API pública e gratuita, com token; limites de 400 req/min das 06h às 24h e 700 req/min das 00h às 06h | Alerta reputacional. Não bloqueia — ver princípio 5 |
| Lista suja do trabalho escravo (MTE) | Empregadores autuados | Sim — publicação semestral (abril e outubro), por download | Alerta bloqueante por política do tenant |
| OFAC / SDN | Sanções dos EUA | Sim — arquivos para download | Relevante em fornecedor estrangeiro |
| SINTEGRA / SEFAZ estadual | Situação da inscrição estadual | Parcial — 27 portais, cobertura por API comercial | Validação de IE |
| DICT (via PSP) / consulta de boleto | Titular da chave PIX ou do boleto | Sim, por parceiro | Validação de titularidade bancária — ver § bancário |
Base própria para buscar, consulta oficial para decidir
Quase todas as APIs gratuitas de CNPJ são derivadas do mesmo dump de dados abertos da Receita e herdam a latência dele — semanas. Para autopreenchimento e busca, isso é ótimo e barato: espelhe os dados abertos. Para uma decisão de homologação com efeito jurídico ("este fornecedor está ativo hoje"), dado defasado é risco: faça consulta pontual no momento da homologação e da revalidação, e grave fonte e carimbo de tempo.
O autopreenchimento é a maior alavanca de conversão do onboarding
Razão social, fantasia, endereço, CNAEs, porte, situação, sócios e Simples estão todos disponíveis a partir do CNPJ. Isso reduz um formulário de trinta campos para cerca de oito digitados. É, na prática, o principal diferencial dos SRMs brasileiros de homologação, e é replicável.
A varredura roda em lote, não só na homologação
Com uma API pública, gratuita e com limite generoso cobrindo quatro cadastros de integridade, não há razão para consultar apenas no onboarding. Um job periódico varre a base inteira e abre alerta quando algo muda — é o melhor custo-benefício de todo o pacote de compliance.
Processo
Homologação
| Campo | Regra |
|---|---|
| supplierId | Homologação é da entidade jurídica; documentos de estabelecimento são conferidos dentro dela. |
| scopeCategoryIds | Nós da árvore de categorias. Um fornecedor pode estar homologado em Serviços de Limpeza e não em Produtos Químicos. |
| questionnaireId / answers | Questionário modular reutilizável entre processos, não template por projeto. |
| riskTier | Low | Medium | High | Critical. Define o pacote de documentos exigido e a periodicidade da revalidação. |
| outcome | Approved | ApprovedWithFindings | Rejected. A opção do meio é o que o mercado brasileiro efetivamente usa e o que evita reprovar por um documento faltante. |
| findings[] | Cada ressalva com descrição, prazo e responsável. Ressalva sem prazo é ressalva esquecida. |
| validTo / nextReviewOn | Críticos tipicamente anual; demais, bienal. |
| approvals[] | Área, aprovador, decisão, data. Em paralelo — jurídico, financeiro, técnico e qualidade revisam ao mesmo tempo, não em cadeia. |
Requalificação preserva o escopo da qualificação anterior — mesmas categorias, mesma faixa de risco. Recomeçar do zero com escopo diferente é como uma homologação vencida vira um fornecedor que ninguém sabe se pode usar.
Segurança
Dados bancários
A fraude não precisa que você pague — precisa que você armazene o dado que alguém a jusante vai usar. Se não houver necessidade real, não guarde. Se guardar, esta seção inteira é requisito, não sugestão. No Brasil a jurisprudência tende a não responsabilizar o banco quando o boleto foi emitido fora da plataforma bancária: a perda fica com quem pagou.
Campos
| Campo | Regra |
|---|---|
| ispb / compeCode | Guardar o ISPB de 8 dígitos como chave — é o identificador moderno no SFN. O COMPE de 3 dígitos fica como conveniência de exibição. |
| branchNumber / branchCheckDigit / accountNumber / accountCheckDigit | Formatos variam por banco; não existe validação universal. |
| accountType | Checking | Savings | Payment. Conta de pagamento cobre fintechs. |
| holderName / holderTaxId | O documento do titular deve bater com o do fornecedor, ao menos pela raiz do CNPJ — permitindo que a filial receba na conta da matriz. Conta de pessoa física para fornecedor pessoa jurídica é bloqueada, salvo exceção aprovada e justificada. |
| pixKeyType / pixKey | CNPJ | CPF | Email | Phone | Random. Ver a tabela de risco abaixo. |
| validFrom / validTo | Versionamento. Nunca UPDATE na linha — sempre nova versão, com autor e justificativa. |
| holderVerification | Resultado da consulta ao DICT ou ao boleto: documento retornado, comparação com o do fornecedor, veredito e carimbo de tempo. |
Chave PIX e risco
| Tipo | Carrega identidade? | Leitura |
|---|---|---|
| CNPJ | Sim, diretamente | menor risco Auto-verificável contra o cadastro. É a chave a preferir e a sugerir ao fornecedor. |
| CPF | Sim | alerta Para fornecedor pessoa jurídica, chave CPF é sinal de alerta. |
| Email / Phone | Não | alerta Exige resolução no DICT para saber de quem é. |
| Aleatória (EVP) | Não carrega nenhuma informação | maior risco É impossível saber o titular olhando. Aceitar sem resolver no DICT é aceitar um destino de pagamento anônimo. |
O mecanismo: proposta de alteração
| Controle | Como funciona |
|---|---|
| Proposta, não edição | A alteração vai para BankAccountChangeProposal. O registro vivo não muda até a aprovação. O aprovador vê atual vs. proposto lado a lado — não se aprova um registro, aprova-se uma mudança. |
| Campos protegidos configuráveis | Banco, agência, conta, chave PIX, titular e razão social. O admin marca quais exigem aprovação; a tela os rotula como tal. |
| Aprovador ≠ solicitante | Obrigatório, sem exceção de urgência. Idealmente o aprovador não é de quem fez a compra. |
| Mesma regra na API e no import | Três modos, no padrão do D365: aceitar sem aprovação, recusar a alteração, ou criar proposta. O default é criar proposta. É aqui que a maioria das implementações vaza. |
| Verificação de titularidade | Resolver a chave PIX no DICT ou consultar o beneficiário do boleto, comparar com o CNPJ do fornecedor e gravar o veredito. Este controle não existe nos concorrentes globais no Brasil. |
| Carência antes do primeiro uso | Janela configurável (24 a 72 h) entre a aprovação da nova conta e a liberação para pagamento. |
| Notificação no canal antigo | Avisar o contato financeiro registrado antes da mudança. Detecta comprometimento de e-mail mesmo quando o atacante controla a caixa nova. |
| Alertas de padrão | Mesma conta em dois fornecedores diferentes; conta em UF descolada do domicílio; mudança pouco antes de um pagamento grande. |
| Trilha imutável | Valor anterior, novo, quem, quando, de qual IP e por qual canal. Em fraude consumada, é isso que determina responsabilidade. |
Domínio · FornecedorCategoria
Categorias fornecidas
Relação N:N com CategoryNode, com entidade associativa própria — o mesmo desenho do Products and Services da Oracle. Duas semânticas que precisam ficar separadas:
SupplierCategory. O que o fornecedor diz — ou foi aprovado — a fornecer. Origem: autodeclaração no portal durante o registro, mais aprovação. Uso: descoberta — montar a lista de convidados de um RFQ, busca, segmentação. Não bloqueia nada. Guarda a origem (autodeclarado ou homologado) e quem informou.
SupplierQualification.scopeCategoryIds e ItemSupplier.status. O que ele pode de fato ter comprado. É o papel da Approved Supplier List da Oracle, cujo status determina se o fornecedor pode ser cotado e se o pedido pode ser aprovado.
Fundir as duas transforma um campo que o próprio fornecedor edita em controle de compliance. A documentação da Oracle é explícita: Products and Services serve para identificar quem convidar para negociações — quem restringe a compra é a ASL.
Ponte com o Catálogo
Item × Fornecedor
Especificado em Cadastro de Item; aqui ficam a chave e as decisões que dependem do fornecedor. A parte de unidade de compra, fator de conversão e preço por quantidade está detalhada no documento de Unidade de Medida.
A chave inclui o estabelecimento
O análogo exato é a ASL da Oracle, chaveada em item ou categoria × organização de entrega × fornecedor × site, com atributos que são quase os mesmos do ItemSupplier: unidade de compra, país de origem, quantidade mínima e múltiplo de lote. No Nexio: itemId + supplierId + establishmentId (nullable). Nulo significa "vale para todos os estabelecimentos" — dá o comportamento da Oracle sem obrigar todo cliente a modelar filiais.
Status é política executável, não rótulo
New | UnderQualification | Approved | Blocked, cada um carregando allowsQuotation e allowsOrder. Na Oracle, o status da ASL determina se o fornecedor pode ser origem do item e se o pedido pode ser aprovado — Debarred impede a aprovação. É controle, não etiqueta.
O eixo que ainda não vamos construir: local de entrega
Preço e prazo de um mesmo item e fornecedor variam por destino. A ASL da Oracle já tem esse eixo. No Nexio ele fica previsto no modelo — shipToLocationId nullable na chave — e desligado até haver cliente com várias filiais compradoras.
Governança
Estados e bloqueios
O status atual do módulo (Approved / UnderReview / Suspended / Blocked) mistura quatro coisas distintas. Oracle e Ariba as separam, e a separação resolve problemas reais.
| Eixo | Valores | Responde |
|---|---|---|
| Relacionamento | Prospect | SpendAuthorized | Até onde este fornecedor pode ir |
| Processo de cadastro | Draft | AwaitingSupplier | UnderReview | Approved | Rejected | Onde está o cadastro |
| Vigência | Active | Inactive + inactiveOn | Se o registro está em uso |
| Bloqueio | bloqueado + motivo + blockedBy + blockedOn | Impedimento operacional pontual |
O que cada estado libera
| Estado | Convidar para RFQ | Receber pedido | Qualificar |
|---|---|---|---|
| Prospect | permitido | bloqueado | permitido |
| SpendAuthorized | permitido | permitido | permitido |
| SpendAuthorized, documento vencido | permitido | conforme política do tipo | permitido |
| SpendAuthorized, bloqueado | aviso | bloqueado | permitido |
| Inactive | bloqueado | bloqueado | bloqueado |
Pedidos em aberto sobrevivem ao bloqueio e à inativação — bloquear o recebimento de um pedido legítimo já colocado transforma uma decisão de cadastro num problema operacional. E Status + inactiveOn existem em cada nível — fornecedor, estabelecimento, endereço, contato — no padrão consistente da Oracle. Não é um status global.
Qualidade de dados
Antiduplicidade
O Nexio tem uma vantagem estrutural sobre os produtos globais: o CNPJ tem dígito verificador e formato fixo. Isso resolve, de graça, o caso difícil que a Oracle ataca normalizando o taxpayer ID para caracteres alfanuméricos.
| # | Regra | Ação |
|---|---|---|
| 1 | CNPJ normalizado — 14 caracteres, caixa alta, sem máscara — índice único por tenant | bloqueia |
| 2 | CPF normalizado, para fornecedor pessoa física | bloqueia |
| 3 | Raiz do CNPJ já existente na base | alerta — oferece vincular ao grupo econômico em vez de duplicar |
| 4 | Similaridade de razão social e nome fantasia (trigram) + domínio de e-mail coincidente | alerta com candidatos |
| 5 | Conta bancária ou chave PIX idêntica entre fornecedores distintos | alerta de segurança — é sinal de fraude, não só de duplicidade |
| 6 | Re-execução na aprovação do cadastro | alerta ao aprovador |
Verifique também contra rascunhos e cadastros pendentes
É o achado mais subestimado da documentação da Oracle: a checagem considera fornecedores existentes e também solicitações de registro pendentes de aprovação ou salvas para completar depois. Sem isso, dois cadastros do mesmo CNPJ passam juntos pela fila.
Aplique em todos os caminhos de entrada
Tela, importação, API e autocadastro. A Oracle é explícita nisso, e é exatamente onde a maioria das implementações vaza — a validação existe na tela e não existe no POST.
Não revele a colisão ao fornecedor
No autocadastro, a mensagem não nomeia qual fornecedor colidiu. A Oracle expõe o nome do fornecedor existente apenas a usuários internos. É controle de vazamento de informação, e é fácil de esquecer.
Diferencial
Desempenho do fornecedor
O Nexio tem um ativo que Ariba e Coupa não têm de graça: ele faz o recebimento. OTIF, atraso médio e divergência de quantidade são deriváveis do próprio banco, sem integração e sem pedir nada ao usuário.
| Métrica | Cálculo | Granularidade |
|---|---|---|
| Pontualidade (OTIF) | Recebimentos dentro da janela de tolerância de data, sobre o total | fornecedor · fornecedor × item |
| Atraso médio | Média de dias entre data prometida e data efetiva, considerando só os atrasados | fornecedor |
| Divergência de quantidade | Recebimentos fora da tolerância, sobre o total | fornecedor × item |
| Aderência de preço | Divergência entre preço do pedido e preço da nota | fornecedor × item |
| Tempo de resposta a RFQ | Da data do convite à data da proposta | fornecedor |
Métricas gravadas como agregados versionados em janela móvel, não recalculadas na leitura. E formulário de avaliação de fornecedor fica fora: a adesão é baixíssima e o dado calculado é melhor e gratuito.
Rastreabilidade
Regras de negócio
CNPJ é texto de 14 caracteres, validado por regex e DV
^[A-Z0-9]{12}[0-9]{2}$ mais módulo 11 com valor do caractere igual a ASCII − 48. Gravado sem máscara e em caixa alta; a entrada normaliza minúsculas. Aceitar os dois formatos, numérico e alfanumérico — a Receita continua emitindo CNPJs só numéricos, então "CNPJ novo" não implica "tem letra".
Todo fornecedor tem exatamente um estabelecimento principal
Criado junto com o fornecedor. Para Company e MEI, o principal é a matriz quando ela existe na base.
Tipo de pessoa governa a obrigatoriedade
Campo obrigatório para um tipo e inaplicável a outro responde 400 SUPPLIER_FIELD_NOT_APPLICABLE nomeando campo e tipo. Estrangeiro não tem CNPJ, IE, IM, CNAE nem regime tributário brasileiro.
Prospect cota, homologado transaciona
Prospect pode ser convidado a RFQ e qualificado; pedido responde 409 SUPPLIER_NOT_SPEND_AUTHORIZED. A promoção acontece por homologação aprovada, por vitória em cotação, ou manualmente com justificativa.
Situação cadastral diferente de Ativa impede homologar
Suspensa, inapta, baixada ou nula bloqueiam a aprovação da homologação e são reavaliadas na revalidação periódica. Fornecedor que fica inapto depois de homologado gera alerta, não bloqueio automático de pedidos em aberto.
Status de documento é sempre derivado da data
Nunca gravado à mão. A janela de "a vencer" é configurável por tipo. O status da homologação não influencia o vencimento do documento — a relação é só nessa direção.
A política de documento vencido é por tipo e graduada
Warn | RequireJustification | BlockNewOrder. Nenhuma política bloqueia recebimento de pedido já colocado.
Requisitos de documento são configuráveis por categoria e faixa de risco
Não existe lista fixa. O motor resolve: dado o fornecedor, suas categorias homologadas e a faixa de risco, quais tipos são exigidos, quais opcionais e quais dispensados.
Homologação é escopada por categoria e a requalificação preserva o escopo
Homologação sem escopo é recusada. Requalificação herda categorias e faixa de risco da anterior.
Sanção pública gera alerta, nunca bloqueio automático
CEIS, CNEP, CEPIM e leniência abrem pendência com decisão registrada. O tenant pode elevar um tipo de sanção a bloqueante por configuração, mas não é o default.
Verificação é append-only
Cada consulta grava fonte, data, resultado e evidência. Nunca sobrescreve a anterior — a série histórica é o que torna a decisão auditável.
Dado bancário nunca é alterado por update
Toda mudança em campo protegido cria BankAccountChangeProposal. O registro vivo permanece intacto até a aprovação por um usuário distinto do solicitante. Vale para tela, API e importação.
Titular da conta deve bater com o fornecedor
Comparação pela raiz do CNPJ, permitindo conta da matriz para filial. Conta de pessoa física para fornecedor pessoa jurídica exige exceção aprovada com justificativa registrada.
Chave PIX aleatória exige resolução de titularidade
Sem verificação bem-sucedida no DICT, a chave fica em estado não verificado e não é oferecida como destino de pagamento.
CNPJ é único por tenant, verificado contra pendentes
A checagem cobre ativos, rascunhos e cadastros pendentes de aprovação, em todos os caminhos de entrada.
Fornecedor não é excluído
Havendo RFQ, pedido, recebimento ou nota, apenas inativação. O DELETE existe só para cadastro em rascunho nunca submetido.
Bloqueio exige motivo e registra autor
motivo, blockedBy e blockedOn são obrigatórios. Desbloqueio idem. Sem isso, ninguém sabe por que aquele fornecedor está parado há seis meses.
Categoria declarada não autoriza compra
Serve a convite de RFQ e busca. A autorização vem da homologação por categoria e do ItemSupplier.status.
Concorrência otimista em todo update
expectedVersion obrigatório no corpo do PUT, checado antes de tocar o agregado.
Auditoria com diff de campos e log de acesso a dado pessoal
IAuditableEntity, categoria Supplier. Além do diff, registrar quem visualizou CPF de quem, e quando — exigência prática da LGPD.
Camada API
Endpoints
Prefixo api/v{version}/nexio, [Authorize] e uma permissão explícita por endpoint. Sucesso 200, inclusive nos POST.
| Rota | Permissão | Observação |
|---|---|---|
| GET /suppliers | supplier:read | Paged. Filtros: search, relacionamento, statusProcesso, bloqueado, categoryNodeId, comDocumentoVencido, faixaRisco, uf. |
| GET /suppliers/{id} | supplier:read | Completo, com estabelecimentos, endereços, contatos, documentos e homologações. |
| POST /suppliers | supplier:create | Nasce em Draft / Prospect. |
| PUT /suppliers/{id} | supplier:update | Campos bancários rejeitados aqui — usam o fluxo de proposta. |
| POST /suppliers/lookup-cnpj | supplier:read | Consulta o CNPJ e devolve os dados para autopreenchimento sem gravar, junto com o resultado da checagem de duplicidade. |
| POST /suppliers/{id}/submit | supplier:create | Envia para análise. |
| POST /suppliers/{id}/approve · /reject | supplier:approve | Aprovação do cadastro. Motivo obrigatório na recusa. |
| POST /suppliers/{id}/promote | supplier:approve | Prospect → SpendAuthorized. Justificativa obrigatória na promoção manual. |
| POST /suppliers/{id}/block · /unblock | supplier:block | Motivo obrigatório nos dois sentidos. |
| GET /suppliers/{id}/establishments POST PUT | supplier:update | CNPJ validado e único. |
| PUT /suppliers/{id}/addresses · /contacts | supplier:update | Reescrevem o conjunto. |
| POST /suppliers/{id}/documents | supplier:update | Multipart. Tipo, número, emissão e vencimento conforme o tipo exige. |
| GET /suppliers/{id}/document-requirements | supplier:read | Resolve o pacote exigido dado categorias e faixa de risco, com o que está pendente, vencido e dispensado. |
| POST /suppliers/{id}/verifications | supplier:verify | Dispara consulta às fontes escolhidas e grava o resultado. |
| GET /suppliers/{id}/verifications | supplier:read | Histórico append-only. |
| GET /suppliers/{id}/bank-accounts | supplier.bank:read | Permissão própria. Números mascarados salvo permissão elevada. |
| POST /suppliers/{id}/bank-accounts/change-proposals | supplier.bank:propose | Cria a proposta. Nunca altera o registro vivo. |
| POST /bank-change-proposals/{id}/approve · /reject | supplier.bank:approve | Aprovador ≠ solicitante, validado no domínio. |
| GET /suppliers/{id}/qualifications POST | supplier.qualification:manage | Homologação por categoria. |
| PUT /suppliers/{id}/categories | supplier:update | Categorias declaradas. |
| GET /suppliers/{id}/performance | supplier:read | Agregados de OTIF, atraso, divergência e aderência de preço. |
| POST /suppliers/invite | supplier:create | Convite de autocadastro por e-mail, com escopo de categorias sugerido. |
| GET /suppliers/{id}/audit | supplier.audit:read | Diff de campos e log de acesso a dado pessoal. |
Contrato
Códigos de erro
| Código | HTTP | Quando |
|---|---|---|
| SUPPLIER_NOT_FOUND | 404 | Fornecedor inexistente no tenant |
| SUPPLIER_CNPJ_INVALID | 400 | Formato ou dígito verificador inválido |
| SUPPLIER_CPF_INVALID | 400 | CPF inválido em fornecedor pessoa física |
| SUPPLIER_FIELD_NOT_APPLICABLE | 400 | Campo preenchido que o tipo de pessoa não usa |
| SUPPLIER_IE_STATE_REQUIRED | 400 | Inscrição estadual informada sem UF |
| SUPPLIER_PRIMARY_ESTABLISHMENT_REQUIRED | 400 | Nenhum ou mais de um estabelecimento principal |
| SUPPLIER_DUPLICATE_CONFLICT | 409 | CNPJ ou CPF já cadastrado, inclusive em rascunho ou pendente. Nome do existente exposto só a usuário interno |
| SUPPLIER_VERSION_CONFLICT | 409 | Versão defasada no PUT |
| SUPPLIER_NOT_SPEND_AUTHORIZED | 409 | Pedido para fornecedor em Prospect |
| SUPPLIER_BLOCKED_CONFLICT | 409 | Operação em fornecedor bloqueado — mensagem traz o motivo |
| SUPPLIER_REGISTRATION_STATUS_INVALID | 409 | Transição de processo inválida |
| SUPPLIER_HAS_DOCUMENTS_CONFLICT | 409 | Exclusão de fornecedor com RFQ, pedido ou nota |
| SUPPLIER_REQUIRED_DOCUMENTS_MISSING | 422 | Homologação sem os documentos exigidos — lista os tipos faltantes |
| SUPPLIER_DOCUMENT_EXPIRED_CONFLICT | 409 | Novo pedido com documento vencido de política bloqueante |
| SUPPLIER_REGISTRATION_STATUS_NOT_ACTIVE | 422 | Homologação de fornecedor com situação cadastral diferente de Ativa |
| QUALIFICATION_SCOPE_REQUIRED | 400 | Homologação sem categorias no escopo |
| BANK_CHANGE_REQUIRES_PROPOSAL | 409 | Tentativa de alterar campo bancário protegido por PUT direto |
| BANK_CHANGE_APPROVER_IS_REQUESTER | 409 | Aprovador igual ao solicitante |
| BANK_HOLDER_MISMATCH_CONFLICT | 409 | Documento do titular não confere com o do fornecedor |
| BANK_PIX_KEY_UNVERIFIED | 422 | Chave aleatória sem resolução de titularidade |
Autorização
Permissões
| Permissão | Cobre |
|---|---|
| supplier:read / create / update / delete | CRUD do cadastro |
| supplier:approve | Aprovar, recusar e promover a homologado |
| supplier:block | Bloquear e desbloquear |
| supplier:verify | Disparar consultas a fontes oficiais |
| supplier.qualification:manage | Homologação, questionários e requisitos de documento |
| supplier.bank:read | Ver dados bancários — números mascarados por padrão |
| supplier.bank:propose | Solicitar alteração bancária |
| supplier.bank:approve | Aprovar alteração bancária. Não deve estar no mesmo perfil de propose |
| supplier.audit:read | Histórico e log de acesso a dado pessoal |
Grupos sugeridos: Nexio - Fornecedores (read/create/update), Nexio - Homologação (+ approve, verify, qualification), Nexio - Tesouraria (bank:read + bank:approve, sem propose) e Nexio - Consulta (read). A separação entre quem propõe e quem aprova mudança bancária é a razão de existirem duas permissões.
Privacidade
LGPD
CNPJ não é dado pessoal. CPF de sócio, contato e fornecedor pessoa física são — e é aí que a lei incide.
| Situação | Base legal sugerida |
|---|---|
| Coletar contatos e dados para contratar e executar | Art. 7º, VI — execução de contrato e procedimentos preliminares a pedido do titular |
| Exigir certidões e guardar comprovações | Art. 7º, II — cumprimento de obrigação legal ou regulatória |
| Due diligence de integridade e prevenção a fraude | Art. 7º, IX — legítimo interesse, com teste de balanceamento documentado |
Consentimento é a base errada aqui
É o erro clássico. Se o fornecedor pode revogar a qualquer momento, o comprador perde a base para manter dados que precisa reter por obrigação legal.
Isole os dados pessoais em tabelas próprias, com retenção própria
SupplierContact e SupplierOwner têm ciclo de vida independente do cadastro da empresa. Contato de fornecedor que nunca fechou negócio não pode ficar para sempre.
Eliminação é anonimização parcial, não delete
Apague o contato pessoal e preserve o registro transacional pseudonimizado necessário à auditoria. Um delete que apaga o histórico de compras cria problema fiscal maior do que resolve.
Certidões cíveis e criminais de sócios são o ponto mais sensível
Coleta indiscriminada de antecedentes de todos os fornecedores dificilmente passa num teste de necessidade e proporcionalidade. Torne opcional, por faixa de risco alta, com justificativa registrada — nunca padrão do sistema.
Fornecedor pessoa física muda o tratamento inteiro
Ali o cadastro da "empresa" é cadastro de pessoa natural. Retenção, acesso e eliminação seguem regra diferente — isso justifica um caminho próprio no código, não um if.
Base compartilhada entre tenants é ótima em UX e é onde mora o risco
Reaproveitar o cadastro que um fornecedor já preencheu para outro comprador é o principal argumento comercial dos SRMs de homologação — e exige base legal explícita e transparência ao fornecedor. Se for construído, é decisão jurídica antes de ser decisão de produto.
Limites
Fora de escopo e pendências
- Título a pagar, aging, provisão, saldo em aberto. O Nexio pode exibir por integração; não é fonte da verdade.
- Cálculo de retenções (IRRF, INSS, ISS, CSRF), códigos de DARF, alíquotas. O Nexio carrega os insumos — regime tributário, IE, IM, natureza do serviço; quem calcula é o ERP fiscal. Resista ao pedido de incluir "só o campo de retenção": ele nunca vem sozinho.
- Conta contábil do fornecedor, plano de contas, conta de reconciliação.
- Calendário de vencimento, juros, multa e desconto. O prazo negociado é do Nexio; o cálculo é financeiro.
- Escrituração: EFD-Reinf, DCTFWeb, SPED, comprovantes de retenção.
- Remessa e retorno CNAB, conciliação bancária, arquivo de pagamento.
- Limite de crédito e campos de 1099 e afins, herdados de produtos americanos.
- Site comercial do fornecedor — condição de pagamento e moeda por unidade de relacionamento. Hoje ficam no estabelecimento.
- Local de entrega no
ItemSupplier— o eixo ship-to da ASL. Campo previsto, desligado. - Portal do fornecedor — autocadastro, upload de documento e resposta a RFQ pelo próprio fornecedor.
PortalUserexiste no modelo; o portal é projeto próprio. - Scorecard com avaliação humana — as métricas calculadas vêm primeiro.
- Integração cXML / punchout — projeto próprio, não campo de cadastro.
Pendências para decidir. (a) Qual fonte de consulta ao CNPJ: base própria a partir dos dados abertos, ou serviço comercial com SLA — a primeira dá soberania e custo previsível, a segunda dá atualidade. (b) O Nexio guarda dados bancários, ou só referencia o que está no ERP? A resposta muda o peso de toda a seção de segurança. (c) Base compartilhada de fornecedores entre tenants — decisão jurídica antes de produto. (d) Contatos e sócios: o quadro societário vem da Receita e é dado pessoal; entra no MVP ou fica para quando houver due diligence formal?