{
  "processId" : 1,
  "id" : 1,
  "name" : "vacation-request",
  "locked" : false,
  "version" : 8,
  "active" : true,
  "nodes" : [ {
    "id" : 1,
    "type" : "task",
    "name" : "run_config",
    "posX" : 0.0,
    "posY" : 0.0,
    "description" : "Initiation form: collects the vacation date range before the workflow starts.",
    "sourcePosition" : "top",
    "targetPosition" : "bottom",
    "transitions" : [ ],
    "script" : null,
    "form" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE workflow-form PUBLIC \"-//OpenKM//DTD Workflow Form 1.0//EN\"\n                                \"https://www.openkm.com/dtd/workflow-form-1.0.dtd\">\n<workflow-form>\n  <text label=\"&lt;span class=&quot;font-weight-bold&quot;&gt;Vacation period request&lt;/span&gt;\" name=\"reg_030_usuario\" data=\"userText\"  />\n  <input label=\"Start date\" name=\"start_date\" type=\"date\" timeFormat=\"none\">\n    <validator type=\"req\"/>\n  </input>\n  <input label=\"End date\" name=\"end_date\" type=\"date\" timeFormat=\"none\">\n    <validator type=\"req\"/>\n  </input>\n</workflow-form>",
    "assignExpr" : "return \"\";",
    "dueDate" : "",
    "repeat" : "",
    "notifyAssignment" : true,
    "notificationSubject" : "Workflow task assignment",
    "notificationBody" : "A workflow task has been assigned",
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 2,
    "type" : "start",
    "name" : "workflow.start",
    "posX" : 383.94429800338435,
    "posY" : -20.243696235193468,
    "description" : null,
    "sourcePosition" : "bottom",
    "targetPosition" : "none",
    "transitions" : [ {
      "id" : 1,
      "type" : "smoothstep",
      "name" : "",
      "color" : "#000000",
      "script" : "",
      "animated" : false,
      "source" : 2,
      "target" : 11
    } ],
    "script" : null,
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 3,
    "type" : "task",
    "name" : "Manager approval",
    "posX" : 382.0332850940665,
    "posY" : 215.20260492040518,
    "description" : "The manager reviews the vacation request. Can approve, deny, request changes or escalate to a second level.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 2,
      "type" : "default",
      "name" : "approve",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 3,
      "target" : 14
    }, {
      "id" : 3,
      "type" : "default",
      "name" : "deny",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 3,
      "target" : 15
    }, {
      "id" : 4,
      "type" : "default",
      "name" : "escalate",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 3,
      "target" : 6
    }, {
      "id" : 5,
      "type" : "default",
      "name" : "request_changes",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 3,
      "target" : 9
    } ],
    "script" : null,
    "form" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE workflow-form PUBLIC \"-//OpenKM//DTD Workflow Form 1.0//EN\"\n                                \"https://www.openkm.com/dtd/workflow-form-1.0.dtd\">\n<workflow-form>\n  <text label=\"\" name=\"user_description\" data=\"user_text\" />\n  <input label=\"Start date\" name=\"start_date\" type=\"date\" timeFormat=\"none\" data=\"start_date\" readonly=\"true\"/>\n  <input label=\"End date\" name=\"end_date\" type=\"date\" timeFormat=\"none\" data=\"end_date\" readonly=\"true\"/>\n  <textarea label=\"Comment\" name=\"manager_comment\">\n    <validator type=\"req\"/>\n  </textarea>\n  <button name=\"btn_approve\" label=\"Approve\" transition=\"approve\" color=\"success\" style=\"yes\" validate=\"true\"/>\n  <button name=\"btn_request_changes\" label=\"Request changes\" transition=\"request_changes\" color=\"warning\" style=\"change\" validate=\"true\"/>\n  <button name=\"btn_escalate\" label=\"Escalate\" transition=\"escalate\" color=\"secondary\" style=\"add\" validate=\"true\"/>\n  <button name=\"btn_deny\" label=\"Deny\" transition=\"deny\" color=\"danger\" style=\"no\" validate=\"true\" confirmation=\"Are you sure you want to deny this request?\"/>\n</workflow-form>",
    "assignExpr" : "import com.openkm.okmflow.util.*;\nimport com.openkm.okmflow.rest.dto.*;\nimport com.openkm.sdk4j.impl.OKMWebservices;\nimport com.openkm.sdk4j.bean.*;\nimport com.openkm.okmflow.bean.*;\nimport com.openkm.bean.form.*;\nimport com.openkm.util.*;\nimport java.util.*;\n\ndef procIns = context.get(\"processInstance\");\nlong piId = procIns.getId();\n\n// Get all previous executions of \"Manager approval\" in this process instance\nList<TaskInstanceDTO> prevTasks = WorkflowUtils.getTaskInstances(piId, \"Manager approval\");\n\nif (prevTasks != null && !prevTasks.isEmpty()) {\n    // Return the first found actor — direct assignment, not a pool\n    for (TaskInstanceDTO t : prevTasks) {\n        if (t.getActor() != null && !t.getActor().isEmpty()) {\n            return t.getActor();\n        }\n    }\n}\n\n// First time: assign to pool of ROLE_RRHH users\nOKMWebservices ws = WebservicesHelper.getInstance();\nList<String> users = new ArrayList();\nfor (CommonUser user : ws.auth.getUsersByRole(\"ROLE_RRHH\")) {\n    users.add(user.getId());\n}\nreturn users;",
    "dueDate" : "",
    "repeat" : "",
    "notifyAssignment" : true,
    "notificationSubject" : "Workflow task assignment",
    "notificationBody" : "A workflow task has been assigned",
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 4,
    "type" : "task",
    "name" : "Submit vacation request",
    "posX" : 1523.8069331471816,
    "posY" : 492.27038031339407,
    "description" : "The employee revises the vacation request following feedback from a reviewer.",
    "sourcePosition" : "top",
    "targetPosition" : "left",
    "transitions" : [ {
      "id" : 6,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 4,
      "target" : 5
    } ],
    "script" : null,
    "form" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE workflow-form PUBLIC \"-//OpenKM//DTD Workflow Form 1.0//EN\"\n                                \"https://www.openkm.com/dtd/workflow-form-1.0.dtd\">\n<workflow-form>\n  <input label=\"Start date\" name=\"start_date\" type=\"date\" timeFormat=\"none\" data=\"start_date\">\n    <validator type=\"req\"/>\n  </input>\n  <input label=\"End date\" name=\"end_date\" type=\"date\" timeFormat=\"none\" data=\"end_date\">\n    <validator type=\"req\"/>\n  </input>\n  <textarea label=\"Reviewer comment\" name=\"reviewer_comment\" data=\"reviewer_comment\" readonly=\"true\"/>\n  <button name=\"btn_submit\" label=\"Submit\" transition=\"\" color=\"primary\" style=\"yes\" validate=\"true\"/>\n</workflow-form>",
    "assignExpr" : "import com.openkm.sdk4j.impl.OKMWebservices;\nimport com.openkm.sdk4j.bean.*;\nimport com.openkm.okmflow.util.*;\nimport com.openkm.okmflow.bean.*;\nimport com.openkm.bean.form.*;\nimport com.openkm.util.*;\n\nActor actor = context.get(\"initiator\");\nreturn actor.getId();",
    "dueDate" : "",
    "repeat" : "",
    "notifyAssignment" : true,
    "notificationSubject" : "Workflow task assignment",
    "notificationBody" : "A workflow task has been assigned",
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 5,
    "type" : "decision",
    "name" : "Who requested changes?",
    "posX" : 1043.6338842979028,
    "posY" : 92.03089825330679,
    "description" : "Routes back to the reviewer who requested the changes based on the request_sender context variable.",
    "sourcePosition" : "left",
    "targetPosition" : "right",
    "transitions" : [ {
      "id" : 7,
      "type" : "default",
      "name" : "manager",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 5,
      "target" : 3
    }, {
      "id" : 8,
      "type" : "default",
      "name" : "second_level",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 5,
      "target" : 6
    } ],
    "script" : "import com.openkm.okmflow.util.*;\nimport com.openkm.bean.form.*;\n\nInput sender = context.get(\"request_sender\");\nreturn sender.getValue();",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 6,
    "type" : "task",
    "name" : "Second level approval",
    "posX" : 792.8512181055678,
    "posY" : 591.817531102588,
    "description" : "Second level reviewer makes the final decision on escalated requests. Can approve, deny or request changes back to the employee.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 9,
      "type" : "default",
      "name" : "approve",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 6,
      "target" : 14
    }, {
      "id" : 10,
      "type" : "default",
      "name" : "deny",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 6,
      "target" : 15
    }, {
      "id" : 11,
      "type" : "default",
      "name" : "request_changes",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 6,
      "target" : 10
    } ],
    "script" : null,
    "form" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE workflow-form PUBLIC \"-//OpenKM//DTD Workflow Form 1.0//EN\"\n                                \"https://www.openkm.com/dtd/workflow-form-1.0.dtd\">\n<workflow-form>\n  <text label=\"\" name=\"user_description\" data=\"user_text\" />\n  <input label=\"Start date\" name=\"start_date\" type=\"date\" timeFormat=\"none\" data=\"start_date\" readonly=\"true\"/>\n  <input label=\"End date\" name=\"end_date\" type=\"date\" timeFormat=\"none\" data=\"end_date\" readonly=\"true\"/>\n  <textarea label=\"Manager comment\" name=\"manager_comment\" data=\"manager_comment\" readonly=\"true\"/>\n  <textarea label=\"Comment\" name=\"second_level_comment\">\n    <validator type=\"req\"/>\n  </textarea>\n  <button name=\"btn_approve\" label=\"Approve\" transition=\"approve\" color=\"success\" style=\"yes\" validate=\"true\"/>\n  <button name=\"btn_request_changes\" label=\"Request changes\" transition=\"request_changes\" color=\"warning\" style=\"change\" validate=\"true\"/>\n  <button name=\"btn_deny\" label=\"Deny\" transition=\"deny\" color=\"danger\" style=\"no\" validate=\"true\" confirmation=\"Are you sure you want to deny this request?\"/>\n</workflow-form>",
    "assignExpr" : "return \"rrhhSupervisor\";",
    "dueDate" : "",
    "repeat" : "",
    "notifyAssignment" : true,
    "notificationSubject" : "Workflow task assignment",
    "notificationBody" : "A workflow task has been assigned",
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 7,
    "type" : "end",
    "name" : "Approved",
    "posX" : 212.52633709139863,
    "posY" : 1120.3905981308533,
    "description" : "",
    "sourcePosition" : null,
    "targetPosition" : "top",
    "transitions" : [ ],
    "script" : null,
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 8,
    "type" : "mail",
    "name" : "Notify approved",
    "posX" : 292.64694464606094,
    "posY" : 999.1708590823646,
    "description" : "Notifies the initiator that the vacation request has been approved.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 12,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 8,
      "target" : 7
    } ],
    "script" : null,
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : "${initiator.email}",
    "subject" : "Your vacation request has been approved",
    "body" : "<p>Dear ${initiator.name},</p><p>Your vacation request from <strong>${start_date_fmt.value}</strong> to <strong>${end_date_fmt.value}</strong> has been <strong>approved</strong>.</p><p>Best regards,</p>"
  }, {
    "id" : 9,
    "type" : "action",
    "name" : "Set sender manager",
    "posX" : 1042.6684239593878,
    "posY" : 404.2924354822322,
    "description" : "Stores 'manager' in the request_sender context variable so the Decision node routes back to Manager approval.",
    "sourcePosition" : "right",
    "targetPosition" : "left",
    "transitions" : [ {
      "id" : 13,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 9,
      "target" : 4
    } ],
    "script" : "import com.openkm.sdk4j.impl.OKMWebservices;\nimport com.openkm.sdk4j.bean.*;\nimport com.openkm.okmflow.util.*;\nimport com.openkm.okmflow.bean.*;\nimport com.openkm.bean.form.*;\nimport com.openkm.util.*;\n\n// Set routing variable\nInput sender = new Input();\nsender.setValue(\"manager\");\ncontext.put(\"request_sender\", sender);\n\n// Copy manager comment so \"Submit vacation request\" can display it\ndef managerComment = context.get(\"manager_comment\");\ncontext.put(\"reviewer_comment\", managerComment);",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 10,
    "type" : "action",
    "name" : "Set sender second level",
    "posX" : 1242.32028648054,
    "posY" : 776.9956731895048,
    "description" : "Stores 'second_level' in the request_sender context variable so the Decision node routes back to Second level approval.",
    "sourcePosition" : "right",
    "targetPosition" : "left",
    "transitions" : [ {
      "id" : 14,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 10,
      "target" : 4
    } ],
    "script" : "import com.openkm.sdk4j.impl.OKMWebservices;\nimport com.openkm.sdk4j.bean.*;\nimport com.openkm.okmflow.util.*;\nimport com.openkm.okmflow.bean.*;\nimport com.openkm.bean.form.*;\nimport com.openkm.util.*;\n\n// Set routing variable\nInput sender = new Input();\nsender.setValue(\"second_level\");\ncontext.put(\"request_sender\", sender);\n\n// Copy second level comment so \"Submit vacation request\" can display it\ndef secondComment = context.get(\"second_level_comment\");\ncontext.put(\"reviewer_comment\", secondComment);",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 11,
    "type" : "action",
    "name" : "Build user name text",
    "posX" : 383.94429800338435,
    "posY" : 93.7284527664987,
    "description" : "",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 15,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 11,
      "target" : 3
    } ],
    "script" : "import com.openkm.sdk4j.impl.OKMWebservices;\nimport com.openkm.sdk4j.bean.*;\nimport com.openkm.okmflow.util.*;\nimport com.openkm.okmflow.bean.*;\nimport com.openkm.bean.form.*;\nimport com.openkm.util.*;\n\n// Create Text object with user description and save in the context\nActor actor = context.get(\"initiator\");\nString userName = actor.getName();\nText userText = new Text();\nuserText.setName(\"user_text\");\nuserText.setLabel(\"The user <span class=\\\"font-weight-bold\\\">\" + userName + \"</span> has requested vacations\");\ncontext.put(\"user_text\", userText);",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 12,
    "type" : "end",
    "name" : "Denied",
    "posX" : 919.4552146615838,
    "posY" : 1120.5918337140413,
    "description" : "",
    "sourcePosition" : null,
    "targetPosition" : "top",
    "transitions" : [ ],
    "script" : null,
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 13,
    "type" : "mail",
    "name" : "Notify denied",
    "posX" : 819.107077182736,
    "posY" : 1004.7102004568494,
    "description" : "Notifies the initiator that the vacation request has been denied.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 16,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 13,
      "target" : 12
    } ],
    "script" : null,
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : "${initiator.email}",
    "subject" : "Your vacation request has been denied",
    "body" : "<p>Dear ${initiator.name},</p><p>Your vacation request from <strong>${start_date_fmt.value}</strong> to <strong>${end_date_fmt.value}</strong> has been <strong>denied</strong>.</p><p>Reason: ${reviewer_comment.value}</p><p>Best regards,</p>"
  }, {
    "id" : 14,
    "type" : "action",
    "name" : "Format dates approved",
    "posX" : 414.39687672588644,
    "posY" : 882.7032377072726,
    "description" : "Formats start_date and end_date into dd/MM/yyyy before sending the approval email.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 17,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 14,
      "target" : 8
    } ],
    "script" : "import com.openkm.bean.form.*;\nimport java.text.*;\n\nSimpleDateFormat raw = new SimpleDateFormat(\"yyyyMMddHHmmss\");\nSimpleDateFormat fmt = new SimpleDateFormat(\"dd/MM/yyyy\");\n\nInput startRaw = context.get(\"start_date\");\nInput endRaw = context.get(\"end_date\");\n\nInput startFmt = new Input();\nstartFmt.setValue(fmt.format(raw.parse(startRaw.getValue())));\ncontext.put(\"start_date_fmt\", startFmt);\n\nInput endFmt = new Input();\nendFmt.setValue(fmt.format(raw.parse(endRaw.getValue())));\ncontext.put(\"end_date_fmt\", endFmt);",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 15,
    "type" : "action",
    "name" : "Format dates denied",
    "posX" : 742.8424926988117,
    "posY" : 878.6893122081186,
    "description" : "Formats start_date and end_date into dd/MM/yyyy before sending the denial email.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 18,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 15,
      "target" : 13
    } ],
    "script" : "import com.openkm.bean.form.*;\nimport java.text.*;\n\nSimpleDateFormat raw = new SimpleDateFormat(\"yyyyMMddHHmmss\");\nSimpleDateFormat fmt = new SimpleDateFormat(\"dd/MM/yyyy\");\n\nInput startRaw = context.get(\"start_date\");\nInput endRaw = context.get(\"end_date\");\n\nInput startFmt = new Input();\nstartFmt.setValue(fmt.format(raw.parse(startRaw.getValue())));\ncontext.put(\"start_date_fmt\", startFmt);\n\nInput endFmt = new Input();\nendFmt.setValue(fmt.format(raw.parse(endRaw.getValue())));\ncontext.put(\"end_date_fmt\", endFmt);",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  } ]
}