@pacp/spec 3.3.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.cjs.map +1 -1
- package/dist/index.d.cts +348 -1
- package/dist/index.d.ts +348 -1
- package/dist/pacp.schema.json +245 -5
- package/dist/profiles/moveis.schema.json +19 -0
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/schema.ts","../src/validate.ts"],"sourcesContent":["export { schema, profiles, profileIds } from \"./schema.js\";\r\nexport { validate } from \"./validate.js\";\r\nexport type {\r\n ScalarValue,\r\n ImageType,\r\n Image,\r\n Measure,\r\n PhysicalDimensions,\r\n AttributeRef,\r\n AttributeValue,\r\n Option,\r\n LotPolicy,\r\n SalesUnit,\r\n Product,\r\n Predicate,\r\n Condition,\r\n Component,\r\n RuleOperation,\r\n Rule,\r\n Ruleset,\r\n LookupAxis,\r\n TableRow,\r\n Table,\r\n Dependency,\r\n Constraint,\r\n PriceList,\r\n Catalog,\r\n ProductRef,\r\n Context,\r\n Pricing,\r\n CatalogDocument,\r\n ProductDocument,\r\n PacpDocument,\r\n ProfileId,\r\n ValidationIssue,\r\n ValidationResult,\r\n} from \"./types.js\";\r\n","import { readFileSync } from \"node:fs\";\r\nimport { join } from \"node:path\";\r\n\r\nfunction loadJson(relativePath: string): Record<string, unknown> {\r\n const fullPath = join(__dirname, relativePath);\r\n return JSON.parse(readFileSync(fullPath, \"utf8\"));\r\n}\r\n\r\nexport const schema = loadJson(\"./pacp.schema.json\") as Record<string, unknown>;\r\n\r\nexport const profiles = {\r\n moveis: loadJson(\"./profiles/moveis.schema.json\") as Record<string, unknown>,\r\n iluminacao: loadJson(\"./profiles/iluminacao.schema.json\") as Record<string, unknown>,\r\n \"pisos-revestimentos\": loadJson(\"./profiles/pisos-revestimentos.schema.json\") as Record<string, unknown>,\r\n \"fiscal-br\": loadJson(\"./profiles/fiscal-br.schema.json\") as Record<string, unknown>,\r\n} as const;\r\n\r\nexport type ProfileId = keyof typeof profiles;\r\n\r\nexport const profileIds = Object.keys(profiles) as ProfileId[];\r\n","import type { ValidationResult, ValidationIssue, PacpDocument } from \"./types.js\";\r\nimport { schema, profiles, type ProfileId } from \"./schema.js\";\r\n\r\nexport function validate(document: unknown): ValidationResult {\r\n let Ajv2020: typeof import(\"ajv/dist/2020\").default;\r\n let addFormats: typeof import(\"ajv-formats\").default;\r\n\r\n try {\r\n Ajv2020 = require(\"ajv/dist/2020\") as typeof import(\"ajv/dist/2020\").default;\r\n addFormats = require(\"ajv-formats\") as typeof import(\"ajv-formats\").default;\r\n } catch {\r\n throw new Error(\r\n 'Para usar validate(), instale ajv e ajv-formats: npm install ajv ajv-formats'\r\n );\r\n }\r\n\r\n const ajv = new Ajv2020({ allErrors: true, strict: false });\r\n addFormats(ajv);\r\n\r\n const issues: ValidationIssue[] = [];\r\n\r\n const validateSchema = ajv.compile(schema);\r\n const valid = validateSchema(document);\r\n\r\n if (!valid && validateSchema.errors) {\r\n for (const error of validateSchema.errors) {\r\n issues.push({\r\n code: \"SCHEMA\",\r\n path: error.instancePath || \"/\",\r\n message: error.message ?? \"Erro de validacao de schema\",\r\n });\r\n }\r\n }\r\n\r\n if (document && typeof document === \"object\" && !Array.isArray(document)) {\r\n const doc = document as Record<string, unknown>;\r\n const declaredProfiles = Array.isArray(doc.profiles) ? doc.profiles : [];\r\n\r\n for (const profileId of declaredProfiles) {\r\n if (typeof profileId !== \"string\") continue;\r\n\r\n const profileSchema = profiles[profileId as ProfileId];\r\n if (!profileSchema) {\r\n issues.push({\r\n code: \"UNKNOWN_PROFILE\",\r\n path: \"/profiles\",\r\n message: `Profile \"${profileId}\" nao e um profile oficial PACP`,\r\n });\r\n continue;\r\n }\r\n\r\n const products = extractProducts(doc);\r\n const validateProfile = ajv.compile(profileSchema);\r\n\r\n for (let i = 0; i < products.length; i++) {\r\n const xFields = extractXFields(products[i]);\r\n if (Object.keys(xFields).length === 0) continue;\r\n\r\n const profileValid = validateProfile(xFields);\r\n if (!profileValid && validateProfile.errors) {\r\n for (const error of validateProfile.errors) {\r\n issues.push({\r\n code: \"PROFILE_VALIDATION\",\r\n path: `products[${i}]${error.instancePath || \"/\"}`,\r\n message: `Profile \"${profileId}\": ${error.message ?? \"erro de validacao\"}`,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n return { valid: issues.length === 0, issues };\r\n}\r\n\r\nfunction extractProducts(doc: Record<string, unknown>): Record<string, unknown>[] {\r\n if (doc.document_type === \"PRODUCT\" && doc.product && typeof doc.product === \"object\") {\r\n return [doc.product as Record<string, unknown>];\r\n }\r\n return [];\r\n}\r\n\r\nfunction extractXFields(obj: Record<string, unknown>): Record<string, unknown> {\r\n const result: Record<string, unknown> = {};\r\n for (const [key, value] of Object.entries(obj)) {\r\n if (key.startsWith(\"x-\")) {\r\n result[key] = value;\r\n }\r\n }\r\n return result;\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,qBAA6B;AAC7B,uBAAqB;AAErB,SAAS,SAAS,cAA+C;AAC/D,QAAM,eAAW,uBAAK,WAAW,YAAY;AAC7C,SAAO,KAAK,UAAM,6BAAa,UAAU,MAAM,CAAC;AAClD;AAEO,IAAM,SAAS,SAAS,oBAAoB;AAE5C,IAAM,WAAW;AAAA,EACtB,QAAQ,SAAS,+BAA+B;AAAA,EAChD,YAAY,SAAS,mCAAmC;AAAA,EACxD,uBAAuB,SAAS,4CAA4C;AAAA,EAC5E,aAAa,SAAS,kCAAkC;AAC1D;AAIO,IAAM,aAAa,OAAO,KAAK,QAAQ;;;AChBvC,SAAS,SAAS,UAAqC;AAC5D,MAAI;AACJ,MAAI;AAEJ,MAAI;AACF,cAAU,QAAQ,eAAe;AACjC,iBAAa,QAAQ,aAAa;AAAA,EACpC,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,MAAM,IAAI,QAAQ,EAAE,WAAW,MAAM,QAAQ,MAAM,CAAC;AAC1D,aAAW,GAAG;AAEd,QAAM,SAA4B,CAAC;AAEnC,QAAM,iBAAiB,IAAI,QAAQ,MAAM;AACzC,QAAM,QAAQ,eAAe,QAAQ;AAErC,MAAI,CAAC,SAAS,eAAe,QAAQ;AACnC,eAAW,SAAS,eAAe,QAAQ;AACzC,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,MAAM,MAAM,gBAAgB;AAAA,QAC5B,SAAS,MAAM,WAAW;AAAA,MAC5B,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,YAAY,OAAO,aAAa,YAAY,CAAC,MAAM,QAAQ,QAAQ,GAAG;AACxE,UAAM,MAAM;AACZ,UAAM,mBAAmB,MAAM,QAAQ,IAAI,QAAQ,IAAI,IAAI,WAAW,CAAC;AAEvE,eAAW,aAAa,kBAAkB;AACxC,UAAI,OAAO,cAAc,SAAU;AAEnC,YAAM,gBAAgB,SAAS,SAAsB;AACrD,UAAI,CAAC,eAAe;AAClB,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,MAAM;AAAA,UACN,SAAS,YAAY,SAAS;AAAA,QAChC,CAAC;AACD;AAAA,MACF;AAEA,YAAM,WAAW,gBAAgB,GAAG;AACpC,YAAM,kBAAkB,IAAI,QAAQ,aAAa;AAEjD,eAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,cAAM,UAAU,eAAe,SAAS,CAAC,CAAC;AAC1C,YAAI,OAAO,KAAK,OAAO,EAAE,WAAW,EAAG;AAEvC,cAAM,eAAe,gBAAgB,OAAO;AAC5C,YAAI,CAAC,gBAAgB,gBAAgB,QAAQ;AAC3C,qBAAW,SAAS,gBAAgB,QAAQ;AAC1C,mBAAO,KAAK;AAAA,cACV,MAAM;AAAA,cACN,MAAM,YAAY,CAAC,IAAI,MAAM,gBAAgB,GAAG;AAAA,cAChD,SAAS,YAAY,SAAS,MAAM,MAAM,WAAW,mBAAmB;AAAA,YAC1E,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,OAAO,WAAW,GAAG,OAAO;AAC9C;AAEA,SAAS,gBAAgB,KAAyD;AAChF,MAAI,IAAI,kBAAkB,aAAa,IAAI,WAAW,OAAO,IAAI,YAAY,UAAU;AACrF,WAAO,CAAC,IAAI,OAAkC;AAAA,EAChD;AACA,SAAO,CAAC;AACV;AAEA,SAAS,eAAe,KAAuD;AAC7E,QAAM,SAAkC,CAAC;AACzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC9C,QAAI,IAAI,WAAW,IAAI,GAAG;AACxB,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/schema.ts","../src/validate.ts"],"sourcesContent":["export { schema, profiles, profileIds } from \"./schema.js\";\r\nexport { validate } from \"./validate.js\";\r\nexport type {\r\n ScalarValue,\r\n ImageType,\r\n Image,\r\n Measure,\r\n PhysicalDimensions,\r\n AttributeRef,\r\n AttributeValue,\r\n Option,\r\n LotPolicy,\r\n SalesUnit,\r\n SourceWhen,\r\n SuppliedMaterial,\r\n SuppliedMaterialCost,\r\n SuppliedMaterialQuantity,\r\n SuppliedMaterialSource,\r\n SupplyOutputEntry,\r\n Product,\r\n Predicate,\r\n Condition,\r\n Component,\r\n RuleOperation,\r\n Rule,\r\n Ruleset,\r\n LookupAxis,\r\n TableRow,\r\n Table,\r\n Dependency,\r\n Constraint,\r\n PriceList,\r\n Catalog,\r\n ProductRef,\r\n Context,\r\n Pricing,\r\n CatalogDocument,\r\n ProductDocument,\r\n PacpDocument,\r\n ProfileId,\r\n ValidationIssue,\r\n ValidationResult,\r\n} from \"./types.js\";\r\n","import { readFileSync } from \"node:fs\";\r\nimport { join } from \"node:path\";\r\n\r\nfunction loadJson(relativePath: string): Record<string, unknown> {\r\n const fullPath = join(__dirname, relativePath);\r\n return JSON.parse(readFileSync(fullPath, \"utf8\"));\r\n}\r\n\r\nexport const schema = loadJson(\"./pacp.schema.json\") as Record<string, unknown>;\r\n\r\nexport const profiles = {\r\n moveis: loadJson(\"./profiles/moveis.schema.json\") as Record<string, unknown>,\r\n iluminacao: loadJson(\"./profiles/iluminacao.schema.json\") as Record<string, unknown>,\r\n \"pisos-revestimentos\": loadJson(\"./profiles/pisos-revestimentos.schema.json\") as Record<string, unknown>,\r\n \"fiscal-br\": loadJson(\"./profiles/fiscal-br.schema.json\") as Record<string, unknown>,\r\n} as const;\r\n\r\nexport type ProfileId = keyof typeof profiles;\r\n\r\nexport const profileIds = Object.keys(profiles) as ProfileId[];\r\n","import type { ValidationResult, ValidationIssue, PacpDocument } from \"./types.js\";\r\nimport { schema, profiles, type ProfileId } from \"./schema.js\";\r\n\r\nexport function validate(document: unknown): ValidationResult {\r\n let Ajv2020: typeof import(\"ajv/dist/2020\").default;\r\n let addFormats: typeof import(\"ajv-formats\").default;\r\n\r\n try {\r\n Ajv2020 = require(\"ajv/dist/2020\") as typeof import(\"ajv/dist/2020\").default;\r\n addFormats = require(\"ajv-formats\") as typeof import(\"ajv-formats\").default;\r\n } catch {\r\n throw new Error(\r\n 'Para usar validate(), instale ajv e ajv-formats: npm install ajv ajv-formats'\r\n );\r\n }\r\n\r\n const ajv = new Ajv2020({ allErrors: true, strict: false });\r\n addFormats(ajv);\r\n\r\n const issues: ValidationIssue[] = [];\r\n\r\n const validateSchema = ajv.compile(schema);\r\n const valid = validateSchema(document);\r\n\r\n if (!valid && validateSchema.errors) {\r\n for (const error of validateSchema.errors) {\r\n issues.push({\r\n code: \"SCHEMA\",\r\n path: error.instancePath || \"/\",\r\n message: error.message ?? \"Erro de validacao de schema\",\r\n });\r\n }\r\n }\r\n\r\n if (document && typeof document === \"object\" && !Array.isArray(document)) {\r\n const doc = document as Record<string, unknown>;\r\n const declaredProfiles = Array.isArray(doc.profiles) ? doc.profiles : [];\r\n\r\n for (const profileId of declaredProfiles) {\r\n if (typeof profileId !== \"string\") continue;\r\n\r\n const profileSchema = profiles[profileId as ProfileId];\r\n if (!profileSchema) {\r\n issues.push({\r\n code: \"UNKNOWN_PROFILE\",\r\n path: \"/profiles\",\r\n message: `Profile \"${profileId}\" nao e um profile oficial PACP`,\r\n });\r\n continue;\r\n }\r\n\r\n const products = extractProducts(doc);\r\n const validateProfile = ajv.compile(profileSchema);\r\n\r\n for (let i = 0; i < products.length; i++) {\r\n const xFields = extractXFields(products[i]);\r\n if (Object.keys(xFields).length === 0) continue;\r\n\r\n const profileValid = validateProfile(xFields);\r\n if (!profileValid && validateProfile.errors) {\r\n for (const error of validateProfile.errors) {\r\n issues.push({\r\n code: \"PROFILE_VALIDATION\",\r\n path: `products[${i}]${error.instancePath || \"/\"}`,\r\n message: `Profile \"${profileId}\": ${error.message ?? \"erro de validacao\"}`,\r\n });\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n return { valid: issues.length === 0, issues };\r\n}\r\n\r\nfunction extractProducts(doc: Record<string, unknown>): Record<string, unknown>[] {\r\n if (doc.document_type === \"PRODUCT\" && doc.product && typeof doc.product === \"object\") {\r\n return [doc.product as Record<string, unknown>];\r\n }\r\n return [];\r\n}\r\n\r\nfunction extractXFields(obj: Record<string, unknown>): Record<string, unknown> {\r\n const result: Record<string, unknown> = {};\r\n for (const [key, value] of Object.entries(obj)) {\r\n if (key.startsWith(\"x-\")) {\r\n result[key] = value;\r\n }\r\n }\r\n return result;\r\n}\r\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,136 +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
|
+
*/
|
|
140
|
+
type SuppliedMaterialSource = "FACTORY" | "CUSTOMER";
|
|
141
|
+
/** Quantidade fixa de insumo (use quando não varia por configuração). */
|
|
142
|
+
interface SuppliedMaterialQuantityValue {
|
|
143
|
+
/** Quantidade positiva. */
|
|
144
|
+
value: number;
|
|
145
|
+
/** Unidade (m², m, kg, un). */
|
|
146
|
+
unit: string;
|
|
147
|
+
}
|
|
148
|
+
/** Quantidade resolvida via lookup em tabela (use quando varia por configuração — ex: sofá 3 vs 4 lugares). */
|
|
149
|
+
interface SuppliedMaterialQuantityTable {
|
|
150
|
+
/** ID de uma tabela `LOOKUP` definida no catálogo. */
|
|
151
|
+
table_id: string;
|
|
152
|
+
/** Unidade do valor retornado pela tabela. */
|
|
153
|
+
unit: string;
|
|
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
|
+
*/
|
|
160
|
+
type SuppliedMaterialQuantity = SuppliedMaterialQuantityValue | SuppliedMaterialQuantityTable;
|
|
161
|
+
/** Custo do material declarado como valor literal. */
|
|
162
|
+
interface SuppliedMaterialCostValue {
|
|
163
|
+
/** Valor ≥ 0. Custo zero é permitido (material gratuito); negativo é inválido. */
|
|
164
|
+
value: number;
|
|
165
|
+
}
|
|
166
|
+
/** Custo do material resolvido via lookup em tabela. */
|
|
167
|
+
interface SuppliedMaterialCostTable {
|
|
168
|
+
table_id: string;
|
|
169
|
+
}
|
|
170
|
+
/** Custo do material resolvido executando um ruleset específico. */
|
|
171
|
+
interface SuppliedMaterialCostRuleset {
|
|
172
|
+
ruleset_id: string;
|
|
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
|
+
*/
|
|
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
|
+
*/
|
|
190
|
+
interface SourceWhen {
|
|
191
|
+
/** Valores que mapeiam para fonte = FACTORY. */
|
|
192
|
+
factory: ScalarValue[];
|
|
193
|
+
/** Valores que mapeiam para fonte = CUSTOMER. */
|
|
194
|
+
customer: ScalarValue[];
|
|
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
|
+
*/
|
|
204
|
+
interface SuppliedMaterial {
|
|
205
|
+
/** ID único do insumo no produto. */
|
|
206
|
+
id: string;
|
|
207
|
+
/** Tipo do material em SNAKE_UPPER (ex: `TECIDO`, `COURO`, `VIDRO`, `MARMORE`). */
|
|
208
|
+
material: string;
|
|
209
|
+
/** Quantidade necessária. */
|
|
210
|
+
quantity: SuppliedMaterialQuantity;
|
|
211
|
+
/** Quem fornece quando não há escolha no orçamento. Default `FACTORY`. */
|
|
212
|
+
default_source?: SuppliedMaterialSource;
|
|
213
|
+
/** Attribute do produto cuja option selecionada decide a fonte. Quando presente, `source_when` é OBRIGATÓRIO. */
|
|
214
|
+
sourcing_attribute_id?: string;
|
|
215
|
+
/** Mapeia `option.value` para `FACTORY`/`CUSTOMER`. Obrigatório quando `sourcing_attribute_id` está presente. */
|
|
216
|
+
source_when?: SourceWhen;
|
|
217
|
+
/** Custo somado quando fonte resolvida = `FACTORY`. Ignorado quando = `CUSTOMER`. */
|
|
218
|
+
factory_cost?: SuppliedMaterialCost;
|
|
219
|
+
/** Bloco livre de requisitos do material. Profile `moveis` padroniza `x-fabric_requirements`. */
|
|
220
|
+
requirements?: Record<string, unknown>;
|
|
221
|
+
[key: `x-${string}`]: unknown;
|
|
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
|
+
*/
|
|
229
|
+
interface SupplyOutputEntry {
|
|
230
|
+
/** ID do `SuppliedMaterial` que originou esta entrada. */
|
|
231
|
+
material_id: string;
|
|
232
|
+
/** Tipo do material (`TECIDO`, `COURO`, etc.). */
|
|
233
|
+
material: string;
|
|
234
|
+
/** Quantidade resolvida pelo engine (após lookup, se aplicável). */
|
|
235
|
+
quantity: number;
|
|
236
|
+
/** Unidade da quantidade. */
|
|
237
|
+
unit: string;
|
|
238
|
+
/** Requisitos copiados do `SuppliedMaterial.requirements`. */
|
|
239
|
+
requirements?: Record<string, unknown>;
|
|
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
|
+
*/
|
|
51
253
|
interface Product {
|
|
254
|
+
/** ID estável do produto, único por catálogo. Case-sensitive. */
|
|
52
255
|
id: string;
|
|
256
|
+
/** Nome legível. */
|
|
53
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
|
+
*/
|
|
54
263
|
visibility?: "PUBLIC" | "INTERNAL";
|
|
264
|
+
/** Código SKU para integração com ERP. */
|
|
55
265
|
sku?: string;
|
|
56
266
|
manufacturer?: string;
|
|
57
267
|
brand?: string;
|
|
58
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
|
+
*/
|
|
59
273
|
category?: string[][];
|
|
274
|
+
/** Código de barras GS1 (8-14 dígitos). */
|
|
60
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
|
+
*/
|
|
61
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
|
+
*/
|
|
62
285
|
unit?: string;
|
|
63
286
|
images?: Image[];
|
|
287
|
+
/** Tags livres para busca. Sem garantia de estabilidade (diferente de `collections`). */
|
|
64
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
|
+
*/
|
|
65
294
|
collections?: string[];
|
|
66
295
|
weight?: Measure;
|
|
67
296
|
dimensions?: PhysicalDimensions;
|
|
68
297
|
lot_policy?: LotPolicy;
|
|
69
298
|
sales_unit?: SalesUnit;
|
|
299
|
+
/** Atributos configuráveis do produto. */
|
|
70
300
|
attributes?: AttributeRef[];
|
|
301
|
+
/** Valores fixos de atributos (não escolhíveis). Complementar a `options`. */
|
|
71
302
|
attribute_values?: AttributeValue[];
|
|
303
|
+
/** Valores selecionáveis dos atributos. */
|
|
72
304
|
options: Option[];
|
|
305
|
+
/** Insumos consumidos pelo produto, com sourcing factory/customer. Ver spec §4.8. */
|
|
306
|
+
supplied_materials?: SuppliedMaterial[];
|
|
307
|
+
/** IDs de rulesets aplicados a este produto. */
|
|
73
308
|
ruleset_ids?: string[];
|
|
74
309
|
[key: `x-${string}`]: unknown;
|
|
75
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
|
+
*/
|
|
76
318
|
interface Predicate {
|
|
319
|
+
/** Fato a avaliar. */
|
|
77
320
|
fact: string;
|
|
78
321
|
operator: "EQ" | "NEQ" | "IN" | "NOT_IN" | "GT" | "GTE" | "LT" | "LTE" | "EXISTS";
|
|
322
|
+
/** Use para operadores escalares (`EQ`, `NEQ`, `GT`, etc.). */
|
|
79
323
|
value?: ScalarValue;
|
|
324
|
+
/** Use para operadores de conjunto (`IN`, `NOT_IN`). */
|
|
80
325
|
values?: ScalarValue[];
|
|
81
326
|
}
|
|
327
|
+
/**
|
|
328
|
+
* Condição lógica composta. `all` = AND; `any` = OR.
|
|
329
|
+
* Pelo menos um dos campos é obrigatório.
|
|
330
|
+
*/
|
|
82
331
|
interface Condition {
|
|
83
332
|
all?: Predicate[];
|
|
84
333
|
any?: Predicate[];
|
|
85
334
|
}
|
|
335
|
+
/** Componente de operações `MAX_OF`/`MIN_OF`/`PICK`. */
|
|
86
336
|
interface Component {
|
|
87
337
|
label?: string;
|
|
88
338
|
value?: number;
|
|
89
339
|
table_id?: string;
|
|
90
340
|
option_id?: string;
|
|
91
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
|
+
*/
|
|
92
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
|
+
*/
|
|
93
358
|
interface Rule {
|
|
359
|
+
/** ID único por ruleset. */
|
|
94
360
|
id: string;
|
|
95
361
|
operation: RuleOperation;
|
|
362
|
+
/** Maior primeiro. Default 0. */
|
|
96
363
|
priority?: number;
|
|
364
|
+
/** Default true. */
|
|
97
365
|
enabled?: boolean;
|
|
366
|
+
/** Quando ausente, regra sempre dispara. */
|
|
98
367
|
when?: Condition;
|
|
368
|
+
/** Para `ADD`/`OVERRIDE`. */
|
|
99
369
|
value?: number;
|
|
370
|
+
/** Para `PERCENT_OF`. */
|
|
100
371
|
percent?: number;
|
|
372
|
+
/** Para `LOOKUP`. */
|
|
101
373
|
table_id?: string;
|
|
374
|
+
/** Para `MAX_OF`/`MIN_OF`/`PICK`. */
|
|
102
375
|
components?: Component[];
|
|
376
|
+
/** Para `ROUND`. */
|
|
103
377
|
precision?: number;
|
|
378
|
+
/** Para `CAP`. */
|
|
104
379
|
max?: number;
|
|
380
|
+
/** Para `FLOOR`. */
|
|
105
381
|
min?: number;
|
|
382
|
+
/** Para `LOOKUP` sem chave correspondente. */
|
|
106
383
|
fallback?: number;
|
|
107
384
|
option_id?: string;
|
|
108
385
|
option_ids?: string[];
|
|
109
386
|
[key: `x-${string}`]: unknown;
|
|
110
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
|
+
*/
|
|
111
393
|
interface Ruleset {
|
|
112
394
|
id: string;
|
|
113
395
|
target: "BASE" | "SUBTOTAL" | "TOTAL";
|
|
114
396
|
rules: Rule[];
|
|
115
397
|
[key: `x-${string}`]: unknown;
|
|
116
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
|
+
*/
|
|
117
406
|
interface LookupAxis {
|
|
407
|
+
/** Nome da chave usada nas `rows`. */
|
|
118
408
|
key: string;
|
|
119
409
|
source: "ATTRIBUTE" | "CONTEXT" | "LITERAL";
|
|
120
410
|
attribute_id?: string;
|
|
121
411
|
context_key?: string;
|
|
122
412
|
literal?: ScalarValue;
|
|
123
413
|
}
|
|
414
|
+
/** Linha de uma tabela `LOOKUP` (chave composta → valor numérico). */
|
|
124
415
|
interface TableRow {
|
|
416
|
+
/** Mapa de chave: `{ "tecido": "VELUDO", "lugares": "3" }`. */
|
|
125
417
|
key: Record<string, ScalarValue>;
|
|
418
|
+
/** Valor retornado quando todas as dimensões batem. */
|
|
126
419
|
value: number;
|
|
127
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
|
+
*/
|
|
128
426
|
interface Table {
|
|
129
427
|
id: string;
|
|
130
428
|
type: "LOOKUP";
|
|
131
429
|
dimensions: LookupAxis[];
|
|
132
430
|
rows: TableRow[];
|
|
133
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
|
+
*/
|
|
134
439
|
interface Dependency {
|
|
135
440
|
id: string;
|
|
136
441
|
type: "REQUIRES" | "IMPLIES" | "AVAILABLE_OPTIONS_WHEN";
|
|
@@ -140,20 +445,33 @@ interface Dependency {
|
|
|
140
445
|
allowed_option_ids?: string[];
|
|
141
446
|
when?: Condition;
|
|
142
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
|
+
*/
|
|
143
453
|
interface Constraint {
|
|
144
454
|
id: string;
|
|
145
455
|
type: "DENY";
|
|
146
456
|
when: Condition;
|
|
457
|
+
/** Mensagem legível exibida ao orçamentista. */
|
|
147
458
|
message: string;
|
|
148
459
|
product_id?: string;
|
|
149
460
|
option_ids?: string[];
|
|
150
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
|
+
*/
|
|
151
467
|
interface PriceList {
|
|
152
468
|
id: string;
|
|
153
469
|
currency: string;
|
|
154
470
|
label?: string;
|
|
471
|
+
/** Casamento com `context` para seleção automática. */
|
|
155
472
|
context_match?: Record<string, ScalarValue>;
|
|
156
473
|
}
|
|
474
|
+
/** Metadados do catálogo (lista de preço, default). */
|
|
157
475
|
interface Catalog {
|
|
158
476
|
id: string;
|
|
159
477
|
name?: string;
|
|
@@ -161,10 +479,18 @@ interface Catalog {
|
|
|
161
479
|
price_lists?: PriceList[];
|
|
162
480
|
[key: `x-${string}`]: unknown;
|
|
163
481
|
}
|
|
482
|
+
/** Referência a um documento `PRODUCT` em arquivo separado, a partir do `CATALOG`. */
|
|
164
483
|
interface ProductRef {
|
|
484
|
+
/** DEVE ser igual ao `product.id` do arquivo apontado. */
|
|
165
485
|
id: string;
|
|
486
|
+
/** Caminho relativo ao diretório do manifesto. */
|
|
166
487
|
path: string;
|
|
167
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
|
+
*/
|
|
168
494
|
interface Context {
|
|
169
495
|
price_list_id?: string;
|
|
170
496
|
region?: string;
|
|
@@ -175,9 +501,16 @@ interface Context {
|
|
|
175
501
|
requested_unit?: string;
|
|
176
502
|
[key: string]: ScalarValue | undefined;
|
|
177
503
|
}
|
|
504
|
+
/** Hint informativo sobre o modo de cálculo predominante do catálogo. */
|
|
178
505
|
interface Pricing {
|
|
179
506
|
calculation_mode?: "CASCADE" | "TABLE_LOOKUP" | "OVERRIDE_BY_VARIANT" | "COST_PLUS";
|
|
180
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
|
+
*/
|
|
181
514
|
interface CatalogDocument {
|
|
182
515
|
document_type: "CATALOG";
|
|
183
516
|
catalog: Catalog;
|
|
@@ -189,11 +522,18 @@ interface CatalogDocument {
|
|
|
189
522
|
tables?: Table[];
|
|
190
523
|
dependencies?: Dependency[];
|
|
191
524
|
constraints?: Constraint[];
|
|
525
|
+
/** Extension profiles ativos (`moveis`, `iluminacao`, `pisos-revestimentos`, `fiscal-br`). */
|
|
192
526
|
profiles?: string[];
|
|
193
527
|
[key: `x-${string}`]: unknown;
|
|
194
528
|
}
|
|
529
|
+
/**
|
|
530
|
+
* Documento isolado de um produto. Referenciado por um `CatalogDocument` via `product_refs[]`.
|
|
531
|
+
*
|
|
532
|
+
* Identifica-se por `document_type: "PRODUCT"`.
|
|
533
|
+
*/
|
|
195
534
|
interface ProductDocument {
|
|
196
535
|
document_type: "PRODUCT";
|
|
536
|
+
/** ID do catálogo ao qual este produto pertence. DEVE bater com `catalog.id` no manifesto. */
|
|
197
537
|
catalog_id: string;
|
|
198
538
|
product: Product;
|
|
199
539
|
rulesets?: Ruleset[];
|
|
@@ -203,13 +543,20 @@ interface ProductDocument {
|
|
|
203
543
|
profiles?: string[];
|
|
204
544
|
[key: `x-${string}`]: unknown;
|
|
205
545
|
}
|
|
546
|
+
/** Qualquer documento PACP válido (CATALOG ou PRODUCT). */
|
|
206
547
|
type PacpDocument = CatalogDocument | ProductDocument;
|
|
548
|
+
/** IDs dos profiles oficiais PACP. */
|
|
207
549
|
type ProfileId = "moveis" | "iluminacao" | "pisos-revestimentos" | "fiscal-br";
|
|
550
|
+
/** Problema reportado pelo validador. */
|
|
208
551
|
interface ValidationIssue {
|
|
552
|
+
/** Código machine-readable (ex: `SCHEMA`, `DUPLICATE_ID`, `MISSING_SOURCING_ATTRIBUTE`). */
|
|
209
553
|
code: string;
|
|
554
|
+
/** JSON Pointer apontando para o local exato do problema. */
|
|
210
555
|
path: string;
|
|
556
|
+
/** Mensagem humana descrevendo o problema. */
|
|
211
557
|
message: string;
|
|
212
558
|
}
|
|
559
|
+
/** Resultado da validação. `valid=true` ⇔ `issues.length === 0`. */
|
|
213
560
|
interface ValidationResult {
|
|
214
561
|
valid: boolean;
|
|
215
562
|
issues: ValidationIssue[];
|
|
@@ -217,4 +564,4 @@ interface ValidationResult {
|
|
|
217
564
|
|
|
218
565
|
declare function validate(document: unknown): ValidationResult;
|
|
219
566
|
|
|
220
|
-
export { type AttributeRef, type AttributeValue, type Catalog, type CatalogDocument, type Component, type Condition, type Constraint, type Context, type Dependency, type Image, type ImageType, type LookupAxis, type LotPolicy, type Measure, type Option, type PacpDocument, type PhysicalDimensions, type Predicate, type PriceList, type Pricing, type Product, type ProductDocument, type ProductRef, type ProfileId, type Rule, type RuleOperation, type Ruleset, type SalesUnit, type ScalarValue, type Table, type TableRow, type ValidationIssue, type ValidationResult, validate };
|
|
567
|
+
export { type AttributeRef, type AttributeValue, type Catalog, type CatalogDocument, type Component, type Condition, type Constraint, type Context, type Dependency, type Image, type ImageType, type LookupAxis, type LotPolicy, type Measure, type Option, type PacpDocument, type PhysicalDimensions, type Predicate, type PriceList, type Pricing, type Product, type ProductDocument, type ProductRef, type ProfileId, type Rule, type RuleOperation, type Ruleset, type SalesUnit, type ScalarValue, type SourceWhen, type SuppliedMaterial, type SuppliedMaterialCost, type SuppliedMaterialQuantity, type SuppliedMaterialSource, type SupplyOutputEntry, type Table, type TableRow, type ValidationIssue, type ValidationResult, validate };
|