{ "edges": [ { "id": "start-1753000001-form-1753000002-edge", "data": {}, "type": "custom", "label": "", "source": "start-1753000001", "target": "form-1753000002", "animated": true, "sourceHandle": "start-1753000001-right", "targetHandle": "form-1753000002-left" }, { "id": "form-1753000002-script-1753000003-edge", "data": {}, "type": "custom", "label": "", "source": "form-1753000002", "target": "script-1753000003", "animated": true, "sourceHandle": "form-1753000002-right", "targetHandle": "script-1753000003-left" }, { "id": "script-1753000003-api-1753000004-edge", "data": {}, "type": "custom", "label": "", "source": "script-1753000003", "target": "api-1753000004", "animated": true, "sourceHandle": "script-1753000003-right", "targetHandle": "api-1753000004-left" }, { "id": "api-1753000004-script-1753000005-edge", "data": {}, "type": "custom", "label": "", "source": "api-1753000004", "target": "script-1753000005", "animated": true, "sourceHandle": "api-1753000004-right", "targetHandle": "script-1753000005-left" }, { "id": "script-1753000005-gateway-1753000006-edge", "data": {}, "type": "custom", "label": "", "source": "script-1753000005", "target": "gateway-1753000006", "animated": true, "sourceHandle": "script-1753000005-right", "targetHandle": "gateway-1753000006-left" }, { "id": "script-1753000009-notification-1753000011-edge", "data": {}, "type": "custom", "label": "", "source": "script-1753000009", "target": "notification-1753000011", "animated": true, "sourceHandle": "script-1753000009-right", "targetHandle": "notification-1753000011-left" }, { "id": "notification-1753000010-end-1753000012-edge", "data": {}, "type": "custom", "label": "", "source": "notification-1753000010", "target": "end-1753000012", "animated": true, "sourceHandle": "notification-1753000010-right", "targetHandle": "end-1753000012-left" }, { "id": "notification-1753000011-end-1753000012-edge", "data": {}, "type": "custom", "label": "", "source": "notification-1753000011", "target": "end-1753000012", "animated": true, "sourceHandle": "notification-1753000011-bottom", "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": [ { "id": "start-1753000001", "data": { "label": "Start Travel Claim", "shape": "circle", "borderColor": "#10b981", "description": "Employee initiates travel reimbursement claim", "backgroundColor": "#dcfce7" }, "type": "start", "label": "Start Travel Claim", "position": { "x": 105, "y": 300 } }, { "id": "form-1753000002", "data": { "label": "Travel Claim Form", "shape": "rectangle", "formId": 2, "formName": "Employee Travel Reimbursement Claim", "formUuid": "travel-reimbursement-form-uuid", "textColor": "#6b21a8", "borderColor": "#9333ea", "description": "Employee fills travel reimbursement claim form", "assignedRoles": [ { "label": "Employee", "value": "3", "description": "Regular employee role" } ], "assignedUsers": [], "inputMappings": [], "assignmentType": "roles", "outputMappings": [ { "formField": "employee_name", "processVariable": "employeeName" }, { "formField": "employee_email", "processVariable": "employeeEmail" }, { "formField": "department", "processVariable": "department" }, { "formField": "trip_purpose", "processVariable": "tripPurpose" }, { "formField": "destination", "processVariable": "destination" }, { "formField": "departure_date", "processVariable": "departureDate" }, { "formField": "return_date", "processVariable": "returnDate" }, { "formField": "travel_type", "processVariable": "travelType" }, { "formField": "transport_cost", "processVariable": "transportCost" }, { "formField": "accommodation_cost", "processVariable": "accommodationCost" }, { "formField": "meals_cost", "processVariable": "mealsCost" }, { "formField": "other_cost", "processVariable": "otherCost" }, { "formField": "has_receipts", "processVariable": "hasReceipts" } ], "backgroundColor": "#faf5ff", "fieldConditions": [], "assignmentVariable": "", "assignmentVariableType": "user_id" }, "type": "form", "label": "Travel Claim Form", "position": { "x": 405, "y": 270 } }, { "id": "script-1753000003", "data": { "label": "Validate & Calculate Total", "shape": "rectangle", "textColor": "#374151", "scriptCode": "// Validate form inputs\nconst transport = parseFloat(processVariables.transportCost) || 0;\nconst accommodation = parseFloat(processVariables.accommodationCost) || 0;\nconst meals = parseFloat(processVariables.mealsCost) || 0;\nconst other = parseFloat(processVariables.otherCost) || 0;\n\n// Calculate total cost\nprocessVariables.totalCost = transport + accommodation + meals + other;\n\n// Validate required fields\nif (!processVariables.employeeName || !processVariables.tripPurpose || !processVariables.destination) {\n processVariables.validationError = 'Required fields are missing';\n processVariables.isValidSubmission = false;\n} else if (processVariables.totalCost <= 0) {\n processVariables.validationError = 'Total cost must be greater than 0';\n processVariables.isValidSubmission = false;\n} else {\n processVariables.validationError = '';\n processVariables.isValidSubmission = true;\n}\n\n// Calculate trip duration\nconst departure = new Date(processVariables.departureDate);\nconst returnDate = new Date(processVariables.returnDate);\nprocessVariables.tripDuration = Math.ceil((returnDate - departure) / (1000 * 60 * 60 * 24)) + 1;\n\n// Create submission timestamp\nprocessVariables.submissionTimestamp = new Date().toISOString();", "borderColor": "#6b7280", "description": "Validate form data and calculate totals", "inputVariables": [ "employeeName", "tripPurpose", "destination", "transportCost", "accommodationCost", "mealsCost", "otherCost", "departureDate", "returnDate" ], "scriptLanguage": "javascript", "backgroundColor": "#f9fafb", "outputVariables": [ { "name": "totalCost", "type": "number", "description": "Total claim amount" }, { "name": "isValidSubmission", "type": "boolean", "description": "Whether submission is valid" }, { "name": "validationError", "type": "string", "description": "Validation error message if any" }, { "name": "tripDuration", "type": "number", "description": "Trip duration in days" }, { "name": "submissionTimestamp", "type": "string", "description": "When claim was submitted" } ] }, "type": "script", "label": "Validate & Calculate Total", "position": { "x": 750, "y": 270 } }, { "id": "api-1753000004", "data": { "body": { "data": "{ \"travel_type\": \"{travelType}\", \"destination\": \"{destination}\", \"trip_duration\": {tripDuration} }", "type": "raw" }, "label": "Get Policy Rates", "shape": "rectangle", "apiUrl": "https://jsonplaceholder.typicode.com/posts", "params": [], "headers": [{ "key": "Content-Type", "value": "application/json" }], "apiMethod": "POST", "textColor": "#1e40af", "borderColor": "#3b82f6", "description": "Get company policy rates for travel type and destination", "requestBody": "", "authorization": { "type": "none" }, "errorVariable": "policyApiError", "outputVariable": "policyApiResponse", "backgroundColor": "#eff6ff", "continueOnError": false }, "type": "api", "label": "Get Policy Rates", "position": { "x": 1095, "y": 270 } }, { "id": "script-1753000005", "data": { "label": "Calculate Reimbursement", "shape": "rectangle", "textColor": "#374151", "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", "description": "Calculate reimbursement based on policy rates", "inputVariables": [ "policyApiResponse", "totalCost", "travelType", "tripDuration" ], "scriptLanguage": "javascript", "backgroundColor": "#f9fafb", "outputVariables": [ { "name": "totalAllowed", "type": "number", "description": "Total allowed reimbursement per policy" }, { "name": "reimbursementAmount", "type": "number", "description": "Final reimbursement amount" }, { "name": "isOverBudget", "type": "boolean", "description": "Whether claim exceeds policy limits" }, { "name": "overBudgetAmount", "type": "number", "description": "Amount over budget" }, { "name": "claimSummary", "type": "string", "description": "Summary of the claim" }, { "name": "approvalStatus", "type": "string", "description": "Current approval status" } ] }, "type": "script", "label": "Calculate Reimbursement", "position": { "x": 1455, "y": 270 } }, { "id": "gateway-1753000006", "data": { "label": "Budget Check", "shape": "diamond", "textColor": "#c2410c", "conditions": [ { "id": "condition-group-1", "output": "Requires Approval", "conditions": [ { "id": "condition-over-budget", "value": "true", "maxValue": "", "minValue": "", "operator": "is_true", "variable": "isOverBudget", "valueType": "boolean", "logicalOperator": "and" } ] }, { "id": "condition-group-2", "output": "Auto Approve", "conditions": [ { "id": "condition-within-budget", "value": "false", "maxValue": "", "minValue": "", "operator": "is_false", "variable": "isOverBudget", "valueType": "boolean", "logicalOperator": "and" } ] } ], "borderColor": "#f97316", "defaultPath": "Auto Approve", "description": "Check if claim exceeds policy limits", "backgroundColor": "#fff7ed" }, "type": "gateway", "label": "Budget Check", "position": { "x": 1755, "y": 330 } }, { "id": "form-1753000007", "data": { "label": "Manager Approval", "shape": "rectangle", "formId": 3, "formName": "Travel Claim Approval Form", "formUuid": "travel-approval-form-uuid", "textColor": "#6b21a8", "borderColor": "#9333ea", "description": "Manager reviews and approves/rejects over-budget travel claim", "assignedRoles": [ { "label": "Manager", "value": "4", "description": "Department manager role" } ], "assignedUsers": [], "inputMappings": [ { "formField": "claim_summary", "processVariable": "claimSummary" }, { "formField": "employee_name_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", "outputMappings": [ { "formField": "manager_decision", "processVariable": "managerDecision" }, { "formField": "manager_comments", "processVariable": "managerComments" }, { "formField": "custom_approved_amount", "processVariable": "customApprovedAmount" } ], "backgroundColor": "#faf5ff", "fieldConditions": [], "assignmentVariable": "", "assignmentVariableType": "user_id" }, "type": "form", "label": "Manager Approval", "position": { "x": 1980, "y": 105 } }, { "id": "script-1753000009", "data": { "label": "Process Manager Decision", "shape": "rectangle", "textColor": "#374151", "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", "description": "Process manager decision and store final result", "inputVariables": ["managerDecision", "managerComments", "totalCost"], "scriptLanguage": "javascript", "backgroundColor": "#f9fafb", "outputVariables": [ { "name": "finalApprovalStatus", "type": "string", "description": "Final approval status after manager review" }, { "name": "approvedAmount", "type": "number", "description": "Final approved amount" }, { "name": "claimId", "type": "string", "description": "Generated claim ID" }, { "name": "approvalTimestamp", "type": "string", "description": "When claim was processed" } ] }, "type": "script", "label": "Process Manager Decision", "position": { "x": 2520, "y": 105 } }, { "id": "notification-1753000010", "data": { "label": "Auto Approval Notification", "message": "Your travel claim has been auto-approved", "subject": "Travel Claim Auto-Approved - {claimId}", "priority": "medium", "expiration": { "unit": "hours", "value": 24, "enabled": false }, "description": "Notify employee of auto-approved claim", "htmlMessage": "
\n

✅ Travel Claim Auto-Approved

\n

Dear {employeeName},

\n

Your travel reimbursement claim has been automatically approved!

\n \n
\n

Claim Details:

\n \n
\n \n

Your reimbursement will be processed within 3-5 business days.

\n \n

Best regards,
\n Travel Management System

\n
", "messageFormat": "html", "recipientRole": "", "recipientType": "email", "recipientUser": "", "recipientEmail": "mdafiqiskandar@gmail.com", "recipientGroup": "", "deliveryOptions": { "sms": false, "email": true, "inApp": true }, "richTextMessage": "", "notificationType": "success", "recipientVariable": "employeeEmail" }, "type": "notification", "label": "Auto Approval Notification", "position": { "x": 2265, "y": 375 } }, { "id": "notification-1753000011", "data": { "label": "Manager Decision Notification", "message": "Your travel claim has been reviewed by your manager", "subject": "Travel Claim Decision - {claimId}", "priority": "high", "expiration": { "unit": "hours", "value": 48, "enabled": false }, "description": "Notify employee of manager's decision", "htmlMessage": "
\n

📋 Travel Claim Decision

\n

Dear {employeeName},

\n

Your manager has reviewed your travel reimbursement claim.

\n \n
\n

Claim Details:

\n \n
\n \n
\n

Manager Comments:

\n

{approvalComments}

\n
\n \n

If approved, your reimbursement will be processed within 3-5 business days.

\n \n

Best regards,
\n Travel Management System

\n
", "messageFormat": "html", "recipientRole": "", "recipientType": "email", "recipientUser": "", "recipientEmail": "mdafiqiskandar@gmail.com", "recipientGroup": "", "deliveryOptions": { "sms": false, "email": true, "inApp": true }, "richTextMessage": "", "notificationType": "info", "recipientVariable": "employeeEmail" }, "type": "notification", "label": "Manager Decision Notification", "position": { "x": 2850, "y": 105 } }, { "id": "end-1753000012", "data": { "label": "End", "shape": "circle", "borderColor": "#f59e0b", "description": "Travel claim process completed", "backgroundColor": "#fef3c7" }, "type": "end", "label": "End", "position": { "x": 3195, "y": 300 } } ], "viewport": { "x": -1535.387843430428, "y": 250.2076943977823, "zoom": 0.8368461998102432 } }