ofsc-utility 1.0.37 → 1.0.38

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.ts CHANGED
@@ -14,7 +14,7 @@ export { generateAllOnHandInventoryOfAllResources, generateAllOnHandInventoryOfA
14
14
  export { getOAuthToken } from './oauthTokenService';
15
15
  export { downloadWorkZoneCSV } from './workZones';
16
16
  export { AllResources, downloadAllResourcesCSV, getworkSkillsOfResource } from './resources';
17
- export { downloadAllUsersCSV, generateUsersCollaborationCSV } from './users';
17
+ export { downloadAllInactiveUsersCSV, downloadAllUsersCSV, generateUsersCollaborationCSV } from './users';
18
18
  export { downloadAllInventoryTypesCSV, getInventoryTypesDetail, updateCreateInventoryType } from './inventoryTypes';
19
19
  export { getActivitybyId, getAllActivities } from './activities';
20
20
  export { createActivityCustomerInventories, getActivityCustomerInventories } from './activityInventories';
package/dist/index.js CHANGED
@@ -36,7 +36,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
36
36
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.createConfigurationFile = exports.createExcelFile = exports.downloadAllEventsOfLastOneHour = exports.downloadAllEventsOfDLastTwoMinutes = exports.downloadAllEventsOfDayCSV = exports.downloadAllEventsOfDay = exports.getActivityCustomerInventories = exports.createActivityCustomerInventories = exports.getAllActivities = exports.getActivitybyId = exports.updateCreateInventoryType = exports.getInventoryTypesDetail = exports.downloadAllInventoryTypesCSV = exports.generateUsersCollaborationCSV = exports.downloadAllUsersCSV = exports.getworkSkillsOfResource = exports.downloadAllResourcesCSV = exports.AllResources = exports.downloadWorkZoneCSV = exports.getOAuthToken = exports.generateAllOnHandInventoryOfAllResourcesCSV = exports.generateAllOnHandInventoryOfAllResources = exports.WorkZone = exports.Utilities = exports.User = exports.Resource = exports.OauthTokenService = exports.CreateConfigurationFile = exports.InventoryType = exports.Inventory = exports.Events = exports.ActivityInventories = exports.Activity = void 0;
39
+ exports.createConfigurationFile = exports.createExcelFile = exports.downloadAllEventsOfLastOneHour = exports.downloadAllEventsOfDLastTwoMinutes = exports.downloadAllEventsOfDayCSV = exports.downloadAllEventsOfDay = exports.getActivityCustomerInventories = exports.createActivityCustomerInventories = exports.getAllActivities = exports.getActivitybyId = exports.updateCreateInventoryType = exports.getInventoryTypesDetail = exports.downloadAllInventoryTypesCSV = exports.generateUsersCollaborationCSV = exports.downloadAllUsersCSV = exports.downloadAllInactiveUsersCSV = exports.getworkSkillsOfResource = exports.downloadAllResourcesCSV = exports.AllResources = exports.downloadWorkZoneCSV = exports.getOAuthToken = exports.generateAllOnHandInventoryOfAllResourcesCSV = exports.generateAllOnHandInventoryOfAllResources = exports.WorkZone = exports.Utilities = exports.User = exports.Resource = exports.OauthTokenService = exports.CreateConfigurationFile = exports.InventoryType = exports.Inventory = exports.Events = exports.ActivityInventories = exports.Activity = void 0;
40
40
  // Export all methods grouped by category
41
41
  exports.Activity = __importStar(require("./activities"));
42
42
  exports.ActivityInventories = __importStar(require("./activityInventories"));
@@ -63,6 +63,7 @@ Object.defineProperty(exports, "AllResources", { enumerable: true, get: function
63
63
  Object.defineProperty(exports, "downloadAllResourcesCSV", { enumerable: true, get: function () { return resources_1.downloadAllResourcesCSV; } });
64
64
  Object.defineProperty(exports, "getworkSkillsOfResource", { enumerable: true, get: function () { return resources_1.getworkSkillsOfResource; } });
65
65
  var users_1 = require("./users");
66
+ Object.defineProperty(exports, "downloadAllInactiveUsersCSV", { enumerable: true, get: function () { return users_1.downloadAllInactiveUsersCSV; } });
66
67
  Object.defineProperty(exports, "downloadAllUsersCSV", { enumerable: true, get: function () { return users_1.downloadAllUsersCSV; } });
67
68
  Object.defineProperty(exports, "generateUsersCollaborationCSV", { enumerable: true, get: function () { return users_1.generateUsersCollaborationCSV; } });
68
69
  var inventoryTypes_1 = require("./inventoryTypes");
@@ -106,7 +106,7 @@ async function generateAllOnHandInventoryOfAllResources(clientId, clientSecret,
106
106
  console.log("--------------------------------------------------");
107
107
  // 2. Fetch on hand inventories for each resource
108
108
  const resourcesToProcess = limit
109
- ? allResources.slice(0, limit)
109
+ ? allResources.slice(-limit)
110
110
  : allResources;
111
111
  const rows = [];
112
112
  for (const [index, resource] of resourcesToProcess.entries()) {
@@ -3,5 +3,7 @@ export { generateUsersCollaborationCSV } from './collaborationGroups';
3
3
  declare const OfscUserUtility: {
4
4
  generateUsersCollaborationCSV: any;
5
5
  downloadAllUsersCSV: typeof downloadAllUsersCSV;
6
+ downloadAllInactiveUsersCSV: typeof downloadAllInactiveUsersCSV;
6
7
  };
8
+ export declare function downloadAllInactiveUsersCSV(clientId: string, clientSecret: string, instanceUrl: string, inactivityThresholdDays?: number): Promise<void>;
7
9
  export default OfscUserUtility;
@@ -38,9 +38,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.generateUsersCollaborationCSV = void 0;
40
40
  exports.downloadAllUsersCSV = downloadAllUsersCSV;
41
+ exports.downloadAllInactiveUsersCSV = downloadAllInactiveUsersCSV;
41
42
  const fs = __importStar(require("fs"));
42
43
  const node_fetch_1 = __importDefault(require("node-fetch"));
43
44
  const index_1 = require("../oauthTokenService/index");
45
+ const index_2 = require("../utilities/index");
44
46
  async function downloadAllUsersCSV(clientId, clientSecret, instanceUrl) {
45
47
  let offset = 0;
46
48
  const limit = 100;
@@ -118,6 +120,99 @@ var collaborationGroups_1 = require("./collaborationGroups");
118
120
  Object.defineProperty(exports, "generateUsersCollaborationCSV", { enumerable: true, get: function () { return collaborationGroups_1.generateUsersCollaborationCSV; } });
119
121
  const OfscUserUtility = {
120
122
  generateUsersCollaborationCSV: require('./collaborationGroups').generateUsersCollaborationCSV,
121
- downloadAllUsersCSV
123
+ downloadAllUsersCSV,
124
+ downloadAllInactiveUsersCSV
122
125
  };
126
+ /**
127
+ * Returns true if the user is "inactive":
128
+ * - has no lastLoginTime at all, OR
129
+ * - lastLoginTime is older than thresholdDays
130
+ */
131
+ function isInactiveUser(item, thresholdDays, now = new Date()) {
132
+ const lastLogin = (0, index_2.parseOFSCDate)(item.lastLoginTime);
133
+ if (!lastLogin)
134
+ return true; // never logged in => treat as inactive
135
+ const diffMs = now.getTime() - lastLogin.getTime();
136
+ const diffDays = diffMs / (1000 * 60 * 60 * 24);
137
+ return diffDays > thresholdDays;
138
+ }
139
+ async function downloadAllInactiveUsersCSV(clientId, clientSecret, instanceUrl, inactivityThresholdDays = 14) {
140
+ let offset = 0;
141
+ const limit = 100;
142
+ let allItems = [];
143
+ let totalFetched = 0;
144
+ console.log("🚀 Starting users download...");
145
+ console.log("-------------------------------------");
146
+ while (true) {
147
+ const url = `https://${instanceUrl}.fs.ocs.oraclecloud.com/rest/ofscCore/v1/users/?offset=${offset}&limit=${limit}`;
148
+ const token = await (0, index_1.getOAuthToken)(clientId, clientSecret, instanceUrl);
149
+ console.log(`➡️ Fetching offset=${offset} limit=${limit}`);
150
+ const res = await (0, node_fetch_1.default)(url, {
151
+ method: "GET",
152
+ headers: {
153
+ Authorization: `Bearer ${token}`,
154
+ Accept: "application/json"
155
+ }
156
+ });
157
+ if (!res.ok) {
158
+ throw new Error(`❌ Fetch failed: ${res.status} ${res.statusText}`);
159
+ }
160
+ const data = (await res.json());
161
+ allItems.push(...data.items);
162
+ totalFetched += data.items.length;
163
+ console.log(` ✔ Received ${data.items.length} items (Total: ${totalFetched})`);
164
+ if (offset + limit >= data.totalResults)
165
+ break;
166
+ offset += limit;
167
+ }
168
+ console.log("-------------------------------------");
169
+ console.log(`🔎 Filtering inactive users (no login in last ${inactivityThresholdDays} days)...`);
170
+ const now = new Date();
171
+ const inactiveItems = allItems.filter(item => isInactiveUser(item, inactivityThresholdDays, now));
172
+ console.log(` ✔ ${inactiveItems.length} of ${allItems.length} users are inactive`);
173
+ console.log("-------------------------------------");
174
+ console.log("🧩 Collecting all unique properties...");
175
+ // Collect union of all properties (from inactive users only)
176
+ const allProperties = new Set();
177
+ for (const item of inactiveItems) {
178
+ for (const key of Object.keys(item)) {
179
+ if (!["resources", "collaborationGroups", "resourceInternalIds", "links"].includes(key)) {
180
+ allProperties.add(key);
181
+ }
182
+ }
183
+ }
184
+ const headers = Array.from(allProperties);
185
+ console.log(`📝 Total unique fields: ${headers.length}`);
186
+ // Build CSV rows
187
+ const csvRows = [];
188
+ csvRows.push(headers.join(","));
189
+ for (const item of inactiveItems) {
190
+ const row = headers.map(field => {
191
+ let value = item[field];
192
+ if (field === "keys") {
193
+ if (Array.isArray(value))
194
+ return `"${value.join("|")}"`;
195
+ if (value)
196
+ return `"${String(value)}"`;
197
+ return "";
198
+ }
199
+ // Objects → JSON-safe string
200
+ if (typeof value === "object" && value !== null) {
201
+ return `"${JSON.stringify(value).replace(/"/g, "'")}"`;
202
+ }
203
+ return value !== undefined ? `"${String(value).replace(/"/g, "'")}"` : "";
204
+ });
205
+ csvRows.push(row.join(","));
206
+ }
207
+ const filePath = "./inactive_users.csv";
208
+ fs.writeFileSync(filePath, csvRows.join("\n"));
209
+ console.log("-------------------------------------");
210
+ console.log("✅ Inactive Users CSV Created Successfully!");
211
+ console.log(`📁 File: ${filePath}`);
212
+ console.log(`📦 Total Fetched: ${totalFetched}`);
213
+ console.log(`🚫 Inactive Records (>${inactivityThresholdDays} days): ${inactiveItems.length}`);
214
+ console.log(`🧩 Total Columns (Dynamic): ${headers.length}`);
215
+ console.log(`🧩 Date Time: ${new Date()}`);
216
+ console.log("-------------------------------------");
217
+ }
123
218
  exports.default = OfscUserUtility;
@@ -30,4 +30,9 @@ interface ValidationResult {
30
30
  export declare function validateDateTimeStrict(dateTimeStr: string): ValidationResult;
31
31
  export declare function getTimeBefore180SecondsAlt(): string;
32
32
  export declare function getTimeBefore3600SecondsAlt(): string;
33
+ /**
34
+ * Parses OFSC-style "YYYY-MM-DD HH:mm:ss" into a Date object.
35
+ * Falls back to null if the value is missing/unparseable.
36
+ */
37
+ export declare function parseOFSCDate(value: unknown): Date | null;
33
38
  export {};
@@ -43,6 +43,7 @@ exports.createExcelFile = createExcelFile;
43
43
  exports.validateDateTimeStrict = validateDateTimeStrict;
44
44
  exports.getTimeBefore180SecondsAlt = getTimeBefore180SecondsAlt;
45
45
  exports.getTimeBefore3600SecondsAlt = getTimeBefore3600SecondsAlt;
46
+ exports.parseOFSCDate = parseOFSCDate;
46
47
  const XLSX = __importStar(require("xlsx-js-style"));
47
48
  const xmldom_1 = require("xmldom");
48
49
  const oauthTokenService_1 = require("../oauthTokenService");
@@ -318,3 +319,15 @@ function getTimeBefore3600SecondsAlt() {
318
319
  .replace('T', ' ')
319
320
  .substring(0, 19);
320
321
  }
322
+ /**
323
+ * Parses OFSC-style "YYYY-MM-DD HH:mm:ss" into a Date object.
324
+ * Falls back to null if the value is missing/unparseable.
325
+ */
326
+ function parseOFSCDate(value) {
327
+ if (!value || typeof value !== "string")
328
+ return null;
329
+ // Convert "2026-08-07 12:31:18" -> "2026-08-07T12:31:18"
330
+ const isoLike = value.trim().replace(" ", "T");
331
+ const d = new Date(isoLike);
332
+ return isNaN(d.getTime()) ? null : d;
333
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ofsc-utility",
3
- "version": "1.0.37",
3
+ "version": "1.0.38",
4
4
  "description": "TypeScript helpers for Oracle Field Service Cloud (OFSC): events, resources, inventories, metadata and CSV/Excel utilities.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",