// 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_display')) || 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); } } }); // Initialize form on load setTimeout(() => { setApprovalDate(); calculateRecommendedAmounts(); // Make display fields read-only by adding visual styling const displayFields = [ 'claim_summary', 'employee_name_display', 'department_display', 'trip_purpose_display', 'destination_display', 'total_cost_display', 'policy_limit_display', 'over_budget_amount_display' ]; displayFields.forEach(fieldName => { const fieldElement = document.querySelector(`[data-name="${fieldName}"] input`); if (fieldElement) { fieldElement.style.backgroundColor = '#f3f4f6'; fieldElement.style.cursor = 'not-allowed'; fieldElement.readOnly = true; } }); showInfo('Review the claim details above and make your approval decision below.'); }, 1000); // Expose validation function for form submission window.validateManagerApprovalForm = validateApprovalForm; console.log('Manager Approval Form Script initialized successfully');