Guia de integração — Tabela de preços
Microserviço: XDPeople.Soba.WebAPI (Core API)
Autenticação: token Bearer (JWT) e contexto de tenant — ver Login Combinado
Introdução
Este guia descreve como integrar com a API para gerir linhas de preços (tabelas de preços) no ecossistema SOBA. Uma linha de preços é composta por um cabeçalho (PriceTableDTO) e por linhas (PriceTableItemDTO), cada uma associada a um artigo (Item) ou a uma família de artigos (ItemGroup).
O modelo distingue dois tipos de tabela no campo priceTableType:
| Valor | Nome (enum) | Significado |
|---|---|---|
0 | Absolute | Preços explícitos por artigo; pode incluir linhas do tipo família (ItemGroup) conforme o modelo; a API exige pelo menos uma linha em items. |
1 | Relative | Variação em relação a uma linha absoluta de referência (absolutePriceLineId); regras adicionais aplicam-se na gravação. |
Cada linha em items usa itemType:
| Valor | Nome (enum) | Significado |
|---|---|---|
0 | Item | Artigo individual (itemKeyId = chave do artigo). |
1 | ItemGroup | Família de artigos (itemKeyId tipicamente o identificador da família como texto). |
O objetivo é apoiar integradores na utilização correta dos endpoints, na construção do corpo JSON e na antecipação de validações e erros devolvidos pelo servidor.
Regras de negócio e limites
As regras abaixo são aplicadas no serviço de aplicação antes de persistir dados. Incumprir uma delas devolve erro com o código indicado (formato típico da API — ver documentação de erros HTTP).
| Regra | Detalhe | Código de erro (exemplo) |
|---|---|---|
| Tabela relativa | Se priceTableType é Relative (1), absolutePriceLineId não pode ser inválido (valor estritamente inferior a 0). | PriceTableValidation.InvalidAbsolutePriceLine |
| Tabela absoluta | Se priceTableType é Absolute (0), a lista items tem de existir e conter pelo menos um elemento. | PriceTableValidation.AbsolutePriceLineRequiredItems |
| Intervalo de datas | startDate não pode ser posterior a endDate. | PriceTableValidation.InvalidDateInterval |
| Identificadores 0–5 | Reservados no produto (preço de custo e linhas de preço 1 a 5). Para novas linhas configuráveis pelo integrador, prefira o identificador devolvido por GET /gateway/price-table/next-id (≥ 6). | — ver GET /gateway/price-table/next-id |
Recomenda-se obter o próximo identificador com GET /gateway/price-table/next-id antes de criar uma nova linha, para evitar colisões e respeitar o mínimo configurado no servidor.
Obrigatoriedade e consistência do payload por priceTableType
O valor de priceTableType altera as validações do servidor e o conjunto de campos que devem estar coerentes no JSON.
Tabela absoluta (priceTableType = 0)
| Aspeto | O que garantir |
|---|---|
| Obrigatório (API) | items tem de existir e ter pelo menos um elemento. Caso contrário: PriceTableValidation.AbsolutePriceLineRequiredItems. |
| Consistência | Preencher discountPercentage1, discountPercentage2, discountPercentage3 no cabeçalho quando o modelo de negócio aplicar descontos globais; replicar ou complementar por linha em items conforme necessário. |
| Consistência | Alinhar isTaxIncludedPrice no cabeçalho com o critério de preço nas linhas: se o preço principal for com IVA, use taxIncludedPrice e isTaxIncludedPrice: true nas entradas relevantes; caso contrário privilegie netPrice e isTaxIncludedPrice: false. |
| Datas | startDate não pode ser posterior a endDate (validação comum a ambos os tipos). |
Tabela relativa (priceTableType = 1)
| Aspeto | O que garantir |
|---|---|
| Obrigatório (API) | absolutePriceLineId não pode ser inferior a 0. Caso contrário: PriceTableValidation.InvalidAbsolutePriceLine. Na prática deve identificar uma linha de preços absoluta existente e válida no vosso contexto (referência para o cálculo relativo). |
| Consistência | Definir percentageReference de acordo com o ajuste percentual global pretendido (valor e sinal conforme a vossa convenção de aumento ou desconto). O DTO expõe apenas percentageReference; não envie propriedades que não existam no contrato. |
| Consistência | Em items, cada artigo ou família (itemType) deve incluir os descontos em percentagem (discountPercentage1–3) e restantes campos exigidos pelo fluxo de preço relativo que implementam. Sem linhas, confirme no vosso analista de negócio se uma tabela relativa sem items é admitida no produto — a validação CanSave atual não exige linhas para o tipo relativo. |
| Datas | Mesma regra que na tabela absoluta (startDate / endDate). |
Campos comuns aos dois tipos
id, description, startDate, endDate e priceTableType devem estar sempre definidos de forma válida no pedido. Os restantes campos do PriceTableDTO permanecem no contrato; valores por omissão (por exemplo 0) só são aceitáveis se forem semanticamente corretos para o caso de uso.
Endpoints disponíveis
Todos os caminhos abaixo assumem o prefixo público /gateway/price-table (Core API através do gateway).
| Método | URL | Descrição resumida |
|---|---|---|
| GET | /gateway/price-table | Lista linhas de preços com paginação opcional. |
| GET | /gateway/price-table/next-id | Devolve o próximo identificador sugerido (mínimo 6). |
| GET | /gateway/price-table/{id} | Obtém uma linha por identificador, incluindo items. |
| POST | /gateway/price-table | Cria uma nova linha de preços. Resposta 201 Created em caso de sucesso. |
| PUT | /gateway/price-table/{id} | Atualiza a linha indicada. Resposta 204 No Content em caso de sucesso. |
| DELETE | /gateway/price-table/{id} | Elimina a linha indicada. Resposta 204 No Content em caso de sucesso. |
Listar linhas de preços
URL: /gateway/price-table
Método: GET
Parâmetros de consulta (opcionais):
| Parâmetro | Tipo | Descrição |
|---|---|---|
page | int | Número da página (base 1), quando aplicável. |
pageSize | int | Tamanho da página. |
Comportamento: devolve uma listagem paginada das tabelas de preços.
Obter o próximo identificador
URL: /gateway/price-table/next-id
Método: GET
Comportamento: devolve um inteiro com o próximo ID sugerido, não inferior a 6, para novas linhas de preços personalizadas.
Obter uma linha por identificador
URL: /gateway/price-table/{id}
Método: GET
Parâmetro de rota:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | int | Sim | Identificador da linha de preços. |
Comportamento: devolve PriceTableDTO com a coleção items preenchida quando existir.
Criar linha de preços
URL: /gateway/price-table
Método: POST
Corpo: JSON no modelo PriceTableDTO (ver tabelas de campos abaixo).
Comportamento em sucesso: 201 Created (sem corpo de resposta no controlador atual).
Atualizar linha de preços
URL: /gateway/price-table/{id}
Método: PUT
Parâmetros: id na rota; corpo PriceTableDTO.
Comportamento em sucesso: 204 No Content.
Eliminar linha de preços
URL: /gateway/price-table/{id}
Método: DELETE
Comportamento em sucesso: 204 No Content.
Estrutura do corpo (PriceTableDTO)
Campos mais relevantes para integração (outros campos de sincronização ou nuvem podem ser omitidos ou nulos consoante o caso de uso). As regras por tipo de tabela estão em Obrigatoriedade e consistência do payload por tipo.
| Campo | Tipo | Obrigatório (API / validação) | Descrição |
|---|---|---|---|
id | int | Sim na prática | Identificador da linha. |
description | string | Sim (máx. 20 caracteres) | Descrição curta. |
priceTableType | int (enum) | Sim | 0 Absoluta, 1 Relativa. |
startDate | date-time | Sim | Início de vigência. |
endDate | date-time | Sim | Fim de vigência (não pode ser anterior a startDate). |
absolutePriceLineId | int | Condição | Obrigatório coerente para tipo relativa (referência a linha absoluta; na validação do servidor não pode ser negativo). |
percentageReference | decimal | Não | Referência percentual global (sinal pode indicar aumento ou desconto consoante convenção do cliente). |
discountPercentage1 | decimal | Não | Desconto 1 (%). |
discountPercentage2 | decimal | Não | Desconto 2 (%). |
discountPercentage3 | decimal | Não | Desconto 3 (%). |
isTaxIncludedPrice | bool | Não | Se os preços nas linhas são tratados com IVA incluído. |
inactive | bool | Não | Linha inativa. |
items | array | Condição | Obrigatório ter elementos para tipo absoluta. |
Estrutura de cada linha (PriceTableItemDTO)
| Campo | Tipo | Descrição |
|---|---|---|
priceLineId | int | Identificador da linha de preço no contexto da tabela. |
itemKeyId | string | Chave do artigo ou identificador usado para família, conforme itemType. |
itemAttributeCode | string | Código de atributo do artigo, quando aplicável. |
itemType | int | 0 Artigo, 1 Família. |
description | string | Descrição apresentável. |
percentageReference | decimal | Referência percentual ao nível da linha. |
discountPercentage1 | decimal | Desconto 1 (%). |
discountPercentage2 | decimal | Desconto 2 (%). |
discountPercentage3 | decimal | Desconto 3 (%). |
netPrice | decimal | Preço líquido. |
taxIncludedPrice | decimal | Preço com imposto incluído. |
isTaxIncludedPrice | bool | Se o preço da linha inclui imposto. |
itemPriceLineId | int? | Linha de preço de referência por artigo (quando usado no produto). |
Exemplo de pedido de criação (tabela absoluta)
Corpo JSON ilustrativo (valores de exemplo):
{
"id": 14,
"description": "Linha 14",
"startDate": "2026-05-13T10:15:58.222Z",
"endDate": "2026-05-14T10:15:58.222Z",
"priceTableType": 0,
"absolutePriceLineId": 0,
"percentageReference": 0,
"discountPercentage1": 1,
"discountPercentage2": 0,
"discountPercentage3": 0,
"isTaxIncludedPrice": true,
"inactive": false,
"items": [
{
"priceLineId": 14,
"itemKeyId": "1",
"itemAttributeCode": "",
"itemType": 0,
"description": "Dom Diogo (Arinto)",
"percentageReference": 0,
"discountPercentage1": 1,
"discountPercentage2": 0,
"discountPercentage3": 0,
"netPrice": 0,
"taxIncludedPrice": 0,
"isTaxIncludedPrice": true,
"itemPriceLineId": null
}
]
}
Exemplo de pedido de criação (tabela relativa)
{
"id": 15,
"description": "Linha 15",
"startDate": "2026-05-13T10:15:58.222Z",
"endDate": "2026-05-14T10:15:58.222Z",
"priceTableType": 1,
"absolutePriceLineId": 1,
"percentageReference": 10,
"discountPercentage1": 0,
"discountPercentage2": 0,
"discountPercentage3": 0,
"isTaxIncludedPrice": false,
"inactive": false,
"items": [
{
"priceLineId": 15,
"itemKeyId": "3",
"itemAttributeCode": "",
"itemType": 1,
"description": "Carnes",
"percentageReference": 0,
"discountPercentage1": 0,
"discountPercentage2": 0,
"discountPercentage3": 0,
"netPrice": 0,
"taxIncludedPrice": 0,
"isTaxIncludedPrice": false,
"itemPriceLineId": null
}
]
}
Notas sobre o payload (apenas API)
- O integrador deve enviar JSON conforme
PriceTableDTOePriceTableItemDTO. As validações descritas neste guia aplicam-se a qualquer sistema cliente da API. - A secção Obrigatoriedade e consistência por tipo resume o que o integrador deve enviar ou alinhar por
priceTableType, além das validações genéricas abaixo. - Em tabela relativa (
priceTableType = 1), preenchaabsolutePriceLineIdde forma coerente com a linha absoluta de referência (a API rejeita referência inválida segundo as regras do servidor). - Em tabela absoluta (
priceTableType = 0), a listaitemstem de ter pelo menos uma entrada. - Os campos
discountPercentage1,discountPercentage2,discountPercentage3epercentageReferenceexistem no contrato no cabeçalho e nas linhas; podem ser utilizados consoante o vosso modelo de preços, desde que o conjunto respeite as validações do servidor. - Carga em massa: não há recurso dedicado para importação de ficheiros; construam
itemsno vosso sistema e utilizemPOSTouPUT.
Erros frequentes
| Código | Tipo típico | Significado e ação sugerida |
|---|---|---|
PriceTable.NotFound | 404 | Identificador inexistente em consulta, atualização ou eliminação. |
PriceTableCreate.Fail | 409 / falha | A persistência da criação falhou; rever dados e repetir; contactar suporte se persistir. |
PriceTableUpdate.Fail | 409 / falha | A atualização falhou no armazenamento. |
PriceTableDelete.Fail | 409 / falha | A eliminação falhou no armazenamento. |
PriceTableValidation.InvalidAbsolutePriceLine | 400 | Tabela relativa com referência absoluta inválida (absolutePriceLineId negativo). |
PriceTableValidation.AbsolutePriceLineRequiredItems | 400 | Tabela absoluta sem linhas em items. |
PriceTableValidation.InvalidDateInterval | 400 | startDate posterior a endDate. |
As respostas de erro seguem o padrão HTTP da API (Problem Details / HttpResponseError conforme versão). Valide sempre o código HTTP e o payload de erros.
Conclusão
A gestão de linhas de preços via Core API resume-se a operações CRUD sobre /gateway/price-table, com validações claras para tipos absoluto e relativo e para o intervalo de datas. Recomenda-se testar em ambiente de staging todos os cenários (criação com next-id, atualização parcial de items, tabelas relativas com referência válida e erros de validação) antes de produção.
Recursos relacionados
- Lista paginada de linhas de preços
- Criar linha de preços
- Atualizar linha de preços
- Eliminar linha de preços
- Obter linha por identificador
- Obter próximo identificador
Última atualização: 13 de Maio de 2026