import { CoreConfiguration } from "../data-sync-service/configuration-manager.js"; import { sdkLogger as logger } from "../reporting-service/logger.js"; import { HTTPClientFactory } from "../../utils/http-client.js"; import type { MMMappedErpResourceRow } from "./types/mm-response-interfaces.js"; /** * One row from `GET /mes/settings/machine-settings`. Field names follow the MES mapping service; * see {@link mapMesMachineSettingsToMappedErpResourceRows} for how each field maps to the SDK. */ export interface MesMachineSettingRow { laborTicketEnabled?: boolean; laborResourceId?: string | null; /** * ERP resource ids this machine can be scheduled as (in addition to {@link laborResourceId} for labor). */ scheduledAs?: ReadonlyArray | null; machineRef?: number | string | null; name?: string | null; type?: string | null; machineGroupId?: string | number | null; isResourceGroup?: boolean; } /** * `GET {mmApiBaseUrl}/mes/settings/machine-settings` — returns a JSON array of machine rows * (auth: bearer `mmApiAuthToken`). * * Requires `mmApiBaseUrl` and `mmApiAuthToken` in {@link CoreConfiguration}. Throws if either is * missing, if the response body is not a JSON array, or if the HTTP request fails. * Used by labor import allowlists and mapped-resource helpers on `MMApiClient`. */ export async function fetchMesMachineSettingsRows(): Promise< MesMachineSettingRow[] > { const config = CoreConfiguration.inst(); const baseUrl = config.mmApiBaseUrl; const token = config.mmApiAuthToken; if (!baseUrl || !token) { throw new Error( "fetchMesMachineSettingsRows: missing mmApiBaseUrl or mmApiAuthToken" ); } const client = HTTPClientFactory.getInstance({ baseUrl, retryAttempts: config.mmApiRetryAttempts, timeoutMs: config.mmApiTimeoutSeconds * 1000, }); const response = await client.request({ url: "/mes/settings/machine-settings", method: "GET", headers: { Accept: "application/json", Authorization: `Bearer ${token}`, }, }); const rows = response.data; if (!Array.isArray(rows)) { throw new Error("fetchMesMachineSettingsRows: response is not a JSON array"); } return rows; } /** * Collects every non-empty {@link MesMachineSettingRow.laborResourceId} and every entry in * {@link MesMachineSettingRow.scheduledAs} across **all** machine-settings rows, deduped * case-insensitively (first-seen casing preserved). Does not filter on `laborTicketEnabled`. * Non-array `scheduledAs` is ignored. */ export function collectMesSchedulableErpResourceIds( rows: ReadonlyArray ): string[] { const seenLower = new Set(); const out: string[] = []; const add = (raw: unknown) => { if (raw === null || raw === undefined) return; const s = typeof raw === "string" ? raw.trim() : String(raw).trim(); if (s === "") return; const low = s.toLowerCase(); if (seenLower.has(low)) return; seenLower.add(low); out.push(s); }; for (const row of rows) { add(row.laborResourceId); const sched = row.scheduledAs; if (!Array.isArray(sched)) continue; for (const id of sched) { add(id); } } return out; } /** * Loads machine-settings and returns {@link collectMesSchedulableErpResourceIds}. * Same configuration and failure behavior as {@link fetchMesMachineSettingsRows}. */ export async function fetchMesSchedulableErpResourceIds(): Promise { const rows = await fetchMesMachineSettingsRows(); const ids = collectMesSchedulableErpResourceIds(rows); logger.info( `fetchMesSchedulableErpResourceIds: ${ids.length} unique ERP resource id(s) from laborResourceId + scheduledAs` ); return ids; } /** * Maps machine-settings rows to {@link MMMappedErpResourceRow} for connectors. * Emits one row per MES machine that has both a finite `machineRef` and a non-empty * `laborResourceId` (ERP labor resource mapping). Optional display / group fields pass through when present. */ export function mapMesMachineSettingsToMappedErpResourceRows( rows: ReadonlyArray ): MMMappedErpResourceRow[] { const out: MMMappedErpResourceRow[] = []; for (const raw of rows) { const row = mapMesMachineSettingRowToMapped(raw); if (row) out.push(row); } return out; } function mapMesMachineSettingRowToMapped( raw: MesMachineSettingRow ): MMMappedErpResourceRow | null { const refRaw = raw.machineRef; if (refRaw === null || refRaw === undefined || refRaw === "") { return null; } const ref = typeof refRaw === "number" ? refRaw : Number(refRaw); if (!Number.isFinite(ref)) { return null; } const ridRaw = raw.laborResourceId; if (ridRaw === null || ridRaw === undefined) { return null; } const resourceId = typeof ridRaw === "string" ? ridRaw.trim() : String(ridRaw).trim(); if (resourceId === "") { return null; } const mgId = raw.machineGroupId; const machineGroupId = mgId === null || mgId === undefined ? null : String(mgId); const name = typeof raw.name === "string" ? raw.name : null; const type = raw.type === null || raw.type === undefined ? null : String(raw.type); return { isResourceGroup: Boolean(raw.isResourceGroup), machineGroupId, machineRef: Math.trunc(ref), resourceId, name, type, }; }