function createTimeEntries({ fetchJson, dates, getResourceUser, saveHeaders }) { const endpoint = "https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/oalset_timeentrymobile/live;profile=PROD/services/auth/1.1/proxy/oke_seaas/uri/https/gxpap.oracle.com/oalcrm/service/set/seaas/mgmt/timeEntries/weekDetails"; async function requestWeekDetails(message) { const debugRequests = []; try { const date = dates.toApi(message.dateReference); const items = await fetchJson(`${endpoint}?dateValue=${encodeURIComponent(date)}`, { method: "GET", credentials: "include", headers: { Authorization: "Session", Accept: "application/json" } }, "requestWeekDetails", debugRequests); if (!Array.isArray(items) || items.length !== 7 || items.some(item => !dates.fromApi(item?.Date) || !dates.fromApi(item?.EndDate)) || new Set(items.map(item => item.Date)).size !== 7) throw new Error("Invalid week details response."); return { ok: true, items, debugRequests }; } catch (error) { error.debugRequests = debugRequests; throw error; } } async function requestTimeEntries(message) { const debugRequests = []; try { if (!/^\d+$/.test(String(message.weekId)) || Number(message.weekId) <= 0) throw new Error("Missing or invalid WeekId."); const resource = await getResourceUser(message); debugRequests.push(...resource.debugRequests); const url = endpoint.replace(/\/weekDetails$/, "") + `?resourceId=${encodeURIComponent(resource.resource.resourcePartyId)}&sortBy=createdDate&sortOrder=ASC&weekId=${encodeURIComponent(message.weekId)}`; const items = await fetchJson(url, { method: "GET", credentials: "include", headers: { Authorization: "Session", Accept: "application/json" } }, "requestTimeEntries", debugRequests); if (!Array.isArray(items)) throw new Error("Invalid time entries response."); return { ok: true, items, debugRequests }; } catch (error) { error.debugRequests = [...debugRequests, ...(error.debugRequests || [])]; throw error; } } async function requestTimeEntriesDelete(message) { const debugRequests = []; try { if (!/^[1-9]\d*$/.test(String(message.id))) throw new Error("Missing or invalid time entry ID."); const url = endpoint.replace(/\/weekDetails$/, "") + `/${message.id}`; const headers = await saveHeaders(url); const result = await fetchJson(url, { method: "DELETE", credentials: "include", headers }, "requestTimeEntriesDelete", debugRequests, { allowEmpty: true }); return { ok: true, result, debugRequests }; } catch (error) { error.debugRequests = debugRequests; throw error; } } async function requestTimeEntriesSave(message) { const debugRequests = []; try { if (!["POST", "PUT"].includes(message.method)) throw new Error("Invalid time entry save method."); if (!Array.isArray(message.items) || !message.items.length) throw new Error("No time entries to save."); const hours = ["saturdayTaskHours", "sundayTaskHours", "mondayTaskHours", "tuesdayTaskHours", "wednesdayTaskHours", "thursdayTaskHours", "fridayTaskHours"]; for (const item of message.items) { if (!item || !["SERVICE", "NON_SERVICE"].includes(item.tag) || !item.taskType || (item.tag === "SERVICE" && (!/^SR\d+$/.test(item.srNumber) || !item.activityCode)) || !/^\d+$/.test(String(item.weekId)) || Number(item.weekId) <= 0 || hours.some(key => typeof item[key] !== "number" || !Number.isFinite(item[key]) || item[key] < 0 || item[key] > 24) || !hours.some(key => item[key] > 0) || (message.method === "PUT" && (!/^\d+$/.test(String(item.id)) || Number(item.id) <= 0))) throw new Error("Invalid or incomplete time entry."); } const resource = await getResourceUser(message); debugRequests.push(...resource.debugRequests); const items = message.items.map(item => ({ ...(message.method === "PUT" ? { id: item.id } : {}), srNumber: item.tag === "NON_SERVICE" ? "non-service-sr" : item.srNumber, activityCode: item.activityCode || "", taskType: item.taskType, deliveryType: item.deliveryType || "", ...Object.fromEntries(hours.map(key => [key, item[key]])), notes: String(item.notes || ""), weekId: item.weekId, resourceId: String(resource.resource.resourcePartyId), tag: item.tag })); const url = endpoint.replace(/\/weekDetails$/, ""); const headers = await saveHeaders(url); const result = await fetchJson(url, { method: message.method, credentials: "include", headers, body: JSON.stringify(items) }, "requestTimeEntriesSave", debugRequests, { allowEmpty: true }); return { ok: true, result, debugRequests }; } catch (error) { error.debugRequests = [...debugRequests, ...(error.debugRequests || [])]; throw error; } } async function requestActiveServiceRequests(message) { const debugRequests = []; try { if (!/^\d+$/.test(String(message.weekId)) || Number(message.weekId) <= 0) throw new Error("Missing or invalid WeekId."); const resource = await getResourceUser(message); debugRequests.push(...resource.debugRequests); const url = endpoint.replace(/weekDetails$/, "activeServiceRequests") + `?resourceId=${encodeURIComponent(resource.resource.resourcePartyId)}&weekId=${encodeURIComponent(message.weekId)}`; const items = await fetchJson(url, { method: "GET", credentials: "include", headers: { Authorization: "Session", Accept: "application/json" } }, "requestActiveServiceRequests", debugRequests); if (!Array.isArray(items)) throw new Error("Invalid active Service Requests response."); return { ok: true, items, debugRequests }; } catch (error) { error.debugRequests = [...debugRequests, ...(error.debugRequests || [])]; throw error; } } async function requestServiceRequestExpand(message) { const debugRequests = []; try { if (!Array.isArray(message.srNumbers)) throw new Error("Missing Service Request numbers."); const numbers = [...new Set(message.srNumbers.map(value => String(value || "").trim()).filter(Boolean))].filter(value => value !== "non-service-sr"); if (numbers.some(value => !/^SR\d+$/.test(value))) throw new Error("Invalid Service Request number."); const batches = []; for (let index = 0; index < numbers.length; index += 50) batches.push(numbers.slice(index, index + 50)); if (!batches.length || batches[batches.length - 1].length === 50) batches.push([]); batches[batches.length - 1].push("non-service-sr"); const base = "https://comcipapic-oalprod.integration.ocp.oraclecloud.com/ic/builder/rt/oalset_timeentrymobile/live;profile=PROD/services/auth/1.1/proxy/crmRestApiSearchResourcesLatestCustomActions/uri/https/eeho.fa.us2.oraclecloud.com/crmRestApi/resources/latest/serviceRequests"; const fields = "SrNumber,SRActivities_c,ProblemDescription,AccountPartyUniqueName,ServiceNew_c,OptyOwner_c,OptyName_c,OptyNumber_c,ReportedByPartyUniqueName,StatusCdMeaning,CountryText_c,AssigneePersonName,OptyStatus_c"; const items = []; for (const batch of batches) { const query = `SrNumber in (${batch.map(value => `'${value}'`).join(",")})`; const url = `${base}?expand=ServiceRequest_SRToInternalSR_Tgt&fields=${encodeURIComponent(fields)}&limit=200&onlyData=true&q=${encodeURIComponent(query).replace(/'/g, "%27")}`; const result = await fetchJson(url, { method: "GET", credentials: "include", headers: { Authorization: "Session", Accept: "application/json", "vb-proxy-header-rest-framework-version": "3" } }, "requestServiceRequestExpand", debugRequests); if (!Array.isArray(result?.items)) throw new Error("Invalid Service Request expansion response."); items.push(...result.items); } return { ok: true, items, debugRequests }; } catch (error) { error.debugRequests = debugRequests; throw error; } } async function requestLookupTaskType() { const debugRequests = []; try { const url = endpoint.replace(/mgmt\/timeEntries\/weekDetails$/, "crm/lookups?lookupType=SCTA_TASK_TYPE&type=CUSTOM"); const result = await fetchJson(url, { method: "GET", credentials: "include", headers: { Authorization: "Session", Accept: "application/json" } }, "requestLookupTaskType", debugRequests); if (!Array.isArray(result?.items)) throw new Error("Invalid Task Type lookup response."); return { ok: true, items: result.items, debugRequests }; } catch (error) { error.debugRequests = debugRequests; throw error; } } return { requestWeekDetails, requestTimeEntries, requestTimeEntriesSave, requestTimeEntriesDelete, requestActiveServiceRequests, requestServiceRequestExpand, requestLookupTaskType }; }