Guia de integração — Configuração de pontos
Microserviço: XDPeople.Soba.WebAPI (Core API)
Autenticação: token Bearer (JWT) e contexto de tenant — ver Login Combinado
Introdução
Este guia descreve a integração com a API para gerir configurações de pontos (regras de atribuição de pontos por documento ou por linha).
O campo criteriaType (PointsConfigCriteriaType) define qual critério aninhado deve estar preenchido no pedido:
| Valor | Nome | Objeto no JSON |
|---|---|---|
0 | Header | defaultHeaderCriteria (regra ao nível do cabeçalho do documento). |
1 | DefaultDetailsWithItemSearchCriteria | defaultDetailsItemCriteria (detalhes com pesquisa por artigo). |
2 | DefaultDetailsWithFamilySearchCriteria | defaultDetailsFamilyCriteria (detalhes com pesquisa por família). |
Os outros dois objetos de critério devem ser null ou omitidos, de forma a que apenas o ramo correspondente a criteriaType esteja definido no corpo.
Endpoints disponíveis
Prefixo público: /gateway/points-config.
| Método | URL | Descrição resumida |
|---|---|---|
| GET | /gateway/points-config | Lista configurações com paginação opcional (page, pageSize); ver regras de paginação. |
| GET | /gateway/points-config/{id} | Obtém uma configuração por Guid. |
| GET | /gateway/points-config/next-order | Devolve o próximo número de ordem sugerido para uma nova entrada. |
| POST | /gateway/points-config | Cria uma configuração; resposta 201 Created com Guid no corpo. |
| PUT | /gateway/points-config | Atualiza uma configuração existente; o id vai no corpo (PointsConfigDTO.Id); resposta 204 No Content. |
| DELETE | /gateway/points-config/{id} | Elimina por Guid; resposta 204 No Content. |
Listar configurações
URL: /gateway/points-config — Método: GET
Obter por identificador
URL: /gateway/points-config/{id} — Método: GET
Próxima ordem
URL: /gateway/points-config/next-order — Método: GET
Criar
URL: /gateway/points-config — Método: POST
Atualizar
URL: /gateway/points-config — Método: PUT (identificador no corpo, não na rota)
Eliminar
URL: /gateway/points-config/{id} — Método: DELETE
Estrutura do corpo (PointsConfigDTO)
| Campo | Tipo | Descrição |
|---|---|---|
id | Guid? | Obrigatório em atualização; omitido ou vazio em criação. |
order | int | Ordem de apresentação / prioridade (validação: ver secção de validações). |
description | string | Descrição (obrigatória no modelo). |
active | bool | Configuração ativa. |
cumulative | bool | Permitir acumular com outras atribuições. |
allowDecimalPoints | bool | Permitir pontos decimais. |
startDate | date-time | Início de vigência. |
endDate | date-time | Fim de vigência. |
criteriaType | int (enum) | Tipo de critério (tabela acima). |
defaultHeaderCriteria | objeto? | Critério de cabeçalho; ver abaixo. |
defaultDetailsItemCriteria | objeto? | Critério detalhe artigo; ver abaixo. |
defaultDetailsFamilyCriteria | objeto? | Critério detalhe família; ver abaixo. |
Campos auxiliares de listagem (StartDateHolder, EndDateHolder, ActiveHolder, IsPreCompiled, etc.) podem existir no contrato gerado; para integração REST concentre-se nos campos acima e nos critérios aninhados.
Base comum aos critérios (BaseCriteriaDTO)
Presente em qualquer critério não nulo:
| Campo | Tipo | Descrição |
|---|---|---|
totalPoints | decimal | Total de pontos (modelo; frequentemente 0 à criação). |
pointsBase | decimal | Base de pontos (validação numérica no DTO). |
eachY | decimal | Denominador “Y” quando a fórmula é X por Y; caso contrário tipicamente 0. |
formulaBase | int (enum) | 0 = XTimes, 1 = XForY. |
defaultHeaderCriteria (DefaultHeaderCriteriaDTO)
Inclui os campos de BaseCriteriaDTO mais:
| Campo | Tipo | Descrição |
|---|---|---|
documentField | int (enum) | Campo do documento usado na base do cálculo (total documento, líquido, impostos, valor pago, etc.). |
defaultDetailsItemCriteria / defaultDetailsFamilyCriteria
Estendem BaseCriteriaDTO com:
| Campo | Tipo | Descrição |
|---|---|---|
detailField | int (enum) | Campo da linha de detalhe (quantidade, preços, totais, etc.). |
searchType | int (enum) | 0 = lista, 1 = individual. |
searchPool | array | Conjunto de referências; cada elemento segue DefaultDetailsItemDTO (artigo) ou DefaultDetailsFamilyDTO (família), conforme o critério. |
Elementos de searchPool
| Critério | DTO do elemento | Propriedades |
|---|---|---|
defaultDetailsItemCriteria | DefaultDetailsItemDTO | id, description, keyId |
defaultDetailsFamilyCriteria | DefaultDetailsFamilyDTO | id, description, idParent (ascendente na hierarquia de famílias) |
O campo searchType no critério de detalhe indica o modo de pesquisa (0 = lista, 1 = individual). O serviço de persistência valida sobretudo que searchPool não está vazio quando o critério correspondente está presente; mantenha searchType coerente com a intenção de negócio e com os consumidores do modelo.
Enums (valores numéricos no JSON)
Valores esperados no corpo JSON.
PointsConfigCriteriaType (criteriaType): 0 Cabeçalho, 1 Detalhe artigo, 2 Detalhe família.
FormulaBaseEnum (formulaBase nos critérios): 0 XTimes, 1 XForY.
SearchTypeEnum (searchType nos critérios de detalhe): 0 Lista, 1 Individual.
DocumentFieldsEnum (documentField em defaultHeaderCriteria):
| Valor | Significado |
|---|---|
0 | Total do documento |
1 | Total líquido |
2 | Total de impostos |
3 | Valor pago |
DetailFieldsEnum (detailField em critérios de detalhe):
| Valor | Significado |
|---|---|
0 | Quantidade |
1 | Preço com IVA |
2 | Total da linha com IVA |
3 | Preço sem IVA |
4 | Total da linha sem IVA |
Obrigatoriedade e consistência do payload
Por criteriaType e formulaBase
criteriaType | Critério a enviar | searchPool | documentField / detailField |
|---|---|---|---|
0 (Header) | defaultHeaderCriteria preenchido; outros critérios null / omitidos. | Não aplicável. | documentField obrigatório no objeto de critério. |
1 (Detalhe artigo) | defaultDetailsItemCriteria preenchido; outros null. | Lista não vazia quando o critério não é null (validação servidor). | detailField obrigatório no objeto. |
2 (Detalhe família) | defaultDetailsFamilyCriteria preenchido; outros null. | Lista não vazia quando o critério não é null (validação servidor). | detailField obrigatório no objeto. |
formulaBase | Requisito adicional (servidor + modelo) |
|---|---|
0 (XTimes) | eachY pode ser 0; foco em pointsBase. |
1 (XForY) | eachY tem de ser estritamente maior que zero (eachY > 0) sempre que o critério aninhado existir e for validado; valores 0 ou negativos falham com PointsConfig.InvalidEachY (no servidor a condição é eachY <= 0). |
criteriaType desconhecido ou não mapeado
Se criteriaType tiver um valor não presente no dicionário interno de validadores do serviço, ValidateCriteria não executa nenhum dos validadores por tipo e devolve sucesso nessa fase (apenas a verificação de datas continua a aplicar-se). Para integrações válidas, use sempre 0, 1 ou 2 conforme o enum PointsConfigCriteriaType.
Intervalo de datas
startDatenão pode ser posterior aendDate. Caso contrário:PointsConfig.InvalidDateRange.
Critério null no servidor
Se o objeto de critério correspondente ao criteriaType for null, o ramo específico de validação (pool vazio, eachY por tipo) não é executado e devolve sucesso nesse trecho. Para dados consistentes, envie sempre o critério alinhado ao criteriaType com as regras acima.
Validações:
Criação e atualização
Aplicado antes de persistir. Na atualização, se o id não existir em ConfigList, a api devolve PointsConfig.NotFound após carregar as definições e antes de gravar.
| Regra | Código de erro |
|---|---|
startDate > endDate | PointsConfig.InvalidDateRange |
Tipo Header, critério não nulo, formulaBase == XForY e eachY <= 0 | PointsConfig.InvalidEachY |
Tipo Detalhe artigo, critério não nulo, searchPool sem elementos | PointsConfig.InvalidItemSearchPool |
Tipo Detalhe artigo, critério não nulo, XForY e eachY <= 0 | PointsConfig.InvalidEachY |
Tipo Detalhe família, critério não nulo, searchPool sem elementos | PointsConfig.InvalidFamilySearchPool |
Tipo Detalhe família, critério não nulo, XForY e eachY <= 0 | PointsConfig.InvalidEachY |
Outros resultados de erro
| Código | Quando ocorre (resumo) |
|---|---|
PointsConfig.NotFound | GET/PUT/DELETE com identificador inexistente na lista guardada. |
PointsConfigCreate.Fail | Exceção ou falha inesperada na criação. |
PointsConfigUpdate.Fail | Exceção ou falha inesperada na atualização. |
PointsConfigDelete.Fail | Exceção ou falha inesperada na eliminação. |
PointsConfigSave.Fail | IConfigProvider.UpdateAsync devolveu false ao gravar definições. |
PointsGetAll.Fail | Falha ao listar (ex.: exceção em GetAllAsync). |
PointsGetById.Fail | Falha ao obter por id (ex.: exceção). |
PointsGetNextOrder.Fail | Falha ao calcular a próxima ordem. |
CreateDefaultSettingsFail.Fail | Falha ao criar definições por omissão quando ainda não existem. |
Config.NotFound | Constante no módulo de erros; associada a configurações em falta em cenários de configuração. |
Validações de listagem (GET)
Em GetAllAsync, os parâmetros de consulta são normalizados em memória:
| Parâmetro | Comportamento |
|---|---|
page | Se omitido ou menor que 1, usa-se página 1. |
pageSize | Se omitido ou menor ou igual a 0, usa-se 20; caso contrário aplica-se o valor pedido até ao máximo 100 (MaxPageSize). |
Exemplos de corpo (POST / PUT)
URL: POST /gateway/points-config (criação) ou PUT /gateway/points-config (atualização com id no corpo).
Propriedades em camelCase. Os outros dois critérios devem ser null (como abaixo) ou omitidos.
Cabeçalho — fórmula X vezes (criteriaType: 0, formulaBase: 0)
{
"order": 1,
"description": "Um ponto por euro no total do documento",
"active": true,
"cumulative": true,
"allowDecimalPoints": false,
"startDate": "2026-01-01T00:00:00",
"endDate": "2026-12-31T23:59:59",
"criteriaType": 0,
"defaultHeaderCriteria": {
"totalPoints": 0,
"pointsBase": 1,
"eachY": 0,
"formulaBase": 0,
"documentField": 0
},
"defaultDetailsItemCriteria": null,
"defaultDetailsFamilyCriteria": null
}
documentField: 0 total do documento, 1 total líquido, 2 total impostos, 3 valor pago.
Cabeçalho — fórmula X por Y (criteriaType: 0, formulaBase: 1)
eachY tem de ser maior que zero; caso contrário o servidor devolve PointsConfig.InvalidEachY.
{
"order": 2,
"description": "10 pontos por cada 50 € de total líquido",
"active": true,
"cumulative": false,
"allowDecimalPoints": false,
"startDate": "2026-01-01T00:00:00",
"endDate": "2026-12-31T23:59:59",
"criteriaType": 0,
"defaultHeaderCriteria": {
"totalPoints": 0,
"pointsBase": 10,
"eachY": 50,
"formulaBase": 1,
"documentField": 1
},
"defaultDetailsItemCriteria": null,
"defaultDetailsFamilyCriteria": null
}
Detalhe por artigo (criteriaType: 1, defaultDetailsItemCriteria)
searchPool não pode estar vazio quando o critério está preenchido (PointsConfig.InvalidItemSearchPool). Cada elemento: id, description, keyId (identificador do artigo no sistema).
Lista (searchType: 0) — pontos aplicáveis às linhas cujo artigo pertença ao conjunto definido.
{
"order": 3,
"description": "Um ponto por unidade de quantidade em artigos seleccionados",
"active": true,
"cumulative": true,
"allowDecimalPoints": false,
"startDate": "2026-01-01T00:00:00",
"endDate": "2026-12-31T23:59:59",
"criteriaType": 1,
"defaultHeaderCriteria": null,
"defaultDetailsItemCriteria": {
"totalPoints": 0,
"pointsBase": 1,
"eachY": 0,
"formulaBase": 0,
"detailField": 0,
"searchType": 0,
"searchPool": [
{ "id": 101, "description": "Artigo A", "keyId": "ART-001" },
{ "id": 102, "description": "Artigo B", "keyId": "ART-002" }
]
},
"defaultDetailsFamilyCriteria": null
}
Pesquisa individual (searchType: 1) — mesma estrutura; searchPool costuma ter um único artigo quando a regra de negócio é “um artigo em concreto”.
{
"order": 4,
"description": "2 pontos por euro no total da linha (IVA) — artigo único",
"active": true,
"cumulative": false,
"allowDecimalPoints": false,
"startDate": "2026-01-01T00:00:00",
"endDate": "2026-12-31T23:59:59",
"criteriaType": 1,
"defaultHeaderCriteria": null,
"defaultDetailsItemCriteria": {
"totalPoints": 0,
"pointsBase": 2,
"eachY": 0,
"formulaBase": 0,
"detailField": 2,
"searchType": 1,
"searchPool": [
{ "id": 200, "description": "Artigo premium", "keyId": "PREM-01" }
]
},
"defaultDetailsFamilyCriteria": null
}
Detalhe artigo com X por Y — formulaBase: 1 e eachY > 0.
{
"order": 5,
"description": "1 ponto por cada 5 € de preço com IVA nas linhas dos artigos listados",
"active": true,
"cumulative": true,
"allowDecimalPoints": false,
"startDate": "2026-01-01T00:00:00",
"endDate": "2026-12-31T23:59:59",
"criteriaType": 1,
"defaultHeaderCriteria": null,
"defaultDetailsItemCriteria": {
"totalPoints": 0,
"pointsBase": 1,
"eachY": 5,
"formulaBase": 1,
"detailField": 1,
"searchType": 0,
"searchPool": [
{ "id": 301, "description": "Refrigerante cola 33cl", "keyId": "BEB-001" }
]
},
"defaultDetailsFamilyCriteria": null
}
Detalhe por família (criteriaType: 2, defaultDetailsFamilyCriteria)
searchPool não pode estar vazio (PointsConfig.InvalidFamilySearchPool). Cada elemento: id, description, idParent (ascendente na hierarquia de famílias).
{
"order": 6,
"description": "Pontos por quantidade em linhas de famílias seleccionadas",
"active": true,
"cumulative": true,
"allowDecimalPoints": false,
"startDate": "2026-01-01T00:00:00",
"endDate": "2026-12-31T23:59:59",
"criteriaType": 2,
"defaultHeaderCriteria": null,
"defaultDetailsItemCriteria": null,
"defaultDetailsFamilyCriteria": {
"totalPoints": 0,
"pointsBase": 1,
"eachY": 0,
"formulaBase": 0,
"detailField": 0,
"searchType": 0,
"searchPool": [
{ "id": 10, "description": "Mercearia", "idParent": 0 },
{ "id": 11, "description": "Bebidas", "idParent": 10 }
]
}
}
Família com X por Y sobre total da linha sem IVA (detailField: 4):
{
"order": 7,
"description": "3 pontos por cada 2 € de total de linha sem IVA (famílias listadas)",
"active": true,
"cumulative": false,
"allowDecimalPoints": false,
"startDate": "2026-01-01T00:00:00",
"endDate": "2026-12-31T23:59:59",
"criteriaType": 2,
"defaultHeaderCriteria": null,
"defaultDetailsItemCriteria": null,
"defaultDetailsFamilyCriteria": {
"totalPoints": 0,
"pointsBase": 3,
"eachY": 2,
"formulaBase": 1,
"detailField": 4,
"searchType": 0,
"searchPool": [
{ "id": 20, "description": "Campânula promocional", "idParent": 0 }
]
}
}
Substitua id, keyId, idParent e descrições por valores válidos no vosso tenant.
Notas de integração
- Use
GET /gateway/points-config/next-orderpara preencherorderem novas configurações. - Em atualização, envie
idcom o mesmoGuidque identifica o registo. - Mantenha um critério aninhado coerente com
criteriaType; evite enviar os três objetos preenchidos se o produto espera exclusividade. - Recomenda-se
order >= 1, em linha com[Range]emPointsConfigDTOe com o valor sugerido porGET .../next-order.
Conclusão
A gestão de configurações de pontos expõe CRUD sobre /gateway/points-config com validações dependentes de criteriaType, de formulaBase e do intervalo de datas. Teste em staging combinações de cabeçalho vs detalhe, lista vs conjunto mínimo em searchPool, e fórmulas XTimes vs XForY antes de produção.
Recursos relacionados
Última atualização: 14 de Maio de 2026