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

@@ -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"
});
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.value2, end + "T00:00:00.000+0000");
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"];
h.setTypes(types);
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",
q: { op: "$and", criteria: [
{ 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,
fields: [...fields, "CustomerAccount.PartyUniqueName", "CustomerAccount.PartyId", "CustomerAccount.PartyNumber", "CustomerAccount.Region_c", "CustomerAccount.PrimaryAddress.CountryCode"],
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 () => {
const calls = [];
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 });
return response(calls.length === 1
? { 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);
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).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.deepEqual(plain(calls[0].options.headers), {
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);
assert.equal(await h.requestOpportunitiesPage("unused", "Current Quarter", range, 0, [], 0, 1), null);
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/);
});
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) => ({
Name: `Synthetic cloud ${number}`, OptyNumber: number, StatusCode: status, ForecastGroup_c: "PIPELINE",
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({
requestTokenRelay: "authentication", requestTokenRelaySalesCommon: "authentication",
requestConsumerTokenService: "authentication", requestCustomerTokenService: "authentication",
requestOpportunities: "opportunities", requestOpptyProducts: "products", requestGenerateAiSummary: "ai",
requestOpportunities: "opportunities", requestOpportunitiesSavedSearch: "opportunities", requestOpptyProducts: "products", requestGenerateAiSummary: "ai",
requestAccountSummary: "consumption", requestAccountPlans: "consumption",
requestInstallBase: "installBase", requestCustomerServiceRequest: "serviceRequests", requestSRInfo: "serviceRequests",
requestConsumptionPlanDetail: "consumption",

View File

@@ -98,6 +98,7 @@
let body;
if (url.pathname === "/fscmRestApi/tokenrelay") body = { access_token: "synthetic-fusion-token", expires_in: 3600 };
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);
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 };