Вы находитесь здесь:
Пример: Проверка данных о посещении для сохранения, подписи и отправки
Этот пример сценария проверяет данные посещения, когда пользователь сохраняет, подписывает или отправляет посещение. Он проверяет наличие обязательных образцов, сведений о продукте, сообщений, выборочных зависимостей и типов организаций участников.
Требуемые версии
| Доступно в версиях: Lightning Experience |
| Доступно в версиях: Enterprise and Unlimited Edition с дополнительной лицензией Life Sciences Cloud, Life Sciences Cloud for Customer Engagement и управляемым пакетом Life Sciences Customer Engagement. |
Правила проверки
Пример сценария содержит шесть правил проверки.
| Правило | Использование | Триггеры | Сообщение об ошибке | При успешном выполнении |
|---|---|---|---|---|
| atLeastOneSampleIsRequired | Обеспечивает наличие как минимум одного образца посещения (ProductDisbursement). | Всегда выполняется | К посещению должен быть добавлен как минимум один образец. | Отображает количество образцов для посещения |
| atLeastOneDetailAndSampleAreRequired | Требуется образец и подробный продукт (ProviderVisitProdDetailing). | Всегда выполняется | К посещению должен быть добавлен как минимум один образец и подробный продукт. | Отображает количество образцов и подробных продуктов |
| atLeastOneMessageIsRequiredForEachVisitDetail | Каждый подробный продукт должен содержать как минимум одно сообщение. | Только если у пользователя есть профиль «Полевой торговый представитель» или канал посещения установлен на «Личный» | Для каждого подробного продукта обязательно как минимум одно сообщение, если канал является «Личным» и у пользователя есть профиль «Полевой торговый представитель» | Пропускает другие профили или не личные посещения |
| specificSampleDependencyCheck | Если выбран определенный продукт, правило проверяет, также ли выбраны другие обязательные продукты. | При наличии образцов | Если <product1> добавлен к посещению, необходимо также добавить <product2>. | — |
| isAtLeastOneHCP | Посещения HCO (медицинской организации) должны иметь как минимум одного посетителя организации HCP (медицинского работника). | Только для организаций учреждений | При создании посещения для HCO (организация здравоохранения) должен быть связан как минимум один HCP (специалист в области здравоохранения). | Пропускает, если основной организацией является организация-лицо (HCP) |
| isMoreThanOneHCO | Ограничивается только одним посетителем HCO (учреждения) на вызов. | Всегда выполняется | На одно посещение можно добавить только 1 посетителя HCO (организация здравоохранения). | Отображает количество организаций HCO |
Методы помощника
Пример сценария также содержит три многоразовых метода помощника.
- getActionName(env)
- Получает имя действия из среды
- Определяет, выполняется ли проверка
- Выполняется только для отправки, подписи и сохранения
- parseContextData(запись)
- Безопасное извлечение контекстных данных из объекта записи
- Обработка строк и объектов JSON (включая объекты Proxy)
- Возвращает пустой объект при ошибке
- getFieldData(contextData, baseFieldName)
- Извлечение данных поля с помощью резервной копии платформы
- Для веб-сайта использует FieldName.VisitId (например,
ProductDisbursement.VisitId) - Для мобильных устройств использует простое имя поля (например,
ProductDisbursement) - Автоматически пробует и то, и другое и возвращает, что существует
Рекомендации
Помните о следующих рекомендациях при внедрении сценария проверки действия посещения.
- На мобильном и веб-приложении при выполнении сценария проверки действия посещения данные для посещения могут храниться только в памяти. Для доступа к текущим данным обработайте поля в contextData. Резервируйте
db.queryдля данных, которые не изменяются во время посещения, например, проверка типа записи организации. - Контекстные данные, переданные настраиваемому сценарию, могут отличаться между мобильным и веб-приложением. Пример сценария обрабатывает эти различия посредством общего
getFieldDataметода помощника.
Пример сценария
(() => {
// Platform detection flag - will be set in entry point
let hasWebField = false;
/**
* Gets the action name from environment
* @param {Object} env - JsEnv object for environment options
* @returns {string} The action name or empty string
*/
function getActionName(env) {
try {
if (env && typeof env.getOption === 'function') {
return env.getOption('actionName') || '';
}
return '';
} catch (error) {
return '';
}
}
// AccountDAO - Data Access Object for account-related operations
var accountDao = (function () {
var instance;
var currentRecord;
var isPersonAccount;
var isInstitution;
var childCallAccounts;
var accountCache = new Map(); // Simple cache for account data
// Helper functions for accountDao - moved inside closure to access currentRecord
async function checkForPersonAccount() {
let accountId = currentRecord.stringValue("AccountId");
// If not found, try extracting directly from context data
if (!accountId) {
try {
const contextData = parseContextData(currentRecord);
// Try different possible locations for AccountId
accountId = contextData.ProviderVisit?.AccountId ||
contextData.Visit?.AccountId ||
contextData.AccountId ||
contextData.Account?.Id ||
contextData.Account;
} catch (e) {
// Error accessing context data, continue with null accountId
accountId = null;
}
}
if (!accountId) {
return false; // Default to not person account if no account ID
}
try {
let account = await selectAccountById(accountId);
let result = account && account.length > 0 ? account[0].boolValue("IsPersonAccount") : false;
return result;
} catch (error) {
return false; // Default to false on error
}
}
async function checkForInstitution() {
let accountId = currentRecord.stringValue("AccountId");
// If not found, try extracting directly from context data
if (!accountId) {
try {
const contextData = parseContextData(currentRecord);
// Try different possible locations for AccountId
accountId = contextData.ProviderVisit?.AccountId ||
contextData.Visit?.AccountId||
contextData.AccountId ||
contextData.Account?.Id ||
contextData.Account;
} catch (e) {
// Error accessing context data, continue with null accountId
}
}
if (!accountId) {
return false; // Default to not institution if no account ID
}
try {
let account = await selectAccountById(accountId);
let isPersonAccount = account && account.length > 0 ? account[0].boolValue("IsPersonAccount") : false;
// If it's not a Person Account, then it's a Business Account (HCO)
let result = !isPersonAccount;
return result;
} catch (error) {
return false; // Default to false on error
}
}
async function selectChildCallAccountsById() {
// Extract attendee account IDs directly from the JSON data
// The attendee data is in the Visit.ParentVisitId array in the JSON
// Get the data from the current record context
let contextData;
try {
contextData = parseContextData(currentRecord);
} catch (error) {
return [];
}
// Extract attendee account IDs from Visit.ParentVisitId array
const attendeeVisits = contextData?.["Visit.ParentVisitId"] || contextData?.["ChildVisit"];
if (!Array.isArray(attendeeVisits) || attendeeVisits.length === 0) {
return [];
}
// Extract AccountIds from the attendee visits
const attendeeAccountIds = attendeeVisits
.map(visit => visit.AccountId || visit.accountid) // Try PascalCase first, then lowercase
.filter(accountId => accountId);
if (attendeeAccountIds.length === 0) {
return [];
}
// Query the Account records for these IDs
let result = await db.query(
"Account",
await new ConditionBuilder(
"Account",
new SetCondition("Id", "IN", attendeeAccountIds)
).build(),
["Id", "Name", "IsPersonAccount"]
);
return result || [];
}
function getRecordId(record) {
return record ? record.stringValue("Id") : null;
}
async function selectAccountById(accountId) {
// Check cache first
if (accountCache.has(accountId)) {
return accountCache.get(accountId);
}
// If not in cache, query database
let accounts = await db.query(
"Account",
await new ConditionBuilder(
"Account",
new FieldCondition("Id", "=", accountId)
).build(),
["Id", "Name", "IsPersonAccount"]
);
// Cache the result
accountCache.set(accountId, accounts);
return accounts;
}
var initialize = async function(record) {
currentRecord = record;
// Clear cache for new record context
accountCache.clear();
isPersonAccount = await checkForPersonAccount();
isInstitution = await checkForInstitution();
childCallAccounts = await selectChildCallAccountsById();
};
var getIsPersonAccount = function () {
return isPersonAccount;
};
var getIsInstitution = function () {
return isInstitution;
};
var getChildCallAccounts = function () {
return childCallAccounts;
};
var createInstance = function () {
return {
initialize: initialize,
getIsPersonAccount: getIsPersonAccount,
getChildCallAccounts: getChildCallAccounts,
getIsInstitution: getIsInstitution,
};
};
return {
getInstance: function () {
return instance || (instance = createInstance());
},
};
})();
// Main function that businessRuleValidator calls
async function validateVisit() {
try {
if (!record) {
return [{
title: "Error in validation",
status: "error",
error: "No record provided"
}];
}
// Use the properly provided business rule parameters from outer scope
const validationResults = await runValidation();
// Platform-specific handling: Web uses Promise.all(), Mobile doesn't
let resolvedResults;
if (hasWebField) {
// Web platform - use Promise.all() to resolve all promises
resolvedResults = await Promise.all(validationResults);
} else {
// Mobile platform - use validationResults directly
resolvedResults = validationResults;
}
// Ensure we always return an array
const finalResults = Array.isArray(resolvedResults) ? resolvedResults : [resolvedResults];
return finalResults;
} catch (error) {
return [{
title: "Error in validation",
status: "error",
error: error.message
}];
}
}
// Function to run the validation with data from outer scope
async function runValidation() {
// Initialize accountDao with the proper record object (JsDbObject)
await accountDao.getInstance().initialize(record);
// Always validate in this version
const isValidationRequired = true;
// Only run validations if needed
let validationResults = [];
if (isValidationRequired) {
// Array of validation functions to run
// Add new validation functions to this array
const validationFunctions = [
atLeastOneSampleIsRequired,
atLeastOneDetailAndSampleAreRequired,
atLeastOneMessageIsRequiredForEachVisitDetail,
specificSampleDependencyCheck,
isAtLeastOneHCP,
isMoreThanOneHCO,
// Add new validation functions here one at a time
// Example: validateSampleType,
// Example: validateComplianceAgreement,
];
// Run all validation functions (handling both sync and async)
validationResults = validationFunctions.map((validationFn, index) => {
try {
// Call validation functions - they access record, user, db, env from outer scope
const result = validationFn();
// If the result is a Promise, return it as is for Promise.all
if (result && typeof result.then === 'function') {
return result.then(asyncResult => {
return asyncResult;
}).catch(error => {
return {
title: `Error in ${validationFn.name}: ${error.message}`,
status: "error",
error: error.message
};
});
}
return result;
} catch (error) {
return {
title: `Error in ${validationFn.name}: ${error.message}`,
status: "error",
error: error.message
};
}
});
} else {
// Default return when validation is not required
validationResults = [{
title: "Validation not required",
status: "success"
}];
}
return validationResults;
}
// Helper function to get context data safely
function parseContextData(record) {
try {
if (!record || typeof record.getContextData !== 'function') {
return {};
}
const contextData = record.getContextData();
// Handle different return types from getContextData()
if (typeof contextData === 'string') {
// If it's a JSON string, parse it
return JSON.parse(contextData);
} else if (typeof contextData === 'object' && contextData !== null) {
// If it's already an object (including Proxy), use it directly
return contextData;
} else {
return {};
}
} catch (error) {
return {};
}
}
/**
* Helper function to get field data with web/mobile fallback
* Web uses nested field paths (e.g., "ObjectName.VisitId")
* Mobile uses simple field names (e.g., "ObjectName")
*
* @param {Object} contextData - The context data object
* @param {string} baseFieldName - The base field name (e.g., "ProductDisbursement")
* @returns {*} The field data from web or mobile field, or undefined
*/
function getFieldData(contextData, baseFieldName) {
const webField = `${baseFieldName}.VisitId`;
const mobileField = baseFieldName;
return contextData?.[webField] || contextData?.[mobileField];
}
// Validation rule: at least one sample is required
function atLeastOneSampleIsRequired() {
let hasSamples = false;
let sampleCount = 0;
try {
// Get context data from the record object (from outer scope)
const contextData = parseContextData(record);
// Use helper to get field data with web/mobile fallback
const sampleData = getFieldData(contextData, "ProductDisbursement") || null;
// Handle Proxy arrays properly
if (sampleData) {
try {
// Try to get length property (works for both arrays and Proxy arrays)
sampleCount = sampleData.length || 0;
hasSamples = sampleCount > 0;
} catch (lengthError) {
// Handle Proxy length access error
// Fallback: check if object has any enumerable properties
try {
const keys = Object.keys(sampleData);
hasSamples = keys.length > 0;
sampleCount = keys.length;
} catch (keysError) {
// Error getting keys - graceful fallback
hasSamples = false;
sampleCount = 0;
}
}
}
} catch (e) {
// Handle validation error gracefully
hasSamples = false;
sampleCount = 0;
}
return {
title: hasSamples ?
`Found ${sampleCount} sample(s)` :
"At least one sample must be added to the visit.",
status: hasSamples ? "success" : "error"
};
}
// Validation rule: at least one detail and sample are required
function atLeastOneDetailAndSampleAreRequired() {
try {
const contextData = parseContextData(record);
// Use helper to get field data with web/mobile fallback
const productDisbursementData = getFieldData(contextData, "ProductDisbursement");
const providerVisitProdDetailingData = getFieldData(contextData, "ProviderVisitProdDetailing");
// Handle Proxy arrays properly for both fields
let sampleCount = 0;
let detailCount = 0;
let hasProductDisbursement = false;
let hasProviderVisitProdDetailing = false;
// Check product disbursement
if (productDisbursementData) {
try {
sampleCount = productDisbursementData.length || 0;
hasProductDisbursement = sampleCount > 0;
} catch (e) {
// Error accessing length property
const keys = Object.keys(productDisbursementData || {});
sampleCount = keys.length;
hasProductDisbursement = sampleCount > 0;
}
}
// Check provider visit prod detailing
if (providerVisitProdDetailingData) {
try {
detailCount = providerVisitProdDetailingData.length || 0;
hasProviderVisitProdDetailing = detailCount > 0;
} catch (e) {
// Error accessing length property - try Object.keys fallback
const keys = Object.keys(providerVisitProdDetailingData);
detailCount = keys.length;
hasProviderVisitProdDetailing = detailCount > 0;
}
}
if (hasProductDisbursement && hasProviderVisitProdDetailing) {
return {
title: `Found ${sampleCount} sample(s) and ${detailCount} detailed product(s)`,
status: "success"
};
}
return {
title: "At least one sample and detailed product must be added to the visit.",
status: "error"
};
} catch (e) {
return {
title: "At least one sample and detailed product must be added to the visit.",
status: "error",
error: e.message
};
}
}
// Validation rule: at least one message is required for each visit detail
async function atLeastOneMessageIsRequiredForEachVisitDetail() {
try {
let userId;
// Try to get user Id from user (from outer scope)
if (user) {
try {
userId = user.stringValue('Id');
} catch (error) {
// Try alternative access methods
userId = user.Id || user["Id"];
if (!userId) {
// Error accessing userId, continue with fallback
}
}
}
if (!userId) {
return {
title: 'Profile validation skipped - no userId available',
status: "success",
};
}
// As rep user don't have access to User.ProfileId and Profile table
// we can only check by ProfileIdentifier in UserAdditionalInfo
//Please replace the Profile_Id with the id of the profile you want to apply this validation
let targetProfileId = 'Profile_Id';
let userAdditionalInfoResults;
let isFieldSalesRep = false;
try {
userAdditionalInfoResults = await db.query(
"UserAdditionalInfo",
await new ConditionBuilder(
"UserAdditionalInfo",
new FieldCondition("UserId", "=", userId)
).build(),
["Id", "ProfileIdentifier"]
);
if (userAdditionalInfoResults && userAdditionalInfoResults.length > 0) {
const profileId = userAdditionalInfoResults[0].stringValue('ProfileIdentifier');
isFieldSalesRep = profileId === targetProfileId;
} else {
return {
title: 'Profile validation skipped - profile not found',
status: "success",
};
}
} catch (error) {
return {
title: 'Profile validation skipped - unable to query profile',
status: "success",
};
}
if (!isFieldSalesRep) {
return {
title: `Profile validation skipped - user is not Field Sales Representative`,
status: "success",
};
}
// Get visit context data from the record object
const visitData = parseContextData(record);
// Check if channel is "In-Person"
const visitChannel = visitData?.Visit?.channel || visitData?.ProviderVisit?.Channel || '';
if (visitChannel !== "In-Person") {
return {
title: `Message validation skipped - visit channel is "${visitChannel}", not "In-Person"`,
status: "success",
};
}
// Check if we have visit details to validate
// Use helper to get field data with web/mobile fallback
const visitDetails = getFieldData(visitData, "ProviderVisitProdDetailing");
if (!Array.isArray(visitDetails) || visitDetails.length === 0) {
return {
title: 'Message validation passed - no visit details to validate',
status: "success"
};
}
// Validate each visit detail has at least one message
let detailsWithoutMessages = [];
visitDetails.forEach((detail, index) => {
// Use helper to get field data with web/mobile fallback
const messages = getFieldData(detail, "ProviderVisitDtlProductMsg");
const hasMessages = Array.isArray(messages) && messages.length > 0;
if (!hasMessages) {
const detailInfo = {
index: index + 1,
productId: detail?.productid || 'Unknown Product',
uid: detail?.uid || 'Unknown Detail'
};
detailsWithoutMessages.push(detailInfo);
}
});
// Set validation result
if (detailsWithoutMessages.length > 0) {
return {
title: "At least one message is required for each detailed product when the channel is 'In-Person' and the user has a 'Field Sales Representative' profile.",
status: "error"
};
} else {
return {
title: `All ${visitDetails.length} detailed products have messages - Field Sales Rep In-Person validation passed`,
status: "success"
};
}
} catch (error) {
return {
title: "At least one message is required for each detailed product when the channel is 'In-Person' and the user has a 'Field Sales Representative' profile.",
status: "error",
error: error.message
};
}
}
/**
* The rule 'specificSampleDependencyCheck' blocks the user from submitting a visit.
* Validation: If sample "Immunexis 10mg" is selected,
* then "ADRAVIL Sample Pack 5mg" must also be selected.
* @returns result { title: string, status: "success" | "error" };
*/
async function specificSampleDependencyCheck() {
try {
// Get visit context data from record (from outer scope)
let visitData = parseContextData(record);
// Check if we have samples to validate
// Use helper to get field data with web/mobile fallback
let samples = getFieldData(visitData, "ProductDisbursement");
// Handle Proxy arrays properly
let samplesCount = 0;
let isValidSamples = false;
if (samples) {
try {
samplesCount = samples.length || 0;
isValidSamples = samplesCount > 0;
} catch (e) {
// Error accessing samples length
const keys = Object.keys(samples || {});
samplesCount = keys.length;
isValidSamples = samplesCount > 0;
}
}
if (!isValidSamples) {
return {
title: 'Sample dependency validation passed - no samples to validate',
status: "success"
};
}
// Get all product item IDs from samples
let productItemIds = [];
try {
if (samples && typeof samples === 'object') {
// Handle both array and Proxy array
for (let i = 0; i < samplesCount; i++) {
try {
const sample = samples[i];
if (sample) {
const productItemId = sample.ProductItemId || sample.productitemid
productItemIds.push(productItemId);
}
} catch (sampleError) {
// Error accessing sample
}
}
}
} catch (mappingError) {
// Error mapping product item IDs
}
if (productItemIds.length === 0) {
return {
title: 'Sample dependency validation passed - no product item IDs found',
status: "success"
};
}
// Query ProductItem to get Product2Id
let productItems = await db.query(
"ProductItem",
await new ConditionBuilder(
"ProductItem",
new SetCondition("Id", "IN", productItemIds)
).build(),
["Id", "Product2Id"]
);
// Extract Product2Ids and create a map of productItemId to Product2Id
let product2Ids = [];
let productItemToProduct2Map = new Map();
if (productItems && Array.isArray(productItems)) {
productItems.forEach(item => {
const productItemId = item.stringValue("Id");
const product2Id = item.stringValue("Product2Id");
if (product2Id) {
product2Ids.push(product2Id);
productItemToProduct2Map.set(productItemId, product2Id);
}
});
}
// Query Product2 to get product names
let product2Items = await db.query(
"Product2",
await new ConditionBuilder(
"Product2",
new SetCondition("Id", "IN", product2Ids)
).build(),
["Id", "Name"]
);
// Create a map of Product2Id to Name
let product2NameMap = new Map();
if (product2Items && Array.isArray(product2Items)) {
product2Items.forEach(item => {
const id = item.stringValue("Id");
const name = item.stringValue("Name");
product2NameMap.set(id, name);
});
}
// Create a map of productItemId to ProductName (via Product2)
let itemToProductNameMap = new Map();
productItemToProduct2Map.forEach((product2Id, productItemId) => {
const productName = product2NameMap.get(product2Id);
if (productName) {
itemToProductNameMap.set(productItemId, productName);
}
});
// Get all sample names for the current visit
let sampleNames = [];
try {
if (samples && typeof samples === 'object') {
// Handle both array and Proxy array for sample names
for (let i = 0; i < samplesCount; i++) {
try {
const sample = samples[i];
if (sample) {
const productItemId = sample.ProductItemId || sample.productitemid;
const productName = itemToProductNameMap.get(productItemId) || '';
if (productName) {
sampleNames.push(productName);
}
}
} catch (sampleError) {
// Error accessing sample for name mapping
}
}
}
} catch (nameMappingError) {
// Error mapping sample names
}
// Check if Immunexis 10mg is present
const targetSample = "Immunexis 10mg";
const requiredSample = "ADRAVIL Sample Pack 5mg";
let hasImmunexis = sampleNames.includes(targetSample);
if (hasImmunexis) {
// If Immunexis is present, check if ADRAVIL is also present
let hasAdravil = sampleNames.includes(requiredSample);
if (!hasAdravil) {
return {
title: "If Immunexis 10mg is added to a visit, ADRAVIL Sample Pack 5mg must also be added. However, ADRAVIL Sample Pack 5mg can be added without Immunexis 10mg.",
status: "error"
};
} else {
return {
title: "Sample dependency validation passed - both Immunexis 10mg and ADRAVIL Sample Pack 5mg present",
status: "success"
};
}
} else {
return {
title: "Sample dependency validation passed - no Immunexis 10mg found",
status: "success"
};
}
} catch (error) {
// Error in specificSampleDependencyCheck
// In case of database error, we might want to pass validation or handle differently
// For now, we'll pass the validation to avoid blocking the user due to technical issues
return {
title: "Sample dependency validation passed - technical error occurred",
status: "success"
};
}
}
/**
* The rule 'isAtLeastOneHCP' blocks the user from submitting a call.
* Validation: Require at least one HCP (Person Account) for a HCO (Institution Account) call on Submit.
* @returns result { title: string, status: "success" | "error" };
*/
async function isAtLeastOneHCP() {
try {
// Log current account details from record (from outer scope)
const currentAccountId = record.stringValue("AccountId");
// Use accountDao to check if current account is a Person Account
let isPersonAccount = await accountDao.getInstance().getIsPersonAccount();
let isInstitution = await accountDao.getInstance().getIsInstitution();
if (isPersonAccount) {
// This is already a Person Account (HCP), so requirement is met
return {
title: "HCP validation passed - current account is a Person Account (HCP)",
status: "success"
};
}
// Only apply HCP validation to Institution accounts
if (!isInstitution) {
return {
title: "HCP validation skipped - account is not an Institution Account",
status: "success"
};
}
// This is an Institution Account, check for HCP attendees
let childCallAccounts = await accountDao.getInstance().getChildCallAccounts();
let isRequirementValid = false;
let hcpAttendees = [];
let nonHcpAttendees = [];
if (Array.isArray(childCallAccounts) && childCallAccounts.length > 0) {
// Check if any attendee is a Person Account (HCP)
for (let i = 0; i < childCallAccounts.length; i++) {
let attendee = childCallAccounts[i];
let attendeeIsPersonAccount = attendee.boolValue("IsPersonAccount");
let attendeeName = attendee.stringValue("Name") || attendee.stringValue("Id");
if (attendeeIsPersonAccount) {
isRequirementValid = true;
hcpAttendees.push(attendeeName);
} else {
nonHcpAttendees.push(attendeeName);
}
}
}
// Add more descriptive message based on the scenario
if (!isRequirementValid) {
return {
title: "At least one HCP (Healthcare Professional) must be associated when creating a visit for an HCO (Healthcare Organization).",
status: "error"
};
} else {
return {
title: `HCP validation passed - Institution Account with ${hcpAttendees.length} HCP attendee(s): ${hcpAttendees.join(', ')}`,
status: "success"
};
}
} catch (error) {
// Error in isAtLeastOneHCP
// In case of error, fail the validation to be safe
return {
title: "HCP validation failed - error occurred during validation",
status: "error",
error: error.message
};
}
}
/**
* The rule 'isMoreThanOneHCO' blocks user from submitting a call.
* Validation: Restrict to one HCO (Institution Account) attendee per Call.
* @returns result { title: string, status: "success" | "error" };
* Note: Expected only 1 HCO attendee per call)
*/
async function isMoreThanOneHCO() {
try {
let counter = 0;
let isPersonAccount = await accountDao.getInstance().getIsPersonAccount();
let accsRelatedToChildCall = await accountDao.getInstance().getChildCallAccounts();
let hcoAccounts = [];
let hcpAccounts = [];
if (isPersonAccount || accsRelatedToChildCall.length) {
for (let i = 0; i < accsRelatedToChildCall.length; i++) {
let relatedAcc = accsRelatedToChildCall[i];
let attendeeIsPersonAccount = relatedAcc.boolValue("IsPersonAccount");
let attendeeName = relatedAcc.stringValue("Name") || relatedAcc.stringValue("Id");
if (!attendeeIsPersonAccount) {
counter++;
hcoAccounts.push(attendeeName);
} else {
hcpAccounts.push(attendeeName);
}
}
} else {
counter++;
}
const isValid = counter <= 1;
if (!isValid) {
return {
title: "Only 1 HCO (Healthcare Organization) attendee can be added per visit.",
status: "error"
};
} else {
return {
title: `HCO count validation passed - found ${counter} HCO account(s)`,
status: "success"
};
}
} catch (error) {
// Error in isMoreThanOneHCO
return {
title: "HCO count validation failed - error occurred during validation",
status: "error",
error: error.message
};
}
}
// Entry point: Check if proper parameters are provided
if (record && user && env && db) {
// Check action name - only run validation for specific actions
const actionName = getActionName(env);
const allowedActions = ['Submit', 'Sign', 'Save'];
if (!allowedActions.includes(actionName)) {
// Skip validation for other actions
return [{
title: `Validation skipped - action is "${actionName}"`,
status: 'success'
}];
}
// Platform detection: Check which field structure exists to determine wrapping behavior
const contextData = parseContextData(record);
// Web uses nested field paths (e.g., "ProviderVisit")
// Mobile uses simple field names (e.g., "Visit")
hasWebField = contextData?.["ProviderVisit"] !== undefined;
// Wrap in array if using web platform, don't wrap for mobile
const wrapAsArray = hasWebField;
// Apply wrapping based on platform
if (wrapAsArray) {
// Web solution - wrap in array
return [validateVisit()];
} else {
// Mobile solution - no wrapping
return validateVisit();
}
}
// If no parameters provided yet, return validation function wrapped in array
return [validateVisit];
})();Эта статья решила вашу проблему?
Оставьте свой отзыв, чтобы мы могли стать лучше!
