Refactor Travel Workflow Components and Update Form Logic
- 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.
This commit is contained in:
parent
84e32e4dc7
commit
597a443453
@ -518,8 +518,7 @@ const variableForm = ref({
|
|||||||
// Variable type options with descriptions
|
// Variable type options with descriptions
|
||||||
const variableTypes = [
|
const variableTypes = [
|
||||||
{ label: 'String - Text values', value: 'string' },
|
{ label: 'String - Text values', value: 'string' },
|
||||||
{ label: 'Int - Whole numbers', value: 'int' },
|
{ label: 'Number - Decimal numbers', value: 'number' },
|
||||||
{ label: 'Decimal - Decimal numbers', value: 'decimal' },
|
|
||||||
{ label: 'Object - Complex data structure', value: 'object' },
|
{ label: 'Object - Complex data structure', value: 'object' },
|
||||||
{ label: 'DateTime - Date and time values', value: 'datetime' },
|
{ label: 'DateTime - Date and time values', value: 'datetime' },
|
||||||
{ label: 'Date - Date values only', value: 'date' },
|
{ label: 'Date - Date values only', value: 'date' },
|
||||||
|
@ -14,7 +14,7 @@ const setApprovalDate = () => {
|
|||||||
const calculateRecommendedAmounts = () => {
|
const calculateRecommendedAmounts = () => {
|
||||||
const totalClaimed = parseFloat(getField("total_cost_display")) || 0;
|
const totalClaimed = parseFloat(getField("total_cost_display")) || 0;
|
||||||
const policyLimit = parseFloat(getField("policy_limit_display")) || 0;
|
const policyLimit = parseFloat(getField("policy_limit_display")) || 0;
|
||||||
const overBudget = parseFloat(getField("over_budget_amount_display")) || 0;
|
const overBudget = parseFloat(getField("over_budget_amount")) || 0;
|
||||||
|
|
||||||
if (totalClaimed > 0 && policyLimit > 0) {
|
if (totalClaimed > 0 && policyLimit > 0) {
|
||||||
const percentageOver = ((overBudget / policyLimit) * 100).toFixed(1);
|
const percentageOver = ((overBudget / policyLimit) * 100).toFixed(1);
|
||||||
@ -222,7 +222,7 @@ onFieldChange("manager_name", (newValue) => {
|
|||||||
function waitForFields(fields, callback, maxAttempts = 20) {
|
function waitForFields(fields, callback, maxAttempts = 20) {
|
||||||
let attempts = 0;
|
let attempts = 0;
|
||||||
function check() {
|
function check() {
|
||||||
const allPresent = fields.every(f => getField(f) !== undefined);
|
const allPresent = fields.every((f) => getField(f) !== undefined);
|
||||||
if (allPresent) {
|
if (allPresent) {
|
||||||
callback();
|
callback();
|
||||||
} else if (attempts < maxAttempts) {
|
} else if (attempts < maxAttempts) {
|
||||||
@ -239,13 +239,15 @@ waitForFields(
|
|||||||
[
|
[
|
||||||
"total_cost_display",
|
"total_cost_display",
|
||||||
"policy_limit_display",
|
"policy_limit_display",
|
||||||
"over_budget_amount_display",
|
"over_budget_amount",
|
||||||
// add any other required fields here
|
// add any other required fields here
|
||||||
],
|
],
|
||||||
() => {
|
() => {
|
||||||
setApprovalDate();
|
setApprovalDate();
|
||||||
calculateRecommendedAmounts();
|
calculateRecommendedAmounts();
|
||||||
showInfo("Review the claim details above and make your approval decision below.");
|
showInfo(
|
||||||
|
"Review the claim details above and make your approval decision below."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -271,3 +273,23 @@ onFieldChange("manager_decision", function () {
|
|||||||
hideField("custom_approved_amount");
|
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");
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"label": "Claim Summary",
|
"label": "Claim Summary",
|
||||||
"width": "100%",
|
"width": "100%",
|
||||||
|
"readonly": true,
|
||||||
"gridColumn": "span 12",
|
"gridColumn": "span 12",
|
||||||
"validation": "",
|
"validation": "",
|
||||||
"placeholder": "Claim summary will be populated from process",
|
"placeholder": "Claim summary will be populated from process",
|
||||||
@ -73,6 +74,7 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"label": "Employee Name",
|
"label": "Employee Name",
|
||||||
"width": "50%",
|
"width": "50%",
|
||||||
|
"readonly": true,
|
||||||
"gridColumn": "span 6",
|
"gridColumn": "span 6",
|
||||||
"validation": "",
|
"validation": "",
|
||||||
"placeholder": "Employee name",
|
"placeholder": "Employee name",
|
||||||
@ -92,6 +94,7 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"label": "Department",
|
"label": "Department",
|
||||||
"width": "50%",
|
"width": "50%",
|
||||||
|
"readonly": true,
|
||||||
"gridColumn": "span 6",
|
"gridColumn": "span 6",
|
||||||
"validation": "",
|
"validation": "",
|
||||||
"placeholder": "Department",
|
"placeholder": "Department",
|
||||||
@ -111,6 +114,7 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"label": "Trip Purpose",
|
"label": "Trip Purpose",
|
||||||
"width": "50%",
|
"width": "50%",
|
||||||
|
"readonly": true,
|
||||||
"gridColumn": "span 6",
|
"gridColumn": "span 6",
|
||||||
"validation": "",
|
"validation": "",
|
||||||
"placeholder": "Trip purpose",
|
"placeholder": "Trip purpose",
|
||||||
@ -130,6 +134,7 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"label": "Destination",
|
"label": "Destination",
|
||||||
"width": "50%",
|
"width": "50%",
|
||||||
|
"readonly": true,
|
||||||
"gridColumn": "span 6",
|
"gridColumn": "span 6",
|
||||||
"validation": "",
|
"validation": "",
|
||||||
"placeholder": "Destination",
|
"placeholder": "Destination",
|
||||||
@ -165,9 +170,16 @@
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"label": "Total Claimed Amount (RM)",
|
"label": "Total Claimed Amount (RM)",
|
||||||
"width": "33.33%",
|
"width": "33.33%",
|
||||||
|
"readonly": true,
|
||||||
"gridColumn": "span 4",
|
"gridColumn": "span 4",
|
||||||
"validation": "",
|
"validation": "",
|
||||||
"placeholder": "0.00"
|
"placeholder": "0.00",
|
||||||
|
"conditionalLogic": {
|
||||||
|
"action": "show",
|
||||||
|
"enabled": false,
|
||||||
|
"operator": "and",
|
||||||
|
"conditions": []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -178,22 +190,36 @@
|
|||||||
"type": "number",
|
"type": "number",
|
||||||
"label": "Policy Limit (RM)",
|
"label": "Policy Limit (RM)",
|
||||||
"width": "33.33%",
|
"width": "33.33%",
|
||||||
|
"readonly": true,
|
||||||
"gridColumn": "span 4",
|
"gridColumn": "span 4",
|
||||||
"validation": "",
|
"validation": "",
|
||||||
"placeholder": "0.00"
|
"placeholder": "0.00",
|
||||||
|
"conditionalLogic": {
|
||||||
|
"action": "show",
|
||||||
|
"enabled": false,
|
||||||
|
"operator": "and",
|
||||||
|
"conditions": []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"props": {
|
"props": {
|
||||||
"help": "Amount exceeding policy limits",
|
"help": "Amount exceeding policy limits",
|
||||||
"name": "over_budget_amount_display",
|
"name": "over_budget_amount",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"label": "Over Budget Amount (RM)",
|
"label": "Over Budget Amount (RM)",
|
||||||
"width": "33.33%",
|
"width": "33.33%",
|
||||||
|
"readonly": true,
|
||||||
"gridColumn": "span 4",
|
"gridColumn": "span 4",
|
||||||
"validation": "",
|
"validation": "",
|
||||||
"placeholder": "0.00"
|
"placeholder": "0.00",
|
||||||
|
"conditionalLogic": {
|
||||||
|
"action": "show",
|
||||||
|
"enabled": false,
|
||||||
|
"operator": "and",
|
||||||
|
"conditions": []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -55,50 +55,6 @@
|
|||||||
"sourceHandle": "script-1753000005-right",
|
"sourceHandle": "script-1753000005-right",
|
||||||
"targetHandle": "gateway-1753000006-left"
|
"targetHandle": "gateway-1753000006-left"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"id": "gateway-1753000006-form-1753000007-edge",
|
|
||||||
"data": { "condition": "isOverBudget === true" },
|
|
||||||
"type": "custom",
|
|
||||||
"label": "Requires Approval",
|
|
||||||
"source": "gateway-1753000006",
|
|
||||||
"target": "form-1753000007",
|
|
||||||
"animated": true,
|
|
||||||
"sourceHandle": "gateway-1753000006-top",
|
|
||||||
"targetHandle": "form-1753000007-left"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "gateway-1753000006-script-1753000008-edge",
|
|
||||||
"data": { "condition": "isOverBudget === false" },
|
|
||||||
"type": "custom",
|
|
||||||
"label": "Auto Approve",
|
|
||||||
"source": "gateway-1753000006",
|
|
||||||
"target": "script-1753000008",
|
|
||||||
"animated": true,
|
|
||||||
"sourceHandle": "gateway-1753000006-bottom",
|
|
||||||
"targetHandle": "script-1753000008-left"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "form-1753000007-script-1753000009-edge",
|
|
||||||
"data": {},
|
|
||||||
"type": "custom",
|
|
||||||
"label": "",
|
|
||||||
"source": "form-1753000007",
|
|
||||||
"target": "script-1753000009",
|
|
||||||
"animated": true,
|
|
||||||
"sourceHandle": "form-1753000007-right",
|
|
||||||
"targetHandle": "script-1753000009-left"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "script-1753000008-notification-1753000010-edge",
|
|
||||||
"data": {},
|
|
||||||
"type": "custom",
|
|
||||||
"label": "",
|
|
||||||
"source": "script-1753000008",
|
|
||||||
"target": "notification-1753000010",
|
|
||||||
"animated": true,
|
|
||||||
"sourceHandle": "script-1753000008-right",
|
|
||||||
"targetHandle": "notification-1753000010-left"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"id": "script-1753000009-notification-1753000011-edge",
|
"id": "script-1753000009-notification-1753000011-edge",
|
||||||
"data": {},
|
"data": {},
|
||||||
@ -131,6 +87,50 @@
|
|||||||
"animated": true,
|
"animated": true,
|
||||||
"sourceHandle": "notification-1753000011-bottom",
|
"sourceHandle": "notification-1753000011-bottom",
|
||||||
"targetHandle": "end-1753000012-top"
|
"targetHandle": "end-1753000012-top"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "form-1753000007-script-set-approved-amount-1753423747167",
|
||||||
|
"data": {},
|
||||||
|
"type": "custom",
|
||||||
|
"label": "",
|
||||||
|
"source": "form-1753000007",
|
||||||
|
"target": "script-set-approved-amount",
|
||||||
|
"animated": true,
|
||||||
|
"sourceHandle": "form-1753000007-right",
|
||||||
|
"targetHandle": "script-set-approved-amount-left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "script-set-approved-amount-script-1753000009-1753423748408",
|
||||||
|
"data": {},
|
||||||
|
"type": "custom",
|
||||||
|
"label": "",
|
||||||
|
"source": "script-set-approved-amount",
|
||||||
|
"target": "script-1753000009",
|
||||||
|
"animated": true,
|
||||||
|
"sourceHandle": "script-set-approved-amount-right",
|
||||||
|
"targetHandle": "script-1753000009-left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "gateway-1753000006-form-1753000007-1753423756117",
|
||||||
|
"data": {},
|
||||||
|
"type": "custom",
|
||||||
|
"label": "Requires Approval",
|
||||||
|
"source": "gateway-1753000006",
|
||||||
|
"target": "form-1753000007",
|
||||||
|
"animated": true,
|
||||||
|
"sourceHandle": "gateway-1753000006-right",
|
||||||
|
"targetHandle": "form-1753000007-left"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "gateway-1753000006-notification-1753000010-1753423759335",
|
||||||
|
"data": {},
|
||||||
|
"type": "custom",
|
||||||
|
"label": "Auto Approve",
|
||||||
|
"source": "gateway-1753000006",
|
||||||
|
"target": "notification-1753000010",
|
||||||
|
"animated": true,
|
||||||
|
"sourceHandle": "gateway-1753000006-right",
|
||||||
|
"targetHandle": "notification-1753000010-left"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"nodes": [
|
"nodes": [
|
||||||
@ -138,14 +138,14 @@
|
|||||||
"id": "start-1753000001",
|
"id": "start-1753000001",
|
||||||
"data": {
|
"data": {
|
||||||
"label": "Start Travel Claim",
|
"label": "Start Travel Claim",
|
||||||
"description": "Employee initiates travel reimbursement claim",
|
|
||||||
"shape": "circle",
|
"shape": "circle",
|
||||||
"backgroundColor": "#dcfce7",
|
"borderColor": "#10b981",
|
||||||
"borderColor": "#10b981"
|
"description": "Employee initiates travel reimbursement claim",
|
||||||
|
"backgroundColor": "#dcfce7"
|
||||||
},
|
},
|
||||||
"type": "start",
|
"type": "start",
|
||||||
"label": "Start Travel Claim",
|
"label": "Start Travel Claim",
|
||||||
"position": { "x": 100, "y": 300 }
|
"position": { "x": 105, "y": 300 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "form-1753000002",
|
"id": "form-1753000002",
|
||||||
@ -159,7 +159,11 @@
|
|||||||
"borderColor": "#9333ea",
|
"borderColor": "#9333ea",
|
||||||
"description": "Employee fills travel reimbursement claim form",
|
"description": "Employee fills travel reimbursement claim form",
|
||||||
"assignedRoles": [
|
"assignedRoles": [
|
||||||
{ "label": "Employee", "value": "3", "description": "Regular employee role" }
|
{
|
||||||
|
"label": "Employee",
|
||||||
|
"value": "3",
|
||||||
|
"description": "Regular employee role"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"assignedUsers": [],
|
"assignedUsers": [],
|
||||||
"inputMappings": [],
|
"inputMappings": [],
|
||||||
@ -174,7 +178,10 @@
|
|||||||
{ "formField": "return_date", "processVariable": "returnDate" },
|
{ "formField": "return_date", "processVariable": "returnDate" },
|
||||||
{ "formField": "travel_type", "processVariable": "travelType" },
|
{ "formField": "travel_type", "processVariable": "travelType" },
|
||||||
{ "formField": "transport_cost", "processVariable": "transportCost" },
|
{ "formField": "transport_cost", "processVariable": "transportCost" },
|
||||||
{ "formField": "accommodation_cost", "processVariable": "accommodationCost" },
|
{
|
||||||
|
"formField": "accommodation_cost",
|
||||||
|
"processVariable": "accommodationCost"
|
||||||
|
},
|
||||||
{ "formField": "meals_cost", "processVariable": "mealsCost" },
|
{ "formField": "meals_cost", "processVariable": "mealsCost" },
|
||||||
{ "formField": "other_cost", "processVariable": "otherCost" },
|
{ "formField": "other_cost", "processVariable": "otherCost" },
|
||||||
{ "formField": "has_receipts", "processVariable": "hasReceipts" }
|
{ "formField": "has_receipts", "processVariable": "hasReceipts" }
|
||||||
@ -186,7 +193,7 @@
|
|||||||
},
|
},
|
||||||
"type": "form",
|
"type": "form",
|
||||||
"label": "Travel Claim Form",
|
"label": "Travel Claim Form",
|
||||||
"position": { "x": 400, "y": 270 }
|
"position": { "x": 405, "y": 270 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "script-1753000003",
|
"id": "script-1753000003",
|
||||||
@ -198,8 +205,15 @@
|
|||||||
"borderColor": "#6b7280",
|
"borderColor": "#6b7280",
|
||||||
"description": "Validate form data and calculate totals",
|
"description": "Validate form data and calculate totals",
|
||||||
"inputVariables": [
|
"inputVariables": [
|
||||||
"employeeName", "tripPurpose", "destination", "transportCost",
|
"employeeName",
|
||||||
"accommodationCost", "mealsCost", "otherCost", "departureDate", "returnDate"
|
"tripPurpose",
|
||||||
|
"destination",
|
||||||
|
"transportCost",
|
||||||
|
"accommodationCost",
|
||||||
|
"mealsCost",
|
||||||
|
"otherCost",
|
||||||
|
"departureDate",
|
||||||
|
"returnDate"
|
||||||
],
|
],
|
||||||
"scriptLanguage": "javascript",
|
"scriptLanguage": "javascript",
|
||||||
"backgroundColor": "#f9fafb",
|
"backgroundColor": "#f9fafb",
|
||||||
@ -260,7 +274,7 @@
|
|||||||
},
|
},
|
||||||
"type": "api",
|
"type": "api",
|
||||||
"label": "Get Policy Rates",
|
"label": "Get Policy Rates",
|
||||||
"position": { "x": 1100, "y": 270 }
|
"position": { "x": 1095, "y": 270 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "script-1753000005",
|
"id": "script-1753000005",
|
||||||
@ -271,7 +285,12 @@
|
|||||||
"scriptCode": "// Process policy API response\nconst policyResponse = processVariables.policyApiResponse || {};\n\n// Mock policy rates based on travel type (in real system, would come from API)\nlet maxTransport = 0, maxAccommodation = 0, maxMeals = 0, maxOther = 0;\n\nswitch(processVariables.travelType) {\n case 'flight':\n maxTransport = 2000;\n maxAccommodation = 300 * processVariables.tripDuration;\n maxMeals = 150 * processVariables.tripDuration;\n maxOther = 100 * processVariables.tripDuration;\n break;\n case 'train':\n maxTransport = 500;\n maxAccommodation = 250 * processVariables.tripDuration;\n maxMeals = 120 * processVariables.tripDuration;\n maxOther = 80 * processVariables.tripDuration;\n break;\n case 'car':\n maxTransport = 800;\n maxAccommodation = 200 * processVariables.tripDuration;\n maxMeals = 100 * processVariables.tripDuration;\n maxOther = 60 * processVariables.tripDuration;\n break;\n default:\n maxTransport = 300;\n maxAccommodation = 150 * processVariables.tripDuration;\n maxMeals = 80 * processVariables.tripDuration;\n maxOther = 50 * processVariables.tripDuration;\n}\n\n// Calculate allowed amounts\nprocessVariables.allowedTransport = Math.min(processVariables.transportCost, maxTransport);\nprocessVariables.allowedAccommodation = Math.min(processVariables.accommodationCost, maxAccommodation);\nprocessVariables.allowedMeals = Math.min(processVariables.mealsCost, maxMeals);\nprocessVariables.allowedOther = Math.min(processVariables.otherCost, maxOther);\n\n// Calculate total allowed and reimbursement\nprocessVariables.totalAllowed = processVariables.allowedTransport + processVariables.allowedAccommodation + processVariables.allowedMeals + processVariables.allowedOther;\nprocessVariables.reimbursementAmount = processVariables.totalAllowed;\n\n// Check if over budget\nprocessVariables.isOverBudget = processVariables.totalCost > processVariables.totalAllowed;\nprocessVariables.overBudgetAmount = Math.max(0, processVariables.totalCost - processVariables.totalAllowed);\n\n// Create claim summary\nprocessVariables.claimSummary = `Travel Claim - ${processVariables.employeeName} - ${processVariables.tripPurpose} - ${processVariables.destination} - RM${processVariables.reimbursementAmount.toFixed(2)} reimbursement`;\n\n// Set initial approval status\nprocessVariables.approvalStatus = processVariables.isOverBudget ? 'pending_approval' : 'auto_approved';",
|
"scriptCode": "// Process policy API response\nconst policyResponse = processVariables.policyApiResponse || {};\n\n// Mock policy rates based on travel type (in real system, would come from API)\nlet maxTransport = 0, maxAccommodation = 0, maxMeals = 0, maxOther = 0;\n\nswitch(processVariables.travelType) {\n case 'flight':\n maxTransport = 2000;\n maxAccommodation = 300 * processVariables.tripDuration;\n maxMeals = 150 * processVariables.tripDuration;\n maxOther = 100 * processVariables.tripDuration;\n break;\n case 'train':\n maxTransport = 500;\n maxAccommodation = 250 * processVariables.tripDuration;\n maxMeals = 120 * processVariables.tripDuration;\n maxOther = 80 * processVariables.tripDuration;\n break;\n case 'car':\n maxTransport = 800;\n maxAccommodation = 200 * processVariables.tripDuration;\n maxMeals = 100 * processVariables.tripDuration;\n maxOther = 60 * processVariables.tripDuration;\n break;\n default:\n maxTransport = 300;\n maxAccommodation = 150 * processVariables.tripDuration;\n maxMeals = 80 * processVariables.tripDuration;\n maxOther = 50 * processVariables.tripDuration;\n}\n\n// Calculate allowed amounts\nprocessVariables.allowedTransport = Math.min(processVariables.transportCost, maxTransport);\nprocessVariables.allowedAccommodation = Math.min(processVariables.accommodationCost, maxAccommodation);\nprocessVariables.allowedMeals = Math.min(processVariables.mealsCost, maxMeals);\nprocessVariables.allowedOther = Math.min(processVariables.otherCost, maxOther);\n\n// Calculate total allowed and reimbursement\nprocessVariables.totalAllowed = processVariables.allowedTransport + processVariables.allowedAccommodation + processVariables.allowedMeals + processVariables.allowedOther;\nprocessVariables.reimbursementAmount = processVariables.totalAllowed;\n\n// Check if over budget\nprocessVariables.isOverBudget = processVariables.totalCost > processVariables.totalAllowed;\nprocessVariables.overBudgetAmount = Math.max(0, processVariables.totalCost - processVariables.totalAllowed);\n\n// Create claim summary\nprocessVariables.claimSummary = `Travel Claim - ${processVariables.employeeName} - ${processVariables.tripPurpose} - ${processVariables.destination} - RM${processVariables.reimbursementAmount.toFixed(2)} reimbursement`;\n\n// Set initial approval status\nprocessVariables.approvalStatus = processVariables.isOverBudget ? 'pending_approval' : 'auto_approved';",
|
||||||
"borderColor": "#6b7280",
|
"borderColor": "#6b7280",
|
||||||
"description": "Calculate reimbursement based on policy rates",
|
"description": "Calculate reimbursement based on policy rates",
|
||||||
"inputVariables": ["policyApiResponse", "totalCost", "travelType", "tripDuration"],
|
"inputVariables": [
|
||||||
|
"policyApiResponse",
|
||||||
|
"totalCost",
|
||||||
|
"travelType",
|
||||||
|
"tripDuration"
|
||||||
|
],
|
||||||
"scriptLanguage": "javascript",
|
"scriptLanguage": "javascript",
|
||||||
"backgroundColor": "#f9fafb",
|
"backgroundColor": "#f9fafb",
|
||||||
"outputVariables": [
|
"outputVariables": [
|
||||||
@ -309,7 +328,7 @@
|
|||||||
},
|
},
|
||||||
"type": "script",
|
"type": "script",
|
||||||
"label": "Calculate Reimbursement",
|
"label": "Calculate Reimbursement",
|
||||||
"position": { "x": 1450, "y": 270 }
|
"position": { "x": 1455, "y": 270 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "gateway-1753000006",
|
"id": "gateway-1753000006",
|
||||||
@ -358,7 +377,7 @@
|
|||||||
},
|
},
|
||||||
"type": "gateway",
|
"type": "gateway",
|
||||||
"label": "Budget Check",
|
"label": "Budget Check",
|
||||||
"position": { "x": 1800, "y": 270 }
|
"position": { "x": 1755, "y": 330 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "form-1753000007",
|
"id": "form-1753000007",
|
||||||
@ -368,71 +387,68 @@
|
|||||||
"formId": 3,
|
"formId": 3,
|
||||||
"formName": "Travel Claim Approval Form",
|
"formName": "Travel Claim Approval Form",
|
||||||
"formUuid": "travel-approval-form-uuid",
|
"formUuid": "travel-approval-form-uuid",
|
||||||
"textColor": "#dc2626",
|
"textColor": "#6b21a8",
|
||||||
"borderColor": "#ef4444",
|
"borderColor": "#9333ea",
|
||||||
"description": "Manager reviews and approves/rejects over-budget travel claim",
|
"description": "Manager reviews and approves/rejects over-budget travel claim",
|
||||||
"assignedRoles": [
|
"assignedRoles": [
|
||||||
{ "label": "Manager", "value": "4", "description": "Department manager role" }
|
{
|
||||||
|
"label": "Manager",
|
||||||
|
"value": "4",
|
||||||
|
"description": "Department manager role"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"assignedUsers": [],
|
"assignedUsers": [],
|
||||||
"inputMappings": [
|
"inputMappings": [
|
||||||
{ "processVariable": "claimSummary", "formField": "claim_summary" },
|
{ "formField": "claim_summary", "processVariable": "claimSummary" },
|
||||||
{ "processVariable": "totalCost", "formField": "total_cost_display" },
|
{
|
||||||
{ "processVariable": "overBudgetAmount", "formField": "over_budget_amount_display" },
|
"formField": "employee_name_display",
|
||||||
{ "processVariable": "totalAllowed", "formField": "policy_limit_display" }
|
"processVariable": "employeeName"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"formField": "department_display",
|
||||||
|
"processVariable": "department"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"formField": "trip_purpose_display",
|
||||||
|
"processVariable": "tripPurpose"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"formField": "destination_display",
|
||||||
|
"processVariable": "destination"
|
||||||
|
},
|
||||||
|
{ "formField": "total_cost_display", "processVariable": "totalCost" },
|
||||||
|
{
|
||||||
|
"formField": "policy_limit_display",
|
||||||
|
"processVariable": "totalAllowed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"formField": "over_budget_amount",
|
||||||
|
"processVariable": "overBudgetAmount"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"assignmentType": "roles",
|
"assignmentType": "roles",
|
||||||
"outputMappings": [
|
"outputMappings": [
|
||||||
{ "formField": "manager_decision", "processVariable": "managerDecision" },
|
{
|
||||||
{ "formField": "manager_comments", "processVariable": "managerComments" }
|
"formField": "manager_decision",
|
||||||
|
"processVariable": "managerDecision"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"formField": "manager_comments",
|
||||||
|
"processVariable": "managerComments"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"formField": "custom_approved_amount",
|
||||||
|
"processVariable": "customApprovedAmount"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"backgroundColor": "#fef2f2",
|
"backgroundColor": "#faf5ff",
|
||||||
"fieldConditions": [],
|
"fieldConditions": [],
|
||||||
"assignmentVariable": "",
|
"assignmentVariable": "",
|
||||||
"assignmentVariableType": "user_id"
|
"assignmentVariableType": "user_id"
|
||||||
},
|
},
|
||||||
"type": "form",
|
"type": "form",
|
||||||
"label": "Manager Approval",
|
"label": "Manager Approval",
|
||||||
"position": { "x": 2150, "y": 100 }
|
"position": { "x": 1980, "y": 105 }
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "script-1753000008",
|
|
||||||
"data": {
|
|
||||||
"label": "Auto Approve & Store",
|
|
||||||
"shape": "rectangle",
|
|
||||||
"textColor": "#374151",
|
|
||||||
"scriptCode": "// Auto-approve claim within budget\nprocessVariables.finalApprovalStatus = 'approved';\nprocessVariables.approvedAmount = processVariables.reimbursementAmount;\nprocessVariables.approvalTimestamp = new Date().toISOString();\nprocessVariables.approvedBy = 'System (Auto-approved)';\nprocessVariables.approvalComments = 'Claim is within policy limits and auto-approved.';\n\n// Create final claim record for storage\nprocessVariables.finalClaimRecord = {\n employeeName: processVariables.employeeName,\n employeeEmail: processVariables.employeeEmail,\n department: processVariables.department,\n tripPurpose: processVariables.tripPurpose,\n destination: processVariables.destination,\n totalClaimed: processVariables.totalCost,\n approvedAmount: processVariables.approvedAmount,\n status: processVariables.finalApprovalStatus,\n submissionDate: processVariables.submissionTimestamp,\n approvalDate: processVariables.approvalTimestamp,\n approvedBy: processVariables.approvedBy\n};\n\n// Mock API call to store claim (in real system, would call actual storage API)\nprocessVariables.claimId = 'CLAIM-' + Date.now();\nprocessVariables.storageResult = 'success';",
|
|
||||||
"borderColor": "#10b981",
|
|
||||||
"description": "Auto-approve claim and store in system",
|
|
||||||
"inputVariables": ["reimbursementAmount", "claimSummary"],
|
|
||||||
"scriptLanguage": "javascript",
|
|
||||||
"backgroundColor": "#f0fdf4",
|
|
||||||
"outputVariables": [
|
|
||||||
{
|
|
||||||
"name": "finalApprovalStatus",
|
|
||||||
"type": "string",
|
|
||||||
"description": "Final approval status"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "approvedAmount",
|
|
||||||
"type": "number",
|
|
||||||
"description": "Final approved amount"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "claimId",
|
|
||||||
"type": "string",
|
|
||||||
"description": "Generated claim ID"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "approvalTimestamp",
|
|
||||||
"type": "string",
|
|
||||||
"description": "When claim was approved"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"type": "script",
|
|
||||||
"label": "Auto Approve & Store",
|
|
||||||
"position": { "x": 2150, "y": 440 }
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "script-1753000009",
|
"id": "script-1753000009",
|
||||||
@ -440,7 +456,7 @@
|
|||||||
"label": "Process Manager Decision",
|
"label": "Process Manager Decision",
|
||||||
"shape": "rectangle",
|
"shape": "rectangle",
|
||||||
"textColor": "#374151",
|
"textColor": "#374151",
|
||||||
"scriptCode": "// Process manager's decision\nprocessVariables.finalApprovalStatus = processVariables.managerDecision === 'approve' ? 'approved' : 'rejected';\nprocessVariables.approvalTimestamp = new Date().toISOString();\nprocessVariables.approvedBy = 'Manager';\nprocessVariables.approvalComments = processVariables.managerComments || '';\n\n// Set approved amount based on decision\nif (processVariables.finalApprovalStatus === 'approved') {\n processVariables.approvedAmount = processVariables.totalCost; // Manager can approve full amount\n} else {\n processVariables.approvedAmount = 0;\n}\n\n// Create final claim record for storage\nprocessVariables.finalClaimRecord = {\n employeeName: processVariables.employeeName,\n employeeEmail: processVariables.employeeEmail,\n department: processVariables.department,\n tripPurpose: processVariables.tripPurpose,\n destination: processVariables.destination,\n totalClaimed: processVariables.totalCost,\n approvedAmount: processVariables.approvedAmount,\n status: processVariables.finalApprovalStatus,\n submissionDate: processVariables.submissionTimestamp,\n approvalDate: processVariables.approvalTimestamp,\n approvedBy: processVariables.approvedBy,\n managerComments: processVariables.approvalComments\n};\n\n// Mock API call to store claim\nprocessVariables.claimId = 'CLAIM-' + Date.now();\nprocessVariables.storageResult = 'success';",
|
"scriptCode": "// Process manager's decision\nconst decision = processVariables.managerDecision;\nconst customAmount = parseFloat(processVariables.customApprovedAmount) || 0;\nconst policyLimit = parseFloat(processVariables.totalAllowed) || 0;\nif (decision === 'approve_full' && customAmount > 0) {\n processVariables.approvedAmount = customAmount;\n} else if (decision === 'approve_policy') {\n processVariables.approvedAmount = policyLimit;\n} else if (decision === 'reject') {\n processVariables.approvedAmount = 0;\n}\nprocessVariables.finalApprovalStatus = processVariables.managerDecision === 'approve' ? 'approved' : 'rejected';\nprocessVariables.approvalTimestamp = new Date().toISOString();\nprocessVariables.approvedBy = 'Manager';\nprocessVariables.approvalComments = processVariables.managerComments || '';\n\n// Set approved amount based on decision\nif (processVariables.finalApprovalStatus === 'approved') {\n processVariables.approvedAmount = processVariables.totalCost; // Manager can approve full amount\n} else {\n processVariables.approvedAmount = 0;\n}\n\n// Create final claim record for storage\nprocessVariables.finalClaimRecord = {\n employeeName: processVariables.employeeName,\n employeeEmail: processVariables.employeeEmail,\n department: processVariables.department,\n tripPurpose: processVariables.tripPurpose,\n destination: processVariables.destination,\n totalClaimed: processVariables.totalCost,\n approvedAmount: processVariables.approvedAmount,\n status: processVariables.finalApprovalStatus,\n submissionDate: processVariables.submissionTimestamp,\n approvalDate: processVariables.approvalTimestamp,\n approvedBy: processVariables.approvedBy,\n managerComments: processVariables.approvalComments\n};\n\n// Mock API call to store claim\nprocessVariables.claimId = 'CLAIM-' + Date.now();\nprocessVariables.storageResult = 'success';",
|
||||||
"borderColor": "#6b7280",
|
"borderColor": "#6b7280",
|
||||||
"description": "Process manager decision and store final result",
|
"description": "Process manager decision and store final result",
|
||||||
"inputVariables": ["managerDecision", "managerComments", "totalCost"],
|
"inputVariables": ["managerDecision", "managerComments", "totalCost"],
|
||||||
@ -471,7 +487,7 @@
|
|||||||
},
|
},
|
||||||
"type": "script",
|
"type": "script",
|
||||||
"label": "Process Manager Decision",
|
"label": "Process Manager Decision",
|
||||||
"position": { "x": 2500, "y": 100 }
|
"position": { "x": 2520, "y": 105 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "notification-1753000010",
|
"id": "notification-1753000010",
|
||||||
@ -487,7 +503,7 @@
|
|||||||
"recipientRole": "",
|
"recipientRole": "",
|
||||||
"recipientType": "email",
|
"recipientType": "email",
|
||||||
"recipientUser": "",
|
"recipientUser": "",
|
||||||
"recipientEmail": "{employeeEmail}",
|
"recipientEmail": "mdafiqiskandar@gmail.com",
|
||||||
"recipientGroup": "",
|
"recipientGroup": "",
|
||||||
"deliveryOptions": { "sms": false, "email": true, "inApp": true },
|
"deliveryOptions": { "sms": false, "email": true, "inApp": true },
|
||||||
"richTextMessage": "",
|
"richTextMessage": "",
|
||||||
@ -496,7 +512,7 @@
|
|||||||
},
|
},
|
||||||
"type": "notification",
|
"type": "notification",
|
||||||
"label": "Auto Approval Notification",
|
"label": "Auto Approval Notification",
|
||||||
"position": { "x": 2500, "y": 440 }
|
"position": { "x": 2265, "y": 375 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "notification-1753000011",
|
"id": "notification-1753000011",
|
||||||
@ -507,12 +523,12 @@
|
|||||||
"priority": "high",
|
"priority": "high",
|
||||||
"expiration": { "unit": "hours", "value": 48, "enabled": false },
|
"expiration": { "unit": "hours", "value": 48, "enabled": false },
|
||||||
"description": "Notify employee of manager's decision",
|
"description": "Notify employee of manager's decision",
|
||||||
"htmlMessage": "<div style=\"font-family: Arial, sans-serif; padding: 20px; border-left: 4px solid #3b82f6;\">\n <h2 style=\"color: #1e40af; margin-top: 0;\">📋 Travel Claim Decision</h2>\n <p>Dear {employeeName},</p>\n <p>Your manager has reviewed your travel reimbursement claim.</p>\n \n <div style=\"background: #eff6ff; padding: 15px; border-radius: 8px; margin: 20px 0;\">\n <h3 style=\"margin-top: 0; color: #1e40af;\">Claim Details:</h3>\n <ul style=\"list-style: none; padding: 0;\">\n <li><strong>Claim ID:</strong> {claimId}</li>\n <li><strong>Trip Purpose:</strong> {tripPurpose}</li>\n <li><strong>Destination:</strong> {destination}</li>\n <li><strong>Total Claimed:</strong> RM{totalCost}</li>\n <li><strong>Approved Amount:</strong> RM{approvedAmount}</li>\n <li><strong>Status:</strong> <span style=\"font-weight: bold; color: {finalApprovalStatus === 'approved' ? '#059669' : '#dc2626'};\">{finalApprovalStatus.toUpperCase()}</span></li>\n </ul>\n </div>\n \n <div style=\"background: #f8fafc; padding: 15px; border-radius: 8px; margin: 20px 0;\">\n <h4 style=\"margin-top: 0;\">Manager Comments:</h4>\n <p style=\"font-style: italic;\">{approvalComments}</p>\n </div>\n \n <p>If approved, your reimbursement will be processed within 3-5 business days.</p>\n \n <p style=\"margin-bottom: 0;\">Best regards,<br>\n <strong>Travel Management System</strong></p>\n</div>",
|
"htmlMessage": "<div style=\"font-family: Arial, sans-serif; padding: 20px; border-left: 4px solid #3b82f6;\">\n <h2 style=\"color: #1e40af; margin-top: 0;\">📋 Travel Claim Decision</h2>\n <p>Dear {employeeName},</p>\n <p>Your manager has reviewed your travel reimbursement claim.</p>\n \n <div style=\"background: #eff6ff; padding: 15px; border-radius: 8px; margin: 20px 0;\">\n <h3 style=\"margin-top: 0; color: #1e40af;\">Claim Details:</h3>\n <ul style=\"list-style: none; padding: 0;\">\n <li><strong>Claim ID:</strong> {claimId}</li>\n <li><strong>Trip Purpose:</strong> {tripPurpose}</li>\n <li><strong>Destination:</strong> {destination}</li>\n <li><strong>Total Claimed:</strong> RM{totalCost}</li>\n <li><strong>Approved Amount:</strong> RM{approvedAmount}</li>\n <li><strong>Status:</strong> <span style=\"font-weight: bold;\">{finalApprovalStatus}</span></li>\n </ul>\n </div>\n \n <div style=\"background: #f8fafc; padding: 15px; border-radius: 8px; margin: 20px 0;\">\n <h4 style=\"margin-top: 0;\">Manager Comments:</h4>\n <p style=\"font-style: italic;\">{approvalComments}</p>\n </div>\n \n <p>If approved, your reimbursement will be processed within 3-5 business days.</p>\n \n <p style=\"margin-bottom: 0;\">Best regards,<br>\n <strong>Travel Management System</strong></p>\n</div>",
|
||||||
"messageFormat": "html",
|
"messageFormat": "html",
|
||||||
"recipientRole": "",
|
"recipientRole": "",
|
||||||
"recipientType": "email",
|
"recipientType": "email",
|
||||||
"recipientUser": "",
|
"recipientUser": "",
|
||||||
"recipientEmail": "{employeeEmail}",
|
"recipientEmail": "mdafiqiskandar@gmail.com",
|
||||||
"recipientGroup": "",
|
"recipientGroup": "",
|
||||||
"deliveryOptions": { "sms": false, "email": true, "inApp": true },
|
"deliveryOptions": { "sms": false, "email": true, "inApp": true },
|
||||||
"richTextMessage": "",
|
"richTextMessage": "",
|
||||||
@ -521,25 +537,25 @@
|
|||||||
},
|
},
|
||||||
"type": "notification",
|
"type": "notification",
|
||||||
"label": "Manager Decision Notification",
|
"label": "Manager Decision Notification",
|
||||||
"position": { "x": 2850, "y": 100 }
|
"position": { "x": 2850, "y": 105 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "end-1753000012",
|
"id": "end-1753000012",
|
||||||
"data": {
|
"data": {
|
||||||
"label": "End",
|
"label": "End",
|
||||||
"description": "Travel claim process completed",
|
|
||||||
"shape": "circle",
|
"shape": "circle",
|
||||||
"backgroundColor": "#fef3c7",
|
"borderColor": "#f59e0b",
|
||||||
"borderColor": "#f59e0b"
|
"description": "Travel claim process completed",
|
||||||
|
"backgroundColor": "#fef3c7"
|
||||||
},
|
},
|
||||||
"type": "end",
|
"type": "end",
|
||||||
"label": "End",
|
"label": "End",
|
||||||
"position": { "x": 3200, "y": 300 }
|
"position": { "x": 3195, "y": 300 }
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"viewport": {
|
"viewport": {
|
||||||
"x": -50,
|
"x": -1535.387843430428,
|
||||||
"y": 50,
|
"y": 250.2076943977823,
|
||||||
"zoom": 0.6
|
"zoom": 0.8368461998102432
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,73 +1,10 @@
|
|||||||
{
|
{
|
||||||
"employeeName": {
|
"claimId": {
|
||||||
"name": "employeeName",
|
"name": "claimId",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"scope": "global",
|
"scope": "global",
|
||||||
"value": "",
|
"value": "",
|
||||||
"description": "Full name of the employee submitting the claim"
|
"description": "Unique identifier generated for the claim"
|
||||||
},
|
|
||||||
"employeeEmail": {
|
|
||||||
"name": "employeeEmail",
|
|
||||||
"type": "string",
|
|
||||||
"scope": "global",
|
|
||||||
"value": "",
|
|
||||||
"description": "Email address of the employee for notifications"
|
|
||||||
},
|
|
||||||
"department": {
|
|
||||||
"name": "department",
|
|
||||||
"type": "string",
|
|
||||||
"scope": "global",
|
|
||||||
"value": "",
|
|
||||||
"description": "Employee's department name"
|
|
||||||
},
|
|
||||||
"tripPurpose": {
|
|
||||||
"name": "tripPurpose",
|
|
||||||
"type": "string",
|
|
||||||
"scope": "global",
|
|
||||||
"value": "",
|
|
||||||
"description": "Purpose or reason for the business trip"
|
|
||||||
},
|
|
||||||
"destination": {
|
|
||||||
"name": "destination",
|
|
||||||
"type": "string",
|
|
||||||
"scope": "global",
|
|
||||||
"value": "",
|
|
||||||
"description": "Travel destination city and country"
|
|
||||||
},
|
|
||||||
"departureDate": {
|
|
||||||
"name": "departureDate",
|
|
||||||
"type": "string",
|
|
||||||
"scope": "global",
|
|
||||||
"value": "",
|
|
||||||
"description": "Trip departure date in ISO format"
|
|
||||||
},
|
|
||||||
"returnDate": {
|
|
||||||
"name": "returnDate",
|
|
||||||
"type": "string",
|
|
||||||
"scope": "global",
|
|
||||||
"value": "",
|
|
||||||
"description": "Trip return date in ISO format"
|
|
||||||
},
|
|
||||||
"travelType": {
|
|
||||||
"name": "travelType",
|
|
||||||
"type": "string",
|
|
||||||
"scope": "global",
|
|
||||||
"value": "",
|
|
||||||
"description": "Primary mode of transportation (flight, train, car, bus)"
|
|
||||||
},
|
|
||||||
"transportCost": {
|
|
||||||
"name": "transportCost",
|
|
||||||
"type": "number",
|
|
||||||
"scope": "global",
|
|
||||||
"value": 0,
|
|
||||||
"description": "Transportation expenses claimed"
|
|
||||||
},
|
|
||||||
"accommodationCost": {
|
|
||||||
"name": "accommodationCost",
|
|
||||||
"type": "number",
|
|
||||||
"scope": "global",
|
|
||||||
"value": 0,
|
|
||||||
"description": "Accommodation expenses claimed"
|
|
||||||
},
|
},
|
||||||
"mealsCost": {
|
"mealsCost": {
|
||||||
"name": "mealsCost",
|
"name": "mealsCost",
|
||||||
@ -83,13 +20,6 @@
|
|||||||
"value": 0,
|
"value": 0,
|
||||||
"description": "Other miscellaneous expenses claimed"
|
"description": "Other miscellaneous expenses claimed"
|
||||||
},
|
},
|
||||||
"hasReceipts": {
|
|
||||||
"name": "hasReceipts",
|
|
||||||
"type": "boolean",
|
|
||||||
"scope": "global",
|
|
||||||
"value": false,
|
|
||||||
"description": "Whether employee has all supporting receipts"
|
|
||||||
},
|
|
||||||
"totalCost": {
|
"totalCost": {
|
||||||
"name": "totalCost",
|
"name": "totalCost",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
@ -97,61 +27,54 @@
|
|||||||
"value": 0,
|
"value": 0,
|
||||||
"description": "Total amount claimed (calculated)"
|
"description": "Total amount claimed (calculated)"
|
||||||
},
|
},
|
||||||
"isValidSubmission": {
|
"approvedBy": {
|
||||||
"name": "isValidSubmission",
|
"name": "approvedBy",
|
||||||
|
"type": "string",
|
||||||
|
"scope": "global",
|
||||||
|
"value": "",
|
||||||
|
"description": "Who approved the claim (System/Manager name)"
|
||||||
|
},
|
||||||
|
"department": {
|
||||||
|
"name": "department",
|
||||||
|
"type": "string",
|
||||||
|
"scope": "global",
|
||||||
|
"value": "",
|
||||||
|
"description": "Employee's department name"
|
||||||
|
},
|
||||||
|
"returnDate": {
|
||||||
|
"name": "returnDate",
|
||||||
|
"type": "string",
|
||||||
|
"scope": "global",
|
||||||
|
"value": "",
|
||||||
|
"description": "Trip return date in ISO format"
|
||||||
|
},
|
||||||
|
"travelType": {
|
||||||
|
"name": "travelType",
|
||||||
|
"type": "string",
|
||||||
|
"scope": "global",
|
||||||
|
"value": "",
|
||||||
|
"description": "Primary mode of transportation (flight, train, car, bus)"
|
||||||
|
},
|
||||||
|
"destination": {
|
||||||
|
"name": "destination",
|
||||||
|
"type": "string",
|
||||||
|
"scope": "global",
|
||||||
|
"value": "",
|
||||||
|
"description": "Travel destination city and country"
|
||||||
|
},
|
||||||
|
"hasReceipts": {
|
||||||
|
"name": "hasReceipts",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"scope": "global",
|
"scope": "global",
|
||||||
"value": false,
|
"value": false,
|
||||||
"description": "Whether the form submission passed validation"
|
"description": "Whether employee has all supporting receipts"
|
||||||
},
|
},
|
||||||
"validationError": {
|
"tripPurpose": {
|
||||||
"name": "validationError",
|
"name": "tripPurpose",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"scope": "global",
|
"scope": "global",
|
||||||
"value": "",
|
"value": "",
|
||||||
"description": "Validation error message if submission is invalid"
|
"description": "Purpose or reason for the business trip"
|
||||||
},
|
|
||||||
"tripDuration": {
|
|
||||||
"name": "tripDuration",
|
|
||||||
"type": "number",
|
|
||||||
"scope": "global",
|
|
||||||
"value": 0,
|
|
||||||
"description": "Trip duration in days (calculated)"
|
|
||||||
},
|
|
||||||
"submissionTimestamp": {
|
|
||||||
"name": "submissionTimestamp",
|
|
||||||
"type": "string",
|
|
||||||
"scope": "global",
|
|
||||||
"value": "",
|
|
||||||
"description": "ISO timestamp when claim was submitted"
|
|
||||||
},
|
|
||||||
"policyApiResponse": {
|
|
||||||
"name": "policyApiResponse",
|
|
||||||
"type": "object",
|
|
||||||
"scope": "global",
|
|
||||||
"value": null,
|
|
||||||
"description": "Response from company policy rates API"
|
|
||||||
},
|
|
||||||
"policyApiError": {
|
|
||||||
"name": "policyApiError",
|
|
||||||
"type": "object",
|
|
||||||
"scope": "global",
|
|
||||||
"value": null,
|
|
||||||
"description": "Error from policy API if request fails"
|
|
||||||
},
|
|
||||||
"allowedTransport": {
|
|
||||||
"name": "allowedTransport",
|
|
||||||
"type": "number",
|
|
||||||
"scope": "global",
|
|
||||||
"value": 0,
|
|
||||||
"description": "Maximum allowed transportation reimbursement per policy"
|
|
||||||
},
|
|
||||||
"allowedAccommodation": {
|
|
||||||
"name": "allowedAccommodation",
|
|
||||||
"type": "number",
|
|
||||||
"scope": "global",
|
|
||||||
"value": 0,
|
|
||||||
"description": "Maximum allowed accommodation reimbursement per policy"
|
|
||||||
},
|
},
|
||||||
"allowedMeals": {
|
"allowedMeals": {
|
||||||
"name": "allowedMeals",
|
"name": "allowedMeals",
|
||||||
@ -167,19 +90,19 @@
|
|||||||
"value": 0,
|
"value": 0,
|
||||||
"description": "Maximum allowed other expenses reimbursement per policy"
|
"description": "Maximum allowed other expenses reimbursement per policy"
|
||||||
},
|
},
|
||||||
"totalAllowed": {
|
"claimSummary": {
|
||||||
"name": "totalAllowed",
|
"name": "claimSummary",
|
||||||
"type": "number",
|
"type": "string",
|
||||||
"scope": "global",
|
"scope": "global",
|
||||||
"value": 0,
|
"value": "",
|
||||||
"description": "Total allowed reimbursement according to company policy"
|
"description": "Formatted summary string of the travel claim"
|
||||||
},
|
},
|
||||||
"reimbursementAmount": {
|
"employeeName": {
|
||||||
"name": "reimbursementAmount",
|
"name": "employeeName",
|
||||||
"type": "number",
|
"type": "string",
|
||||||
"scope": "global",
|
"scope": "global",
|
||||||
"value": 0,
|
"value": "",
|
||||||
"description": "Final calculated reimbursement amount"
|
"description": "Full name of the employee submitting the claim"
|
||||||
},
|
},
|
||||||
"isOverBudget": {
|
"isOverBudget": {
|
||||||
"name": "isOverBudget",
|
"name": "isOverBudget",
|
||||||
@ -188,19 +111,47 @@
|
|||||||
"value": false,
|
"value": false,
|
||||||
"description": "Whether claimed amount exceeds policy limits"
|
"description": "Whether claimed amount exceeds policy limits"
|
||||||
},
|
},
|
||||||
"overBudgetAmount": {
|
"totalAllowed": {
|
||||||
"name": "overBudgetAmount",
|
"name": "totalAllowed",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"scope": "global",
|
"scope": "global",
|
||||||
"value": 0,
|
"value": 0,
|
||||||
"description": "Amount by which claim exceeds policy limits"
|
"description": "Total allowed reimbursement according to company policy"
|
||||||
},
|
},
|
||||||
"claimSummary": {
|
"tripDuration": {
|
||||||
"name": "claimSummary",
|
"name": "tripDuration",
|
||||||
|
"type": "number",
|
||||||
|
"scope": "global",
|
||||||
|
"value": 0,
|
||||||
|
"description": "Trip duration in days (calculated)"
|
||||||
|
},
|
||||||
|
"departureDate": {
|
||||||
|
"name": "departureDate",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"scope": "global",
|
"scope": "global",
|
||||||
"value": "",
|
"value": "",
|
||||||
"description": "Formatted summary string of the travel claim"
|
"description": "Trip departure date in ISO format"
|
||||||
|
},
|
||||||
|
"employeeEmail": {
|
||||||
|
"name": "employeeEmail",
|
||||||
|
"type": "string",
|
||||||
|
"scope": "global",
|
||||||
|
"value": "",
|
||||||
|
"description": "Email address of the employee for notifications"
|
||||||
|
},
|
||||||
|
"storageResult": {
|
||||||
|
"name": "storageResult",
|
||||||
|
"type": "string",
|
||||||
|
"scope": "global",
|
||||||
|
"value": "",
|
||||||
|
"description": "Result of storing claim in database (success/error)"
|
||||||
|
},
|
||||||
|
"transportCost": {
|
||||||
|
"name": "transportCost",
|
||||||
|
"type": "number",
|
||||||
|
"scope": "global",
|
||||||
|
"value": 0,
|
||||||
|
"description": "Transportation expenses claimed"
|
||||||
},
|
},
|
||||||
"approvalStatus": {
|
"approvalStatus": {
|
||||||
"name": "approvalStatus",
|
"name": "approvalStatus",
|
||||||
@ -209,12 +160,19 @@
|
|||||||
"value": "pending",
|
"value": "pending",
|
||||||
"description": "Current approval status (pending_approval, auto_approved, etc.)"
|
"description": "Current approval status (pending_approval, auto_approved, etc.)"
|
||||||
},
|
},
|
||||||
"managerDecision": {
|
"approvedAmount": {
|
||||||
"name": "managerDecision",
|
"name": "approvedAmount",
|
||||||
"type": "string",
|
"type": "number",
|
||||||
"scope": "global",
|
"scope": "global",
|
||||||
"value": "",
|
"value": 0,
|
||||||
"description": "Manager's approval decision (approve/reject)"
|
"description": "Final approved reimbursement amount"
|
||||||
|
},
|
||||||
|
"policyApiError": {
|
||||||
|
"name": "policyApiError",
|
||||||
|
"type": "object",
|
||||||
|
"scope": "global",
|
||||||
|
"value": null,
|
||||||
|
"description": "Error from policy API if request fails"
|
||||||
},
|
},
|
||||||
"managerComments": {
|
"managerComments": {
|
||||||
"name": "managerComments",
|
"name": "managerComments",
|
||||||
@ -223,33 +181,26 @@
|
|||||||
"value": "",
|
"value": "",
|
||||||
"description": "Manager's comments on the approval decision"
|
"description": "Manager's comments on the approval decision"
|
||||||
},
|
},
|
||||||
"finalApprovalStatus": {
|
"managerDecision": {
|
||||||
"name": "finalApprovalStatus",
|
"name": "managerDecision",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"scope": "global",
|
"scope": "global",
|
||||||
"value": "",
|
"value": "",
|
||||||
"description": "Final approval status after all reviews (approved/rejected)"
|
"description": "Manager's approval decision (approve/reject)"
|
||||||
},
|
},
|
||||||
"approvedAmount": {
|
"validationError": {
|
||||||
"name": "approvedAmount",
|
"name": "validationError",
|
||||||
|
"type": "string",
|
||||||
|
"scope": "global",
|
||||||
|
"value": "",
|
||||||
|
"description": "Validation error message if submission is invalid"
|
||||||
|
},
|
||||||
|
"allowedTransport": {
|
||||||
|
"name": "allowedTransport",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"scope": "global",
|
"scope": "global",
|
||||||
"value": 0,
|
"value": 0,
|
||||||
"description": "Final approved reimbursement amount"
|
"description": "Maximum allowed transportation reimbursement per policy"
|
||||||
},
|
|
||||||
"approvalTimestamp": {
|
|
||||||
"name": "approvalTimestamp",
|
|
||||||
"type": "string",
|
|
||||||
"scope": "global",
|
|
||||||
"value": "",
|
|
||||||
"description": "ISO timestamp when claim was approved/rejected"
|
|
||||||
},
|
|
||||||
"approvedBy": {
|
|
||||||
"name": "approvedBy",
|
|
||||||
"type": "string",
|
|
||||||
"scope": "global",
|
|
||||||
"value": "",
|
|
||||||
"description": "Who approved the claim (System/Manager name)"
|
|
||||||
},
|
},
|
||||||
"approvalComments": {
|
"approvalComments": {
|
||||||
"name": "approvalComments",
|
"name": "approvalComments",
|
||||||
@ -265,18 +216,67 @@
|
|||||||
"value": null,
|
"value": null,
|
||||||
"description": "Complete claim record object for storage/archival"
|
"description": "Complete claim record object for storage/archival"
|
||||||
},
|
},
|
||||||
"claimId": {
|
"overBudgetAmount": {
|
||||||
"name": "claimId",
|
"name": "overBudgetAmount",
|
||||||
"type": "string",
|
"type": "number",
|
||||||
"scope": "global",
|
"scope": "global",
|
||||||
"value": "",
|
"value": 0,
|
||||||
"description": "Unique identifier generated for the claim"
|
"description": "Amount by which claim exceeds policy limits"
|
||||||
},
|
},
|
||||||
"storageResult": {
|
"accommodationCost": {
|
||||||
"name": "storageResult",
|
"name": "accommodationCost",
|
||||||
|
"type": "number",
|
||||||
|
"scope": "global",
|
||||||
|
"value": 0,
|
||||||
|
"description": "Accommodation expenses claimed"
|
||||||
|
},
|
||||||
|
"approvalTimestamp": {
|
||||||
|
"name": "approvalTimestamp",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"scope": "global",
|
"scope": "global",
|
||||||
"value": "",
|
"value": "",
|
||||||
"description": "Result of storing claim in database (success/error)"
|
"description": "ISO timestamp when claim was approved/rejected"
|
||||||
|
},
|
||||||
|
"isValidSubmission": {
|
||||||
|
"name": "isValidSubmission",
|
||||||
|
"type": "boolean",
|
||||||
|
"scope": "global",
|
||||||
|
"value": false,
|
||||||
|
"description": "Whether the form submission passed validation"
|
||||||
|
},
|
||||||
|
"policyApiResponse": {
|
||||||
|
"name": "policyApiResponse",
|
||||||
|
"type": "object",
|
||||||
|
"scope": "global",
|
||||||
|
"value": null,
|
||||||
|
"description": "Response from company policy rates API"
|
||||||
|
},
|
||||||
|
"finalApprovalStatus": {
|
||||||
|
"name": "finalApprovalStatus",
|
||||||
|
"type": "string",
|
||||||
|
"scope": "global",
|
||||||
|
"value": "",
|
||||||
|
"description": "Final approval status after all reviews (approved/rejected)"
|
||||||
|
},
|
||||||
|
"reimbursementAmount": {
|
||||||
|
"name": "reimbursementAmount",
|
||||||
|
"type": "number",
|
||||||
|
"scope": "global",
|
||||||
|
"value": 0,
|
||||||
|
"description": "Final calculated reimbursement amount"
|
||||||
|
},
|
||||||
|
"submissionTimestamp": {
|
||||||
|
"name": "submissionTimestamp",
|
||||||
|
"type": "string",
|
||||||
|
"scope": "global",
|
||||||
|
"value": "",
|
||||||
|
"description": "ISO timestamp when claim was submitted"
|
||||||
|
},
|
||||||
|
"allowedAccommodation": {
|
||||||
|
"name": "allowedAccommodation",
|
||||||
|
"type": "number",
|
||||||
|
"scope": "global",
|
||||||
|
"value": 0,
|
||||||
|
"description": "Maximum allowed accommodation reimbursement per policy"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -901,45 +901,48 @@ onMounted(() => {
|
|||||||
// Watch for step changes to auto-execute non-form steps or load form data
|
// Watch for step changes to auto-execute non-form steps or load form data
|
||||||
watch(currentStep, async (newStep) => {
|
watch(currentStep, async (newStep) => {
|
||||||
if (currentNode.value) {
|
if (currentNode.value) {
|
||||||
if (['api', 'script', 'notification'].includes(currentNode.value.type)) {
|
stepLoading.value = true; // Start loading for any node
|
||||||
await executeCurrentStep();
|
try {
|
||||||
} else if (currentNode.value.type === 'form') {
|
if (["api", "script", "notification"].includes(currentNode.value.type)) {
|
||||||
// Load form data for form nodes
|
await executeCurrentStep();
|
||||||
const formId = currentNode.value.data?.formId;
|
} else if (currentNode.value.type === "form") {
|
||||||
if (formId) {
|
// Reset all form-related state to prevent flush errors
|
||||||
currentForm.value = await loadFormData(formId);
|
formData.value = {};
|
||||||
|
fieldStates.value = {};
|
||||||
// Apply input mappings to pre-fill form
|
|
||||||
if (currentNode.value.data?.inputMappings) {
|
|
||||||
applyInputMappings(
|
|
||||||
currentNode.value.data,
|
|
||||||
processVariables.value,
|
|
||||||
formData.value
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply field conditions
|
|
||||||
if (currentNode.value.data?.fieldConditions) {
|
|
||||||
fieldStates.value = applyFieldConditions(
|
|
||||||
currentNode.value.data,
|
|
||||||
processVariables.value
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update form store with form components and data for ComponentPreview
|
|
||||||
// Clear previous form state to prevent stale/leaked fields
|
|
||||||
formStore.formComponents = [];
|
|
||||||
formStore.updatePreviewFormData({});
|
formStore.updatePreviewFormData({});
|
||||||
if (currentForm.value?.formComponents) {
|
formStore.formComponents = [];
|
||||||
formStore.formComponents = currentForm.value.formComponents;
|
// Load form data for form nodes
|
||||||
formStore.updatePreviewFormData(formData.value);
|
const formId = currentNode.value.data?.formId;
|
||||||
|
if (formId) {
|
||||||
|
currentForm.value = await loadFormData(formId);
|
||||||
|
// Apply input mappings to pre-fill form
|
||||||
|
if (currentNode.value.data?.inputMappings) {
|
||||||
|
applyInputMappings(
|
||||||
|
currentNode.value.data,
|
||||||
|
processVariables.value,
|
||||||
|
formData.value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Apply field conditions
|
||||||
|
if (currentNode.value.data?.fieldConditions) {
|
||||||
|
fieldStates.value = applyFieldConditions(
|
||||||
|
currentNode.value.data,
|
||||||
|
processVariables.value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Update form store with form components and data for ComponentPreview
|
||||||
|
if (currentForm.value?.formComponents) {
|
||||||
|
formStore.formComponents = currentForm.value.formComponents;
|
||||||
|
formStore.updatePreviewFormData(formData.value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else if (["decision", "gateway"].includes(currentNode.value.type)) {
|
||||||
|
await executeDecisionNode();
|
||||||
}
|
}
|
||||||
} else if (['decision', 'gateway'].includes(currentNode.value.type)) {
|
// html nodes are handled in template - no auto-execution needed
|
||||||
// Handle decision nodes
|
} finally {
|
||||||
await executeDecisionNode();
|
stepLoading.value = false; // End loading after all async work
|
||||||
}
|
}
|
||||||
// html nodes are handled in template - no auto-execution needed
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1369,10 +1372,10 @@ function getConditionGroupResult(conditionGroup, variables) {
|
|||||||
:actions="false"
|
:actions="false"
|
||||||
:incomplete-message="false"
|
:incomplete-message="false"
|
||||||
validation-visibility="submit"
|
validation-visibility="submit"
|
||||||
:key="currentNode.value?.id"
|
:key="currentForm?.formId || currentNode.value?.id"
|
||||||
>
|
>
|
||||||
<div class="grid grid-cols-12 gap-2">
|
<div class="grid grid-cols-12 gap-2">
|
||||||
<template v-for="(component, index) in currentForm.formComponents" :key="index">
|
<template v-for="component in currentForm.formComponents" :key="component.id || component.props.name">
|
||||||
<ComponentPreview
|
<ComponentPreview
|
||||||
:component="component"
|
:component="component"
|
||||||
:is-preview="false"
|
:is-preview="false"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user