- Updated VariableManager.vue to change variable type labels for clarity, replacing 'Int' and 'Decimal' with 'Number'. - Modified manager-approval-customScript.js to correct field references and enhance conditional logic for displaying the custom approved amount. - Enhanced manager-approval-form.json by adding 'readonly' attributes to several fields, ensuring they are non-editable during the approval process. - Revised travel-workflow-process.json to improve node connections and labels for better workflow clarity. - Updated travel-workflow-variables.json to refine variable descriptions and ensure consistency across the workflow. - Adjusted [id].vue to improve form data handling and loading states, enhancing user experience during workflow execution.
296 lines
8.2 KiB
JavaScript
296 lines
8.2 KiB
JavaScript
// Manager Approval Form Custom Script Engine
|
|
// This script provides dynamic behavior for the manager approval form
|
|
|
|
console.log("Manager Approval Form Script Loaded");
|
|
|
|
// Auto-set approval date to today
|
|
const setApprovalDate = () => {
|
|
const today = new Date();
|
|
const formattedDate = today.toISOString().split("T")[0]; // YYYY-MM-DD format
|
|
setField("approval_date", formattedDate);
|
|
};
|
|
|
|
// Calculate and display recommended approval amounts
|
|
const calculateRecommendedAmounts = () => {
|
|
const totalClaimed = parseFloat(getField("total_cost_display")) || 0;
|
|
const policyLimit = parseFloat(getField("policy_limit_display")) || 0;
|
|
const overBudget = parseFloat(getField("over_budget_amount")) || 0;
|
|
|
|
if (totalClaimed > 0 && policyLimit > 0) {
|
|
const percentageOver = ((overBudget / policyLimit) * 100).toFixed(1);
|
|
showInfo(
|
|
`This claim is ${percentageOver}% over the policy limit. Policy limit: RM${policyLimit.toFixed(2)}, Claimed: RM${totalClaimed.toFixed(2)}`
|
|
);
|
|
}
|
|
};
|
|
|
|
// Validate manager decision and provide guidance
|
|
const handleDecisionChange = (decision) => {
|
|
const totalClaimed = parseFloat(getField("total_cost_display")) || 0;
|
|
const policyLimit = parseFloat(getField("policy_limit_display")) || 0;
|
|
|
|
console.log("Manager decision changed to:", decision);
|
|
|
|
switch (decision) {
|
|
case "approve_full":
|
|
showField("custom_approved_amount");
|
|
showInfo(
|
|
`💰 Approving full amount: RM${totalClaimed.toFixed(2)}. You can enter a custom amount if needed.`
|
|
);
|
|
setField("custom_approved_amount", totalClaimed.toString());
|
|
break;
|
|
|
|
case "approve_policy":
|
|
hideField("custom_approved_amount");
|
|
showInfo(
|
|
`⚖️ Approving policy limit only: RM${policyLimit.toFixed(2)}. Employee will be notified of the reduced amount.`
|
|
);
|
|
break;
|
|
|
|
case "reject":
|
|
hideField("custom_approved_amount");
|
|
showError(
|
|
"❌ Claim will be rejected. Please provide detailed comments explaining the rejection reason."
|
|
);
|
|
break;
|
|
|
|
default:
|
|
hideField("custom_approved_amount");
|
|
}
|
|
};
|
|
|
|
// Validate custom approved amount
|
|
const validateCustomAmount = (amount) => {
|
|
const numAmount = parseFloat(amount) || 0;
|
|
const totalClaimed = parseFloat(getField("total_cost_display")) || 0;
|
|
const policyLimit = parseFloat(getField("policy_limit_display")) || 0;
|
|
|
|
if (numAmount < 0) {
|
|
showError("Approved amount cannot be negative");
|
|
return false;
|
|
}
|
|
|
|
if (numAmount > totalClaimed) {
|
|
showError(
|
|
`Approved amount (RM${numAmount}) cannot exceed claimed amount (RM${totalClaimed})`
|
|
);
|
|
return false;
|
|
}
|
|
|
|
if (numAmount > 0 && numAmount < policyLimit) {
|
|
showInfo(
|
|
`Custom amount (RM${numAmount}) is less than policy limit (RM${policyLimit}). Consider approving policy limit instead.`
|
|
);
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
// Validate manager comments based on decision
|
|
const validateComments = (comments, decision) => {
|
|
if (!comments || comments.trim().length < 10) {
|
|
showError("Please provide detailed comments (minimum 10 characters)");
|
|
return false;
|
|
}
|
|
|
|
if (decision === "reject" && comments.length < 50) {
|
|
showError(
|
|
"Rejection requires detailed explanation (minimum 50 characters)"
|
|
);
|
|
return false;
|
|
}
|
|
|
|
if (decision === "approve_full") {
|
|
const totalClaimed = parseFloat(getField("total_cost_display")) || 0;
|
|
const policyLimit = parseFloat(getField("policy_limit_display")) || 0;
|
|
const overBudget = totalClaimed - policyLimit;
|
|
|
|
if (overBudget > 500 && !comments.toLowerCase().includes("business")) {
|
|
showInfo(
|
|
"Consider mentioning business justification for approving over-budget amounts > RM500"
|
|
);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
// Format manager name (title case)
|
|
const formatManagerName = (name) => {
|
|
if (!name || typeof name !== "string") return name;
|
|
|
|
return name
|
|
.toLowerCase()
|
|
.split(" ")
|
|
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
.join(" ");
|
|
};
|
|
|
|
// Form validation before submission
|
|
const validateApprovalForm = () => {
|
|
let isValid = true;
|
|
const errors = [];
|
|
|
|
// Check required fields
|
|
const requiredFields = {
|
|
manager_decision: "Approval Decision",
|
|
manager_comments: "Manager Comments",
|
|
manager_name: "Manager Name",
|
|
approval_date: "Approval Date",
|
|
};
|
|
|
|
Object.entries(requiredFields).forEach(([fieldName, displayName]) => {
|
|
const value = getField(fieldName);
|
|
if (!value || value.toString().trim() === "") {
|
|
errors.push(`${displayName} is required`);
|
|
isValid = false;
|
|
}
|
|
});
|
|
|
|
// Validate decision-specific requirements
|
|
const decision = getField("manager_decision");
|
|
const comments = getField("manager_comments");
|
|
const customAmount = getField("custom_approved_amount");
|
|
|
|
if (decision && comments) {
|
|
if (!validateComments(comments, decision)) {
|
|
isValid = false;
|
|
}
|
|
}
|
|
|
|
if (decision === "approve_full" && customAmount) {
|
|
if (!validateCustomAmount(customAmount)) {
|
|
isValid = false;
|
|
}
|
|
}
|
|
|
|
// Validate approval date is not in the future
|
|
const approvalDate = getField("approval_date");
|
|
if (approvalDate) {
|
|
const selectedDate = new Date(approvalDate);
|
|
const today = new Date();
|
|
today.setHours(23, 59, 59, 999); // End of today
|
|
|
|
if (selectedDate > today) {
|
|
errors.push("Approval date cannot be in the future");
|
|
isValid = false;
|
|
}
|
|
}
|
|
|
|
// Show validation results
|
|
if (errors.length > 0) {
|
|
showError(`Please fix the following errors:\n• ${errors.join("\n• ")}`);
|
|
} else {
|
|
showSuccess("Form validation passed! Ready to submit approval decision.");
|
|
}
|
|
|
|
return isValid;
|
|
};
|
|
|
|
// Set up field change handlers
|
|
onFieldChange("manager_decision", (newValue) => {
|
|
if (newValue) {
|
|
handleDecisionChange(newValue);
|
|
}
|
|
});
|
|
|
|
onFieldChange("custom_approved_amount", (newValue) => {
|
|
if (newValue) {
|
|
validateCustomAmount(newValue);
|
|
}
|
|
});
|
|
|
|
onFieldChange("manager_comments", (newValue) => {
|
|
const decision = getField("manager_decision");
|
|
if (newValue && decision) {
|
|
validateComments(newValue, decision);
|
|
}
|
|
});
|
|
|
|
onFieldChange("manager_name", (newValue) => {
|
|
if (newValue && typeof newValue === "string") {
|
|
const formatted = formatManagerName(newValue);
|
|
if (formatted !== newValue) {
|
|
setTimeout(() => {
|
|
setField("manager_name", formatted);
|
|
}, 100);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Wait until all required fields are present before running initialization
|
|
function waitForFields(fields, callback, maxAttempts = 20) {
|
|
let attempts = 0;
|
|
function check() {
|
|
const allPresent = fields.every((f) => getField(f) !== undefined);
|
|
if (allPresent) {
|
|
callback();
|
|
} else if (attempts < maxAttempts) {
|
|
attempts++;
|
|
setTimeout(check, 100);
|
|
} else {
|
|
showError("Some required fields are missing. Please reload the page.");
|
|
}
|
|
}
|
|
check();
|
|
}
|
|
|
|
waitForFields(
|
|
[
|
|
"total_cost_display",
|
|
"policy_limit_display",
|
|
"over_budget_amount",
|
|
// add any other required fields here
|
|
],
|
|
() => {
|
|
setApprovalDate();
|
|
calculateRecommendedAmounts();
|
|
showInfo(
|
|
"Review the claim details above and make your approval decision below."
|
|
);
|
|
}
|
|
);
|
|
|
|
// Expose validation function for form submission
|
|
window.validateManagerApprovalForm = validateApprovalForm;
|
|
|
|
console.log("Manager Approval Form Script initialized successfully");
|
|
|
|
// Conditional logic for field: custom_approved_amount
|
|
onFieldChange("manager_decision", function () {
|
|
if (getField("manager_decision") === "approve_full") {
|
|
showField("custom_approved_amount");
|
|
} else {
|
|
hideField("custom_approved_amount");
|
|
}
|
|
});
|
|
|
|
// Initial evaluation for field: custom_approved_amount
|
|
(function () {
|
|
if (getField("manager_decision") === "approve_full") {
|
|
showField("custom_approved_amount");
|
|
} else {
|
|
hideField("custom_approved_amount");
|
|
}
|
|
})();
|
|
|
|
// Conditional Logic Script
|
|
|
|
// Conditional logic for field: custom_approved_amount
|
|
onFieldChange("manager_decision", function () {
|
|
if (getField("manager_decision") === "approve_full") {
|
|
showField("custom_approved_amount");
|
|
} else {
|
|
hideField("custom_approved_amount");
|
|
}
|
|
});
|
|
|
|
// Initial evaluation for field: custom_approved_amount
|
|
(function () {
|
|
if (getField("manager_decision") === "approve_full") {
|
|
showField("custom_approved_amount");
|
|
} else {
|
|
hideField("custom_approved_amount");
|
|
}
|
|
})();
|