4. Modelo de Dados — Entrada¶
Este capítulo detalha a estrutura esperada dos dados que você deve enviar para cada endpoint.
O Que Atualizou¶
16/09/2026 — Venda Diária (ErpDailySales)¶
Endpoints: POST /erp-data/daily-sale, PUT /erp-data/daily-sale e suas versões em lote (/batch).
| Campo | Tipo | Obrigatoriedade | Validação | O que é |
|---|---|---|---|---|
| sellDateTimeUtc | datetime |
Obrigatório | ISO 8601 em UTC, terminado em Z |
Data e hora reais da venda |
| erpId | String | Obrigatório | Máx. 128 caracteres | Identificador da linha de venda no ERP |
| invoiceNumber | String | Opcional | Máx. 64 caracteres | Número da nota fiscal da venda |
| transactionCode | String | Opcional | Máx. 64 caracteres | Código da transação/cupom no ERP |
date deixou de ser aceito
O campo date foi substituído por sellDateTimeUtc. Registro enviado com date é recusado
com HTTP 400 e a mensagem O campo 'date' foi substituído por 'sellDateTimeUtc'.
Orientações de envio:
sellDateTimeUtc: o momento em que a venda ocorreu, com hora, minuto e segundo, em UTC. O envio apenas da data, com o horário fixo em00:00:00, deixa de ser o formato esperado.- Converter do horário de Brasília (UTC−3) somando 3 horas. Quando a soma passa da meia-noite, a
data em UTC é a do dia seguinte — e esse é o comportamento correto. Venda às 22:30 de 11/09 em
Brasília vai como
"2026-09-12T01:30:00Z". - Todas as linhas da mesma compra trazem o mesmo
sellDateTimeUtc,invoiceNumberetransactionCode. erpId: informado em todos os registros de venda diária, com um valor próprio por linha de venda.invoiceNumberetransactionCode: informados sempre que a venda possuir esses dados.
Regras de preenchimento em 4.3 Estrutura de Venda Diária.
4.1 Estrutura de Produto (ErpProduct)¶
Campos Obrigatórios¶
| Campo | Tipo | Tamanho | Descrição | Exemplo |
|---|---|---|---|---|
| erpId | Long (Número inteiro) | até 19 dígitos | ID único do produto no seu ERP | 12345 |
| ncmCode | String | até 8 caracteres | Código NCM do produto | "84733090" |
| status | String | até 50 caracteres | Status do produto (Active, Inactive, etc.) | "Active" |
| description | String | até 500 caracteres | Nome/descrição do produto | "Dipirona 500mg Cápsulas" |
Campos Opcionais (Altamente Recomendados)¶
| Campo | Tipo | Tamanho | Descrição | Exemplo |
|---|---|---|---|---|
| ean | String | até 13 caracteres | Código de barras EAN | "7896045000001" |
| brand | String | até 100 caracteres | Marca do produto | "Genérico" |
| sku | String | até 100 caracteres | Identificador SKU interno | "SKU-DIPO-500-001" |
| internalDescription | String | até 500 caracteres | Descrição interna | "Analgésico - Genérico" |
| healthRegistration | String | até 50 caracteres | Número do registro de saúde | "61541" |
| manufacturer | String | até 200 caracteres | Nome do fabricante | "Laboratório Exemplo" |
| manufacturerCnpj | String | 14 caracteres (com ou sem formatação) | CNPJ do fabricante | "12.345.678/0001-90" |
Campos Opcionais (Complementares)¶
| Campo | Tipo | Tamanho | Descrição | Exemplo |
|---|---|---|---|---|
| webName | String | até 200 caracteres | Nome para exibição na web | "Dipirona 500mg" |
| specification | String | até 1000 caracteres | Especificações técnicas | "Cápsulas de 500mg, frasco com 20" |
| metaDescription | String | até 500 caracteres | Meta-descrição para SEO | "Compre Dipirona 500mg online" |
| weightGr | Decimal | até 99.999,99 | Peso em gramas | 25.50 |
| lengthCm | Decimal | até 99.999,99 | Comprimento em cm | 10.0 |
| widthCm | Decimal | até 99.999,99 | Largura em cm | 5.0 |
| heightCm | Decimal | até 99.999,99 | Altura em cm | 15.0 |
| ipi | Boolean | --- | Sujeito a IPI? | true |
| dun | String | até 14 caracteres | Código DUN | "2345678900018" |
| purchaseGroup | String | até 100 caracteres | Grupo de compra | "Analgésicos" |
| purchaseStatus | String | até 50 caracteres | Status para compra | "Available" |
| taxClassification | String | até 50 caracteres | Classificação fiscal | "ClassA" |
| boxQuantity | String | até 50 caracteres | Quantidade por caixa | "20" |
| billingQuantity | String | até 50 caracteres | Quantidade para faturamento | "1" |
| activePrinciple | String | até 200 caracteres | Princípio ativo | "Dipirona Monoidratada" |
| healthRegistrationReason | String | até 200 caracteres | Motivo do registro | "Medicamento" |
| keywords | String | até 500 caracteres | Palavras-chave para busca | "dor, febre, analgésico" |
| indication | String | até 1000 caracteres | Indicações de uso | "Dor leve a moderada, febre" |
| contraindication | String | até 1000 caracteres | Contra-indicações | "Alergia à dipirona" |
| medicalPrescriptionType | String | até 50 caracteres | Tipo de prescrição | "None" ou "Required" |
| continuousUse | Boolean | --- | Medicamento de uso contínuo? | false |
| controlledSale | Boolean | --- | Venda controlada? | false |
| minimumPurchaseMultiple | Integer | até 9.999 | Múltiplo mínimo de compra | 1 |
Exemplo Válido — Mínimo¶
{
"erpId": 12345,
"ncmCode": "84733090",
"status": "Active",
"description": "Dipirona 500mg Cápsulas"
}
Exemplo Válido — Completo¶
{
"erpId": 12345,
"ncmCode": "84733090",
"status": "Active",
"ean": "7896045000001",
"description": "Dipirona 500mg Cápsulas",
"internalDescription": "Genérico - Analgésico",
"webName": "Dipirona 500mg",
"specification": "Cápsulas de 500mg, frasco com 20",
"metaDescription": "Compre Dipirona 500mg online",
"brand": "Genérico",
"sku": "SKU-DIPO-500-001",
"healthRegistration": "61541",
"manufacturer": "Laboratório Exemplo",
"manufacturerCnpj": "12.345.678/0001-90",
"weightGr": 25.5,
"lengthCm": 10.0,
"widthCm": 5.0,
"heightCm": 15.0,
"ipi": false,
"purchaseGroup": "Analgésicos",
"purchaseStatus": "Available",
"activePrinciple": "Dipirona Monoidratada",
"indication": "Dor leve a moderada, febre",
"contraindication": "Alergia à dipirona",
"medicalPrescriptionType": "None",
"continuousUse": false,
"controlledSale": false,
"minimumPurchaseMultiple": 1
}
Exemplos Inválidos¶
❌ Exemplo 1: Campo Obrigatório Ausente¶
Erro esperado:
❌ Exemplo 2: Tipo de Dado Incorreto¶
{
"erpId": "não é um número",
"ncmCode": "84733090",
"status": "Active",
"description": "Dipirona 500mg"
}
Erro esperado:
❌ Exemplo 3: Campo Vazio¶
Erro esperado:
❌ Exemplo 4: Tamanho Máximo Excedido¶
{
"erpId": 12345,
"ncmCode": "84733090123456789", // Máximo 8 caracteres
"status": "Active",
"description": "Dipirona 500mg"
}
Erro esperado:
4.2 Estrutura de Estoque (ErpStock)¶
Campos Obrigatórios¶
| Campo | Tipo | Descrição | Exemplo |
|---|---|---|---|
| company | Decimal | Código da empresa | 1 |
| companyName | String | Nome da empresa | "Loja Centro" |
| address | String | Endereço da loja | "Rua Principal, 100" |
| productDescription | String | Descrição do produto | "Dipirona 500mg" |
Campos Recomendados¶
| Campo | Tipo | Descrição | Exemplo |
|---|---|---|---|
| currentStock | Decimal | Quantidade em estoque | 500.00 |
| warehouseTransit | Decimal | Quantidade em trânsito | 100.00 |
| distributionCenterStock | Decimal | Estoque no CD | 2000.00 |
| brand | String | Marca | "Genérico" |
| currentAbcCurve | String | Classificação ABC | "A" |
| cnpj | String | CNPJ da loja | "12.345.678/0001-90" |
| venancioBarcodeCode | String | Código de barras | "7896045000001" |
Exemplo Válido¶
{
"company": 1,
"companyName": "Loja Centro",
"address": "Rua Principal, 100",
"productDescription": "Dipirona 500mg",
"currentStock": 500.0,
"warehouseTransit": 100.0,
"distributionCenterStock": 2000.0,
"brand": "Genérico",
"currentAbcCurve": "A",
"cnpj": "12.345.678/0001-90"
}
4.3 Estrutura de Venda Diária (ErpDailySales)¶
Campos Obrigatórios¶
| Campo | Tipo | Descrição | Validação | Exemplo |
|---|---|---|---|---|
| erpId | String | Identificador da linha de venda no ERP | Máx. 128 caracteres | "CUPOM-100234-LINHA-1" |
| erpProductId | String | ID do produto no ERP | Deve existir | "12345" |
| erpStoreId | String | ID da loja no ERP | Deve existir | "1001" |
| sellDateTimeUtc | DateTime | Data e hora reais da venda | Deve ser UTC | "2026-09-11T17:32:10Z" |
| quantity | Decimal | Quantidade vendida | > 0 | 15.00 |
| totalSellValue | Decimal | Valor total da venda | >= 0 | 125.50 |
Campos Opcionais¶
| Campo | Tipo | Descrição | Validação | Exemplo |
|---|---|---|---|---|
| invoiceNumber | String | Número da nota fiscal da venda | Máx. 64 caracteres | "000123456" |
| transactionCode | String | Código da transação/cupom no ERP | Máx. 64 caracteres | "CUPOM-100234" |
| origin | String | Origem da venda | Máx. 128 caracteres | "Balcão" |
| deliveryMethod | String | Método de entrega | Máx. 64 caracteres | "Retirada" |
O campo erpId¶
Identificador da linha de venda no ERP (o item do cupom ou da transação). Obrigatório em todos os registros de venda diária.
- Use o identificador da linha que o próprio ERP já gera. Não gere o valor a partir de outros campos do payload (por exemplo, um hash de produto + loja + data).
- Cada linha de venda tem seu próprio
erpId. Uma compra com três produtos gera três registros, com trêserpIddiferentes. - O valor deve ser estável: a mesma linha de venda tem sempre o mesmo
erpId, em qualquer envio. - Correções: para corrigir uma venda já enviada, reenvie o registro com o mesmo
erpIde os valores corretos. O registro anterior é substituído.
Os campos invoiceNumber e transactionCode¶
Identificam a compra à qual a linha de venda pertence. Opcionais.
| Campo | O que enviar |
|---|---|
invoiceNumber |
Número da nota fiscal da venda. |
transactionCode |
Código da transação ou do cupom no ERP. |
- Todas as linhas da mesma compra devem trazer o mesmo
invoiceNumbere/outransactionCode. - Envie os dois quando a venda tiver os dois. Se tiver só um, envie só esse.
- Envie o valor exatamente como está no ERP. Máscara, série, zeros à esquerda e a chave de acesso de 44 dígitos são aceitos, desde que caibam em 64 caracteres.
- Não gere esses valores a partir de outros campos do payload.
- Esses campos não substituem o
erpId:erpIdidentifica a linha einvoiceNumber/transactionCodeidentificam a compra.
Importante: Tratamento de Data¶
Mudança de 16/09/2026. O campo
datepassou a se chamarsellDateTimeUtce o nome antigo deixou de ser aceito — payload comdaterecebe HTTP 400 com a mensagem O campo 'date' foi substituído por 'sellDateTimeUtc'. Mudou também o conteúdo: espera-se o instante real da venda (hora, minuto e segundo), e não mais o dia com00:00:00Z.
⚠️ CRÍTICO PARA POSTGRESQL
A data DEVE estar em formato ISO 8601 com timezone UTC:
✅ Formatos Válidos:
❌ Formatos Inválidos:
2026-09-11 // Sem hora
17:32:10 // Sem data
2026-09-11T17:32:10 // Sem Z (timezone)
2026-09-11T14:32:10-03:00 // Fuso local; converter para UTC
11/09/2026 14:32:10 // Fora do padrão ISO 8601
Conversão do horário de Brasília (UTC−3): somar 3 horas. Venda às 22:30 de 11/09 em
Brasília vai como "2026-09-12T01:30:00Z" — dia seguinte em UTC, e isso está correto.
Exemplo Válido¶
{
"erpId": "CUPOM-100234-LINHA-1",
"erpProductId": "12345",
"erpStoreId": "1001",
"sellDateTimeUtc": "2026-09-11T17:32:10Z",
"quantity": 15.0,
"totalSellValue": 125.5,
"invoiceNumber": "000123456",
"transactionCode": "CUPOM-100234",
"origin": "Balcão",
"deliveryMethod": "Retirada"
}
Exemplo Inválido — Data Sem Timezone¶
{
"erpId": "CUPOM-100234-LINHA-1",
"erpProductId": "12345",
"erpStoreId": "1001",
"sellDateTimeUtc": "2026-09-11T17:32:10", // ❌ Faltando Z
"quantity": 15.0,
"totalSellValue": 125.5
}
Erro esperado:
4.4 Estrutura de Loja (ErpStore)¶
Campos Obrigatórios¶
| Campo | Tipo | Descrição | Exemplo |
|---|---|---|---|
| erpId | String | ID da loja no ERP | "1001" |
| title | String | Nome da loja | "Farmácia Centro" |
Campos Recomendados¶
| Campo | Tipo | Descrição | Exemplo |
|---|---|---|---|
| taxId | String | CNPJ da loja | "12.345.678/0001-90" |
| stateRegistration | String | Inscrição Estadual | "123.456.789.012" |
| zipCode | String | CEP | "01234-567" |
| address | String | Logradouro | "Rua Principal" |
| number | String | Número | "100" |
| complement | String | Complemento | "Próximo à estação" |
| neighborhood | String | Bairro (máx. 128 caracteres) | "Centro" |
| city | String | Cidade (máx. 128 caracteres) | "São Paulo" |
| state | String | UF, sigla de 2 letras | "SP" |
Campos de Características¶
| Campo | Tipo | Descrição | Exemplo |
|---|---|---|---|
| performsInjection | Boolean | Realiza injeções? | true |
| sellsControlled | Boolean | Vende controlados? | false |
| hasPopularFarmacy | Boolean | Farmácia Popular? | true |
| storeType | String | Tipo de loja | "Popular" |
| storeSize | String | Tamanho (P, M, G) | "M" |
Campos de Funcionamento¶
| Campo | Tipo | Descrição | Formato |
|---|---|---|---|
| weekdayHours | String | Horário seg-sex | "09:00-20:00" |
| saturdayHours | String | Horário sábado | "09:00-18:00" |
| sundayHours | String | Horário domingo | "10:00-16:00" |
| openingDate | DateTime | Data de abertura | "2020-01-15T00:00:00Z" |
| isActive | Boolean | Loja ativa? | true |
Exemplo Válido¶
{
"erpId": "1001",
"title": "Farmácia Centro",
"taxId": "12.345.678/0001-90",
"stateRegistration": "123.456.789.012",
"zipCode": "01234-567",
"address": "Rua Principal",
"number": "100",
"complement": "Próximo à estação",
"neighborhood": "Centro",
"city": "São Paulo",
"state": "SP",
"performsInjection": true,
"sellsControlled": false,
"hasPopularFarmacy": true,
"storeType": "Popular",
"storeSize": "M",
"weekdayHours": "09:00-20:00",
"saturdayHours": "09:00-18:00",
"sundayHours": "10:00-16:00",
"openingDate": "2020-01-15T00:00:00Z",
"isActive": true
}
4.5 Estrutura de Fornecedor (ErpSupplier)¶
Campos Típicos¶
| Campo | Tipo | Descrição | Exemplo |
|---|---|---|---|
| erpId | String | ID do fornecedor | "5001" |
| name | String | Nome do fornecedor | "Laboratório Exemplo" |
| cnpj | String | CNPJ | "98.765.432/0001-11" |
| address | String | Endereço | "Av. Paulista, 1000" |
| stateRegistration | String | IE | "987.654.321.012" |
4.6 Estrutura de Venda Mensal (ErpMonthlySales)¶
Similar à Venda Diária, mas com data agregada:
| Campo | Tipo | Descrição | Exemplo |
|---|---|---|---|
| erpProductId | String | ID do produto | "12345" |
| erpStoreId | String | ID da loja | "1001" |
| month | DateTime | Mês da venda | "2024-12-01T00:00:00Z" |
| quantity | Decimal | Quantidade vendida | 450.00 |
| totalSellValue | Decimal | Valor total | 3750.00 |
4.7 Validações Gerais Aplicadas¶
Validações de Tipo¶
✓ String → Texto
✓ Decimal → Números com vírgula (0.00)
✓ Boolean → true ou false
✓ DateTime → ISO 8601 com Z
✗ Qualquer outro tipo → Erro 400
Validações de Tamanho¶
✓ Campo com até 50 caracteres → Aceita de 0-50
✗ Campo com até 50 caracteres → Rejeita > 50
✓ Campo obrigatório → Não pode ser vazio
✗ Campo obrigatório → Se vazio, erro
Validações de Formato¶
✓ NCM: 8 caracteres numéricos
✓ EAN: 13 caracteres (com ou sem dígito verificador)
✓ CNPJ: 14 caracteres (com ou sem formatação)
✓ CEP: 8 caracteres (com ou sem hífen)
✓ Data: ISO 8601 UTC com Z
Checklist de Dados — Antes de Enviar¶
- [ ] Todos os campos obrigatórios estão preenchidos?
- [ ] Nenhum campo obrigatório está vazio ou null?
- [ ] Números estão em formato decimal (ex: 123.45)?
- [ ] Datas estão no formato UTC ISO 8601 com Z?
- [ ] Strings não excedem o tamanho máximo?
- [ ] Booleanos estão como true/false (não "1"/"0")?
- [ ] Códigos (NCM, EAN, CNPJ) têm o tamanho correto?
- [ ] Nenhum caractere especial indevido nas strings?