@pacp/spec 3.4.0 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.cts +304 -0
- package/dist/index.d.ts +304 -0
- package/dist/pacp.schema.json +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,179 +1,441 @@
|
|
|
1
1
|
export { profileIds, profiles, schema } from './schema.cjs';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Valor escalar simples permitido em options, contexts, tabelas e regras.
|
|
5
|
+
* Sempre primitivo: string, number ou boolean (sem objetos ou arrays).
|
|
6
|
+
*/
|
|
3
7
|
type ScalarValue = string | number | boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Tipo semântico de uma imagem. Consumidores podem usar para selecionar
|
|
10
|
+
* a imagem certa em cada contexto (vitrine, detalhe, ambientação, técnica).
|
|
11
|
+
*/
|
|
4
12
|
type ImageType = "MAIN" | "DETAIL" | "AMBIANCE" | "TECHNICAL" | "OTHER";
|
|
13
|
+
/**
|
|
14
|
+
* Referência a uma imagem de produto ou variante.
|
|
15
|
+
*
|
|
16
|
+
* Quando uma `option` possui `images`, consumidores DEVEM priorizá-las sobre
|
|
17
|
+
* `product.images` para exibição contextual daquela variante.
|
|
18
|
+
*
|
|
19
|
+
* Ver spec/latest/pacp.md §4.
|
|
20
|
+
*/
|
|
5
21
|
interface Image {
|
|
22
|
+
/** URI válida da imagem. */
|
|
6
23
|
url: string;
|
|
24
|
+
/** Rótulo legível / legenda. */
|
|
7
25
|
label?: string;
|
|
26
|
+
/** Texto alternativo descritivo (acessibilidade). */
|
|
8
27
|
alt?: string;
|
|
28
|
+
/** Inteiro ≥ 0 para ordenação explícita. Quando ausente em todas as imagens, prevalece a ordem do array. */
|
|
9
29
|
position?: number;
|
|
30
|
+
/** Tipo semântico. */
|
|
10
31
|
type?: ImageType;
|
|
11
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Medida física com valor numérico e unidade.
|
|
35
|
+
*
|
|
36
|
+
* Exemplo: `{ value: 65, unit: "kg" }`.
|
|
37
|
+
*/
|
|
12
38
|
interface Measure {
|
|
39
|
+
/** Valor numérico positivo. */
|
|
13
40
|
value: number;
|
|
41
|
+
/** Unidade SI ou comercial (ex: `kg`, `g`, `m`, `cm`). */
|
|
14
42
|
unit: string;
|
|
15
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Dimensões físicas de um produto (largura × altura × profundidade).
|
|
46
|
+
*
|
|
47
|
+
* `unit` é obrigatório; cada dimensão individual é opcional.
|
|
48
|
+
* Exemplo: `{ width: 230, height: 95, depth: 100, unit: "cm" }`.
|
|
49
|
+
*/
|
|
16
50
|
interface PhysicalDimensions {
|
|
17
51
|
width?: number;
|
|
18
52
|
height?: number;
|
|
19
53
|
depth?: number;
|
|
54
|
+
/** Unidade comum a todas as dimensões (ex: `cm`, `mm`, `m`). */
|
|
20
55
|
unit: string;
|
|
21
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Declaração de um atributo configurável do produto (ex.: "cor", "tecido", "tamanho").
|
|
59
|
+
*
|
|
60
|
+
* Apenas declara o atributo; os valores selecionáveis vivem em `Option[]`
|
|
61
|
+
* referenciando esse `id` via `attribute_id`.
|
|
62
|
+
*/
|
|
22
63
|
interface AttributeRef {
|
|
64
|
+
/** ID estável do atributo, único por produto. */
|
|
23
65
|
id: string;
|
|
66
|
+
/** Rótulo legível ao usuário final. */
|
|
24
67
|
label?: string;
|
|
25
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Valor fixo de um atributo no nível do produto (não escolhível, informativo).
|
|
71
|
+
*
|
|
72
|
+
* Complementar a `Option[]` — use `AttributeValue` para atributos que NÃO variam
|
|
73
|
+
* no orçamento. Use `Option` para atributos selecionáveis. Ver spec §4.4.
|
|
74
|
+
*/
|
|
26
75
|
interface AttributeValue {
|
|
27
76
|
attribute_id: string;
|
|
28
77
|
value: ScalarValue;
|
|
29
78
|
label?: string;
|
|
30
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Valor selecionável de um atributo do produto (ex.: "VELUDO" para `tecido`).
|
|
82
|
+
*
|
|
83
|
+
* O `id` é o handle PACP-interno (use em rules, dependencies, etc.);
|
|
84
|
+
* o `value` é o valor semântico do atributo (use em tabelas e `source_when`).
|
|
85
|
+
*/
|
|
31
86
|
interface Option {
|
|
87
|
+
/** ID estável da option, único por catálogo. */
|
|
32
88
|
id: string;
|
|
89
|
+
/** Atributo ao qual esta option pertence. DEVE existir em `Product.attributes`. */
|
|
33
90
|
attribute_id: string;
|
|
91
|
+
/** Valor semântico (string/number/boolean). Usado em lookups de tabelas e em `source_when`. */
|
|
34
92
|
value: ScalarValue;
|
|
93
|
+
/** Rótulo legível ao usuário final. */
|
|
35
94
|
label?: string;
|
|
95
|
+
/** Imagens contextuais da variante (priorizadas sobre `product.images`). */
|
|
36
96
|
images?: Image[];
|
|
37
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Política de lote obrigatório no nível do produto. Ver spec §4.1.
|
|
100
|
+
*
|
|
101
|
+
* - `source: "CONTEXT"` → lote vem de `context[context_key]`.
|
|
102
|
+
* - `source: "ATTRIBUTE"` → lote vem da option selecionada do attribute.
|
|
103
|
+
*
|
|
104
|
+
* Quando `required=true`, ausência do lote bloqueia o cálculo.
|
|
105
|
+
*/
|
|
38
106
|
interface LotPolicy {
|
|
39
107
|
required: boolean;
|
|
40
108
|
source: "CONTEXT" | "ATTRIBUTE";
|
|
109
|
+
/** Obrigatório quando `source="CONTEXT"`. */
|
|
41
110
|
context_key?: string;
|
|
111
|
+
/** Obrigatório quando `source="ATTRIBUTE"`. */
|
|
42
112
|
attribute_id?: string;
|
|
43
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Política de conversão de unidade solicitada → unidade vendável. Ver spec §4.2 e §5.5.
|
|
116
|
+
*
|
|
117
|
+
* Exemplo: piso vendido em caixas de 2.5 m². Cliente pede 18 m² →
|
|
118
|
+
* `required_sell_units = CEIL(18 / 2.5) = 8 caixas`.
|
|
119
|
+
*
|
|
120
|
+
* Em PACP, `rounding` DEVE ser `CEIL`.
|
|
121
|
+
*/
|
|
44
122
|
interface SalesUnit {
|
|
123
|
+
/** Unidade do pedido (m², L, kg). DEVE ser igual a `Product.unit` quando ambos existem. */
|
|
45
124
|
requested_unit: string;
|
|
125
|
+
/** Unidade comercial vendável (caixa, galão, saco). */
|
|
46
126
|
sell_unit: string;
|
|
127
|
+
/** Quantidade da unidade solicitada que cabe em 1 unidade vendável. */
|
|
47
128
|
quantity_per_sell_unit: number;
|
|
129
|
+
/** Em PACP DEVE ser `CEIL` (regra normativa). */
|
|
48
130
|
rounding: "CEIL" | "FLOOR" | "ROUND" | "HALF_UP";
|
|
131
|
+
/** Piso mínimo de unidades vendáveis. */
|
|
49
132
|
min_sell_units?: number;
|
|
50
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Quem fornece o material físico para a fábrica produzir o item.
|
|
136
|
+
*
|
|
137
|
+
* - `FACTORY`: fábrica fornece (preço somado via `factory_cost`).
|
|
138
|
+
* - `CUSTOMER`: cliente fornece (preço ignorado; sai em `supplied_quantities[]`).
|
|
139
|
+
*/
|
|
51
140
|
type SuppliedMaterialSource = "FACTORY" | "CUSTOMER";
|
|
141
|
+
/** Quantidade fixa de insumo (use quando não varia por configuração). */
|
|
52
142
|
interface SuppliedMaterialQuantityValue {
|
|
143
|
+
/** Quantidade positiva. */
|
|
53
144
|
value: number;
|
|
145
|
+
/** Unidade (m², m, kg, un). */
|
|
54
146
|
unit: string;
|
|
55
147
|
}
|
|
148
|
+
/** Quantidade resolvida via lookup em tabela (use quando varia por configuração — ex: sofá 3 vs 4 lugares). */
|
|
56
149
|
interface SuppliedMaterialQuantityTable {
|
|
150
|
+
/** ID de uma tabela `LOOKUP` definida no catálogo. */
|
|
57
151
|
table_id: string;
|
|
152
|
+
/** Unidade do valor retornado pela tabela. */
|
|
58
153
|
unit: string;
|
|
59
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Quantidade de insumo necessária por produto. Aceita valor fixo OU lookup.
|
|
157
|
+
*
|
|
158
|
+
* Sempre exige `unit`. Ver spec §4.8.
|
|
159
|
+
*/
|
|
60
160
|
type SuppliedMaterialQuantity = SuppliedMaterialQuantityValue | SuppliedMaterialQuantityTable;
|
|
161
|
+
/** Custo do material declarado como valor literal. */
|
|
61
162
|
interface SuppliedMaterialCostValue {
|
|
163
|
+
/** Valor ≥ 0. Custo zero é permitido (material gratuito); negativo é inválido. */
|
|
62
164
|
value: number;
|
|
63
165
|
}
|
|
166
|
+
/** Custo do material resolvido via lookup em tabela. */
|
|
64
167
|
interface SuppliedMaterialCostTable {
|
|
65
168
|
table_id: string;
|
|
66
169
|
}
|
|
170
|
+
/** Custo do material resolvido executando um ruleset específico. */
|
|
67
171
|
interface SuppliedMaterialCostRuleset {
|
|
68
172
|
ruleset_id: string;
|
|
69
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Custo do material quando fonte resolvida = `FACTORY`.
|
|
176
|
+
* Exatamente um de `value`, `table_id` ou `ruleset_id`.
|
|
177
|
+
*
|
|
178
|
+
* Ausente → engine NÃO soma (custo já incluso em `base_price` ou em rulesets externos).
|
|
179
|
+
*/
|
|
70
180
|
type SuppliedMaterialCost = SuppliedMaterialCostValue | SuppliedMaterialCostTable | SuppliedMaterialCostRuleset;
|
|
181
|
+
/**
|
|
182
|
+
* Mapeia valores de `option.value` (do attribute referenciado por `sourcing_attribute_id`)
|
|
183
|
+
* para o modo de sourcing.
|
|
184
|
+
*
|
|
185
|
+
* Cada `value` distinto de option do attribute DEVE aparecer em `factory[]` OU `customer[]`;
|
|
186
|
+
* validadores reportam `UNCOVERED_OPTION_VALUE` caso contrário.
|
|
187
|
+
*
|
|
188
|
+
* Exemplo: `{ factory: ["FABRICA", "OWN"], customer: ["EU_FORNECO", "COB"] }`.
|
|
189
|
+
*/
|
|
71
190
|
interface SourceWhen {
|
|
191
|
+
/** Valores que mapeiam para fonte = FACTORY. */
|
|
72
192
|
factory: ScalarValue[];
|
|
193
|
+
/** Valores que mapeiam para fonte = CUSTOMER. */
|
|
73
194
|
customer: ScalarValue[];
|
|
74
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Insumo consumido pelo produto, com regra de quem fornece (fábrica ou cliente).
|
|
198
|
+
*
|
|
199
|
+
* Caso-tipo: sofá que aceita tecido próprio do lojista. Ver spec §4.8.
|
|
200
|
+
*
|
|
201
|
+
* Convenção dura: quando `supplied_materials` está presente, `base_price` representa
|
|
202
|
+
* o produto SEM os materiais declarados. Custo vive em `factory_cost`.
|
|
203
|
+
*/
|
|
75
204
|
interface SuppliedMaterial {
|
|
205
|
+
/** ID único do insumo no produto. */
|
|
76
206
|
id: string;
|
|
207
|
+
/** Tipo do material em SNAKE_UPPER (ex: `TECIDO`, `COURO`, `VIDRO`, `MARMORE`). */
|
|
77
208
|
material: string;
|
|
209
|
+
/** Quantidade necessária. */
|
|
78
210
|
quantity: SuppliedMaterialQuantity;
|
|
211
|
+
/** Quem fornece quando não há escolha no orçamento. Default `FACTORY`. */
|
|
79
212
|
default_source?: SuppliedMaterialSource;
|
|
213
|
+
/** Attribute do produto cuja option selecionada decide a fonte. Quando presente, `source_when` é OBRIGATÓRIO. */
|
|
80
214
|
sourcing_attribute_id?: string;
|
|
215
|
+
/** Mapeia `option.value` para `FACTORY`/`CUSTOMER`. Obrigatório quando `sourcing_attribute_id` está presente. */
|
|
81
216
|
source_when?: SourceWhen;
|
|
217
|
+
/** Custo somado quando fonte resolvida = `FACTORY`. Ignorado quando = `CUSTOMER`. */
|
|
82
218
|
factory_cost?: SuppliedMaterialCost;
|
|
219
|
+
/** Bloco livre de requisitos do material. Profile `moveis` padroniza `x-fabric_requirements`. */
|
|
83
220
|
requirements?: Record<string, unknown>;
|
|
84
221
|
[key: `x-${string}`]: unknown;
|
|
85
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* Entrada no output do orçamento descrevendo material que o CLIENTE precisa fornecer.
|
|
225
|
+
*
|
|
226
|
+
* O engine produz uma entrada por cada `SuppliedMaterial` cuja fonte resolvida = `CUSTOMER`.
|
|
227
|
+
* PDV consome para exibir "fornecer X m² de tecido"; sistema de gestão gera pedido de fornecimento.
|
|
228
|
+
*/
|
|
86
229
|
interface SupplyOutputEntry {
|
|
230
|
+
/** ID do `SuppliedMaterial` que originou esta entrada. */
|
|
87
231
|
material_id: string;
|
|
232
|
+
/** Tipo do material (`TECIDO`, `COURO`, etc.). */
|
|
88
233
|
material: string;
|
|
234
|
+
/** Quantidade resolvida pelo engine (após lookup, se aplicável). */
|
|
89
235
|
quantity: number;
|
|
236
|
+
/** Unidade da quantidade. */
|
|
90
237
|
unit: string;
|
|
238
|
+
/** Requisitos copiados do `SuppliedMaterial.requirements`. */
|
|
91
239
|
requirements?: Record<string, unknown>;
|
|
92
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* Produto único do catálogo. Ver spec §4.
|
|
243
|
+
*
|
|
244
|
+
* Campos descritivos (`sku`, `manufacturer`, `category`, etc.) são opcionais e não alteram cálculo.
|
|
245
|
+
* Configurabilidade vem de `attributes` + `options` + `rulesets` + `tables`.
|
|
246
|
+
*
|
|
247
|
+
* Estrutura típica:
|
|
248
|
+
* - `id`, `name`, `base_price`
|
|
249
|
+
* - `attributes: [{ id: "tecido" }, { id: "cor" }]`
|
|
250
|
+
* - `options: [{ id: "opt_veludo", attribute_id: "tecido", value: "VELUDO" }, ...]`
|
|
251
|
+
* - `ruleset_ids: ["rs_base"]`
|
|
252
|
+
*/
|
|
93
253
|
interface Product {
|
|
254
|
+
/** ID estável do produto, único por catálogo. Case-sensitive. */
|
|
94
255
|
id: string;
|
|
256
|
+
/** Nome legível. */
|
|
95
257
|
name?: string;
|
|
258
|
+
/**
|
|
259
|
+
* `PUBLIC` (default): exibível em vitrines.
|
|
260
|
+
* `INTERNAL`: existe no catálogo para orçamento mas não para vitrine pública.
|
|
261
|
+
* Caso típico INTERNAL: insumos, ferragens, componentes.
|
|
262
|
+
*/
|
|
96
263
|
visibility?: "PUBLIC" | "INTERNAL";
|
|
264
|
+
/** Código SKU para integração com ERP. */
|
|
97
265
|
sku?: string;
|
|
98
266
|
manufacturer?: string;
|
|
99
267
|
brand?: string;
|
|
100
268
|
description?: string;
|
|
269
|
+
/**
|
|
270
|
+
* Categorias hierárquicas. Cada path é um array da raiz à folha.
|
|
271
|
+
* Permite múltipla classificação. Exemplo: `[["Móveis", "Estofados", "Sofá"], ["Promoções"]]`.
|
|
272
|
+
*/
|
|
101
273
|
category?: string[][];
|
|
274
|
+
/** Código de barras GS1 (8-14 dígitos). */
|
|
102
275
|
gtin?: string;
|
|
276
|
+
/**
|
|
277
|
+
* Preço base do produto. Ponto de partida dos rulesets de `BASE`.
|
|
278
|
+
* Quando `supplied_materials` está presente, representa o produto SEM os materiais declarados.
|
|
279
|
+
*/
|
|
103
280
|
base_price?: number;
|
|
281
|
+
/**
|
|
282
|
+
* Unidade base na qual `base_price` é cotado (ex: `un`, `m2`, `kg`). Default implícito: `un`.
|
|
283
|
+
* Quando coexistir com `sales_unit`, `sales_unit.requested_unit` DEVE ser igual a `unit`.
|
|
284
|
+
*/
|
|
104
285
|
unit?: string;
|
|
105
286
|
images?: Image[];
|
|
287
|
+
/** Tags livres para busca. Sem garantia de estabilidade (diferente de `collections`). */
|
|
106
288
|
tags?: string[];
|
|
289
|
+
/**
|
|
290
|
+
* IDs de coleções (agrupamento curatorial/sazonal estável).
|
|
291
|
+
* Disponível em rules como fato `product.collections` com operadores `IN`/`NOT_IN`.
|
|
292
|
+
* Exemplo: `["verao_2026", "linha_premium"]`. Ver spec §4.7.
|
|
293
|
+
*/
|
|
107
294
|
collections?: string[];
|
|
108
295
|
weight?: Measure;
|
|
109
296
|
dimensions?: PhysicalDimensions;
|
|
110
297
|
lot_policy?: LotPolicy;
|
|
111
298
|
sales_unit?: SalesUnit;
|
|
299
|
+
/** Atributos configuráveis do produto. */
|
|
112
300
|
attributes?: AttributeRef[];
|
|
301
|
+
/** Valores fixos de atributos (não escolhíveis). Complementar a `options`. */
|
|
113
302
|
attribute_values?: AttributeValue[];
|
|
303
|
+
/** Valores selecionáveis dos atributos. */
|
|
114
304
|
options: Option[];
|
|
305
|
+
/** Insumos consumidos pelo produto, com sourcing factory/customer. Ver spec §4.8. */
|
|
115
306
|
supplied_materials?: SuppliedMaterial[];
|
|
307
|
+
/** IDs de rulesets aplicados a este produto. */
|
|
116
308
|
ruleset_ids?: string[];
|
|
117
309
|
[key: `x-${string}`]: unknown;
|
|
118
310
|
}
|
|
311
|
+
/**
|
|
312
|
+
* Condição atômica em `Condition.all`/`Condition.any`.
|
|
313
|
+
*
|
|
314
|
+
* Fatos disponíveis incluem: `option.<id>`, `attribute.<id>`, `context.<key>`,
|
|
315
|
+
* `product.collections`, `product.category`, `supplied_materials.<id>.source`,
|
|
316
|
+
* `supplied_materials.<id>.quantity`, `supplied_materials.any.source`, `supplied_materials.all.source`.
|
|
317
|
+
*/
|
|
119
318
|
interface Predicate {
|
|
319
|
+
/** Fato a avaliar. */
|
|
120
320
|
fact: string;
|
|
121
321
|
operator: "EQ" | "NEQ" | "IN" | "NOT_IN" | "GT" | "GTE" | "LT" | "LTE" | "EXISTS";
|
|
322
|
+
/** Use para operadores escalares (`EQ`, `NEQ`, `GT`, etc.). */
|
|
122
323
|
value?: ScalarValue;
|
|
324
|
+
/** Use para operadores de conjunto (`IN`, `NOT_IN`). */
|
|
123
325
|
values?: ScalarValue[];
|
|
124
326
|
}
|
|
327
|
+
/**
|
|
328
|
+
* Condição lógica composta. `all` = AND; `any` = OR.
|
|
329
|
+
* Pelo menos um dos campos é obrigatório.
|
|
330
|
+
*/
|
|
125
331
|
interface Condition {
|
|
126
332
|
all?: Predicate[];
|
|
127
333
|
any?: Predicate[];
|
|
128
334
|
}
|
|
335
|
+
/** Componente de operações `MAX_OF`/`MIN_OF`/`PICK`. */
|
|
129
336
|
interface Component {
|
|
130
337
|
label?: string;
|
|
131
338
|
value?: number;
|
|
132
339
|
table_id?: string;
|
|
133
340
|
option_id?: string;
|
|
134
341
|
}
|
|
342
|
+
/**
|
|
343
|
+
* Operação executada por uma regra. Ver spec §6.
|
|
344
|
+
*
|
|
345
|
+
* - `ADD` / `PERCENT_OF`: acumulam.
|
|
346
|
+
* - `OVERRIDE` / `PICK`: substituem.
|
|
347
|
+
* - `LOOKUP`: busca em tabela.
|
|
348
|
+
* - `MAX_OF` / `MIN_OF`: agregam componentes.
|
|
349
|
+
* - `ROUND` / `CAP` / `FLOOR`: pós-processamento.
|
|
350
|
+
*/
|
|
135
351
|
type RuleOperation = "ADD" | "PERCENT_OF" | "OVERRIDE" | "LOOKUP" | "MAX_OF" | "MIN_OF" | "PICK" | "ROUND" | "CAP" | "FLOOR";
|
|
352
|
+
/**
|
|
353
|
+
* Regra de precificação aplicada dentro de um ruleset.
|
|
354
|
+
*
|
|
355
|
+
* Ordem de execução: por `priority` decrescente, desempate por `id` lexicográfico.
|
|
356
|
+
* Default: `priority=0`, `enabled=true`, `when` sempre verdadeiro.
|
|
357
|
+
*/
|
|
136
358
|
interface Rule {
|
|
359
|
+
/** ID único por ruleset. */
|
|
137
360
|
id: string;
|
|
138
361
|
operation: RuleOperation;
|
|
362
|
+
/** Maior primeiro. Default 0. */
|
|
139
363
|
priority?: number;
|
|
364
|
+
/** Default true. */
|
|
140
365
|
enabled?: boolean;
|
|
366
|
+
/** Quando ausente, regra sempre dispara. */
|
|
141
367
|
when?: Condition;
|
|
368
|
+
/** Para `ADD`/`OVERRIDE`. */
|
|
142
369
|
value?: number;
|
|
370
|
+
/** Para `PERCENT_OF`. */
|
|
143
371
|
percent?: number;
|
|
372
|
+
/** Para `LOOKUP`. */
|
|
144
373
|
table_id?: string;
|
|
374
|
+
/** Para `MAX_OF`/`MIN_OF`/`PICK`. */
|
|
145
375
|
components?: Component[];
|
|
376
|
+
/** Para `ROUND`. */
|
|
146
377
|
precision?: number;
|
|
378
|
+
/** Para `CAP`. */
|
|
147
379
|
max?: number;
|
|
380
|
+
/** Para `FLOOR`. */
|
|
148
381
|
min?: number;
|
|
382
|
+
/** Para `LOOKUP` sem chave correspondente. */
|
|
149
383
|
fallback?: number;
|
|
150
384
|
option_id?: string;
|
|
151
385
|
option_ids?: string[];
|
|
152
386
|
[key: `x-${string}`]: unknown;
|
|
153
387
|
}
|
|
388
|
+
/**
|
|
389
|
+
* Conjunto de regras aplicadas em um estágio (`target`) do cálculo.
|
|
390
|
+
*
|
|
391
|
+
* Estágios: `BASE` (preço base), `SUBTOTAL` (após base), `TOTAL` (final).
|
|
392
|
+
*/
|
|
154
393
|
interface Ruleset {
|
|
155
394
|
id: string;
|
|
156
395
|
target: "BASE" | "SUBTOTAL" | "TOTAL";
|
|
157
396
|
rules: Rule[];
|
|
158
397
|
[key: `x-${string}`]: unknown;
|
|
159
398
|
}
|
|
399
|
+
/**
|
|
400
|
+
* Dimensão de uma tabela `LOOKUP`. Define como obter o valor da chave.
|
|
401
|
+
*
|
|
402
|
+
* - `ATTRIBUTE`: usa option selecionada do attribute.
|
|
403
|
+
* - `CONTEXT`: usa valor de `context[context_key]`.
|
|
404
|
+
* - `LITERAL`: usa valor fixo.
|
|
405
|
+
*/
|
|
160
406
|
interface LookupAxis {
|
|
407
|
+
/** Nome da chave usada nas `rows`. */
|
|
161
408
|
key: string;
|
|
162
409
|
source: "ATTRIBUTE" | "CONTEXT" | "LITERAL";
|
|
163
410
|
attribute_id?: string;
|
|
164
411
|
context_key?: string;
|
|
165
412
|
literal?: ScalarValue;
|
|
166
413
|
}
|
|
414
|
+
/** Linha de uma tabela `LOOKUP` (chave composta → valor numérico). */
|
|
167
415
|
interface TableRow {
|
|
416
|
+
/** Mapa de chave: `{ "tecido": "VELUDO", "lugares": "3" }`. */
|
|
168
417
|
key: Record<string, ScalarValue>;
|
|
418
|
+
/** Valor retornado quando todas as dimensões batem. */
|
|
169
419
|
value: number;
|
|
170
420
|
}
|
|
421
|
+
/**
|
|
422
|
+
* Tabela de lookup determinística usada por regras `LOOKUP` ou por `supplied_materials.quantity.table_id`.
|
|
423
|
+
*
|
|
424
|
+
* A chave de busca é construída pelas `dimensions` na ordem declarada.
|
|
425
|
+
*/
|
|
171
426
|
interface Table {
|
|
172
427
|
id: string;
|
|
173
428
|
type: "LOOKUP";
|
|
174
429
|
dimensions: LookupAxis[];
|
|
175
430
|
rows: TableRow[];
|
|
176
431
|
}
|
|
432
|
+
/**
|
|
433
|
+
* Relação lógica entre opções. Avaliada na fase de validação (antes do cálculo).
|
|
434
|
+
*
|
|
435
|
+
* - `REQUIRES`: opção A exige opção B selecionada.
|
|
436
|
+
* - `IMPLIES`: seleção de A implica B.
|
|
437
|
+
* - `AVAILABLE_OPTIONS_WHEN`: lista opções habilitadas sob condição.
|
|
438
|
+
*/
|
|
177
439
|
interface Dependency {
|
|
178
440
|
id: string;
|
|
179
441
|
type: "REQUIRES" | "IMPLIES" | "AVAILABLE_OPTIONS_WHEN";
|
|
@@ -183,20 +445,33 @@ interface Dependency {
|
|
|
183
445
|
allowed_option_ids?: string[];
|
|
184
446
|
when?: Condition;
|
|
185
447
|
}
|
|
448
|
+
/**
|
|
449
|
+
* Bloqueio duro de combinação. Quando `when` é verdadeiro, cálculo é interrompido.
|
|
450
|
+
*
|
|
451
|
+
* Avaliada antes do cálculo de preço (junto com dependencies).
|
|
452
|
+
*/
|
|
186
453
|
interface Constraint {
|
|
187
454
|
id: string;
|
|
188
455
|
type: "DENY";
|
|
189
456
|
when: Condition;
|
|
457
|
+
/** Mensagem legível exibida ao orçamentista. */
|
|
190
458
|
message: string;
|
|
191
459
|
product_id?: string;
|
|
192
460
|
option_ids?: string[];
|
|
193
461
|
}
|
|
462
|
+
/**
|
|
463
|
+
* Lista de preço do catálogo.
|
|
464
|
+
*
|
|
465
|
+
* `context.price_list_id` seleciona qual lista usar; fallback para `catalog.default_price_list_id`.
|
|
466
|
+
*/
|
|
194
467
|
interface PriceList {
|
|
195
468
|
id: string;
|
|
196
469
|
currency: string;
|
|
197
470
|
label?: string;
|
|
471
|
+
/** Casamento com `context` para seleção automática. */
|
|
198
472
|
context_match?: Record<string, ScalarValue>;
|
|
199
473
|
}
|
|
474
|
+
/** Metadados do catálogo (lista de preço, default). */
|
|
200
475
|
interface Catalog {
|
|
201
476
|
id: string;
|
|
202
477
|
name?: string;
|
|
@@ -204,10 +479,18 @@ interface Catalog {
|
|
|
204
479
|
price_lists?: PriceList[];
|
|
205
480
|
[key: `x-${string}`]: unknown;
|
|
206
481
|
}
|
|
482
|
+
/** Referência a um documento `PRODUCT` em arquivo separado, a partir do `CATALOG`. */
|
|
207
483
|
interface ProductRef {
|
|
484
|
+
/** DEVE ser igual ao `product.id` do arquivo apontado. */
|
|
208
485
|
id: string;
|
|
486
|
+
/** Caminho relativo ao diretório do manifesto. */
|
|
209
487
|
path: string;
|
|
210
488
|
}
|
|
489
|
+
/**
|
|
490
|
+
* Contexto de execução do orçamento. Carrega dados externos que rules e validações leem.
|
|
491
|
+
*
|
|
492
|
+
* Chaves arbitrárias `x-*` são permitidas para extensões customizadas.
|
|
493
|
+
*/
|
|
211
494
|
interface Context {
|
|
212
495
|
price_list_id?: string;
|
|
213
496
|
region?: string;
|
|
@@ -218,9 +501,16 @@ interface Context {
|
|
|
218
501
|
requested_unit?: string;
|
|
219
502
|
[key: string]: ScalarValue | undefined;
|
|
220
503
|
}
|
|
504
|
+
/** Hint informativo sobre o modo de cálculo predominante do catálogo. */
|
|
221
505
|
interface Pricing {
|
|
222
506
|
calculation_mode?: "CASCADE" | "TABLE_LOOKUP" | "OVERRIDE_BY_VARIANT" | "COST_PLUS";
|
|
223
507
|
}
|
|
508
|
+
/**
|
|
509
|
+
* Manifesto do catálogo. Contém metadados, listas de preço, rulesets globais,
|
|
510
|
+
* tabelas, dependencies, constraints e referências para arquivos `PRODUCT`.
|
|
511
|
+
*
|
|
512
|
+
* Identifica-se por `document_type: "CATALOG"`.
|
|
513
|
+
*/
|
|
224
514
|
interface CatalogDocument {
|
|
225
515
|
document_type: "CATALOG";
|
|
226
516
|
catalog: Catalog;
|
|
@@ -232,11 +522,18 @@ interface CatalogDocument {
|
|
|
232
522
|
tables?: Table[];
|
|
233
523
|
dependencies?: Dependency[];
|
|
234
524
|
constraints?: Constraint[];
|
|
525
|
+
/** Extension profiles ativos (`moveis`, `iluminacao`, `pisos-revestimentos`, `fiscal-br`). */
|
|
235
526
|
profiles?: string[];
|
|
236
527
|
[key: `x-${string}`]: unknown;
|
|
237
528
|
}
|
|
529
|
+
/**
|
|
530
|
+
* Documento isolado de um produto. Referenciado por um `CatalogDocument` via `product_refs[]`.
|
|
531
|
+
*
|
|
532
|
+
* Identifica-se por `document_type: "PRODUCT"`.
|
|
533
|
+
*/
|
|
238
534
|
interface ProductDocument {
|
|
239
535
|
document_type: "PRODUCT";
|
|
536
|
+
/** ID do catálogo ao qual este produto pertence. DEVE bater com `catalog.id` no manifesto. */
|
|
240
537
|
catalog_id: string;
|
|
241
538
|
product: Product;
|
|
242
539
|
rulesets?: Ruleset[];
|
|
@@ -246,13 +543,20 @@ interface ProductDocument {
|
|
|
246
543
|
profiles?: string[];
|
|
247
544
|
[key: `x-${string}`]: unknown;
|
|
248
545
|
}
|
|
546
|
+
/** Qualquer documento PACP válido (CATALOG ou PRODUCT). */
|
|
249
547
|
type PacpDocument = CatalogDocument | ProductDocument;
|
|
548
|
+
/** IDs dos profiles oficiais PACP. */
|
|
250
549
|
type ProfileId = "moveis" | "iluminacao" | "pisos-revestimentos" | "fiscal-br";
|
|
550
|
+
/** Problema reportado pelo validador. */
|
|
251
551
|
interface ValidationIssue {
|
|
552
|
+
/** Código machine-readable (ex: `SCHEMA`, `DUPLICATE_ID`, `MISSING_SOURCING_ATTRIBUTE`). */
|
|
252
553
|
code: string;
|
|
554
|
+
/** JSON Pointer apontando para o local exato do problema. */
|
|
253
555
|
path: string;
|
|
556
|
+
/** Mensagem humana descrevendo o problema. */
|
|
254
557
|
message: string;
|
|
255
558
|
}
|
|
559
|
+
/** Resultado da validação. `valid=true` ⇔ `issues.length === 0`. */
|
|
256
560
|
interface ValidationResult {
|
|
257
561
|
valid: boolean;
|
|
258
562
|
issues: ValidationIssue[];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,179 +1,441 @@
|
|
|
1
1
|
export { profileIds, profiles, schema } from './schema.js';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Valor escalar simples permitido em options, contexts, tabelas e regras.
|
|
5
|
+
* Sempre primitivo: string, number ou boolean (sem objetos ou arrays).
|
|
6
|
+
*/
|
|
3
7
|
type ScalarValue = string | number | boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Tipo semântico de uma imagem. Consumidores podem usar para selecionar
|
|
10
|
+
* a imagem certa em cada contexto (vitrine, detalhe, ambientação, técnica).
|
|
11
|
+
*/
|
|
4
12
|
type ImageType = "MAIN" | "DETAIL" | "AMBIANCE" | "TECHNICAL" | "OTHER";
|
|
13
|
+
/**
|
|
14
|
+
* Referência a uma imagem de produto ou variante.
|
|
15
|
+
*
|
|
16
|
+
* Quando uma `option` possui `images`, consumidores DEVEM priorizá-las sobre
|
|
17
|
+
* `product.images` para exibição contextual daquela variante.
|
|
18
|
+
*
|
|
19
|
+
* Ver spec/latest/pacp.md §4.
|
|
20
|
+
*/
|
|
5
21
|
interface Image {
|
|
22
|
+
/** URI válida da imagem. */
|
|
6
23
|
url: string;
|
|
24
|
+
/** Rótulo legível / legenda. */
|
|
7
25
|
label?: string;
|
|
26
|
+
/** Texto alternativo descritivo (acessibilidade). */
|
|
8
27
|
alt?: string;
|
|
28
|
+
/** Inteiro ≥ 0 para ordenação explícita. Quando ausente em todas as imagens, prevalece a ordem do array. */
|
|
9
29
|
position?: number;
|
|
30
|
+
/** Tipo semântico. */
|
|
10
31
|
type?: ImageType;
|
|
11
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Medida física com valor numérico e unidade.
|
|
35
|
+
*
|
|
36
|
+
* Exemplo: `{ value: 65, unit: "kg" }`.
|
|
37
|
+
*/
|
|
12
38
|
interface Measure {
|
|
39
|
+
/** Valor numérico positivo. */
|
|
13
40
|
value: number;
|
|
41
|
+
/** Unidade SI ou comercial (ex: `kg`, `g`, `m`, `cm`). */
|
|
14
42
|
unit: string;
|
|
15
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Dimensões físicas de um produto (largura × altura × profundidade).
|
|
46
|
+
*
|
|
47
|
+
* `unit` é obrigatório; cada dimensão individual é opcional.
|
|
48
|
+
* Exemplo: `{ width: 230, height: 95, depth: 100, unit: "cm" }`.
|
|
49
|
+
*/
|
|
16
50
|
interface PhysicalDimensions {
|
|
17
51
|
width?: number;
|
|
18
52
|
height?: number;
|
|
19
53
|
depth?: number;
|
|
54
|
+
/** Unidade comum a todas as dimensões (ex: `cm`, `mm`, `m`). */
|
|
20
55
|
unit: string;
|
|
21
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Declaração de um atributo configurável do produto (ex.: "cor", "tecido", "tamanho").
|
|
59
|
+
*
|
|
60
|
+
* Apenas declara o atributo; os valores selecionáveis vivem em `Option[]`
|
|
61
|
+
* referenciando esse `id` via `attribute_id`.
|
|
62
|
+
*/
|
|
22
63
|
interface AttributeRef {
|
|
64
|
+
/** ID estável do atributo, único por produto. */
|
|
23
65
|
id: string;
|
|
66
|
+
/** Rótulo legível ao usuário final. */
|
|
24
67
|
label?: string;
|
|
25
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Valor fixo de um atributo no nível do produto (não escolhível, informativo).
|
|
71
|
+
*
|
|
72
|
+
* Complementar a `Option[]` — use `AttributeValue` para atributos que NÃO variam
|
|
73
|
+
* no orçamento. Use `Option` para atributos selecionáveis. Ver spec §4.4.
|
|
74
|
+
*/
|
|
26
75
|
interface AttributeValue {
|
|
27
76
|
attribute_id: string;
|
|
28
77
|
value: ScalarValue;
|
|
29
78
|
label?: string;
|
|
30
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Valor selecionável de um atributo do produto (ex.: "VELUDO" para `tecido`).
|
|
82
|
+
*
|
|
83
|
+
* O `id` é o handle PACP-interno (use em rules, dependencies, etc.);
|
|
84
|
+
* o `value` é o valor semântico do atributo (use em tabelas e `source_when`).
|
|
85
|
+
*/
|
|
31
86
|
interface Option {
|
|
87
|
+
/** ID estável da option, único por catálogo. */
|
|
32
88
|
id: string;
|
|
89
|
+
/** Atributo ao qual esta option pertence. DEVE existir em `Product.attributes`. */
|
|
33
90
|
attribute_id: string;
|
|
91
|
+
/** Valor semântico (string/number/boolean). Usado em lookups de tabelas e em `source_when`. */
|
|
34
92
|
value: ScalarValue;
|
|
93
|
+
/** Rótulo legível ao usuário final. */
|
|
35
94
|
label?: string;
|
|
95
|
+
/** Imagens contextuais da variante (priorizadas sobre `product.images`). */
|
|
36
96
|
images?: Image[];
|
|
37
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Política de lote obrigatório no nível do produto. Ver spec §4.1.
|
|
100
|
+
*
|
|
101
|
+
* - `source: "CONTEXT"` → lote vem de `context[context_key]`.
|
|
102
|
+
* - `source: "ATTRIBUTE"` → lote vem da option selecionada do attribute.
|
|
103
|
+
*
|
|
104
|
+
* Quando `required=true`, ausência do lote bloqueia o cálculo.
|
|
105
|
+
*/
|
|
38
106
|
interface LotPolicy {
|
|
39
107
|
required: boolean;
|
|
40
108
|
source: "CONTEXT" | "ATTRIBUTE";
|
|
109
|
+
/** Obrigatório quando `source="CONTEXT"`. */
|
|
41
110
|
context_key?: string;
|
|
111
|
+
/** Obrigatório quando `source="ATTRIBUTE"`. */
|
|
42
112
|
attribute_id?: string;
|
|
43
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Política de conversão de unidade solicitada → unidade vendável. Ver spec §4.2 e §5.5.
|
|
116
|
+
*
|
|
117
|
+
* Exemplo: piso vendido em caixas de 2.5 m². Cliente pede 18 m² →
|
|
118
|
+
* `required_sell_units = CEIL(18 / 2.5) = 8 caixas`.
|
|
119
|
+
*
|
|
120
|
+
* Em PACP, `rounding` DEVE ser `CEIL`.
|
|
121
|
+
*/
|
|
44
122
|
interface SalesUnit {
|
|
123
|
+
/** Unidade do pedido (m², L, kg). DEVE ser igual a `Product.unit` quando ambos existem. */
|
|
45
124
|
requested_unit: string;
|
|
125
|
+
/** Unidade comercial vendável (caixa, galão, saco). */
|
|
46
126
|
sell_unit: string;
|
|
127
|
+
/** Quantidade da unidade solicitada que cabe em 1 unidade vendável. */
|
|
47
128
|
quantity_per_sell_unit: number;
|
|
129
|
+
/** Em PACP DEVE ser `CEIL` (regra normativa). */
|
|
48
130
|
rounding: "CEIL" | "FLOOR" | "ROUND" | "HALF_UP";
|
|
131
|
+
/** Piso mínimo de unidades vendáveis. */
|
|
49
132
|
min_sell_units?: number;
|
|
50
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Quem fornece o material físico para a fábrica produzir o item.
|
|
136
|
+
*
|
|
137
|
+
* - `FACTORY`: fábrica fornece (preço somado via `factory_cost`).
|
|
138
|
+
* - `CUSTOMER`: cliente fornece (preço ignorado; sai em `supplied_quantities[]`).
|
|
139
|
+
*/
|
|
51
140
|
type SuppliedMaterialSource = "FACTORY" | "CUSTOMER";
|
|
141
|
+
/** Quantidade fixa de insumo (use quando não varia por configuração). */
|
|
52
142
|
interface SuppliedMaterialQuantityValue {
|
|
143
|
+
/** Quantidade positiva. */
|
|
53
144
|
value: number;
|
|
145
|
+
/** Unidade (m², m, kg, un). */
|
|
54
146
|
unit: string;
|
|
55
147
|
}
|
|
148
|
+
/** Quantidade resolvida via lookup em tabela (use quando varia por configuração — ex: sofá 3 vs 4 lugares). */
|
|
56
149
|
interface SuppliedMaterialQuantityTable {
|
|
150
|
+
/** ID de uma tabela `LOOKUP` definida no catálogo. */
|
|
57
151
|
table_id: string;
|
|
152
|
+
/** Unidade do valor retornado pela tabela. */
|
|
58
153
|
unit: string;
|
|
59
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Quantidade de insumo necessária por produto. Aceita valor fixo OU lookup.
|
|
157
|
+
*
|
|
158
|
+
* Sempre exige `unit`. Ver spec §4.8.
|
|
159
|
+
*/
|
|
60
160
|
type SuppliedMaterialQuantity = SuppliedMaterialQuantityValue | SuppliedMaterialQuantityTable;
|
|
161
|
+
/** Custo do material declarado como valor literal. */
|
|
61
162
|
interface SuppliedMaterialCostValue {
|
|
163
|
+
/** Valor ≥ 0. Custo zero é permitido (material gratuito); negativo é inválido. */
|
|
62
164
|
value: number;
|
|
63
165
|
}
|
|
166
|
+
/** Custo do material resolvido via lookup em tabela. */
|
|
64
167
|
interface SuppliedMaterialCostTable {
|
|
65
168
|
table_id: string;
|
|
66
169
|
}
|
|
170
|
+
/** Custo do material resolvido executando um ruleset específico. */
|
|
67
171
|
interface SuppliedMaterialCostRuleset {
|
|
68
172
|
ruleset_id: string;
|
|
69
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Custo do material quando fonte resolvida = `FACTORY`.
|
|
176
|
+
* Exatamente um de `value`, `table_id` ou `ruleset_id`.
|
|
177
|
+
*
|
|
178
|
+
* Ausente → engine NÃO soma (custo já incluso em `base_price` ou em rulesets externos).
|
|
179
|
+
*/
|
|
70
180
|
type SuppliedMaterialCost = SuppliedMaterialCostValue | SuppliedMaterialCostTable | SuppliedMaterialCostRuleset;
|
|
181
|
+
/**
|
|
182
|
+
* Mapeia valores de `option.value` (do attribute referenciado por `sourcing_attribute_id`)
|
|
183
|
+
* para o modo de sourcing.
|
|
184
|
+
*
|
|
185
|
+
* Cada `value` distinto de option do attribute DEVE aparecer em `factory[]` OU `customer[]`;
|
|
186
|
+
* validadores reportam `UNCOVERED_OPTION_VALUE` caso contrário.
|
|
187
|
+
*
|
|
188
|
+
* Exemplo: `{ factory: ["FABRICA", "OWN"], customer: ["EU_FORNECO", "COB"] }`.
|
|
189
|
+
*/
|
|
71
190
|
interface SourceWhen {
|
|
191
|
+
/** Valores que mapeiam para fonte = FACTORY. */
|
|
72
192
|
factory: ScalarValue[];
|
|
193
|
+
/** Valores que mapeiam para fonte = CUSTOMER. */
|
|
73
194
|
customer: ScalarValue[];
|
|
74
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* Insumo consumido pelo produto, com regra de quem fornece (fábrica ou cliente).
|
|
198
|
+
*
|
|
199
|
+
* Caso-tipo: sofá que aceita tecido próprio do lojista. Ver spec §4.8.
|
|
200
|
+
*
|
|
201
|
+
* Convenção dura: quando `supplied_materials` está presente, `base_price` representa
|
|
202
|
+
* o produto SEM os materiais declarados. Custo vive em `factory_cost`.
|
|
203
|
+
*/
|
|
75
204
|
interface SuppliedMaterial {
|
|
205
|
+
/** ID único do insumo no produto. */
|
|
76
206
|
id: string;
|
|
207
|
+
/** Tipo do material em SNAKE_UPPER (ex: `TECIDO`, `COURO`, `VIDRO`, `MARMORE`). */
|
|
77
208
|
material: string;
|
|
209
|
+
/** Quantidade necessária. */
|
|
78
210
|
quantity: SuppliedMaterialQuantity;
|
|
211
|
+
/** Quem fornece quando não há escolha no orçamento. Default `FACTORY`. */
|
|
79
212
|
default_source?: SuppliedMaterialSource;
|
|
213
|
+
/** Attribute do produto cuja option selecionada decide a fonte. Quando presente, `source_when` é OBRIGATÓRIO. */
|
|
80
214
|
sourcing_attribute_id?: string;
|
|
215
|
+
/** Mapeia `option.value` para `FACTORY`/`CUSTOMER`. Obrigatório quando `sourcing_attribute_id` está presente. */
|
|
81
216
|
source_when?: SourceWhen;
|
|
217
|
+
/** Custo somado quando fonte resolvida = `FACTORY`. Ignorado quando = `CUSTOMER`. */
|
|
82
218
|
factory_cost?: SuppliedMaterialCost;
|
|
219
|
+
/** Bloco livre de requisitos do material. Profile `moveis` padroniza `x-fabric_requirements`. */
|
|
83
220
|
requirements?: Record<string, unknown>;
|
|
84
221
|
[key: `x-${string}`]: unknown;
|
|
85
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* Entrada no output do orçamento descrevendo material que o CLIENTE precisa fornecer.
|
|
225
|
+
*
|
|
226
|
+
* O engine produz uma entrada por cada `SuppliedMaterial` cuja fonte resolvida = `CUSTOMER`.
|
|
227
|
+
* PDV consome para exibir "fornecer X m² de tecido"; sistema de gestão gera pedido de fornecimento.
|
|
228
|
+
*/
|
|
86
229
|
interface SupplyOutputEntry {
|
|
230
|
+
/** ID do `SuppliedMaterial` que originou esta entrada. */
|
|
87
231
|
material_id: string;
|
|
232
|
+
/** Tipo do material (`TECIDO`, `COURO`, etc.). */
|
|
88
233
|
material: string;
|
|
234
|
+
/** Quantidade resolvida pelo engine (após lookup, se aplicável). */
|
|
89
235
|
quantity: number;
|
|
236
|
+
/** Unidade da quantidade. */
|
|
90
237
|
unit: string;
|
|
238
|
+
/** Requisitos copiados do `SuppliedMaterial.requirements`. */
|
|
91
239
|
requirements?: Record<string, unknown>;
|
|
92
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* Produto único do catálogo. Ver spec §4.
|
|
243
|
+
*
|
|
244
|
+
* Campos descritivos (`sku`, `manufacturer`, `category`, etc.) são opcionais e não alteram cálculo.
|
|
245
|
+
* Configurabilidade vem de `attributes` + `options` + `rulesets` + `tables`.
|
|
246
|
+
*
|
|
247
|
+
* Estrutura típica:
|
|
248
|
+
* - `id`, `name`, `base_price`
|
|
249
|
+
* - `attributes: [{ id: "tecido" }, { id: "cor" }]`
|
|
250
|
+
* - `options: [{ id: "opt_veludo", attribute_id: "tecido", value: "VELUDO" }, ...]`
|
|
251
|
+
* - `ruleset_ids: ["rs_base"]`
|
|
252
|
+
*/
|
|
93
253
|
interface Product {
|
|
254
|
+
/** ID estável do produto, único por catálogo. Case-sensitive. */
|
|
94
255
|
id: string;
|
|
256
|
+
/** Nome legível. */
|
|
95
257
|
name?: string;
|
|
258
|
+
/**
|
|
259
|
+
* `PUBLIC` (default): exibível em vitrines.
|
|
260
|
+
* `INTERNAL`: existe no catálogo para orçamento mas não para vitrine pública.
|
|
261
|
+
* Caso típico INTERNAL: insumos, ferragens, componentes.
|
|
262
|
+
*/
|
|
96
263
|
visibility?: "PUBLIC" | "INTERNAL";
|
|
264
|
+
/** Código SKU para integração com ERP. */
|
|
97
265
|
sku?: string;
|
|
98
266
|
manufacturer?: string;
|
|
99
267
|
brand?: string;
|
|
100
268
|
description?: string;
|
|
269
|
+
/**
|
|
270
|
+
* Categorias hierárquicas. Cada path é um array da raiz à folha.
|
|
271
|
+
* Permite múltipla classificação. Exemplo: `[["Móveis", "Estofados", "Sofá"], ["Promoções"]]`.
|
|
272
|
+
*/
|
|
101
273
|
category?: string[][];
|
|
274
|
+
/** Código de barras GS1 (8-14 dígitos). */
|
|
102
275
|
gtin?: string;
|
|
276
|
+
/**
|
|
277
|
+
* Preço base do produto. Ponto de partida dos rulesets de `BASE`.
|
|
278
|
+
* Quando `supplied_materials` está presente, representa o produto SEM os materiais declarados.
|
|
279
|
+
*/
|
|
103
280
|
base_price?: number;
|
|
281
|
+
/**
|
|
282
|
+
* Unidade base na qual `base_price` é cotado (ex: `un`, `m2`, `kg`). Default implícito: `un`.
|
|
283
|
+
* Quando coexistir com `sales_unit`, `sales_unit.requested_unit` DEVE ser igual a `unit`.
|
|
284
|
+
*/
|
|
104
285
|
unit?: string;
|
|
105
286
|
images?: Image[];
|
|
287
|
+
/** Tags livres para busca. Sem garantia de estabilidade (diferente de `collections`). */
|
|
106
288
|
tags?: string[];
|
|
289
|
+
/**
|
|
290
|
+
* IDs de coleções (agrupamento curatorial/sazonal estável).
|
|
291
|
+
* Disponível em rules como fato `product.collections` com operadores `IN`/`NOT_IN`.
|
|
292
|
+
* Exemplo: `["verao_2026", "linha_premium"]`. Ver spec §4.7.
|
|
293
|
+
*/
|
|
107
294
|
collections?: string[];
|
|
108
295
|
weight?: Measure;
|
|
109
296
|
dimensions?: PhysicalDimensions;
|
|
110
297
|
lot_policy?: LotPolicy;
|
|
111
298
|
sales_unit?: SalesUnit;
|
|
299
|
+
/** Atributos configuráveis do produto. */
|
|
112
300
|
attributes?: AttributeRef[];
|
|
301
|
+
/** Valores fixos de atributos (não escolhíveis). Complementar a `options`. */
|
|
113
302
|
attribute_values?: AttributeValue[];
|
|
303
|
+
/** Valores selecionáveis dos atributos. */
|
|
114
304
|
options: Option[];
|
|
305
|
+
/** Insumos consumidos pelo produto, com sourcing factory/customer. Ver spec §4.8. */
|
|
115
306
|
supplied_materials?: SuppliedMaterial[];
|
|
307
|
+
/** IDs de rulesets aplicados a este produto. */
|
|
116
308
|
ruleset_ids?: string[];
|
|
117
309
|
[key: `x-${string}`]: unknown;
|
|
118
310
|
}
|
|
311
|
+
/**
|
|
312
|
+
* Condição atômica em `Condition.all`/`Condition.any`.
|
|
313
|
+
*
|
|
314
|
+
* Fatos disponíveis incluem: `option.<id>`, `attribute.<id>`, `context.<key>`,
|
|
315
|
+
* `product.collections`, `product.category`, `supplied_materials.<id>.source`,
|
|
316
|
+
* `supplied_materials.<id>.quantity`, `supplied_materials.any.source`, `supplied_materials.all.source`.
|
|
317
|
+
*/
|
|
119
318
|
interface Predicate {
|
|
319
|
+
/** Fato a avaliar. */
|
|
120
320
|
fact: string;
|
|
121
321
|
operator: "EQ" | "NEQ" | "IN" | "NOT_IN" | "GT" | "GTE" | "LT" | "LTE" | "EXISTS";
|
|
322
|
+
/** Use para operadores escalares (`EQ`, `NEQ`, `GT`, etc.). */
|
|
122
323
|
value?: ScalarValue;
|
|
324
|
+
/** Use para operadores de conjunto (`IN`, `NOT_IN`). */
|
|
123
325
|
values?: ScalarValue[];
|
|
124
326
|
}
|
|
327
|
+
/**
|
|
328
|
+
* Condição lógica composta. `all` = AND; `any` = OR.
|
|
329
|
+
* Pelo menos um dos campos é obrigatório.
|
|
330
|
+
*/
|
|
125
331
|
interface Condition {
|
|
126
332
|
all?: Predicate[];
|
|
127
333
|
any?: Predicate[];
|
|
128
334
|
}
|
|
335
|
+
/** Componente de operações `MAX_OF`/`MIN_OF`/`PICK`. */
|
|
129
336
|
interface Component {
|
|
130
337
|
label?: string;
|
|
131
338
|
value?: number;
|
|
132
339
|
table_id?: string;
|
|
133
340
|
option_id?: string;
|
|
134
341
|
}
|
|
342
|
+
/**
|
|
343
|
+
* Operação executada por uma regra. Ver spec §6.
|
|
344
|
+
*
|
|
345
|
+
* - `ADD` / `PERCENT_OF`: acumulam.
|
|
346
|
+
* - `OVERRIDE` / `PICK`: substituem.
|
|
347
|
+
* - `LOOKUP`: busca em tabela.
|
|
348
|
+
* - `MAX_OF` / `MIN_OF`: agregam componentes.
|
|
349
|
+
* - `ROUND` / `CAP` / `FLOOR`: pós-processamento.
|
|
350
|
+
*/
|
|
135
351
|
type RuleOperation = "ADD" | "PERCENT_OF" | "OVERRIDE" | "LOOKUP" | "MAX_OF" | "MIN_OF" | "PICK" | "ROUND" | "CAP" | "FLOOR";
|
|
352
|
+
/**
|
|
353
|
+
* Regra de precificação aplicada dentro de um ruleset.
|
|
354
|
+
*
|
|
355
|
+
* Ordem de execução: por `priority` decrescente, desempate por `id` lexicográfico.
|
|
356
|
+
* Default: `priority=0`, `enabled=true`, `when` sempre verdadeiro.
|
|
357
|
+
*/
|
|
136
358
|
interface Rule {
|
|
359
|
+
/** ID único por ruleset. */
|
|
137
360
|
id: string;
|
|
138
361
|
operation: RuleOperation;
|
|
362
|
+
/** Maior primeiro. Default 0. */
|
|
139
363
|
priority?: number;
|
|
364
|
+
/** Default true. */
|
|
140
365
|
enabled?: boolean;
|
|
366
|
+
/** Quando ausente, regra sempre dispara. */
|
|
141
367
|
when?: Condition;
|
|
368
|
+
/** Para `ADD`/`OVERRIDE`. */
|
|
142
369
|
value?: number;
|
|
370
|
+
/** Para `PERCENT_OF`. */
|
|
143
371
|
percent?: number;
|
|
372
|
+
/** Para `LOOKUP`. */
|
|
144
373
|
table_id?: string;
|
|
374
|
+
/** Para `MAX_OF`/`MIN_OF`/`PICK`. */
|
|
145
375
|
components?: Component[];
|
|
376
|
+
/** Para `ROUND`. */
|
|
146
377
|
precision?: number;
|
|
378
|
+
/** Para `CAP`. */
|
|
147
379
|
max?: number;
|
|
380
|
+
/** Para `FLOOR`. */
|
|
148
381
|
min?: number;
|
|
382
|
+
/** Para `LOOKUP` sem chave correspondente. */
|
|
149
383
|
fallback?: number;
|
|
150
384
|
option_id?: string;
|
|
151
385
|
option_ids?: string[];
|
|
152
386
|
[key: `x-${string}`]: unknown;
|
|
153
387
|
}
|
|
388
|
+
/**
|
|
389
|
+
* Conjunto de regras aplicadas em um estágio (`target`) do cálculo.
|
|
390
|
+
*
|
|
391
|
+
* Estágios: `BASE` (preço base), `SUBTOTAL` (após base), `TOTAL` (final).
|
|
392
|
+
*/
|
|
154
393
|
interface Ruleset {
|
|
155
394
|
id: string;
|
|
156
395
|
target: "BASE" | "SUBTOTAL" | "TOTAL";
|
|
157
396
|
rules: Rule[];
|
|
158
397
|
[key: `x-${string}`]: unknown;
|
|
159
398
|
}
|
|
399
|
+
/**
|
|
400
|
+
* Dimensão de uma tabela `LOOKUP`. Define como obter o valor da chave.
|
|
401
|
+
*
|
|
402
|
+
* - `ATTRIBUTE`: usa option selecionada do attribute.
|
|
403
|
+
* - `CONTEXT`: usa valor de `context[context_key]`.
|
|
404
|
+
* - `LITERAL`: usa valor fixo.
|
|
405
|
+
*/
|
|
160
406
|
interface LookupAxis {
|
|
407
|
+
/** Nome da chave usada nas `rows`. */
|
|
161
408
|
key: string;
|
|
162
409
|
source: "ATTRIBUTE" | "CONTEXT" | "LITERAL";
|
|
163
410
|
attribute_id?: string;
|
|
164
411
|
context_key?: string;
|
|
165
412
|
literal?: ScalarValue;
|
|
166
413
|
}
|
|
414
|
+
/** Linha de uma tabela `LOOKUP` (chave composta → valor numérico). */
|
|
167
415
|
interface TableRow {
|
|
416
|
+
/** Mapa de chave: `{ "tecido": "VELUDO", "lugares": "3" }`. */
|
|
168
417
|
key: Record<string, ScalarValue>;
|
|
418
|
+
/** Valor retornado quando todas as dimensões batem. */
|
|
169
419
|
value: number;
|
|
170
420
|
}
|
|
421
|
+
/**
|
|
422
|
+
* Tabela de lookup determinística usada por regras `LOOKUP` ou por `supplied_materials.quantity.table_id`.
|
|
423
|
+
*
|
|
424
|
+
* A chave de busca é construída pelas `dimensions` na ordem declarada.
|
|
425
|
+
*/
|
|
171
426
|
interface Table {
|
|
172
427
|
id: string;
|
|
173
428
|
type: "LOOKUP";
|
|
174
429
|
dimensions: LookupAxis[];
|
|
175
430
|
rows: TableRow[];
|
|
176
431
|
}
|
|
432
|
+
/**
|
|
433
|
+
* Relação lógica entre opções. Avaliada na fase de validação (antes do cálculo).
|
|
434
|
+
*
|
|
435
|
+
* - `REQUIRES`: opção A exige opção B selecionada.
|
|
436
|
+
* - `IMPLIES`: seleção de A implica B.
|
|
437
|
+
* - `AVAILABLE_OPTIONS_WHEN`: lista opções habilitadas sob condição.
|
|
438
|
+
*/
|
|
177
439
|
interface Dependency {
|
|
178
440
|
id: string;
|
|
179
441
|
type: "REQUIRES" | "IMPLIES" | "AVAILABLE_OPTIONS_WHEN";
|
|
@@ -183,20 +445,33 @@ interface Dependency {
|
|
|
183
445
|
allowed_option_ids?: string[];
|
|
184
446
|
when?: Condition;
|
|
185
447
|
}
|
|
448
|
+
/**
|
|
449
|
+
* Bloqueio duro de combinação. Quando `when` é verdadeiro, cálculo é interrompido.
|
|
450
|
+
*
|
|
451
|
+
* Avaliada antes do cálculo de preço (junto com dependencies).
|
|
452
|
+
*/
|
|
186
453
|
interface Constraint {
|
|
187
454
|
id: string;
|
|
188
455
|
type: "DENY";
|
|
189
456
|
when: Condition;
|
|
457
|
+
/** Mensagem legível exibida ao orçamentista. */
|
|
190
458
|
message: string;
|
|
191
459
|
product_id?: string;
|
|
192
460
|
option_ids?: string[];
|
|
193
461
|
}
|
|
462
|
+
/**
|
|
463
|
+
* Lista de preço do catálogo.
|
|
464
|
+
*
|
|
465
|
+
* `context.price_list_id` seleciona qual lista usar; fallback para `catalog.default_price_list_id`.
|
|
466
|
+
*/
|
|
194
467
|
interface PriceList {
|
|
195
468
|
id: string;
|
|
196
469
|
currency: string;
|
|
197
470
|
label?: string;
|
|
471
|
+
/** Casamento com `context` para seleção automática. */
|
|
198
472
|
context_match?: Record<string, ScalarValue>;
|
|
199
473
|
}
|
|
474
|
+
/** Metadados do catálogo (lista de preço, default). */
|
|
200
475
|
interface Catalog {
|
|
201
476
|
id: string;
|
|
202
477
|
name?: string;
|
|
@@ -204,10 +479,18 @@ interface Catalog {
|
|
|
204
479
|
price_lists?: PriceList[];
|
|
205
480
|
[key: `x-${string}`]: unknown;
|
|
206
481
|
}
|
|
482
|
+
/** Referência a um documento `PRODUCT` em arquivo separado, a partir do `CATALOG`. */
|
|
207
483
|
interface ProductRef {
|
|
484
|
+
/** DEVE ser igual ao `product.id` do arquivo apontado. */
|
|
208
485
|
id: string;
|
|
486
|
+
/** Caminho relativo ao diretório do manifesto. */
|
|
209
487
|
path: string;
|
|
210
488
|
}
|
|
489
|
+
/**
|
|
490
|
+
* Contexto de execução do orçamento. Carrega dados externos que rules e validações leem.
|
|
491
|
+
*
|
|
492
|
+
* Chaves arbitrárias `x-*` são permitidas para extensões customizadas.
|
|
493
|
+
*/
|
|
211
494
|
interface Context {
|
|
212
495
|
price_list_id?: string;
|
|
213
496
|
region?: string;
|
|
@@ -218,9 +501,16 @@ interface Context {
|
|
|
218
501
|
requested_unit?: string;
|
|
219
502
|
[key: string]: ScalarValue | undefined;
|
|
220
503
|
}
|
|
504
|
+
/** Hint informativo sobre o modo de cálculo predominante do catálogo. */
|
|
221
505
|
interface Pricing {
|
|
222
506
|
calculation_mode?: "CASCADE" | "TABLE_LOOKUP" | "OVERRIDE_BY_VARIANT" | "COST_PLUS";
|
|
223
507
|
}
|
|
508
|
+
/**
|
|
509
|
+
* Manifesto do catálogo. Contém metadados, listas de preço, rulesets globais,
|
|
510
|
+
* tabelas, dependencies, constraints e referências para arquivos `PRODUCT`.
|
|
511
|
+
*
|
|
512
|
+
* Identifica-se por `document_type: "CATALOG"`.
|
|
513
|
+
*/
|
|
224
514
|
interface CatalogDocument {
|
|
225
515
|
document_type: "CATALOG";
|
|
226
516
|
catalog: Catalog;
|
|
@@ -232,11 +522,18 @@ interface CatalogDocument {
|
|
|
232
522
|
tables?: Table[];
|
|
233
523
|
dependencies?: Dependency[];
|
|
234
524
|
constraints?: Constraint[];
|
|
525
|
+
/** Extension profiles ativos (`moveis`, `iluminacao`, `pisos-revestimentos`, `fiscal-br`). */
|
|
235
526
|
profiles?: string[];
|
|
236
527
|
[key: `x-${string}`]: unknown;
|
|
237
528
|
}
|
|
529
|
+
/**
|
|
530
|
+
* Documento isolado de um produto. Referenciado por um `CatalogDocument` via `product_refs[]`.
|
|
531
|
+
*
|
|
532
|
+
* Identifica-se por `document_type: "PRODUCT"`.
|
|
533
|
+
*/
|
|
238
534
|
interface ProductDocument {
|
|
239
535
|
document_type: "PRODUCT";
|
|
536
|
+
/** ID do catálogo ao qual este produto pertence. DEVE bater com `catalog.id` no manifesto. */
|
|
240
537
|
catalog_id: string;
|
|
241
538
|
product: Product;
|
|
242
539
|
rulesets?: Ruleset[];
|
|
@@ -246,13 +543,20 @@ interface ProductDocument {
|
|
|
246
543
|
profiles?: string[];
|
|
247
544
|
[key: `x-${string}`]: unknown;
|
|
248
545
|
}
|
|
546
|
+
/** Qualquer documento PACP válido (CATALOG ou PRODUCT). */
|
|
249
547
|
type PacpDocument = CatalogDocument | ProductDocument;
|
|
548
|
+
/** IDs dos profiles oficiais PACP. */
|
|
250
549
|
type ProfileId = "moveis" | "iluminacao" | "pisos-revestimentos" | "fiscal-br";
|
|
550
|
+
/** Problema reportado pelo validador. */
|
|
251
551
|
interface ValidationIssue {
|
|
552
|
+
/** Código machine-readable (ex: `SCHEMA`, `DUPLICATE_ID`, `MISSING_SOURCING_ATTRIBUTE`). */
|
|
252
553
|
code: string;
|
|
554
|
+
/** JSON Pointer apontando para o local exato do problema. */
|
|
253
555
|
path: string;
|
|
556
|
+
/** Mensagem humana descrevendo o problema. */
|
|
254
557
|
message: string;
|
|
255
558
|
}
|
|
559
|
+
/** Resultado da validação. `valid=true` ⇔ `issues.length === 0`. */
|
|
256
560
|
interface ValidationResult {
|
|
257
561
|
valid: boolean;
|
|
258
562
|
issues: ValidationIssue[];
|
package/dist/pacp.schema.json
CHANGED
package/package.json
CHANGED