Untitled
unknown
plain_text
24 days ago
17 kB
8
Indexable
var ACWAPP = ACWAPP || {};
ACWAPP.AwardAmount = (function () {
const SUBGRID_NAME = "RelatedCaseRef";
const AMOUNT_FIELD = "acwapp_amountofrewardgrantedtoeachinformant";
const CONFIG_TABLE = "acwapp_awardconfiguration";
const CONFIG_AMOUNT_FIELD = "acwapp_totalawardamount";
const AWARD_RESULT_FIELD = "acwapp_awardresult";
const APPROVED_VALUE = 100000000;
const REJECTED_VALUE = 100000001;
const REQUIRE_FIELDS_WHEN_APPROVED = [
"acwapp_amountofrewardgrantedtoeachinformant",
"acwapp_awardamountapproval"
];
const LOCK_FIELDS_WHEN_REJECTED = [
"acwapp_amountofrewardgrantedtoeachinformant",
"acwapp_awardamountapproval"
];
const ALLEGATION_STATUS_FIELD = "acwapp_allegationstatus";
const REVIEW_SUBMIT_DATE_FIELD = "acwapp_reviewsubmitteddate";
const REVIEW_STATUS = 100000001;
const RESULT_STATUS = 100000002;
// New const
const ALLEGATION_ENTITY = "acwapp_suspectedabuse";
const ALLEGATION_CASE_LOOKUP = "acwapp_abusecase";
const DATE_ISSUANCE_NTQ_FIELD = "acwapp_dateofissuanceofntq";
const DATE_ACTUAL_TERMINATION_FIELD = "acwapp_dateofactualterminationoftenancy";
const ACTIONS_FOR_SUGGESTED_TENANCY_FIELD = "acwapp_actionsforsuggestedtenancy";
const REASON_NO_TENANCY_ACTION_FIELD = "acwapp_reasonofnotenancyactionrequired";
const ACTION_ISSUANCE_OF_NTQ = 100000000;
const ACTION_FLAT_RETURNED_BEFORE_NTQ = 100000001;
const ACTION_FLAT_RETURNED_BEFORE_ACTION_TAKEN = 100000003;
const REASON_FLAT_RETURNED_DURING_INVESTIGATION = 100000002;
//---------------------------------------------------------
const CASE_ENTITY = "acwapp_abusecases";
const CASE_ID_FIELD = "acwapp_abusecasesid";
const RELATED_CASE_RELATIONSHIP = "acwapp_acwapp_abusecases_acwapp_abusecases";
const CONFIRM_AMOUNT_FIELD = "acwapp_awardamountapproval";
const YES_OPTION_VALUE = 100000000;
const AWARD_FIELDS_TO_COPY = [
"acwapp_awardresult",
"acwapp_panelresultsdate",
"acwapp_dateofrejection",
"acwapp_rejectionreason",
"acwapp_amountofrewardgrantedtoeachinformant",
"acwapp_awardamountapproval"
];
let isCopyingAwardData = false;
//-----------------------------
var Sdk = window.Sdk || {};
Sdk.AssociateRequest = function (target, relatedEntities, relationship) {
this.target = target;
this.relatedEntities = relatedEntities;
this.relationship = relationship;
};
Sdk.AssociateRequest.prototype.getMetadata = function () {
return {
boundParameter: null,
parameterTypes: {
target: {
typeName: "mscrm.crmbaseentity",
structuralProperty: 5
},
relatedEntities: {
typeName: "Collection(mscrm.crmbaseentity)",
structuralProperty: 4
},
relationship: {
typeName: "Edm.String",
structuralProperty: 1
}
},
operationType: 2,
operationName: "Associate"
};
};
function OnSave(executionContext) {
const formContext = executionContext.getFormContext();
setReviewSubmittedDate(formContext);
}
function OnLoad(executionContext) {
const formContext = executionContext.getFormContext();
lockFieldsIfRejected(formContext);
requireFieldsIfApproved(formContext);
handleTenancyDateFields(formContext);
registerPostSaveHandler(formContext);
window.setTimeout(function () {
validateAmount(formContext);
registerSubgridOnLoad(formContext);
}, 1000);
}
function OnAmountChange(executionContext) {
const formContext = executionContext.getFormContext();
validateAmount(formContext);
}
function registerSubgridOnLoad(formContext) {
const subgrid = formContext.getControl(SUBGRID_NAME);
if (subgrid && !subgrid._awardAmountRegistered) {
subgrid.addOnLoad(function () {
validateAmount(formContext);
});
subgrid._awardAmountRegistered = true;
}
}
async function getTotalAwardAmount() {
const result = await Xrm.WebApi.retrieveMultipleRecords(
CONFIG_TABLE,
"?$select=" + CONFIG_AMOUNT_FIELD + "&$filter=statecode eq 0&$top=1"
);
if (!result.entities || result.entities.length === 0) {
return null;
}
return result.entities[0][CONFIG_AMOUNT_FIELD];
}
async function validateAmount(formContext) {
const subgrid = formContext.getControl(SUBGRID_NAME);
const amountAttr = formContext.getAttribute(AMOUNT_FIELD);
const amountCtrl = formContext.getControl(AMOUNT_FIELD);
if (!subgrid || !amountAttr || !amountCtrl) return;
const grid = subgrid.getGrid();
if (!grid) return;
const rowCount = grid.getTotalRecordCount();
amountCtrl.clearNotification("amount_limit");
if (rowCount <= 0) return;
const totalAmount = await getTotalAwardAmount();
if (totalAmount === null) {
amountCtrl.setNotification(
"Award configuration is missing. Please contact an administrator.",
"amount_limit"
);
return;
}
const perRowAmount = totalAmount / rowCount;
const currentAmount = amountAttr.getValue();
if (currentAmount !== null && currentAmount > perRowAmount) {
amountCtrl.setNotification(
"Amount cannot exceed " + perRowAmount + ".",
"amount_limit"
);
}
}
function lockFieldsIfRejected(formContext) {
const awardResultAttr = formContext.getAttribute(AWARD_RESULT_FIELD);
if (!awardResultAttr) return;
const isRejected = awardResultAttr.getValue() === REJECTED_VALUE;
LOCK_FIELDS_WHEN_REJECTED.forEach(function (fieldName) {
const control = formContext.getControl(fieldName);
if (control) {
control.setDisabled(isRejected);
}
});
}
function requireFieldsIfApproved(formContext) {
const awardResultAttr = formContext.getAttribute(AWARD_RESULT_FIELD);
if (!awardResultAttr) return;
const isApproved = awardResultAttr.getValue() === APPROVED_VALUE;
REQUIRE_FIELDS_WHEN_APPROVED.forEach(function (fieldName) {
const attr = formContext.getAttribute(fieldName);
if (attr) {
attr.setRequiredLevel(isApproved ? "required" : "none");
}
});
}
function OnAwardResultChange(executionContext) {
const formContext = executionContext.getFormContext();
lockFieldsIfRejected(formContext);
requireFieldsIfApproved(formContext);
}
function setReviewSubmittedDate(formContext) {
const statusAttr = formContext.getAttribute(ALLEGATION_STATUS_FIELD);
const submitDateAttr = formContext.getAttribute(REVIEW_SUBMIT_DATE_FIELD);
if (!statusAttr || !submitDateAttr) return;
const currentStatus = statusAttr.getValue();
const currentDate = submitDateAttr.getValue();
if (currentStatus === RESULT_STATUS && !currentDate) {
submitDateAttr.setValue(new Date());
}
if (currentStatus === REVIEW_STATUS) {
submitDateAttr.setValue(null);
}
}
async function fetchAllegations(caseId) {
const fetchXml = `
<fetch>
<entity name="${ALLEGATION_ENTITY}">
<attribute name="${ACTIONS_FOR_SUGGESTED_TENANCY_FIELD}" />
<attribute name="${REASON_NO_TENANCY_ACTION_FIELD}" />
<filter>
<condition attribute="${ALLEGATION_CASE_LOOKUP}"
operator="eq"
value="${caseId}" />
</filter>
</entity>
</fetch>`;
try {
const result = await Xrm.WebApi.retrieveMultipleRecords(
ALLEGATION_ENTITY,
"?fetchXml=" + encodeURIComponent(fetchXml)
);
return result.entities || [];
} catch (e) {
console.error("Error fetching Allegations:", e);
return [];
}
}
function setVisibleAndRequired(formContext, fieldName, required) {
const attr = formContext.getAttribute(fieldName);
const ctrl = formContext.getControl(fieldName);
if (ctrl) {
ctrl.setVisible(required);
}
if (attr) {
attr.setRequiredLevel(required ? "required" : "none");
}
}
async function handleTenancyDateFields(formContext) {
const caseIdRaw = formContext.data.entity.getId();
if (!caseIdRaw) return;
const caseId = caseIdRaw.replace(/[{}]/g, "");
const allegations = await fetchAllegations(caseId);
const showIssuanceNTQ = allegations.some(function (a) {
return a[ACTIONS_FOR_SUGGESTED_TENANCY_FIELD] === ACTION_ISSUANCE_OF_NTQ;
});
const showActualTermination = allegations.some(function (a) {
return (
a[ACTIONS_FOR_SUGGESTED_TENANCY_FIELD] === ACTION_FLAT_RETURNED_BEFORE_NTQ ||
a[ACTIONS_FOR_SUGGESTED_TENANCY_FIELD] === ACTION_FLAT_RETURNED_BEFORE_ACTION_TAKEN ||
a[REASON_NO_TENANCY_ACTION_FIELD] === REASON_FLAT_RETURNED_DURING_INVESTIGATION
);
});
setVisibleAndRequired(formContext, DATE_ISSUANCE_NTQ_FIELD, showIssuanceNTQ);
setVisibleAndRequired(formContext, DATE_ACTUAL_TERMINATION_FIELD, showActualTermination);
}
function registerPostSaveHandler(formContext) {
try {
formContext.data.entity.removeOnPostSave(OnPostSave);
} catch (e) {
// Ignore if not already registered
}
formContext.data.entity.addOnPostSave(OnPostSave);
}
async function OnPostSave(executionContext) {
const formContext = executionContext.getFormContext();
if (isCopyingAwardData) {
return;
}
const confirmAttr = formContext.getAttribute(CONFIRM_AMOUNT_FIELD);
if (!confirmAttr) {
console.warn("Confirm Amount field not found:", CONFIRM_AMOUNT_FIELD);
return;
}
const confirmValue = confirmAttr.getValue();
if (!isYes(confirmValue)) {
return;
}
try {
isCopyingAwardData = true;
Xrm.Utility.showProgressIndicator("Copying award data to related cases...");
await copyAwardFieldsAndSubgridToRelatedCases(formContext);
Xrm.Utility.closeProgressIndicator();
await Xrm.Navigation.openAlertDialog({
text: "Award fields and related case references have been copied to all related cases."
});
const subgrid = formContext.getControl(SUBGRID_NAME);
if (subgrid) {
subgrid.refresh();
}
} catch (error) {
console.error("Failed to copy award data:", error);
Xrm.Utility.closeProgressIndicator();
await Xrm.Navigation.openAlertDialog({
text: error?.message || "Failed to copy award data to related cases."
});
} finally {
isCopyingAwardData = false;
}
}
async function copyAwardFieldsAndSubgridToRelatedCases(formContext) {
const sourceCaseId = getCurrentCaseId(formContext);
if (!sourceCaseId) {
throw new Error("Current case ID is missing.");
}
const relatedCaseIds = getRelatedCaseIdsFromSubgrid(formContext);
if (relatedCaseIds.length === 0) {
console.log("No related cases found in Related Case Ref subgrid.");
return;
}
const sourceData = await retrieveSourceAwardData(sourceCaseId);
for (const relatedCaseId of relatedCaseIds) {
if (!relatedCaseId || relatedCaseId === sourceCaseId) {
continue;
}
await Xrm.WebApi.updateRecord(
CASE_ENTITY,
relatedCaseId,
sourceData
);
}
const fullCaseList = [
sourceCaseId,
...relatedCaseIds
];
const uniqueCaseIds = [...new Set(fullCaseList)];
await copyRelatedCaseRelationships(uniqueCaseIds);
}
function getCurrentCaseId(formContext) {
const id = formContext.data.entity.getId();
return stripBraces(id);
}
function stripBraces(id) {
return (id || "").replace(/[{}]/g, "").toLowerCase();
}
function isYes(value) {
return value === true || value === YES_OPTION_VALUE;
}
function getRelatedCaseIdsFromSubgrid(formContext) {
const ids = [];
const subgrid = formContext.getControl(SUBGRID_NAME);
if (!subgrid || !subgrid.getGrid) {
console.warn("Related Case Ref subgrid not found:", SUBGRID_NAME);
return ids;
}
const grid = subgrid.getGrid();
if (!grid) {
console.warn("Related Case Ref grid is not loaded yet.");
return ids;
}
grid.getRows().forEach(function (row) {
const id = stripBraces(row.getData().getEntity().getId());
if (id) {
ids.push(id);
}
});
return [...new Set(ids)];
}
async function retrieveSourceAwardData(sourceCaseId) {
const selectQuery = "?$select=" + AWARD_FIELDS_TO_COPY.join(",");
const sourceRecord = await Xrm.WebApi.retrieveRecord(
CASE_ENTITY,
sourceCaseId,
selectQuery
);
const data = {};
AWARD_FIELDS_TO_COPY.forEach(function (fieldName) {
if (sourceRecord.hasOwnProperty(fieldName)) {
data[fieldName] = sourceRecord[fieldName];
}
});
return data;
}
async function copyRelatedCaseRelationships(caseIds) {
for (const parentId of caseIds) {
for (const childId of caseIds) {
if (!parentId || !childId) {
continue;
}
if (parentId === childId) {
continue;
}
await associateRelatedCase(parentId, childId);
}
}
}
async function associateRelatedCase(parentId, relatedId) {
try {
await Xrm.WebApi.online.execute(
new Sdk.AssociateRequest(
{
entityType: CASE_ENTITY,
id: parentId
},
[
{
entityType: CASE_ENTITY,
id: relatedId
}
],
RELATED_CASE_RELATIONSHIP
)
);
} catch (error) {
const message = error?.message || "";
if (
message.includes("duplicate") ||
message.includes("already exists") ||
message.includes("A record with matching key values already exists")
) {
console.log("Relationship already exists:", parentId, relatedId);
return;
}
console.error("Associate failed:", parentId, relatedId, error);
throw error;
}
}
return {
OnSave: OnSave,
OnLoad: OnLoad,
OnPostSave: OnPostSave,
OnAmountChange: OnAmountChange,
OnAwardResultChange: OnAwardResultChange
};
})();Editor is loading...
Leave a Comment