Updated the logic to retrieve the default savedSearchNumber dynamically

This commit is contained in:
2026-10-26 11:39:21 -03:00
parent 0f1f399d1a
commit 45428c9626
7 changed files with 118 additions and 29 deletions

View File

@@ -2653,12 +2653,29 @@ function createFusionOpportunities({
environment environment
}) { }) {
const { fetch } = environment; const { fetch } = environment;
async function requestOpportunitiesPage(token, period, dateRange, offset, accumulatedItems, requestVersion, page) { async function requestOpportunitiesSavedSearch(token) {
const url = OPPORTUNITIES_QUERY_URL + "?access=userAdmin&applications=461e5791-9f15-4cd1-b5cd-19e8480cbce4&entity=Opportunity&language=en&limit=-1&returnIdentifierOnlyFields=true";
const headers = { Accept: "application/json", Authorization: `Bearer ${token}` };
const entry = logRequestStart({ name: "requestOpportunitiesSavedSearch", method: "GET", url, headers });
try {
const response = await fetch.call(environment.window, url, { method: "GET", credentials: "include", headers });
logRequestSuccess(entry, response, await readResponseBodyForDebug(response));
if (!response.ok) throw new Error(`requestOpportunitiesSavedSearch failed with status ${response.status}.`);
const data = await response.json();
if (!Array.isArray(data?.items)) throw new Error("requestOpportunitiesSavedSearch returned an invalid response.");
const defaults = data.items.filter(item => item.isDefault === true);
if (defaults.length !== 1 || typeof defaults[0].savedSearchNumber !== "string" || !defaults[0].savedSearchNumber.trim()) throw new Error("A unique default Opportunity saved search with savedSearchNumber was not returned.");
return defaults[0].savedSearchNumber.trim();
} catch (error) { logRequestFailure(entry, error.message); throw error; }
}
async function requestOpportunitiesPage(token, period, dateRange, offset, accumulatedItems, requestVersion, page, savedSearchNumber) {
if (!isCurrentPeriodRequest(requestVersion)) { if (!isCurrentPeriodRequest(requestVersion)) {
return null; return null;
} }
const payload = createOpportunitiesQueryPayload(dateRange, offset); if (!savedSearchNumber) savedSearchNumber = await requestOpportunitiesSavedSearch(token);
if (!isCurrentPeriodRequest(requestVersion)) return null;
const payload = createOpportunitiesQueryPayload(dateRange, offset, savedSearchNumber);
const requestBody = JSON.stringify(payload); const requestBody = JSON.stringify(payload);
const requestEntry = logRequestStart({ const requestEntry = logRequestStart({
name: "requestOpportunities", name: "requestOpportunities",
@@ -2682,7 +2699,7 @@ function createFusionOpportunities({
}); });
try { try {
const response = await fetch(OPPORTUNITIES_QUERY_URL, { const response = await fetch.call(environment.window, OPPORTUNITIES_QUERY_URL, {
method: "POST", method: "POST",
credentials: "include", credentials: "include",
headers: { headers: {
@@ -2726,7 +2743,8 @@ function createFusionOpportunities({
currentOffset + receivedCount, currentOffset + receivedCount,
allItems, allItems,
requestVersion, requestVersion,
page + 1 page + 1,
savedSearchNumber
); );
} catch (error) { } catch (error) {
logRequestFailure(requestEntry, error.message || "Request failed."); logRequestFailure(requestEntry, error.message || "Request failed.");
@@ -2734,7 +2752,8 @@ function createFusionOpportunities({
} }
} }
function createOpportunitiesQueryPayload(dateRange, offset) { function createOpportunitiesQueryPayload(dateRange, offset, savedSearchNumber) {
if (typeof savedSearchNumber !== "string" || !savedSearchNumber.trim()) throw new Error("Missing default Opportunity savedSearchNumber.");
return { return {
aggregationResults: false, aggregationResults: false,
applications: ["ORACLE-ISS-APP"], applications: ["ORACLE-ISS-APP"],
@@ -2802,13 +2821,13 @@ function createFusionOpportunities({
language: "en", language: "en",
skipInValidFields: true, skipInValidFields: true,
skipHiddenFromUIFields: true, skipHiddenFromUIFields: true,
copiedFrom: "queries/d5dbcd01-9ff3-40be-9b5b-64744cbf7162", copiedFrom: "queries/" + savedSearchNumber,
limit: OPPORTUNITIES_PAGE_LIMIT, limit: OPPORTUNITIES_PAGE_LIMIT,
offset offset
}; };
} }
return { requestOpportunitiesPage, createOpportunitiesQueryPayload }; return { requestOpportunitiesPage, createOpportunitiesQueryPayload, requestOpportunitiesSavedSearch };
} }
// Source: src/services/fusion/crm-service-requests.js // Source: src/services/fusion/crm-service-requests.js
@@ -9847,7 +9866,7 @@ function createDebugContentView({
function getRequestCategory(entry) { function getRequestCategory(entry) {
if (/^request(?:CurrentUser|TokenRelay|ConsumerTokenService|CustomerTokenService)/.test(entry.name)) return "authentication"; if (/^request(?:CurrentUser|TokenRelay|ConsumerTokenService|CustomerTokenService)/.test(entry.name)) return "authentication";
if (entry.name === "requestOpportunities") return "opportunities"; if (["requestOpportunities", "requestOpportunitiesSavedSearch"].includes(entry.name)) return "opportunities";
if (entry.name === "requestOpptyProducts") return "products"; if (entry.name === "requestOpptyProducts") return "products";
if (["requestWlActions", "requestActionTeamMembers", "requestActionFindLookup", "requestMgmtAction"].includes(entry.name)) return "actions"; if (["requestWlActions", "requestActionTeamMembers", "requestActionFindLookup", "requestMgmtAction"].includes(entry.name)) return "actions";
if (entry.name === "requestGenerateAiSummary") return "ai"; if (entry.name === "requestGenerateAiSummary") return "ai";

View File

@@ -2653,12 +2653,29 @@ function createFusionOpportunities({
environment environment
}) { }) {
const { fetch } = environment; const { fetch } = environment;
async function requestOpportunitiesPage(token, period, dateRange, offset, accumulatedItems, requestVersion, page) { async function requestOpportunitiesSavedSearch(token) {
const url = OPPORTUNITIES_QUERY_URL + "?access=userAdmin&applications=461e5791-9f15-4cd1-b5cd-19e8480cbce4&entity=Opportunity&language=en&limit=-1&returnIdentifierOnlyFields=true";
const headers = { Accept: "application/json", Authorization: `Bearer ${token}` };
const entry = logRequestStart({ name: "requestOpportunitiesSavedSearch", method: "GET", url, headers });
try {
const response = await fetch.call(environment.window, url, { method: "GET", credentials: "include", headers });
logRequestSuccess(entry, response, await readResponseBodyForDebug(response));
if (!response.ok) throw new Error(`requestOpportunitiesSavedSearch failed with status ${response.status}.`);
const data = await response.json();
if (!Array.isArray(data?.items)) throw new Error("requestOpportunitiesSavedSearch returned an invalid response.");
const defaults = data.items.filter(item => item.isDefault === true);
if (defaults.length !== 1 || typeof defaults[0].savedSearchNumber !== "string" || !defaults[0].savedSearchNumber.trim()) throw new Error("A unique default Opportunity saved search with savedSearchNumber was not returned.");
return defaults[0].savedSearchNumber.trim();
} catch (error) { logRequestFailure(entry, error.message); throw error; }
}
async function requestOpportunitiesPage(token, period, dateRange, offset, accumulatedItems, requestVersion, page, savedSearchNumber) {
if (!isCurrentPeriodRequest(requestVersion)) { if (!isCurrentPeriodRequest(requestVersion)) {
return null; return null;
} }
const payload = createOpportunitiesQueryPayload(dateRange, offset); if (!savedSearchNumber) savedSearchNumber = await requestOpportunitiesSavedSearch(token);
if (!isCurrentPeriodRequest(requestVersion)) return null;
const payload = createOpportunitiesQueryPayload(dateRange, offset, savedSearchNumber);
const requestBody = JSON.stringify(payload); const requestBody = JSON.stringify(payload);
const requestEntry = logRequestStart({ const requestEntry = logRequestStart({
name: "requestOpportunities", name: "requestOpportunities",
@@ -2682,7 +2699,7 @@ function createFusionOpportunities({
}); });
try { try {
const response = await fetch(OPPORTUNITIES_QUERY_URL, { const response = await fetch.call(environment.window, OPPORTUNITIES_QUERY_URL, {
method: "POST", method: "POST",
credentials: "include", credentials: "include",
headers: { headers: {
@@ -2726,7 +2743,8 @@ function createFusionOpportunities({
currentOffset + receivedCount, currentOffset + receivedCount,
allItems, allItems,
requestVersion, requestVersion,
page + 1 page + 1,
savedSearchNumber
); );
} catch (error) { } catch (error) {
logRequestFailure(requestEntry, error.message || "Request failed."); logRequestFailure(requestEntry, error.message || "Request failed.");
@@ -2734,7 +2752,8 @@ function createFusionOpportunities({
} }
} }
function createOpportunitiesQueryPayload(dateRange, offset) { function createOpportunitiesQueryPayload(dateRange, offset, savedSearchNumber) {
if (typeof savedSearchNumber !== "string" || !savedSearchNumber.trim()) throw new Error("Missing default Opportunity savedSearchNumber.");
return { return {
aggregationResults: false, aggregationResults: false,
applications: ["ORACLE-ISS-APP"], applications: ["ORACLE-ISS-APP"],
@@ -2802,13 +2821,13 @@ function createFusionOpportunities({
language: "en", language: "en",
skipInValidFields: true, skipInValidFields: true,
skipHiddenFromUIFields: true, skipHiddenFromUIFields: true,
copiedFrom: "queries/d5dbcd01-9ff3-40be-9b5b-64744cbf7162", copiedFrom: "queries/" + savedSearchNumber,
limit: OPPORTUNITIES_PAGE_LIMIT, limit: OPPORTUNITIES_PAGE_LIMIT,
offset offset
}; };
} }
return { requestOpportunitiesPage, createOpportunitiesQueryPayload }; return { requestOpportunitiesPage, createOpportunitiesQueryPayload, requestOpportunitiesSavedSearch };
} }
// Source: src/services/fusion/crm-service-requests.js // Source: src/services/fusion/crm-service-requests.js
@@ -9847,7 +9866,7 @@ function createDebugContentView({
function getRequestCategory(entry) { function getRequestCategory(entry) {
if (/^request(?:CurrentUser|TokenRelay|ConsumerTokenService|CustomerTokenService)/.test(entry.name)) return "authentication"; if (/^request(?:CurrentUser|TokenRelay|ConsumerTokenService|CustomerTokenService)/.test(entry.name)) return "authentication";
if (entry.name === "requestOpportunities") return "opportunities"; if (["requestOpportunities", "requestOpportunitiesSavedSearch"].includes(entry.name)) return "opportunities";
if (entry.name === "requestOpptyProducts") return "products"; if (entry.name === "requestOpptyProducts") return "products";
if (["requestWlActions", "requestActionTeamMembers", "requestActionFindLookup", "requestMgmtAction"].includes(entry.name)) return "actions"; if (["requestWlActions", "requestActionTeamMembers", "requestActionFindLookup", "requestMgmtAction"].includes(entry.name)) return "actions";
if (entry.name === "requestGenerateAiSummary") return "ai"; if (entry.name === "requestGenerateAiSummary") return "ai";

View File

@@ -21,7 +21,7 @@ function createDebugContentView({
function getRequestCategory(entry) { function getRequestCategory(entry) {
if (/^request(?:CurrentUser|TokenRelay|ConsumerTokenService|CustomerTokenService)/.test(entry.name)) return "authentication"; if (/^request(?:CurrentUser|TokenRelay|ConsumerTokenService|CustomerTokenService)/.test(entry.name)) return "authentication";
if (entry.name === "requestOpportunities") return "opportunities"; if (["requestOpportunities", "requestOpportunitiesSavedSearch"].includes(entry.name)) return "opportunities";
if (entry.name === "requestOpptyProducts") return "products"; if (entry.name === "requestOpptyProducts") return "products";
if (["requestWlActions", "requestActionTeamMembers", "requestActionFindLookup", "requestMgmtAction"].includes(entry.name)) return "actions"; if (["requestWlActions", "requestActionTeamMembers", "requestActionFindLookup", "requestMgmtAction"].includes(entry.name)) return "actions";
if (entry.name === "requestGenerateAiSummary") return "ai"; if (entry.name === "requestGenerateAiSummary") return "ai";

View File

@@ -11,12 +11,29 @@ function createFusionOpportunities({
environment environment
}) { }) {
const { fetch } = environment; const { fetch } = environment;
async function requestOpportunitiesPage(token, period, dateRange, offset, accumulatedItems, requestVersion, page) { async function requestOpportunitiesSavedSearch(token) {
const url = OPPORTUNITIES_QUERY_URL + "?access=userAdmin&applications=461e5791-9f15-4cd1-b5cd-19e8480cbce4&entity=Opportunity&language=en&limit=-1&returnIdentifierOnlyFields=true";
const headers = { Accept: "application/json", Authorization: `Bearer ${token}` };
const entry = logRequestStart({ name: "requestOpportunitiesSavedSearch", method: "GET", url, headers });
try {
const response = await fetch.call(environment.window, url, { method: "GET", credentials: "include", headers });
logRequestSuccess(entry, response, await readResponseBodyForDebug(response));
if (!response.ok) throw new Error(`requestOpportunitiesSavedSearch failed with status ${response.status}.`);
const data = await response.json();
if (!Array.isArray(data?.items)) throw new Error("requestOpportunitiesSavedSearch returned an invalid response.");
const defaults = data.items.filter(item => item.isDefault === true);
if (defaults.length !== 1 || typeof defaults[0].savedSearchNumber !== "string" || !defaults[0].savedSearchNumber.trim()) throw new Error("A unique default Opportunity saved search with savedSearchNumber was not returned.");
return defaults[0].savedSearchNumber.trim();
} catch (error) { logRequestFailure(entry, error.message); throw error; }
}
async function requestOpportunitiesPage(token, period, dateRange, offset, accumulatedItems, requestVersion, page, savedSearchNumber) {
if (!isCurrentPeriodRequest(requestVersion)) { if (!isCurrentPeriodRequest(requestVersion)) {
return null; return null;
} }
const payload = createOpportunitiesQueryPayload(dateRange, offset); if (!savedSearchNumber) savedSearchNumber = await requestOpportunitiesSavedSearch(token);
if (!isCurrentPeriodRequest(requestVersion)) return null;
const payload = createOpportunitiesQueryPayload(dateRange, offset, savedSearchNumber);
const requestBody = JSON.stringify(payload); const requestBody = JSON.stringify(payload);
const requestEntry = logRequestStart({ const requestEntry = logRequestStart({
name: "requestOpportunities", name: "requestOpportunities",
@@ -40,7 +57,7 @@ function createFusionOpportunities({
}); });
try { try {
const response = await fetch(OPPORTUNITIES_QUERY_URL, { const response = await fetch.call(environment.window, OPPORTUNITIES_QUERY_URL, {
method: "POST", method: "POST",
credentials: "include", credentials: "include",
headers: { headers: {
@@ -84,7 +101,8 @@ function createFusionOpportunities({
currentOffset + receivedCount, currentOffset + receivedCount,
allItems, allItems,
requestVersion, requestVersion,
page + 1 page + 1,
savedSearchNumber
); );
} catch (error) { } catch (error) {
logRequestFailure(requestEntry, error.message || "Request failed."); logRequestFailure(requestEntry, error.message || "Request failed.");
@@ -92,7 +110,8 @@ function createFusionOpportunities({
} }
} }
function createOpportunitiesQueryPayload(dateRange, offset) { function createOpportunitiesQueryPayload(dateRange, offset, savedSearchNumber) {
if (typeof savedSearchNumber !== "string" || !savedSearchNumber.trim()) throw new Error("Missing default Opportunity savedSearchNumber.");
return { return {
aggregationResults: false, aggregationResults: false,
applications: ["ORACLE-ISS-APP"], applications: ["ORACLE-ISS-APP"],
@@ -160,11 +179,11 @@ function createFusionOpportunities({
language: "en", language: "en",
skipInValidFields: true, skipInValidFields: true,
skipHiddenFromUIFields: true, skipHiddenFromUIFields: true,
copiedFrom: "queries/d5dbcd01-9ff3-40be-9b5b-64744cbf7162", copiedFrom: "queries/" + savedSearchNumber,
limit: OPPORTUNITIES_PAGE_LIMIT, limit: OPPORTUNITIES_PAGE_LIMIT,
offset offset
}; };
} }
return { requestOpportunitiesPage, createOpportunitiesQueryPayload }; return { requestOpportunitiesPage, createOpportunitiesQueryPayload, requestOpportunitiesSavedSearch };
} }

View File

@@ -105,7 +105,7 @@ test("fiscal dates preserve quarter/year boundaries, leap year and unsupported r
startCloseDate: start + "T00:00:00.000Z", endCloseDate: end + "T00:00:00.000Z" startCloseDate: start + "T00:00:00.000Z", endCloseDate: end + "T00:00:00.000Z"
}); });
const dateRange = h.getFiscalPeriodRange(period, new Date(...date)); const dateRange = h.getFiscalPeriodRange(period, new Date(...date));
const criterion = h.createOpportunitiesQueryPayload(dateRange, 0).q.criteria[1]; const criterion = h.createOpportunitiesQueryPayload(dateRange, 0, "default-search").q.criteria[1];
assert.equal(criterion.value1, start + "T00:00:00.000+0000"); assert.equal(criterion.value1, start + "T00:00:00.000+0000");
assert.equal(criterion.value2, end + "T00:00:00.000+0000"); assert.equal(criterion.value2, end + "T00:00:00.000+0000");
assert.equal(dateRange.endCloseDate, end + "T00:00:00.000Z", "payload must not mutate the shared date range"); assert.equal(dateRange.endCloseDate, end + "T00:00:00.000Z", "payload must not mutate the shared date range");
@@ -118,7 +118,7 @@ test("opportunity query preserves fields, record-set OR, date AND, and paginatio
const types = ["ORA_MYSALESTEAMOPTIES", "ORA_MYASSGTERROPTIES", "ORA_CREDITRECEIVER_ISME"]; const types = ["ORA_MYSALESTEAMOPTIES", "ORA_MYASSGTERROPTIES", "ORA_CREDITRECEIVER_ISME"];
h.setTypes(types); h.setTypes(types);
const fields = ["Name", "OptyNumber", "PrimaryRevenue.WinProb", "CustomerAccount", "PrimaryRevenue.RevnAmount", "EffectiveDate", "StatusCode", "DealRisk_c", "Owner", "ForecastGroup_c", "LastUpdateDate", "PrimaryRevenue.RevnAmountCurcyCode", "OptyId"]; const fields = ["Name", "OptyNumber", "PrimaryRevenue.WinProb", "CustomerAccount", "PrimaryRevenue.RevnAmount", "EffectiveDate", "StatusCode", "DealRisk_c", "Owner", "ForecastGroup_c", "LastUpdateDate", "PrimaryRevenue.RevnAmountCurcyCode", "OptyId"];
assert.deepEqual(plain(h.createOpportunitiesQueryPayload(range, 15)), { assert.deepEqual(plain(h.createOpportunitiesQueryPayload(range, 15, "default-search")), {
aggregationResults: false, applications: ["ORACLE-ISS-APP"], onlyData: true, entity: "Opportunity", aggregationResults: false, applications: ["ORACLE-ISS-APP"], onlyData: true, entity: "Opportunity",
q: { op: "$and", criteria: [ q: { op: "$and", criteria: [
{ op: "$and", criteria: [{ op: "$or", criteria: types.map(value => ({ op: "$eq", attribute: "RecordSet", value })) }] }, { op: "$and", criteria: [{ op: "$or", criteria: types.map(value => ({ op: "$eq", attribute: "RecordSet", value })) }] },
@@ -126,13 +126,14 @@ test("opportunity query preserves fields, record-set OR, date AND, and paginatio
] }, keywords: null, keywordsFields: fields, ] }, keywords: null, keywordsFields: fields,
fields: [...fields, "CustomerAccount.PartyUniqueName", "CustomerAccount.PartyId", "CustomerAccount.PartyNumber", "CustomerAccount.Region_c", "CustomerAccount.PrimaryAddress.CountryCode"], fields: [...fields, "CustomerAccount.PartyUniqueName", "CustomerAccount.PartyId", "CustomerAccount.PartyNumber", "CustomerAccount.Region_c", "CustomerAccount.PrimaryAddress.CountryCode"],
sort: null, language: "en", skipInValidFields: true, skipHiddenFromUIFields: true, sort: null, language: "en", skipInValidFields: true, skipHiddenFromUIFields: true,
copiedFrom: "queries/d5dbcd01-9ff3-40be-9b5b-64744cbf7162", limit: 15, offset: 15 copiedFrom: "queries/default-search", limit: 15, offset: 15
}); });
}); });
test("opportunity pagination uses response offsets/count, ignores stale versions and detects stalled pages", async () => { test("opportunity pagination uses response offsets/count, ignores stale versions and detects stalled pages", async () => {
const calls = []; const calls = [];
const h = loadContent({ fetch: async (url, options) => { const h = loadContent({ fetch: async (url, options) => {
if (options.method === "GET") return response({ items: [{ isDefault: false, savedSearchNumber: "other" }, { isDefault: true, savedSearchNumber: "user-default" }] });
calls.push({ url, options }); calls.push({ url, options });
return response(calls.length === 1 return response(calls.length === 1
? { items: [{ OptyNumber: "S1" }], offset: 0, count: 1, hasMore: true } ? { items: [{ OptyNumber: "S1" }], offset: 0, count: 1, hasMore: true }
@@ -141,6 +142,7 @@ test("opportunity pagination uses response offsets/count, ignores stale versions
const items = await h.requestOpportunitiesPage("synthetic-token", "Current Quarter", range, 0, [], 0, 1); const items = await h.requestOpportunitiesPage("synthetic-token", "Current Quarter", range, 0, [], 0, 1);
assert.deepEqual(plain(items), [{ OptyNumber: "S1" }, { OptyNumber: "S2" }]); assert.deepEqual(plain(items), [{ OptyNumber: "S1" }, { OptyNumber: "S2" }]);
assert.deepEqual(calls.map(call => JSON.parse(call.options.body).offset), [0, 1]); assert.deepEqual(calls.map(call => JSON.parse(call.options.body).offset), [0, 1]);
assert.deepEqual(calls.map(call => JSON.parse(call.options.body).copiedFrom), ["queries/user-default", "queries/user-default"]);
assert.equal(calls[0].url, "https://eeho.fa.us2.oraclecloud.com/crmRestApi/searchResources/11.13.18.05/custom-actions/queries"); assert.equal(calls[0].url, "https://eeho.fa.us2.oraclecloud.com/crmRestApi/searchResources/11.13.18.05/custom-actions/queries");
assert.deepEqual(plain(calls[0].options.headers), { assert.deepEqual(plain(calls[0].options.headers), {
Accept: "application/json", Authorization: "Bearer synthetic-token", "Content-Type": "application/json", Accept: "application/json", Authorization: "Bearer synthetic-token", "Content-Type": "application/json",
@@ -151,10 +153,39 @@ test("opportunity pagination uses response offsets/count, ignores stale versions
h.setVersion(1); h.setVersion(1);
assert.equal(await h.requestOpportunitiesPage("unused", "Current Quarter", range, 0, [], 0, 1), null); assert.equal(await h.requestOpportunitiesPage("unused", "Current Quarter", range, 0, [], 0, 1), null);
assert.equal(calls.length, 2); assert.equal(calls.length, 2);
const stalled = loadContent({ fetch: async () => response({ items: [], count: 0, hasMore: true }) }); const stalled = loadContent({ fetch: async (_, options) => response(options.method === "GET" ? { items: [{ isDefault: true, savedSearchNumber: "default" }] } : { items: [], count: 0, hasMore: true }) });
await assert.rejects(stalled.requestOpportunitiesPage("synthetic", "Current Quarter", range, 0, [], 0, 1), /without additional results/); await assert.rejects(stalled.requestOpportunitiesPage("synthetic", "Current Quarter", range, 0, [], 0, 1), /without additional results/);
}); });
test("saved search GET precedes all opportunity pages and supplies the user's default", async () => {
const calls = [];
const h = loadContent({ fetch: async (url, options) => {
calls.push({url,options});
if (options.method === "GET") return response({items:[{isDefault:false,savedSearchNumber:"not-default"},{isDefault:true,savedSearchNumber:"selected-default"}]});
const offset = JSON.parse(options.body).offset;
return response({items:[{OptyNumber:String(offset)}],offset,count:1,hasMore:offset===0});
}});
await h.requestOpportunitiesPage("relay-token","Current Quarter",range,0,[],0,1);
assert.deepEqual(calls.map(call=>call.options.method),["GET","POST","POST"]);
const url = new URL(calls[0].url);
assert.deepEqual(Object.fromEntries(url.searchParams),{access:"userAdmin",applications:"461e5791-9f15-4cd1-b5cd-19e8480cbce4",entity:"Opportunity",language:"en",limit:"-1",returnIdentifierOnlyFields:"true"});
assert.equal(calls[0].options.headers.Authorization,"Bearer relay-token");
for (const call of calls.slice(1)) assert.equal(JSON.parse(call.options.body).copiedFrom,"queries/selected-default");
});
test("missing or failed default search blocks opportunities POST and stale lookup is ignored", async () => {
for (const data of [{items:[]},{items:[{isDefault:true}]},{items:[{isDefault:true,savedSearchNumber:"a"},{isDefault:true,savedSearchNumber:"b"}]},null]) {
const calls=[];
const h=loadContent({fetch:async(_,options)=>{calls.push(options.method);return response(data,data===null?403:200);}});
await assert.rejects(h.requestOpportunitiesPage("token","Current Quarter",range,0,[],0,1));
assert.deepEqual(calls,["GET"]);
assert.equal(h.requestLog.at(-1).name,"requestOpportunitiesSavedSearch");
assert.equal(h.requestLog.at(-1).status,"failed");
}
const h=loadContent({fetch:async()=>{h.setVersion(1);return response({items:[{isDefault:true,savedSearchNumber:"default"}]});}});
assert.equal(await h.requestOpportunitiesPage("token","Current Quarter",range,0,[],0,1),null);
});
const opportunity = (number, status, amount) => ({ const opportunity = (number, status, amount) => ({
Name: `Synthetic cloud ${number}`, OptyNumber: number, StatusCode: status, ForecastGroup_c: "PIPELINE", Name: `Synthetic cloud ${number}`, OptyNumber: number, StatusCode: status, ForecastGroup_c: "PIPELINE",
CustomerAccount: { PartyId: "customer-1", PartyUniqueName: "Synthetic Customer", PartyNumber: "party-1" }, CustomerAccount: { PartyId: "customer-1", PartyUniqueName: "Synthetic Customer", PartyNumber: "party-1" },

View File

@@ -89,7 +89,7 @@ test("request categories cover every current family and unknown requests stay vi
for (const [name, category] of Object.entries({ for (const [name, category] of Object.entries({
requestTokenRelay: "authentication", requestTokenRelaySalesCommon: "authentication", requestTokenRelay: "authentication", requestTokenRelaySalesCommon: "authentication",
requestConsumerTokenService: "authentication", requestCustomerTokenService: "authentication", requestConsumerTokenService: "authentication", requestCustomerTokenService: "authentication",
requestOpportunities: "opportunities", requestOpptyProducts: "products", requestGenerateAiSummary: "ai", requestOpportunities: "opportunities", requestOpportunitiesSavedSearch: "opportunities", requestOpptyProducts: "products", requestGenerateAiSummary: "ai",
requestAccountSummary: "consumption", requestAccountPlans: "consumption", requestAccountSummary: "consumption", requestAccountPlans: "consumption",
requestInstallBase: "installBase", requestCustomerServiceRequest: "serviceRequests", requestSRInfo: "serviceRequests", requestInstallBase: "installBase", requestCustomerServiceRequest: "serviceRequests", requestSRInfo: "serviceRequests",
requestConsumptionPlanDetail: "consumption", requestConsumptionPlanDetail: "consumption",

View File

@@ -98,6 +98,7 @@
let body; let body;
if (url.pathname === "/fscmRestApi/tokenrelay") body = { access_token: "synthetic-fusion-token", expires_in: 3600 }; if (url.pathname === "/fscmRestApi/tokenrelay") body = { access_token: "synthetic-fusion-token", expires_in: 3600 };
else if (url.pathname.endsWith("custom-actions/queries")) { else if (url.pathname.endsWith("custom-actions/queries")) {
if (options.method === "GET") return Response.json({ items: [{ isDefault: true, savedSearchNumber: "fixture-default" }] });
const { offset, limit, entity } = JSON.parse(options.body); const { offset, limit, entity } = JSON.parse(options.body);
if (entity === "CRMServiceRequest") return new Response(JSON.stringify({ items: [{ SrId: "123456", SrNumber: "SR123456", Title: "Example parent SR", PrimaryPillarNew_c: "Tech_Cloud_Infrastructure", CustomerDeadline_c: "2026-11-30T00:00:00.000+0000", ReportedHours_c: 4, OpportunityName_Id_c: { OptyNumber: "TEST1" } }], hasMore: false }), { status: 200 }); if (entity === "CRMServiceRequest") return new Response(JSON.stringify({ items: [{ SrId: "123456", SrNumber: "SR123456", Title: "Example parent SR", PrimaryPillarNew_c: "Tech_Cloud_Infrastructure", CustomerDeadline_c: "2026-11-30T00:00:00.000+0000", ReportedHours_c: 4, OpportunityName_Id_c: { OptyNumber: "TEST1" } }], hasMore: false }), { status: 200 });
body = { items: opportunities.slice(offset, offset + limit), totalResults: opportunities.length, count: Math.min(limit, opportunities.length - offset), hasMore: offset + limit < opportunities.length, offset, limit }; body = { items: opportunities.slice(offset, offset + limit), totalResults: opportunities.length, count: Math.min(limit, opportunities.length - offset), hasMore: offset + limit < opportunities.length, offset, limit };