multicloud_rule_manager 1.1.80 → 1.1.82
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/commands/retrieveproduct.js +135 -117
- package/package.json +1 -1
|
@@ -5,167 +5,207 @@ import { getAlias } from "../utils/aliasManager.js";
|
|
|
5
5
|
export default {
|
|
6
6
|
command: "retrieveproduct <alias> <productName>",
|
|
7
7
|
describe: "Recupera struttura prodotto e genera Excel",
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
handler: async (argv) => {
|
|
9
10
|
try {
|
|
10
11
|
console.log("🔹 Retrieve in corso..");
|
|
11
12
|
console.log("🔹 Recupero credenziali per alias:", argv.alias);
|
|
13
|
+
|
|
12
14
|
const cred = getAlias(argv.alias);
|
|
13
15
|
|
|
14
|
-
//
|
|
16
|
+
// =========================
|
|
17
|
+
// 🔢 CONTATORI GLOBALI
|
|
18
|
+
// =========================
|
|
19
|
+
let totalCategories = 0;
|
|
20
|
+
let totalChildren = 0;
|
|
21
|
+
let totalFamilies = 0;
|
|
22
|
+
let totalAttributes = 0;
|
|
23
|
+
let totalDomains = 0;
|
|
24
|
+
|
|
25
|
+
// =========================
|
|
26
|
+
// 🔑 TOKEN
|
|
27
|
+
// =========================
|
|
15
28
|
console.log("🔹 Inizio richiesta token...");
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
|
|
30
|
+
const loginResp = await fetch(
|
|
31
|
+
`https://login-eon-no-prod.bit2win.cloud/auth/realms/${cred.realm}/protocol/openid-connect/token`,
|
|
32
|
+
{
|
|
33
|
+
method: "POST",
|
|
34
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
35
|
+
body: new URLSearchParams({
|
|
36
|
+
client_id: cred.clientId,
|
|
37
|
+
client_secret: cred.clientSecret,
|
|
38
|
+
username: cred.username,
|
|
39
|
+
password: cred.password,
|
|
40
|
+
grant_type: "password",
|
|
41
|
+
}),
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const loginData = await loginResp.json();
|
|
29
46
|
const access_token = loginData.access_token;
|
|
30
47
|
|
|
31
48
|
if (!access_token) {
|
|
32
|
-
throw new Error("Token non ricevuto
|
|
49
|
+
throw new Error("Token non ricevuto");
|
|
33
50
|
}
|
|
34
51
|
|
|
52
|
+
console.log("✅ Token ricevuto");
|
|
35
53
|
|
|
54
|
+
// =========================
|
|
55
|
+
// 📦 PRODUCTS
|
|
56
|
+
// =========================
|
|
57
|
+
console.log("🔹 Chiamo products...");
|
|
36
58
|
|
|
37
|
-
|
|
38
|
-
// --- SECONDA CHIAMATA: retrieve ---
|
|
39
|
-
console.log("🔹 Inizio richiesta dati API...");
|
|
40
59
|
const apiResp = await fetch(
|
|
41
60
|
`https://${cred.realm}.bit2win.cloud/api/data/v1/products`,
|
|
42
|
-
|
|
43
|
-
method: "GET",
|
|
61
|
+
{
|
|
44
62
|
headers: {
|
|
45
|
-
|
|
46
|
-
|
|
63
|
+
Authorization: `Bearer ${access_token}`,
|
|
64
|
+
Accept: "application/json",
|
|
47
65
|
},
|
|
48
|
-
redirect: "manual"
|
|
49
66
|
}
|
|
50
67
|
);
|
|
51
68
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
console.log(" Chiamo products"+argv.productName);
|
|
55
69
|
const products = await safeJson(apiResp, "products");
|
|
70
|
+
console.log(`📦 Totale products ricevuti: ${products.length}`);
|
|
56
71
|
|
|
57
|
-
|
|
58
|
-
|
|
72
|
+
const product = products.find(
|
|
73
|
+
(p) => p.name === argv.productName
|
|
74
|
+
);
|
|
59
75
|
|
|
60
76
|
if (!product) {
|
|
61
77
|
throw new Error(`Prodotto "${argv.productName}" non trovato`);
|
|
62
78
|
}
|
|
63
79
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
80
|
+
console.log(`✅ Prodotto trovato: ${product.name}`);
|
|
67
81
|
|
|
82
|
+
const rootGuid = product.guid;
|
|
68
83
|
|
|
69
84
|
// =========================
|
|
70
85
|
// 🌳 STRUCTURE
|
|
71
86
|
// =========================
|
|
72
|
-
|
|
73
|
-
console.log("Chiamo products structure");
|
|
87
|
+
console.log("🔹 Chiamo structure...");
|
|
74
88
|
|
|
75
89
|
const structResp = await fetch(
|
|
76
90
|
`https://${cred.realm}.bit2win.cloud/api/data/v1/products_structure`,
|
|
77
|
-
|
|
78
|
-
method: "GET",
|
|
91
|
+
{
|
|
79
92
|
headers: {
|
|
80
|
-
|
|
81
|
-
|
|
93
|
+
Authorization: `Bearer ${access_token}`,
|
|
94
|
+
Accept: "application/json",
|
|
82
95
|
},
|
|
83
|
-
redirect: "manual"
|
|
84
96
|
}
|
|
85
97
|
);
|
|
86
98
|
|
|
87
|
-
const structure = await safeJson(
|
|
99
|
+
const structure = await safeJson(
|
|
100
|
+
structResp,
|
|
101
|
+
"products_structure"
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const productStructureRootId = products.find(
|
|
105
|
+
(p) => p.product_id === rootGuid
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
console.log(`🌳 Totale elementi structure: ${structure.length}`);
|
|
88
109
|
|
|
89
110
|
// =========================
|
|
90
111
|
// 📂 HELPERS
|
|
91
112
|
// =========================
|
|
92
|
-
const sortByName = arr =>
|
|
93
|
-
arr.sort((a, b) =>
|
|
113
|
+
const sortByName = (arr) =>
|
|
114
|
+
arr.sort((a, b) =>
|
|
115
|
+
(a.name || "").localeCompare(b.name || "")
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
|
|
94
119
|
|
|
95
120
|
const getCategories = () =>
|
|
96
121
|
sortByName(
|
|
97
122
|
structure.filter(
|
|
98
|
-
e =>
|
|
123
|
+
(e) =>
|
|
124
|
+
e.parent_guid === productStructureRootId &&
|
|
125
|
+
e.type === "category"
|
|
99
126
|
)
|
|
100
127
|
);
|
|
101
128
|
|
|
102
129
|
const getChildren = (categoryGuid) =>
|
|
103
130
|
sortByName(
|
|
104
|
-
structure.filter(
|
|
131
|
+
structure.filter(
|
|
132
|
+
(e) => e.parent_guid === categoryGuid
|
|
133
|
+
)
|
|
105
134
|
);
|
|
106
135
|
|
|
107
136
|
// =========================
|
|
108
137
|
// 📡 FAMILIES
|
|
109
138
|
// =========================
|
|
110
|
-
|
|
111
|
-
console.log("Chiamo families");
|
|
112
|
-
|
|
113
139
|
const getFamilies = async (productId) => {
|
|
114
140
|
const resp = await fetch(
|
|
115
141
|
`https://${cred.realm}.bit2win.cloud/api/catalog/v1/products/${productId}/families`,
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
142
|
+
{
|
|
143
|
+
headers: {
|
|
144
|
+
Authorization: `Bearer ${access_token}`,
|
|
145
|
+
Accept: "application/json",
|
|
146
|
+
},
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
const data = await safeJson(
|
|
151
|
+
resp,
|
|
152
|
+
`families:${productId}`
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
console.log(
|
|
156
|
+
`👨👩👧 Product ${productId} → ${data.length} families`
|
|
157
|
+
);
|
|
126
158
|
|
|
127
|
-
|
|
159
|
+
totalFamilies += data.length;
|
|
128
160
|
|
|
129
|
-
return (data || [])
|
|
130
|
-
|
|
131
|
-
|
|
161
|
+
return (data || []).map((f) => {
|
|
162
|
+
totalAttributes += (f.attributes || []).length;
|
|
163
|
+
|
|
164
|
+
return {
|
|
132
165
|
name: f.name,
|
|
133
166
|
visible: f.visible,
|
|
134
167
|
visible_web: f.visible_web,
|
|
135
|
-
attributes: (f.attributes || [])
|
|
136
|
-
|
|
137
|
-
|
|
168
|
+
attributes: (f.attributes || []).map((a) => {
|
|
169
|
+
totalDomains += (a.domains || []).length;
|
|
170
|
+
|
|
171
|
+
return {
|
|
138
172
|
name: a.name,
|
|
139
173
|
value_default: a.value_default,
|
|
140
174
|
read_only: a.read_only,
|
|
141
175
|
required: a.required,
|
|
142
176
|
visible: a.visible,
|
|
143
|
-
domains:
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
default: d.default
|
|
149
|
-
}))
|
|
150
|
-
}))
|
|
151
|
-
}));
|
|
177
|
+
domains: a.domains || [],
|
|
178
|
+
};
|
|
179
|
+
}),
|
|
180
|
+
};
|
|
181
|
+
});
|
|
152
182
|
};
|
|
153
183
|
|
|
154
184
|
// =========================
|
|
155
|
-
// 📊 DATASET
|
|
185
|
+
// 📊 DATASET
|
|
156
186
|
// =========================
|
|
157
187
|
const rows1 = [];
|
|
188
|
+
const rows2 = [];
|
|
158
189
|
|
|
159
190
|
const categories = getCategories();
|
|
191
|
+
totalCategories = categories.length;
|
|
192
|
+
|
|
193
|
+
console.log(`📂 Totale categorie: ${categories.length}`);
|
|
160
194
|
|
|
161
195
|
for (const cat of categories) {
|
|
162
196
|
const children = getChildren(cat.guid);
|
|
163
197
|
|
|
198
|
+
console.log(
|
|
199
|
+
`➡️ Categoria "${cat.name}" → ${children.length} children`
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
totalChildren += children.length;
|
|
203
|
+
|
|
164
204
|
if (children.length === 0) {
|
|
165
205
|
rows1.push({
|
|
166
206
|
product: product.name,
|
|
167
207
|
category: cat.name,
|
|
168
|
-
child: ""
|
|
208
|
+
child: "",
|
|
169
209
|
});
|
|
170
210
|
}
|
|
171
211
|
|
|
@@ -173,23 +213,14 @@ export default {
|
|
|
173
213
|
rows1.push({
|
|
174
214
|
product: product.name,
|
|
175
215
|
category: cat.name,
|
|
176
|
-
child: child.name
|
|
216
|
+
child: child.name,
|
|
177
217
|
});
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// =========================
|
|
182
|
-
// 📊 DATASET 2
|
|
183
|
-
// =========================
|
|
184
|
-
const rows2 = [];
|
|
185
|
-
|
|
186
|
-
for (const cat of categories) {
|
|
187
|
-
const children = getChildren(cat.guid);
|
|
188
218
|
|
|
189
|
-
for (const child of children) {
|
|
190
219
|
if (!child.product_id) continue;
|
|
191
220
|
|
|
192
|
-
const families = await getFamilies(
|
|
221
|
+
const families = await getFamilies(
|
|
222
|
+
child.product_id
|
|
223
|
+
);
|
|
193
224
|
|
|
194
225
|
for (const f of families) {
|
|
195
226
|
for (const attr of f.attributes) {
|
|
@@ -199,15 +230,8 @@ export default {
|
|
|
199
230
|
category: cat.name,
|
|
200
231
|
child: child.name,
|
|
201
232
|
family: f.name,
|
|
202
|
-
family_visible: f.visible,
|
|
203
|
-
family_visible_web: f.visible_web,
|
|
204
233
|
attribute: attr.name,
|
|
205
|
-
attr_default: attr.value_default,
|
|
206
|
-
attr_required: attr.required,
|
|
207
|
-
attr_visible: attr.visible,
|
|
208
234
|
domain_value: dom.value,
|
|
209
|
-
domain_visible: dom.visible,
|
|
210
|
-
domain_default: dom.default
|
|
211
235
|
});
|
|
212
236
|
}
|
|
213
237
|
}
|
|
@@ -216,15 +240,17 @@ export default {
|
|
|
216
240
|
}
|
|
217
241
|
|
|
218
242
|
// =========================
|
|
219
|
-
//
|
|
243
|
+
// 📊 RISULTATI
|
|
220
244
|
// =========================
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
Object.values(a).join("|").localeCompare(Object.values(b).join("|"))
|
|
224
|
-
);
|
|
245
|
+
console.log(`📊 Righe dataset 1: ${rows1.length}`);
|
|
246
|
+
console.log(`📊 Righe dataset 2: ${rows2.length}`);
|
|
225
247
|
|
|
226
|
-
|
|
227
|
-
|
|
248
|
+
console.log("📈 STATISTICHE GLOBALI:");
|
|
249
|
+
console.log(`Categorie: ${totalCategories}`);
|
|
250
|
+
console.log(`Children: ${totalChildren}`);
|
|
251
|
+
console.log(`Families: ${totalFamilies}`);
|
|
252
|
+
console.log(`Attributi: ${totalAttributes}`);
|
|
253
|
+
console.log(`Domini: ${totalDomains}`);
|
|
228
254
|
|
|
229
255
|
// =========================
|
|
230
256
|
// 📁 EXCEL
|
|
@@ -236,8 +262,8 @@ export default {
|
|
|
236
262
|
XLSX.writeFile(wb, fileName);
|
|
237
263
|
};
|
|
238
264
|
|
|
239
|
-
writeExcel("product_structure.xlsx",
|
|
240
|
-
writeExcel("product_details.xlsx",
|
|
265
|
+
writeExcel("product_structure.xlsx", rows1);
|
|
266
|
+
writeExcel("product_details.xlsx", rows2);
|
|
241
267
|
|
|
242
268
|
console.log("✅ Excel generati con successo");
|
|
243
269
|
|
|
@@ -245,28 +271,20 @@ export default {
|
|
|
245
271
|
console.error("❌ Errore:", err.message);
|
|
246
272
|
}
|
|
247
273
|
|
|
248
|
-
|
|
249
|
-
|
|
250
274
|
async function safeJson(resp, label) {
|
|
251
275
|
const text = await resp.text();
|
|
252
|
-
console.log("RAW products:", resp);
|
|
253
|
-
console.log("RAW products:", text);
|
|
254
276
|
|
|
255
277
|
if (!resp.ok) {
|
|
256
|
-
throw new Error(
|
|
278
|
+
throw new Error(
|
|
279
|
+
`${label} HTTP ${resp.status}: ${text.slice(0, 200)}`
|
|
280
|
+
);
|
|
257
281
|
}
|
|
258
282
|
|
|
259
283
|
if (!text) {
|
|
260
284
|
throw new Error(`${label} risposta vuota`);
|
|
261
285
|
}
|
|
262
286
|
|
|
263
|
-
|
|
264
|
-
return JSON.parse(text);
|
|
265
|
-
} catch (e) {
|
|
266
|
-
throw new Error(`${label} NON JSON valido: ${text.slice(0, 200)}`);
|
|
267
|
-
}
|
|
287
|
+
return JSON.parse(text);
|
|
268
288
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
289
|
+
},
|
|
272
290
|
};
|