Case Punching Feature Done
This commit is contained in:
@@ -27,7 +27,7 @@ function GetRowData(SelectedRow)
|
||||
$("#"+SelectedRow.id+"col").html("<img src='/matrix/images/edited.png' title='Details has been edited successfully. Please click refresh button to see the changes' />");
|
||||
}*/
|
||||
$("#uuid").val($("#"+SelectedRow.id+"uuid").val());
|
||||
SubmitForm("caseedit", "_blank", "caseGrid");
|
||||
SubmitForm("caseedit", "_blank", "caseGrid");
|
||||
}
|
||||
function keyListen(param1,param2,e) {
|
||||
var keycode = e.keyCode;
|
||||
|
||||
@@ -19,7 +19,7 @@ function GetMoreDetails(SelectedRow)
|
||||
$("#"+SelectedRow.id+"col").html("<img src='/matrix/images/edited.png' title='Details has been edited successfully. Please click refresh button to see the changes' />");
|
||||
}*/
|
||||
$("#uuid").val($("#"+SelectedRow.id+"uuid").val());
|
||||
SubmitForm("caseedit", "_blank", "caseGrid");
|
||||
SubmitForm("caseedit", "_blank", "caseGrid");
|
||||
}
|
||||
function ValidateEmailSearch()
|
||||
{
|
||||
|
||||
170
cygnus-onprem-app/build/WebContent/js/edp/initiation.js
Normal file
170
cygnus-onprem-app/build/WebContent/js/edp/initiation.js
Normal file
@@ -0,0 +1,170 @@
|
||||
(function (window, document) {
|
||||
"use strict";
|
||||
|
||||
const API = Object.freeze({ key: "payload-key", save: "application-save" });
|
||||
const BOOLEAN_FIELDS = Object.freeze({
|
||||
residenceVerification: "rv",
|
||||
residenceTelephoneVerification: "rtv",
|
||||
officeVerification: "ov",
|
||||
officeTelephoneVerification: "otv",
|
||||
propertyVerification: "pv",
|
||||
referenceVerification: "refv",
|
||||
documentVerification: "docv",
|
||||
residenceCoApplicant: "rco",
|
||||
residenceCoProprietor: "rcp",
|
||||
officeCoProprietor: "ocp",
|
||||
sameResidenceAddress: "sradd",
|
||||
sameOfficeAddress: "soadd",
|
||||
samePropertyAddress: "spadd",
|
||||
autoCutOff: "autocut"
|
||||
});
|
||||
const VALUE_FIELDS = Object.freeze({
|
||||
applicationId: "case_id", portfolioId: "portfolio_id", bankBranchId: "bank_branch_id",
|
||||
applicationNumber: "applno", bankCode: "bankcode", product: "product",
|
||||
loanAmount: "loanamount", customerName: "customername", fatherName: "fathername",
|
||||
applicationType: "apptype", category: "category", dateOfBirth: "dob",
|
||||
contactPerson: "contactperson", mobileNumber: "mobileno", specialInstruction: "specialinst",
|
||||
residenceAddress1: "raddr1", residenceAddress2: "raddr2", residenceAddress3: "raddr3",
|
||||
residenceLandmark: "rlandmark", residenceColonyId: "Rcolony", residenceCity: "rcity",
|
||||
residencePincode: "rpincode", residencePhone: "rphone", companyName: "companyname",
|
||||
officeAddress1: "oaddr1", officeAddress2: "oaddr2", officeAddress3: "oaddr3",
|
||||
officeLandmark: "olandmark", officeColonyId: "Ocolony", officeCity: "ocity",
|
||||
officePincode: "opincode", department: "department", designation: "designation",
|
||||
officePhone: "ophone", extension: "extension", propertyAddress1: "paddr1",
|
||||
propertyAddress2: "paddr2", propertyAddress3: "paddr3", propertyLandmark: "plandmark",
|
||||
propertyColonyId: "Pcolony", propertyCity: "pcity", propertyPincode: "ppincode",
|
||||
referenceName1: "refname1", referenceAddress1: "refaddress1",
|
||||
referenceContactNumber1: "refcontactno1", referenceName2: "refname2",
|
||||
referenceAddress2: "refaddress2", referenceContactNumber2: "refcontactno2",
|
||||
formMode: "formmode"
|
||||
});
|
||||
const INTEGER_FIELDS = new Set(["applicationId", "portfolioId", "bankBranchId", "residenceColonyId",
|
||||
"officeColonyId", "propertyColonyId", "formMode"]);
|
||||
const element = (id) => document.getElementById(id);
|
||||
const value = (id) => element(id)?.value?.trim() ?? "";
|
||||
const integer = (id) => {
|
||||
const parsed = Number.parseInt(value(id), 10);
|
||||
return Number.isFinite(parsed) ? parsed : 0;
|
||||
};
|
||||
const checked = (id) => Boolean(element(id)?.checked);
|
||||
|
||||
function collectDynamicFields() {
|
||||
const names = value("dynamicfields").split(window.ColDelim || "!C0L!").filter(Boolean);
|
||||
return names.reduce((result, name) => {
|
||||
if (/^(?:field(?:[1-9]|1[0-2])|dtfield1)$/.test(name) && element(name)) {
|
||||
result[name] = value(name);
|
||||
}
|
||||
return result;
|
||||
}, {});
|
||||
}
|
||||
|
||||
function collectCase() {
|
||||
const details = {};
|
||||
Object.entries(VALUE_FIELDS).forEach(([property, id]) => {
|
||||
details[property] = INTEGER_FIELDS.has(property) ? integer(id) : value(id);
|
||||
});
|
||||
Object.entries(BOOLEAN_FIELDS).forEach(([property, id]) => { details[property] = checked(id); });
|
||||
details.dynamicFields = collectDynamicFields();
|
||||
return details;
|
||||
}
|
||||
|
||||
function validateForm() {
|
||||
const verificationIds = ["rv", "rtv", "ov", "otv", "pv", "refv", "docv"];
|
||||
if (!verificationIds.some(checked)) {
|
||||
showAlert("danger", "APP-4221", "At least one verification type is required.");
|
||||
return false;
|
||||
}
|
||||
window.invalidFields = 0;
|
||||
window.validate(element("applno"), "t", "AlphaNumeric");
|
||||
window.validate(element("bank_branch_id"), "t", "");
|
||||
window.validate(element("product"), "t", "");
|
||||
window.validate(element("customername"), "t", "AlphaSpace");
|
||||
window.validate(element("apptype"), "t", "");
|
||||
if (checked("rv")) window.CheckForm(element("rv"), "raddr1,raddr2,raddr3,rlandmark,colr,rcity,rpincode", "t,f,t,f,t,t,f", "SplInstruction,SplInstruction,SplInstruction,SplInstruction,SplInstruction,,Pincode");
|
||||
if (checked("ov")) window.CheckForm(element("ov"), "companyname,oaddr1,oaddr2,oaddr3,olandmark,colo,ocity,opincode,department,designation", "f,t,f,t,f,t,t,f,f,f", "SplInstruction,SplInstruction,SplInstruction,SplInstruction,SplInstruction,SplInstruction,,Pincode,SplInstruction,SplInstruction");
|
||||
if (checked("pv")) window.CheckForm(element("pv"), "paddr1,paddr2,paddr3,plandmark,colp,pcity,ppincode", "t,f,t,f,t,t,f", "SplInstruction,SplInstruction,SplInstruction,SplInstruction,SplInstruction,,Pincode");
|
||||
if (checked("rtv")) window.CheckForm(element("rtv"), "rphone", "t", "Phone");
|
||||
if (checked("otv")) window.CheckForm(element("otv"), "ophone", "t", "Phone");
|
||||
if (checked("refv")) window.CheckForm(element("refv"), "refname1,refaddress1,refcontactno1", "t,f,t", "AlphaSpace,SplInstruction,Phone");
|
||||
[["rv", "Rcolony", "colr"], ["ov", "Ocolony", "colo"], ["pv", "Pcolony", "colp"]]
|
||||
.forEach(([flag, hidden, visible]) => {
|
||||
if (checked(flag) && integer(hidden) === 0) window.highlightField(element(visible));
|
||||
});
|
||||
if (document.querySelector(".matrix-validation-error-icon")) {
|
||||
showAlert("danger", "APP-4221", "Correct the highlighted fields and submit the application again.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function showAlert(level, code, message, referenceId) {
|
||||
let host = element("case-save-alerts");
|
||||
if (!host) {
|
||||
host = document.createElement("div");
|
||||
host.id = "case-save-alerts";
|
||||
host.className = "position-fixed top-0 start-50 translate-middle-x p-3";
|
||||
host.style.cssText = "z-index:1085;max-width:720px;width:calc(100% - 2rem)";
|
||||
document.body.append(host);
|
||||
}
|
||||
const alert = document.createElement("div");
|
||||
alert.className = `alert alert-${level} alert-dismissible fade show shadow-sm`;
|
||||
alert.setAttribute("role", "alert");
|
||||
const strong = document.createElement("strong");
|
||||
strong.textContent = `${code}: `;
|
||||
alert.append(strong, document.createTextNode(message));
|
||||
if (referenceId) {
|
||||
const reference = document.createElement("small");
|
||||
reference.className = "d-block mt-1";
|
||||
reference.textContent = `Reference: ${referenceId}`;
|
||||
alert.append(reference);
|
||||
}
|
||||
const close = document.createElement("button");
|
||||
close.type = "button";
|
||||
close.className = "btn-close";
|
||||
close.setAttribute("data-bs-dismiss", "alert");
|
||||
close.setAttribute("aria-label", "Close");
|
||||
alert.append(close);
|
||||
host.replaceChildren(alert);
|
||||
window.setTimeout(() => window.bootstrap?.Alert.getOrCreateInstance(alert).close(), 7000);
|
||||
}
|
||||
|
||||
function applyResult(result, originalApplicationId) {
|
||||
element("case_id").value = result.applicationId;
|
||||
if (element("mvcode")) element("mvcode").value = result.mvCode || "";
|
||||
if (Array.isArray(window.fields?.[0]) && Array.isArray(window.records?.[window.recpos])) {
|
||||
[["case_id", result.applicationId], ["mvcode", result.mvCode]].forEach(([name, fieldValue]) => {
|
||||
const index = window.fields[0].indexOf(name);
|
||||
if (index >= 0) window.records[window.recpos][index] = fieldValue;
|
||||
});
|
||||
}
|
||||
showAlert("success", "APP-2001", `Application ${result.mvCode || result.applicationId} saved successfully.`);
|
||||
if (originalApplicationId === 0 && typeof window.AddNewRecord === "function") window.AddNewRecord();
|
||||
else if (originalApplicationId > 0 && typeof window.findRecord === "function") window.findRecord(3);
|
||||
}
|
||||
|
||||
async function save(event) {
|
||||
event?.preventDefault();
|
||||
if (!validateForm()) return false;
|
||||
const button = element("btnsave");
|
||||
if (button?.disabled) return false;
|
||||
const details = collectCase();
|
||||
if (button) button.disabled = true;
|
||||
try {
|
||||
const envelope = await window.CygnusPayloadCrypto.encrypt(details, { keyUrl: API.key });
|
||||
const response = await fetch(API.save, { method: "POST", credentials: "same-origin",
|
||||
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
||||
body: JSON.stringify(envelope) });
|
||||
const body = await response.json().catch(() => null);
|
||||
if (!response.ok || !body?.success) throw body?.message || body || {};
|
||||
applyResult(body.data, details.applicationId);
|
||||
} catch (error) {
|
||||
showAlert("danger", error.code || "APP-5001",
|
||||
error.message || "Cygnus could not save the application details.", error.referenceId);
|
||||
} finally {
|
||||
if (button) button.disabled = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
window.CygnusInitiation = Object.freeze({ save });
|
||||
}(window, document));
|
||||
91
cygnus-onprem-app/build/WebContent/js/lib/payload-crypto.js
Normal file
91
cygnus-onprem-app/build/WebContent/js/lib/payload-crypto.js
Normal file
@@ -0,0 +1,91 @@
|
||||
(function (window) {
|
||||
"use strict";
|
||||
|
||||
const keyRequests = new Map();
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
function toBase64Url(bytes) {
|
||||
let binary = "";
|
||||
const view = new Uint8Array(bytes);
|
||||
for (let offset = 0; offset < view.length; offset += 0x8000) {
|
||||
binary += String.fromCharCode(...view.subarray(offset, offset + 0x8000));
|
||||
}
|
||||
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
||||
}
|
||||
|
||||
function fromBase64Url(text) {
|
||||
const normalized = text.replace(/-/g, "+").replace(/_/g, "/");
|
||||
const binary = atob(normalized + "=".repeat((4 - normalized.length % 4) % 4));
|
||||
return Uint8Array.from(binary, (character) => character.charCodeAt(0));
|
||||
}
|
||||
|
||||
function fetchKey(keyUrl) {
|
||||
if (!keyUrl) {
|
||||
return Promise.reject(new Error("A payload encryption key URL is required."));
|
||||
}
|
||||
if (!keyRequests.has(keyUrl)) {
|
||||
const request = fetch(keyUrl, {
|
||||
credentials: "same-origin",
|
||||
headers: { Accept: "application/json" }
|
||||
}).then(async (response) => {
|
||||
const body = await response.json();
|
||||
if (!response.ok) throw body;
|
||||
if (!body.keyId || !body.publicKey) {
|
||||
throw new Error("The payload encryption key response is invalid.");
|
||||
}
|
||||
return body;
|
||||
}).catch((error) => {
|
||||
keyRequests.delete(keyUrl);
|
||||
throw error;
|
||||
});
|
||||
keyRequests.set(keyUrl, request);
|
||||
}
|
||||
return keyRequests.get(keyUrl);
|
||||
}
|
||||
|
||||
async function encrypt(payload, options) {
|
||||
if (!window.crypto?.subtle) {
|
||||
throw new Error("Secure payload encryption is not supported by this browser.");
|
||||
}
|
||||
const keyInfo = await fetchKey(options?.keyUrl);
|
||||
const publicKey = await window.crypto.subtle.importKey(
|
||||
"spki",
|
||||
fromBase64Url(keyInfo.publicKey),
|
||||
{ name: "RSA-OAEP", hash: "SHA-256" },
|
||||
false,
|
||||
["encrypt"]
|
||||
);
|
||||
const aesKey = await window.crypto.subtle.generateKey(
|
||||
{ name: "AES-GCM", length: 256 }, true, ["encrypt"]
|
||||
);
|
||||
const initializationVector = window.crypto.getRandomValues(new Uint8Array(12));
|
||||
const requestId = window.crypto.randomUUID();
|
||||
const timestamp = new Date().toISOString();
|
||||
const additionalData = encoder.encode(`${keyInfo.keyId}|${requestId}|${timestamp}`);
|
||||
const encryptedPayload = await window.crypto.subtle.encrypt(
|
||||
{ name: "AES-GCM", iv: initializationVector, additionalData },
|
||||
aesKey,
|
||||
encoder.encode(JSON.stringify(payload))
|
||||
);
|
||||
const rawKey = await window.crypto.subtle.exportKey("raw", aesKey);
|
||||
const encryptedKey = await window.crypto.subtle.encrypt(
|
||||
{ name: "RSA-OAEP" }, publicKey, rawKey
|
||||
);
|
||||
|
||||
return Object.freeze({
|
||||
keyId: keyInfo.keyId,
|
||||
encryptedKey: toBase64Url(encryptedKey),
|
||||
initializationVector: toBase64Url(initializationVector),
|
||||
encryptedPayload: toBase64Url(encryptedPayload),
|
||||
requestId,
|
||||
timestamp
|
||||
});
|
||||
}
|
||||
|
||||
function clearKeyCache(keyUrl) {
|
||||
if (keyUrl) keyRequests.delete(keyUrl);
|
||||
else keyRequests.clear();
|
||||
}
|
||||
|
||||
window.CygnusPayloadCrypto = Object.freeze({ encrypt, clearKeyCache });
|
||||
}(window));
|
||||
Reference in New Issue
Block a user