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.
@@ -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
- handler: async (argv) => {
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
- // --- PRIMA CHIAMATA: token ---
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
- const loginResp = await fetch(`https://login-eon-no-prod.bit2win.cloud/auth/realms/${cred.realm}/protocol/openid-connect/token`, {
17
- method: "POST",
18
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
19
- body: new URLSearchParams({
20
- client_id: cred.clientId,
21
- client_secret: cred.clientSecret,
22
- username: cred.username,
23
- password: cred.password,
24
- grant_type: "password"
25
- })
26
- });
27
-
28
- const loginData = await loginResp.json(); // leggi direttamente JSON
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 nel campo 'access_token'");
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
- "Authorization": `Bearer ${access_token}`,
46
- "Accept": "application/json"
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
- console.log(" Chiamo products finita "+argv.productName);
58
- const product = products.find(p => p.name === argv.productName);
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
- const rootGuid = product.guid;
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
- "Authorization": `Bearer ${access_token}`,
81
- "Accept": "application/json"
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(structResp, "products_structure");
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) => (a.name || "").localeCompare(b.name || ""));
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 => e.parent_guid === rootGuid && e.type === "category"
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(e => e.parent_guid === categoryGuid)
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
- method: "GET",
118
- headers: {
119
- "Authorization": `Bearer ${access_token}`,
120
- "Accept": "application/json"
121
- },
122
- redirect: "manual"
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
- const data = await safeJson(resp, `families:${productId}`);
159
+ totalFamilies += data.length;
128
160
 
129
- return (data || [])
130
- .sort((a, b) => a.name.localeCompare(b.name))
131
- .map(f => ({
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
- .sort((a, b) => a.name.localeCompare(b.name))
137
- .map(a => ({
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: (a.domains || [])
144
- .sort((a, b) => (a.value || "").localeCompare(b.value || ""))
145
- .map(d => ({
146
- value: d.value,
147
- visible: d.visible,
148
- default: d.default
149
- }))
150
- }))
151
- }));
177
+ domains: a.domains || [],
178
+ };
179
+ }),
180
+ };
181
+ });
152
182
  };
153
183
 
154
184
  // =========================
155
- // 📊 DATASET 1
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(child.product_id);
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
- // 🔤 SORT GLOBALE
243
+ // 📊 RISULTATI
220
244
  // =========================
221
- const sortRows = (rows) =>
222
- rows.sort((a, b) =>
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
- const sorted1 = sortRows(rows1);
227
- const sorted2 = sortRows(rows2);
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", sorted1);
240
- writeExcel("product_details.xlsx", sorted2);
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(`${label} HTTP ${resp.status}: ${text.slice(0, 200)}`);
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
- try {
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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multicloud_rule_manager",
3
- "version": "1.1.80",
3
+ "version": "1.1.82",
4
4
  "description": "CLI interna per retrieve/upload con token",
5
5
  "main": "index.js",
6
6
  "type": "module",