multicloud_rule_manager 1.1.80 → 1.1.81
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 +129 -117
- package/package.json +1 -1
|
@@ -5,167 +5,201 @@ 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
|
+
console.log(`🌳 Totale elementi structure: ${structure.length}`);
|
|
88
105
|
|
|
89
106
|
// =========================
|
|
90
107
|
// 📂 HELPERS
|
|
91
108
|
// =========================
|
|
92
|
-
const sortByName = arr =>
|
|
93
|
-
arr.sort((a, b) =>
|
|
109
|
+
const sortByName = (arr) =>
|
|
110
|
+
arr.sort((a, b) =>
|
|
111
|
+
(a.name || "").localeCompare(b.name || "")
|
|
112
|
+
);
|
|
94
113
|
|
|
95
114
|
const getCategories = () =>
|
|
96
115
|
sortByName(
|
|
97
116
|
structure.filter(
|
|
98
|
-
e =>
|
|
117
|
+
(e) =>
|
|
118
|
+
e.parent_guid === rootGuid &&
|
|
119
|
+
e.type === "category"
|
|
99
120
|
)
|
|
100
121
|
);
|
|
101
122
|
|
|
102
123
|
const getChildren = (categoryGuid) =>
|
|
103
124
|
sortByName(
|
|
104
|
-
structure.filter(
|
|
125
|
+
structure.filter(
|
|
126
|
+
(e) => e.parent_guid === categoryGuid
|
|
127
|
+
)
|
|
105
128
|
);
|
|
106
129
|
|
|
107
130
|
// =========================
|
|
108
131
|
// 📡 FAMILIES
|
|
109
132
|
// =========================
|
|
110
|
-
|
|
111
|
-
console.log("Chiamo families");
|
|
112
|
-
|
|
113
133
|
const getFamilies = async (productId) => {
|
|
114
134
|
const resp = await fetch(
|
|
115
135
|
`https://${cred.realm}.bit2win.cloud/api/catalog/v1/products/${productId}/families`,
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
136
|
+
{
|
|
137
|
+
headers: {
|
|
138
|
+
Authorization: `Bearer ${access_token}`,
|
|
139
|
+
Accept: "application/json",
|
|
140
|
+
},
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const data = await safeJson(
|
|
145
|
+
resp,
|
|
146
|
+
`families:${productId}`
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
console.log(
|
|
150
|
+
`👨👩👧 Product ${productId} → ${data.length} families`
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
totalFamilies += data.length;
|
|
126
154
|
|
|
127
|
-
|
|
155
|
+
return (data || []).map((f) => {
|
|
156
|
+
totalAttributes += (f.attributes || []).length;
|
|
128
157
|
|
|
129
|
-
|
|
130
|
-
.sort((a, b) => a.name.localeCompare(b.name))
|
|
131
|
-
.map(f => ({
|
|
158
|
+
return {
|
|
132
159
|
name: f.name,
|
|
133
160
|
visible: f.visible,
|
|
134
161
|
visible_web: f.visible_web,
|
|
135
|
-
attributes: (f.attributes || [])
|
|
136
|
-
|
|
137
|
-
|
|
162
|
+
attributes: (f.attributes || []).map((a) => {
|
|
163
|
+
totalDomains += (a.domains || []).length;
|
|
164
|
+
|
|
165
|
+
return {
|
|
138
166
|
name: a.name,
|
|
139
167
|
value_default: a.value_default,
|
|
140
168
|
read_only: a.read_only,
|
|
141
169
|
required: a.required,
|
|
142
170
|
visible: a.visible,
|
|
143
|
-
domains:
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
default: d.default
|
|
149
|
-
}))
|
|
150
|
-
}))
|
|
151
|
-
}));
|
|
171
|
+
domains: a.domains || [],
|
|
172
|
+
};
|
|
173
|
+
}),
|
|
174
|
+
};
|
|
175
|
+
});
|
|
152
176
|
};
|
|
153
177
|
|
|
154
178
|
// =========================
|
|
155
|
-
// 📊 DATASET
|
|
179
|
+
// 📊 DATASET
|
|
156
180
|
// =========================
|
|
157
181
|
const rows1 = [];
|
|
182
|
+
const rows2 = [];
|
|
158
183
|
|
|
159
184
|
const categories = getCategories();
|
|
185
|
+
totalCategories = categories.length;
|
|
186
|
+
|
|
187
|
+
console.log(`📂 Totale categorie: ${categories.length}`);
|
|
160
188
|
|
|
161
189
|
for (const cat of categories) {
|
|
162
190
|
const children = getChildren(cat.guid);
|
|
163
191
|
|
|
192
|
+
console.log(
|
|
193
|
+
`➡️ Categoria "${cat.name}" → ${children.length} children`
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
totalChildren += children.length;
|
|
197
|
+
|
|
164
198
|
if (children.length === 0) {
|
|
165
199
|
rows1.push({
|
|
166
200
|
product: product.name,
|
|
167
201
|
category: cat.name,
|
|
168
|
-
child: ""
|
|
202
|
+
child: "",
|
|
169
203
|
});
|
|
170
204
|
}
|
|
171
205
|
|
|
@@ -173,23 +207,14 @@ export default {
|
|
|
173
207
|
rows1.push({
|
|
174
208
|
product: product.name,
|
|
175
209
|
category: cat.name,
|
|
176
|
-
child: child.name
|
|
210
|
+
child: child.name,
|
|
177
211
|
});
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
212
|
|
|
181
|
-
// =========================
|
|
182
|
-
// 📊 DATASET 2
|
|
183
|
-
// =========================
|
|
184
|
-
const rows2 = [];
|
|
185
|
-
|
|
186
|
-
for (const cat of categories) {
|
|
187
|
-
const children = getChildren(cat.guid);
|
|
188
|
-
|
|
189
|
-
for (const child of children) {
|
|
190
213
|
if (!child.product_id) continue;
|
|
191
214
|
|
|
192
|
-
const families = await getFamilies(
|
|
215
|
+
const families = await getFamilies(
|
|
216
|
+
child.product_id
|
|
217
|
+
);
|
|
193
218
|
|
|
194
219
|
for (const f of families) {
|
|
195
220
|
for (const attr of f.attributes) {
|
|
@@ -199,15 +224,8 @@ export default {
|
|
|
199
224
|
category: cat.name,
|
|
200
225
|
child: child.name,
|
|
201
226
|
family: f.name,
|
|
202
|
-
family_visible: f.visible,
|
|
203
|
-
family_visible_web: f.visible_web,
|
|
204
227
|
attribute: attr.name,
|
|
205
|
-
attr_default: attr.value_default,
|
|
206
|
-
attr_required: attr.required,
|
|
207
|
-
attr_visible: attr.visible,
|
|
208
228
|
domain_value: dom.value,
|
|
209
|
-
domain_visible: dom.visible,
|
|
210
|
-
domain_default: dom.default
|
|
211
229
|
});
|
|
212
230
|
}
|
|
213
231
|
}
|
|
@@ -216,15 +234,17 @@ export default {
|
|
|
216
234
|
}
|
|
217
235
|
|
|
218
236
|
// =========================
|
|
219
|
-
//
|
|
237
|
+
// 📊 RISULTATI
|
|
220
238
|
// =========================
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
Object.values(a).join("|").localeCompare(Object.values(b).join("|"))
|
|
224
|
-
);
|
|
239
|
+
console.log(`📊 Righe dataset 1: ${rows1.length}`);
|
|
240
|
+
console.log(`📊 Righe dataset 2: ${rows2.length}`);
|
|
225
241
|
|
|
226
|
-
|
|
227
|
-
|
|
242
|
+
console.log("📈 STATISTICHE GLOBALI:");
|
|
243
|
+
console.log(`Categorie: ${totalCategories}`);
|
|
244
|
+
console.log(`Children: ${totalChildren}`);
|
|
245
|
+
console.log(`Families: ${totalFamilies}`);
|
|
246
|
+
console.log(`Attributi: ${totalAttributes}`);
|
|
247
|
+
console.log(`Domini: ${totalDomains}`);
|
|
228
248
|
|
|
229
249
|
// =========================
|
|
230
250
|
// 📁 EXCEL
|
|
@@ -236,8 +256,8 @@ export default {
|
|
|
236
256
|
XLSX.writeFile(wb, fileName);
|
|
237
257
|
};
|
|
238
258
|
|
|
239
|
-
writeExcel("product_structure.xlsx",
|
|
240
|
-
writeExcel("product_details.xlsx",
|
|
259
|
+
writeExcel("product_structure.xlsx", rows1);
|
|
260
|
+
writeExcel("product_details.xlsx", rows2);
|
|
241
261
|
|
|
242
262
|
console.log("✅ Excel generati con successo");
|
|
243
263
|
|
|
@@ -245,28 +265,20 @@ export default {
|
|
|
245
265
|
console.error("❌ Errore:", err.message);
|
|
246
266
|
}
|
|
247
267
|
|
|
248
|
-
|
|
249
|
-
|
|
250
268
|
async function safeJson(resp, label) {
|
|
251
269
|
const text = await resp.text();
|
|
252
|
-
console.log("RAW products:", resp);
|
|
253
|
-
console.log("RAW products:", text);
|
|
254
270
|
|
|
255
271
|
if (!resp.ok) {
|
|
256
|
-
throw new Error(
|
|
272
|
+
throw new Error(
|
|
273
|
+
`${label} HTTP ${resp.status}: ${text.slice(0, 200)}`
|
|
274
|
+
);
|
|
257
275
|
}
|
|
258
276
|
|
|
259
277
|
if (!text) {
|
|
260
278
|
throw new Error(`${label} risposta vuota`);
|
|
261
279
|
}
|
|
262
280
|
|
|
263
|
-
|
|
264
|
-
return JSON.parse(text);
|
|
265
|
-
} catch (e) {
|
|
266
|
-
throw new Error(`${label} NON JSON valido: ${text.slice(0, 200)}`);
|
|
267
|
-
}
|
|
281
|
+
return JSON.parse(text);
|
|
268
282
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
283
|
+
},
|
|
272
284
|
};
|