@pacp/spec 3.4.0 → 3.4.2

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 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[];
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://cdn.jsdelivr.net/npm/@pacp/spec@latest/dist/pacp.schema.json",
4
- "title": "PACP v3.4.0",
4
+ "title": "PACP v3.4.2",
5
5
  "oneOf": [
6
6
  {
7
7
  "$ref": "#/$defs/catalog_document"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pacp/spec",
3
- "version": "3.4.0",
3
+ "version": "3.4.2",
4
4
  "description": "PACP - Padrão Aberto de Catálogo e Precificação. Schema, profiles e validador para catálogos de produtos.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",