Implemented the Organization Chart feature to create customer organizational
This commit is contained in:
105
src/services/fusion/account-contact.js
Normal file
105
src/services/fusion/account-contact.js
Normal file
@@ -0,0 +1,105 @@
|
||||
function createFusionAccountContact({ environment, getToken, logRequestStart, logRequestSuccess, logRequestFailure, readResponseBodyForDebug }) {
|
||||
async function requestQueryAccountContact(accountId, keywords, isActive = () => true, contactPartyId = null) {
|
||||
if (!/^\d+$/.test(String(accountId)) || !Number.isSafeInteger(Number(accountId))) throw new Error("The customer's PartyId is unavailable.");
|
||||
if (contactPartyId != null && !/^\d+$/.test(String(contactPartyId))) throw new Error("The contact's PartyId is unavailable.");
|
||||
if ((!String(keywords || "").trim() && contactPartyId == null) || !isActive()) return [];
|
||||
const token = await getToken();
|
||||
if (!isActive()) return [];
|
||||
const url = "https://eeho.fa.us2.oraclecloud.com/crmRestApi/searchResources/latest/custom-actions/queries";
|
||||
const fields = ["PartyName", "PrimaryEmail.EmailAddress", "JobTitle", "PrimaryAccount.PartyName", "PartyId", "PartyNumber"];
|
||||
const payload = { aggregationResults: false, skipInValidFields: true, skipHiddenFromUIFields: true,
|
||||
language: "en", onlyData: true, keywords, entity: "Contact", fields, keywordsFields: fields,
|
||||
q: { op: "$and", criteria: [{ op: "$or", innerQuery: true, criteria: [{ attribute: "PrimaryAccount.PartyId", op: "$eq", value: Number(accountId) }] }], innerQuery: true },
|
||||
sort: [{ attribute: "_score", direction: "descending" }], limit: 15, offset: 0 };
|
||||
if (contactPartyId != null) {
|
||||
payload.keywords = "";
|
||||
payload.q.criteria.push({ attribute: "PartyId", op: "$eq", value: String(contactPartyId) });
|
||||
}
|
||||
const headers = { Accept: "application/json", "Content-Type": "application/json", Authorization: `Bearer ${token}`, Preference: "transient", Origin: "https://eeho.fa.us2.oraclecloud.com" };
|
||||
const entry = logRequestStart({ name: "requestQueryAccountContact", method: "POST", url, headers, body: JSON.stringify(payload, null, 2) });
|
||||
try {
|
||||
const response = await environment.fetch.call(environment.window, url, { method: "POST", credentials: "include", headers, body: JSON.stringify(payload) });
|
||||
logRequestSuccess(entry, response, await readResponseBodyForDebug(response));
|
||||
if (!response.ok) throw new Error(`requestQueryAccountContact failed with status ${response.status}.`);
|
||||
const data = await response.json();
|
||||
if (!data || !Array.isArray(data.items)) throw new Error("requestQueryAccountContact returned an invalid response.");
|
||||
if (!isActive()) return [];
|
||||
const contacts = new Map();
|
||||
for (const item of data.items) if (item?.PartyId != null && typeof item.PartyName === "string" && item.PartyName.trim()) {
|
||||
contacts.set(String(item.PartyId), { ...item, PartyId: String(item.PartyId) });
|
||||
}
|
||||
return [...contacts.values()];
|
||||
} catch (error) { logRequestFailure(entry, error.message); throw error; }
|
||||
}
|
||||
async function requestPersistContact(account, values) {
|
||||
if (!/^\d+$/.test(String(account?.PartyId)) || !String(account?.PartyNumber || "").trim()) throw new Error("The customer's PartyId or PartyNumber is unavailable.");
|
||||
const phone = (number, country) => {
|
||||
if (!number && !country) return "";
|
||||
if (!number || !country) throw new Error("Select a country code and enter a phone number for each phone provided.");
|
||||
const digits = number.replace(/[\s().-]/g, "");
|
||||
if (!/^\d+$/.test(digits)) throw new Error("Enter the phone number using digits only, without the country code.");
|
||||
return country + "-" + digits;
|
||||
};
|
||||
const payload = {
|
||||
FirstName: values.firstName.trim(), LastName: values.lastName.trim(),
|
||||
AccountPartyId: String(account.PartyId), AccountPartyNumber: String(account.PartyNumber),
|
||||
JobTitle: values.jobTitle.trim(), Type: "ZCA_CONTACT",
|
||||
EmailAddress: values.email.trim(),
|
||||
RawWorkPhoneNumber: phone(values.workPhone.trim(), values.workCountry), WorkPhoneCountryCode: values.workCountry,
|
||||
WorkPhoneExtension: values.workExtension.trim(), MobileCountryCode: values.mobileCountry,
|
||||
RawMobileNumber: phone(values.mobilePhone.trim(), values.mobileCountry)
|
||||
};
|
||||
if (!payload.FirstName || !payload.LastName || !payload.EmailAddress) throw new Error("First Name, Last Name and Email Address are required.");
|
||||
for (const key of Object.keys(payload)) if (payload[key] === "") delete payload[key];
|
||||
for (const [choice, allow, deny] of [
|
||||
[values.emailConsent, "DoContactEmailFlag", "DoNotContactEmailFlag"],
|
||||
[values.workConsent, "DoCallWorkPhoneFlag", "DoNotCallWorkPhoneFlag"],
|
||||
[values.mobileConsent, "DoCallMobilePhoneFlag", "DoNotCallMobileFlag"]
|
||||
]) {
|
||||
if (choice === "allow" || choice === "deny") {
|
||||
payload[allow] = choice === "allow";
|
||||
payload[deny] = choice === "deny";
|
||||
}
|
||||
}
|
||||
const body = JSON.stringify(payload);
|
||||
const token = await getToken();
|
||||
const url = "https://eeho.fa.us2.oraclecloud.com/crmRestApi/rest/rv:e75ce5f9-a69f-4c6a-8591-6b06a538829e/en/11.13.18.05:9/contacts?onlyData=true";
|
||||
const headers = { Accept: "application/json", "Content-Type": "application/json", Authorization: `Bearer ${token}`, Origin: "https://eeho.fa.us2.oraclecloud.com" };
|
||||
const entry = logRequestStart({ name: "requestPersistContact", method: "POST", url, headers, body: JSON.stringify(payload, null, 2) });
|
||||
try {
|
||||
const response = await environment.fetch.call(environment.window, url, { method: "POST", credentials: "include", headers, body });
|
||||
logRequestSuccess(entry, response, await readResponseBodyForDebug(response));
|
||||
if (!response.ok) throw new Error(`requestPersistContact failed with status ${response.status}.`);
|
||||
const text = await response.text();
|
||||
try { return text ? JSON.parse(text) : null; } catch { return null; }
|
||||
} catch (error) { logRequestFailure(entry, error.message); throw error; }
|
||||
}
|
||||
async function requestOpportunitiesByContact(partyNumber, offset = 0, context = {}) {
|
||||
const baseUrl = "https://eeho.fa.us2.oraclecloud.com/crmRestApi/rest/rv:e75ce5f9-a69f-4c6a-8591-6b06a538829e/en/11.13.18.05:9/opportunities";
|
||||
let entry;
|
||||
try {
|
||||
if (!String(partyNumber || "").trim() && context.resolvePartyNumber) partyNumber = await context.resolvePartyNumber();
|
||||
partyNumber = String(partyNumber || "").trim();
|
||||
if (!/^[A-Za-z0-9]{1,100}$/.test(partyNumber)) throw new Error("The person's PartyNumber is missing or invalid. The opportunities HTTP request was not sent.");
|
||||
if (context.isActive && !context.isActive()) throw new Error("Opportunities lookup cancelled because its dialog was closed. HTTP request was not sent.");
|
||||
const token = await getToken();
|
||||
const fields = "SalesStageId,KeyContactId,EffectiveDate,WinProb,CurrencyCode,Revenue,SalesStage,Name,ManageRestrictedProfileDataFlag,OptyId,OptyNumber,ManageRevenueDataFlag,StatusCode";
|
||||
const query = encodeURIComponent("(OpportunityContact.ContactPartyNumber='" + partyNumber + "')").replace(/[()']/g, character => "%" + character.charCodeAt(0).toString(16).toUpperCase());
|
||||
const url = baseUrl + "?onlyData=true&q=" + query + "&totalResults=true&fields=" + encodeURIComponent(fields) + "&orderBy=LastUpdateDate%3Adesc&limit=5&offset=" + offset;
|
||||
const headers = { Accept: "application/json", "Content-Type": "application/json", Authorization: `Bearer ${token}`, Preference: "transient", Origin: "https://eeho.fa.us2.oraclecloud.com" };
|
||||
entry = logRequestStart({ name: "requestOpportunitiesByContact", method: "GET", url, headers,
|
||||
metadata: { contactPartyId: context.contactPartyId || "", contactName: context.contactName || "", partyNumber, offset, httpRequestSent: true } });
|
||||
const response = await environment.fetch.call(environment.window, url, { method: "GET", credentials: "include", headers });
|
||||
logRequestSuccess(entry, response, await readResponseBodyForDebug(response));
|
||||
if (!response.ok) throw new Error(`requestOpportunitiesByContact failed with status ${response.status}.`);
|
||||
const data = await response.json();
|
||||
if (!Array.isArray(data?.items)) throw new Error("requestOpportunitiesByContact returned an invalid response.");
|
||||
return data;
|
||||
} catch (error) {
|
||||
if (!entry) entry = logRequestStart({ name: "resolveContactForOpportunities", method: "LOCAL", url: "(HTTP request not sent)",
|
||||
metadata: { contactPartyId: context.contactPartyId || "", contactName: context.contactName || "", offset, httpRequestSent: false, targetRequest: "requestOpportunitiesByContact" } });
|
||||
logRequestFailure(entry, error.message); throw error;
|
||||
}
|
||||
}
|
||||
return { requestQueryAccountContact, requestPersistContact, requestOpportunitiesByContact };
|
||||
}
|
||||
Reference in New Issue
Block a user