{
  "processId" : 1,
  "id" : 1,
  "name" : "expense-report-approval",
  "documentationUrl": "https://docs.openkm.com/kcenter/view/okmflow-1x/expense-report-approval.html",
  "locked" : false,
  "version" : 11,
  "active" : true,
  "nodes" : [ {
    "id" : 1,
    "type" : "start",
    "name" : "workflow.start",
    "posX" : 488.60848100951944,
    "posY" : 108.60848100951944,
    "description" : "",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 1,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 1,
      "target" : 3
    } ],
    "script" : null,
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 2,
    "type" : "task",
    "name" : "Expense Submission",
    "posX" : 548.1836869516064,
    "posY" : 357.59672584851273,
    "description" : "",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 2,
      "type" : "default",
      "name" : "submit",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 2,
      "target" : 15
    } ],
    "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=\"Fill in the details of your expense and attach your receipts (invoices, tickets, boarding passes, etc.) below.\" name=\"instructions\" width=\"100%\"/>\n  <select label=\"Department\" name=\"department\" type=\"simple\">\n    <option label=\"IT\" value=\"it\"/>\n    <option label=\"Finance\" value=\"finance\"/>\n    <option label=\"Operations\" value=\"operations\"/>\n    <option label=\"Sales\" value=\"sales\"/>\n    <option label=\"HR\" value=\"hr\"/>\n    <validator type=\"req\"/>\n  </select>\n  <input label=\"Expense Date\" name=\"expenseDate\" type=\"date\" timeFormat=\"none\">\n    <validator type=\"req\"/>\n  </input>\n  <select label=\"Category\" name=\"category\" type=\"simple\">\n    <option label=\"Travel\" value=\"travel\"/>\n    <option label=\"Meals\" value=\"meals\"/>\n    <option label=\"Accommodation\" value=\"accommodation\"/>\n    <option label=\"Office Supplies\" value=\"office_supplies\"/>\n    <option label=\"Other\" value=\"other\"/>\n    <validator type=\"req\"/>\n  </select>\n  <input label=\"Amount\" name=\"amount\" type=\"text\">\n    <validator type=\"req\"/>\n    <validator type=\"dec\"/>\n    <validator type=\"gt\" parameter=\"0\"/>\n  </input>\n  <select label=\"Currency\" name=\"currency\" type=\"simple\">\n    <option label=\"EUR\" value=\"EUR\"/>\n    <option label=\"USD\" value=\"USD\"/>\n    <option label=\"GBP\" value=\"GBP\"/>\n    <validator type=\"req\"/>\n  </select>\n  <textarea label=\"Description\" name=\"description\" type=\"text\">\n    <validator type=\"req\"/>\n  </textarea>\n  <upload label=\"Receipts\" name=\"receipts\" data=\"receiptsUploadData\" multiple=\"true\" allowedExtensions=\"pdf;jpg;jpeg;png\"/>\n  <button name=\"submit\" label=\"Submit\" transition=\"submit\" color=\"success\"/>\n</workflow-form>\n",
    "assignExpr" : "import com.openkm.okmflow.bean.*;\n\nActor initiator = context.get(\"initiator\");\nreturn initiator.getId();\n",
    "dueDate" : "",
    "repeat" : "",
    "notifyAssignment" : true,
    "notificationSubject" : "Workflow task assigment",
    "notificationBody" : "A workflow task has been assigned",
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 3,
    "type" : "action",
    "name" : "Create Expense Record",
    "posX" : 533.0190799195128,
    "posY" : 231.20824278982244,
    "description" : "",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 3,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 3,
      "target" : 2
    } ],
    "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.*;\nimport java.util.Calendar;\n\nOKMWebservices ws = WebservicesHelper.getInstance();\n\n// Read and increment counter from APP_COUNTER table\nSqlQueryResults counterResult = ws.repository.executeSqlQuery(\n    \"SELECT counter_value FROM APP_COUNTER WHERE counter_key = 'expense_report'\");\nint currentValue = Integer.parseInt(counterResult.getResults().get(0).getColumns().get(0));\nint nextValue = currentValue + 1;\nws.repository.executeSqlQuery(\n    \"UPDATE APP_COUNTER SET counter_value = \" + nextValue + \" WHERE counter_key = 'expense_report'\");\n\n// Build Expense reference: RECEIPTS-YYYY-NNNNN (5 digits)\nint year = Calendar.getInstance().get(Calendar.YEAR);\nString expenseNumber = String.format(\"RECEIPTS-%d-%05d\", year, currentValue);\nFileLogger.info(\"expense-report-approval\", \"Expense number generated: \" + expenseNumber);\n\n// Create year folder if it does not exist\nString yearFolderPath = \"/okm:root/Expense Report Approval/\" + year;\nif (!ws.repository.hasNode(yearFolderPath)) {\n  ws.folder.createMissingFolders(yearFolderPath);\n}\nString yearFolderUuid = ws.repository.getNodeUuid(yearFolderPath);\n\n// Create the expense record inside the year folder.\n// All uploaded documents are receipts, so they are stored directly at the\n// root of the record - no separate \"receipts\" subfolder is needed.\nRecord expenseRecord = ws.record.create(yearFolderUuid, expenseNumber, \"\", 0);\nString expenseRecordUuid = expenseRecord.getUuid();\nString expenseRecordPath = yearFolderPath + \"/\" + expenseNumber;\nFileLogger.info(\"expense-report-approval\", \"Expense record created: \" + expenseRecordPath);\n\n// Store references in the workflow context for use by subsequent nodes\nInput expenseNumberInput = new Input();\nexpenseNumberInput.setValue(expenseNumber);\ncontext.put(\"expenseNumber\", expenseNumberInput);\ncontext.put(\"expenseRecordPath\", expenseRecordPath);\ncontext.put(\"expenseRecordUuid\", expenseRecordUuid);\n\n// Upload descriptor so the receipts field in Expense Submission targets the record root\nUpload receiptsUpload = new Upload();\nreceiptsUpload.setFolderUuid(expenseRecordUuid);\ncontext.put(\"receiptsUploadData\", receiptsUpload);\n\n// Link the process instance to the expense record so the workflow is accessible\n// directly from the document explorer\nWorkflowUtils.setProcessInstanceNode(context, expenseRecordUuid);\n",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 4,
    "type" : "task",
    "name" : "Manager Approval",
    "posX" : 713.9014226033293,
    "posY" : 690.3307429767135,
    "description" : "",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 4,
      "type" : "default",
      "name" : "approved",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 4,
      "target" : 5
    }, {
      "id" : 5,
      "type" : "default",
      "name" : "clarification",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 4,
      "target" : 24
    }, {
      "id" : 6,
      "type" : "default",
      "name" : "rejected",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 4,
      "target" : 16
    } ],
    "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=\"Review the expense request below. You can approve it, request clarification from the employee, or reject it definitively.\" name=\"instructions\" width=\"100%\"/>\n  <input label=\"Expense Record\" name=\"expenseRecordLink\" type=\"folder\" data=\"expenseRecordUuid\" readonly=\"true\"/>\n  <input label=\"Employee\" name=\"employeeReview\" type=\"text\" data=\"employee\" readonly=\"true\"/>\n  <select label=\"Department\" name=\"departmentReview\" type=\"simple\" data=\"department\" readonly=\"true\">\n    <option label=\"IT\" value=\"it\"/>\n    <option label=\"Finance\" value=\"finance\"/>\n    <option label=\"Operations\" value=\"operations\"/>\n    <option label=\"Sales\" value=\"sales\"/>\n    <option label=\"HR\" value=\"hr\"/>\n  </select>\n  <input label=\"Expense Date\" name=\"expenseDateReview\" type=\"date\" timeFormat=\"none\" data=\"expenseDate\" readonly=\"true\"/>\n  <select label=\"Category\" name=\"categoryReview\" type=\"simple\" data=\"category\" readonly=\"true\">\n    <option label=\"Travel\" value=\"travel\"/>\n    <option label=\"Meals\" value=\"meals\"/>\n    <option label=\"Accommodation\" value=\"accommodation\"/>\n    <option label=\"Office Supplies\" value=\"office_supplies\"/>\n    <option label=\"Other\" value=\"other\"/>\n  </select>\n  <input label=\"Amount\" name=\"amountReview\" type=\"text\" data=\"amount\" readonly=\"true\"/>\n  <select label=\"Currency\" name=\"currencyReview\" type=\"simple\" data=\"currency\" readonly=\"true\">\n    <option label=\"EUR\" value=\"EUR\"/>\n    <option label=\"USD\" value=\"USD\"/>\n    <option label=\"GBP\" value=\"GBP\"/>\n  </select>\n  <textarea label=\"Description\" name=\"descriptionReview\" data=\"description\" readonly=\"true\"/>\n  <textarea label=\"Manager Comments\" name=\"managerComments\"/>\n  <button name=\"approve\" label=\"Approve\" transition=\"approved\" color=\"success\"/>\n  <button name=\"clarify\" label=\"Request Clarification\" transition=\"clarification\" color=\"warning\"/>\n  <button name=\"reject\" label=\"Reject\" transition=\"rejected\" color=\"danger\"/>\n</workflow-form>\n",
    "assignExpr" : "import com.openkm.bean.form.*;\n\nSelect departmentSelect = (Select) context.get(\"department\");\nString department = departmentSelect.getValue();\n\nswitch (department) {\n  case \"it\":\n    return \"itManager\";\n  case \"finance\":\n    return \"financeManager\";\n  case \"operations\":\n    return \"operationsManager\";\n  case \"sales\":\n    return \"salesManager\";\n  case \"hr\":\n    return \"hrManager\";\n  default:\n    return \"okmAdmin\";\n}\n",
    "dueDate" : "",
    "repeat" : "",
    "notifyAssignment" : true,
    "notificationSubject" : "Workflow task assigment",
    "notificationBody" : "A workflow task has been assigned",
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 5,
    "type" : "action",
    "name" : "Set status - Pending Finance",
    "posX" : 657.1863850669952,
    "posY" : 1038.117485474258,
    "description" : "",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 7,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 5,
      "target" : 6
    } ],
    "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.*;\nimport java.util.*;\n\nOKMWebservices ws = WebservicesHelper.getInstance();\n\nString expenseRecordUuid = (String) context.get(\"expenseRecordUuid\");\nTextArea managerCommentsTextArea = (TextArea) context.get(\"managerComments\");\nString managerComments = managerCommentsTextArea != null ? managerCommentsTextArea.getValue() : \"\";\n\nMap<String, String> properties = new HashMap();\nproperties.put(\"okp:expense_report.status\", \"[\\\"pending_finance_validation\\\"]\");\nproperties.put(\"okp:expense_report.managerComments\", managerComments);\n\nws.propertyGroup.setProperties(expenseRecordUuid, \"okg:expense_report\", properties);\n\nFileLogger.info(\"expense-report-approval\", \"Approved by manager, pending finance: \" + expenseRecordUuid);\n",
    "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" : "Finance Validation",
    "posX" : 699.8440481801714,
    "posY" : 1274.7947274068215,
    "description" : "",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 8,
      "type" : "default",
      "name" : "approved",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 6,
      "target" : 7
    }, {
      "id" : 9,
      "type" : "default",
      "name" : "rejected",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 6,
      "target" : 19
    } ],
    "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=\"Validate the expense against company policy and available budget, then approve or reject.\" name=\"instructions\" width=\"100%\"/>\n  <input label=\"Expense Record\" name=\"expenseRecordLink\" type=\"folder\" data=\"expenseRecordUuid\" readonly=\"true\"/>\n  <input label=\"Employee\" name=\"employeeReview\" type=\"text\" data=\"employee\" readonly=\"true\"/>\n  <select label=\"Department\" name=\"departmentReview\" type=\"simple\" data=\"department\" readonly=\"true\">\n    <option label=\"IT\" value=\"it\"/>\n    <option label=\"Finance\" value=\"finance\"/>\n    <option label=\"Operations\" value=\"operations\"/>\n    <option label=\"Sales\" value=\"sales\"/>\n    <option label=\"HR\" value=\"hr\"/>\n  </select>\n  <input label=\"Expense Date\" name=\"expenseDateReview\" type=\"date\" timeFormat=\"none\" data=\"expenseDate\" readonly=\"true\"/>\n  <select label=\"Category\" name=\"categoryReview\" type=\"simple\" data=\"category\" readonly=\"true\">\n    <option label=\"Travel\" value=\"travel\"/>\n    <option label=\"Meals\" value=\"meals\"/>\n    <option label=\"Accommodation\" value=\"accommodation\"/>\n    <option label=\"Office Supplies\" value=\"office_supplies\"/>\n    <option label=\"Other\" value=\"other\"/>\n  </select>\n  <input label=\"Amount\" name=\"amountReview\" type=\"text\" data=\"amount\" readonly=\"true\"/>\n  <select label=\"Currency\" name=\"currencyReview\" type=\"simple\" data=\"currency\" readonly=\"true\">\n    <option label=\"EUR\" value=\"EUR\"/>\n    <option label=\"USD\" value=\"USD\"/>\n    <option label=\"GBP\" value=\"GBP\"/>\n  </select>\n  <textarea label=\"Description\" name=\"descriptionReview\" data=\"description\" readonly=\"true\"/>\n  <textarea label=\"Manager's Reply (if this expense was returned by the manager)\" name=\"managerReplyReview\" data=\"managerComments\" readonly=\"true\"/>\n  <textarea label=\"Finance Comments\" name=\"financeComments\"/>\n  <button name=\"approve\" label=\"Approve\" transition=\"approved\" color=\"success\"/>\n  <button name=\"reject\" label=\"Reject\" transition=\"rejected\" color=\"danger\"/>\n</workflow-form>\n",
    "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();\nList<TaskInstanceDTO> prevTasks = WorkflowUtils.getTaskInstances(piId, \"Finance Validation\");\n\nif (prevTasks != null && !prevTasks.isEmpty()) {\n  // Walk backwards: if this task has already been handled once, re-assign directly to the same user\n  for (int i = prevTasks.size() - 1; i >= 0; i--) {\n    TaskInstanceDTO t = prevTasks.get(i);\n    if (t.getActor() != null && !t.getActor().isEmpty()) {\n      return t.getActor(); // Direct re-assignment — return String, not List\n    }\n  }\n}\n\n// First time: pool of all ROLE_FINANCE users, any of them can self-assign\nOKMWebservices ws = WebservicesHelper.getInstance();\nList<String> users = new ArrayList();\nfor (CommonUser commonUser : ws.auth.getUsersByRole(\"ROLE_FINANCE\")) {\n  users.add(commonUser.getId());\n}\nreturn users;\n",
    "dueDate" : "",
    "repeat" : "",
    "notifyAssignment" : true,
    "notificationSubject" : "Workflow task assigment",
    "notificationBody" : "A workflow task has been assigned",
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 7,
    "type" : "action",
    "name" : "Set status - Approved",
    "posX" : 796.6307933603907,
    "posY" : 1656.8503286068762,
    "description" : "",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 10,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 7,
      "target" : 8
    } ],
    "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.*;\nimport java.util.*;\n\nOKMWebservices ws = WebservicesHelper.getInstance();\n\nString expenseRecordUuid = (String) context.get(\"expenseRecordUuid\");\nTextArea financeCommentsTextArea = (TextArea) context.get(\"financeComments\");\nString financeComments = financeCommentsTextArea != null ? financeCommentsTextArea.getValue() : \"\";\n\nMap<String, String> properties = new HashMap();\nproperties.put(\"okp:expense_report.status\", \"[\\\"approved\\\"]\");\nproperties.put(\"okp:expense_report.financeComments\", financeComments);\n\nws.propertyGroup.setProperties(expenseRecordUuid, \"okg:expense_report\", properties);\n\nFileLogger.info(\"expense-report-approval\", \"Approved by finance: \" + expenseRecordUuid);\n",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 8,
    "type" : "task",
    "name" : "Payment Processing",
    "posX" : 827.3536531531462,
    "posY" : 1846.8569622682592,
    "description" : "",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 11,
      "type" : "default",
      "name" : "paid",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 8,
      "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=\"This expense has been approved. Review the details below and record the payment.\" name=\"instructions\" width=\"100%\"/>\n  <input label=\"Pay to (Employee)\" name=\"employeeReview\" type=\"text\" data=\"employee\" readonly=\"true\"/>\n  <select label=\"Department\" name=\"departmentReview\" type=\"simple\" data=\"department\" readonly=\"true\">\n    <option label=\"IT\" value=\"it\"/>\n    <option label=\"Finance\" value=\"finance\"/>\n    <option label=\"Operations\" value=\"operations\"/>\n    <option label=\"Sales\" value=\"sales\"/>\n    <option label=\"HR\" value=\"hr\"/>\n  </select>\n  <input label=\"Expense Date\" name=\"expenseDateReview\" type=\"date\" timeFormat=\"none\" data=\"expenseDate\" readonly=\"true\"/>\n  <select label=\"Category\" name=\"categoryReview\" type=\"simple\" data=\"category\" readonly=\"true\">\n    <option label=\"Travel\" value=\"travel\"/>\n    <option label=\"Meals\" value=\"meals\"/>\n    <option label=\"Accommodation\" value=\"accommodation\"/>\n    <option label=\"Office Supplies\" value=\"office_supplies\"/>\n    <option label=\"Other\" value=\"other\"/>\n  </select>\n  <input label=\"Amount\" name=\"amountReview\" type=\"text\" data=\"amount\" readonly=\"true\"/>\n  <select label=\"Currency\" name=\"currencyReview\" type=\"simple\" data=\"currency\" readonly=\"true\">\n    <option label=\"EUR\" value=\"EUR\"/>\n    <option label=\"USD\" value=\"USD\"/>\n    <option label=\"GBP\" value=\"GBP\"/>\n  </select>\n  <textarea label=\"Description\" name=\"descriptionReview\" data=\"description\" readonly=\"true\"/>\n  <input label=\"Payment Date\" name=\"paymentDate\" type=\"date\" timeFormat=\"none\">\n    <validator type=\"req\"/>\n  </input>\n  <input label=\"Payment Reference\" name=\"paymentReference\" type=\"text\">\n    <validator type=\"req\"/>\n  </input>\n  <button name=\"markPaid\" label=\"Mark as Paid\" transition=\"paid\" color=\"success\"/>\n</workflow-form>",
    "assignExpr" : "return \"paymentManager\";",
    "dueDate" : "",
    "repeat" : "",
    "notifyAssignment" : true,
    "notificationSubject" : "Workflow task assigment",
    "notificationBody" : "A workflow task has been assigned",
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 9,
    "type" : "action",
    "name" : "Set status - Paid",
    "posX" : 987.7849957190612,
    "posY" : 2072.3668768027005,
    "description" : "",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 12,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 9,
      "target" : 10
    } ],
    "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.*;\nimport java.util.*;\nimport java.text.SimpleDateFormat;\n\nOKMWebservices ws = WebservicesHelper.getInstance();\n\nString expenseRecordUuid = (String) context.get(\"expenseRecordUuid\");\nInput paymentDateInput = (Input) context.get(\"paymentDate\");\nInput paymentReferenceInput = (Input) context.get(\"paymentReference\");\n\nMap<String, String> properties = new HashMap();\nproperties.put(\"okp:expense_report.status\", \"[\\\"paid\\\"]\");\nproperties.put(\"okp:expense_report.paymentDate\", paymentDateInput.getValue());\nproperties.put(\"okp:expense_report.paymentReference\", paymentReferenceInput.getValue());\n\nws.propertyGroup.setProperties(expenseRecordUuid, \"okg:expense_report\", properties);\n\n// Formatted date (yyyy-MM-dd) is only needed for display in the Mail node,\n// never for the stored metadata property (which must stay yyyyMMddHHmmss)\nSimpleDateFormat srcFmt = new SimpleDateFormat(\"yyyyMMddHHmmss\");\nSimpleDateFormat dstFmt = new SimpleDateFormat(\"yyyy-MM-dd\");\nString paymentDateFormatted = dstFmt.format(srcFmt.parse(paymentDateInput.getValue()));\nInput paymentDateFmt = new Input();\npaymentDateFmt.setValue(paymentDateFormatted);\ncontext.put(\"paymentDate_fmt\", paymentDateFmt);\n\nFileLogger.info(\"expense-report-approval\", \"Expense marked as paid: \" + expenseRecordUuid);\n",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 10,
    "type" : "mail",
    "name" : "Mail - Payment Completed",
    "posX" : 1086.90737461615,
    "posY" : 2224.7487990163054,
    "description" : "",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 13,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 10,
      "target" : 11
    } ],
    "script" : null,
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : "${initiator.email}",
    "subject" : "Your expense report ${expenseNumber.value} has been paid",
    "body" : "<p>Hello ${initiator.name},</p><p>Your expense report <strong>${expenseNumber.value}</strong> has been paid.</p><p>Payment date: ${paymentDate_fmt.value}</p><p>Payment reference: ${paymentReference.value}</p>"
  }, {
    "id" : 11,
    "type" : "end",
    "name" : "workflow.end",
    "posX" : 1178.8210034137585,
    "posY" : 2382.592669898016,
    "description" : "",
    "sourcePosition" : "bottom",
    "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" : 12,
    "type" : "mail",
    "name" : "Mail - Clarification Requested",
    "posX" : 1817.4704290261327,
    "posY" : 957.93455546198,
    "description" : "",
    "sourcePosition" : "top",
    "targetPosition" : "bottom",
    "transitions" : [ {
      "id" : 14,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 12,
      "target" : 13
    } ],
    "script" : null,
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : "${initiator.email}",
    "subject" : "Clarification requested for expense report ${expenseNumber.value}",
    "body" : "<p>Hello ${initiator.name},</p>\n<p>Your manager has requested more information about your expense report <strong>${expenseNumber.value}</strong>:</p>\n<p>${managerComments.value}</p>\n<p>Please review and resubmit your request.</p>"
  }, {
    "id" : 13,
    "type" : "task",
    "name" : "Employee Edit & Resubmit",
    "posX" : 1287.4583021605738,
    "posY" : 761.0595308961321,
    "description" : "",
    "sourcePosition" : "left",
    "targetPosition" : "right",
    "transitions" : [ {
      "id" : 15,
      "type" : "default",
      "name" : "resubmit",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 13,
      "target" : 14
    } ],
    "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=\"Your manager has requested more information about this expense report:\" name=\"clarificationIntro\" width=\"100%\"/>\n  <textarea label=\"Manager's request\" name=\"managerCommentsReview\" data=\"managerComments\" readonly=\"true\"/>\n  <input label=\"Expense Record\" name=\"expenseRecordLink\" type=\"folder\" data=\"expenseRecordUuid\" readonly=\"true\"/>\n  <select label=\"Department\" name=\"department\" type=\"simple\" data=\"department\">\n    <option label=\"IT\" value=\"it\"/>\n    <option label=\"Finance\" value=\"finance\"/>\n    <option label=\"Operations\" value=\"operations\"/>\n    <option label=\"Sales\" value=\"sales\"/>\n    <option label=\"HR\" value=\"hr\"/>\n    <validator type=\"req\"/>\n  </select>\n  <input label=\"Expense Date\" name=\"expenseDate\" type=\"date\" timeFormat=\"none\" data=\"expenseDate\">\n    <validator type=\"req\"/>\n  </input>\n  <select label=\"Category\" name=\"category\" type=\"simple\" data=\"category\">\n    <option label=\"Travel\" value=\"travel\"/>\n    <option label=\"Meals\" value=\"meals\"/>\n    <option label=\"Accommodation\" value=\"accommodation\"/>\n    <option label=\"Office Supplies\" value=\"office_supplies\"/>\n    <option label=\"Other\" value=\"other\"/>\n    <validator type=\"req\"/>\n  </select>\n  <input label=\"Amount\" name=\"amount\" type=\"text\" data=\"amount\">\n    <validator type=\"req\"/>\n    <validator type=\"dec\"/>\n    <validator type=\"gt\" parameter=\"0\"/>\n  </input>\n  <select label=\"Currency\" name=\"currency\" type=\"simple\" data=\"currency\">\n    <option label=\"EUR\" value=\"EUR\"/>\n    <option label=\"USD\" value=\"USD\"/>\n    <option label=\"GBP\" value=\"GBP\"/>\n    <validator type=\"req\"/>\n  </select>\n  <textarea label=\"Description\" name=\"description\" data=\"description\">\n    <validator type=\"req\"/>\n  </textarea>\n  <upload label=\"Additional Receipts\" name=\"additionalReceipts\" data=\"receiptsUploadData\" multiple=\"true\" allowedExtensions=\"pdf;jpg;jpeg;png\"/>\n  <button name=\"resubmit\" label=\"Resubmit\" transition=\"resubmit\" color=\"success\"/>\n</workflow-form>\n",
    "assignExpr" : "import com.openkm.okmflow.bean.*;\n\nActor initiator = context.get(\"initiator\");\nreturn initiator.getId();\n",
    "dueDate" : "",
    "repeat" : "",
    "notifyAssignment" : true,
    "notificationSubject" : "Workflow task assigment",
    "notificationBody" : "A workflow task has been assigned",
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 14,
    "type" : "action",
    "name" : "Set status - Pending Manager",
    "posX" : 1026.3495180636196,
    "posY" : 593.2201785760457,
    "description" : "",
    "sourcePosition" : "left",
    "targetPosition" : "right",
    "transitions" : [ {
      "id" : 16,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 14,
      "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.*;\nimport java.util.*;\n\nOKMWebservices ws = WebservicesHelper.getInstance();\n\nString expenseRecordUuid = (String) context.get(\"expenseRecordUuid\");\n\nSelect departmentSelect = (Select) context.get(\"department\");\nInput expenseDateInput = (Input) context.get(\"expenseDate\");\nSelect categorySelect = (Select) context.get(\"category\");\nInput amountInput = (Input) context.get(\"amount\");\nSelect currencySelect = (Select) context.get(\"currency\");\nTextArea descriptionTextArea = (TextArea) context.get(\"description\");\n\nMap<String, String> properties = new HashMap();\nproperties.put(\"okp:expense_report.department\", \"[\\\"\" + departmentSelect.getValue() + \"\\\"]\");\nproperties.put(\"okp:expense_report.expenseDate\", expenseDateInput.getValue());\nproperties.put(\"okp:expense_report.category\", \"[\\\"\" + categorySelect.getValue() + \"\\\"]\");\nproperties.put(\"okp:expense_report.amount\", amountInput.getValue());\nproperties.put(\"okp:expense_report.currency\", \"[\\\"\" + currencySelect.getValue() + \"\\\"]\");\nproperties.put(\"okp:expense_report.description\", descriptionTextArea.getValue());\nproperties.put(\"okp:expense_report.status\", \"[\\\"pending_manager_approval\\\"]\");\n\nws.propertyGroup.setProperties(expenseRecordUuid, \"okg:expense_report\", properties);\n\nFileLogger.info(\"expense-report-approval\", \"Expense resubmitted by employee, metadata updated: \" + expenseRecordUuid);\n",
    "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" : "Save Expense Metadata",
    "posX" : 664.8409694777299,
    "posY" : 572.8310300700879,
    "description" : "",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 17,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 15,
      "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.*;\nimport java.util.*;\nimport java.text.SimpleDateFormat;\n\nOKMWebservices ws = WebservicesHelper.getInstance();\n\nString expenseRecordUuid = (String) context.get(\"expenseRecordUuid\");\nInput expenseNumberInput = (Input) context.get(\"expenseNumber\");\nString expenseNumber = expenseNumberInput.getValue();\n\n// Employee: the workflow initiator\nActor initiator = context.get(\"initiator\");\nString employeeName = initiator.getName();\nInput employeeInput = new Input();\nemployeeInput.setValue(employeeName);\ncontext.put(\"employee\", employeeInput);\n\n// Collect submitted form values\nSelect departmentSelect = (Select) context.get(\"department\");\nInput expenseDateInput = (Input) context.get(\"expenseDate\");\nSelect categorySelect = (Select) context.get(\"category\");\nInput amountInput = (Input) context.get(\"amount\");\nSelect currencySelect = (Select) context.get(\"currency\");\nTextArea descriptionTextArea = (TextArea) context.get(\"description\");\n\nMap<String, String> properties = new HashMap();\nproperties.put(\"okp:expense_report.expenseNumber\", expenseNumber);\nproperties.put(\"okp:expense_report.employee\", employeeName);\nproperties.put(\"okp:expense_report.department\", \"[\\\"\" + departmentSelect.getValue() + \"\\\"]\");\nproperties.put(\"okp:expense_report.expenseDate\", expenseDateInput.getValue());\nproperties.put(\"okp:expense_report.category\", \"[\\\"\" + categorySelect.getValue() + \"\\\"]\");\nproperties.put(\"okp:expense_report.amount\", amountInput.getValue());\nproperties.put(\"okp:expense_report.currency\", \"[\\\"\" + currencySelect.getValue() + \"\\\"]\");\nproperties.put(\"okp:expense_report.description\", descriptionTextArea.getValue());\nproperties.put(\"okp:expense_report.status\", \"[\\\"pending_manager_approval\\\"]\");\n\nif (!ws.propertyGroup.hasGroup(expenseRecordUuid, \"okg:expense_report\")) {\n  ws.propertyGroup.addGroup(expenseRecordUuid, \"okg:expense_report\", properties);\n} else {\n  ws.propertyGroup.setProperties(expenseRecordUuid, \"okg:expense_report\", properties);\n}\n\nFileLogger.info(\"expense-report-approval\", \"Metadata saved for \" + expenseNumber);",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 16,
    "type" : "action",
    "name" : "Set status - Rejected by manager",
    "posX" : 297.3288594417669,
    "posY" : 882.4448313668498,
    "description" : "",
    "sourcePosition" : "left",
    "targetPosition" : "right",
    "transitions" : [ {
      "id" : 18,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 16,
      "target" : 17
    } ],
    "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.*;\nimport java.util.*;\n\nOKMWebservices ws = WebservicesHelper.getInstance();\n\nString expenseRecordUuid = (String) context.get(\"expenseRecordUuid\");\nTextArea managerCommentsTextArea = (TextArea) context.get(\"managerComments\");\nString managerComments = managerCommentsTextArea != null ? managerCommentsTextArea.getValue() : \"\";\n\nMap<String, String> properties = new HashMap();\nproperties.put(\"okp:expense_report.status\", \"[\\\"rejected_manager\\\"]\");\nproperties.put(\"okp:expense_report.managerComments\", managerComments);\n\nws.propertyGroup.setProperties(expenseRecordUuid, \"okg:expense_report\", properties);\n\nFileLogger.info(\"expense-report-approval\", \"Expense rejected (final) by manager: \" + expenseRecordUuid);",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 17,
    "type" : "mail",
    "name" : "Mail - Final Rejection by manager",
    "posX" : 153.03457353840716,
    "posY" : 1012.582009814364,
    "description" : "",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 19,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 17,
      "target" : 18
    } ],
    "script" : null,
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : "${initiator.email}",
    "subject" : "Your expense report ${expenseNumber.value} has been rejected",
    "body" : "<p>Hello ${initiator.name},</p>\n<p>Your expense report <strong>${expenseNumber.value}</strong> has been rejected by your manager.</p>\n<p>Reason: ${managerComments.value}</p>"
  }, {
    "id" : 18,
    "type" : "end",
    "name" : "End by manager",
    "posX" : 114.82603361143504,
    "posY" : 1157.9283166343405,
    "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" : 19,
    "type" : "task",
    "name" : "Manager Review",
    "posX" : 1187.58639513741,
    "posY" : 1432.7681271891543,
    "description" : "",
    "sourcePosition" : "right",
    "targetPosition" : "left",
    "transitions" : [ {
      "id" : 20,
      "type" : "default",
      "name" : "clarification",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 19,
      "target" : 24
    }, {
      "id" : 21,
      "type" : "default",
      "name" : "replyFinance",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 19,
      "target" : 20
    }, {
      "id" : 22,
      "type" : "default",
      "name" : "rejected",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 19,
      "target" : 21
    } ],
    "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=\"Finance has rejected this expense report. Review the details and Finance's comments below, then decide how to proceed.\" name=\"instructions\" width=\"100%\"/>\n  <input label=\"Expense Record\" name=\"expenseRecordLink\" type=\"folder\" data=\"expenseRecordUuid\" readonly=\"true\"/>\n  <input label=\"Employee\" name=\"employeeReview\" type=\"text\" data=\"employee\" readonly=\"true\"/>\n  <select label=\"Department\" name=\"departmentReview\" type=\"simple\" data=\"department\" readonly=\"true\">\n    <option label=\"IT\" value=\"it\"/>\n    <option label=\"Finance\" value=\"finance\"/>\n    <option label=\"Operations\" value=\"operations\"/>\n    <option label=\"Sales\" value=\"sales\"/>\n    <option label=\"HR\" value=\"hr\"/>\n  </select>\n  <input label=\"Expense Date\" name=\"expenseDateReview\" type=\"date\" timeFormat=\"none\" data=\"expenseDate\" readonly=\"true\"/>\n  <select label=\"Category\" name=\"categoryReview\" type=\"simple\" data=\"category\" readonly=\"true\">\n    <option label=\"Travel\" value=\"travel\"/>\n    <option label=\"Meals\" value=\"meals\"/>\n    <option label=\"Accommodation\" value=\"accommodation\"/>\n    <option label=\"Office Supplies\" value=\"office_supplies\"/>\n    <option label=\"Other\" value=\"other\"/>\n  </select>\n  <input label=\"Amount\" name=\"amountReview\" type=\"text\" data=\"amount\" readonly=\"true\"/>\n  <select label=\"Currency\" name=\"currencyReview\" type=\"simple\" data=\"currency\" readonly=\"true\">\n    <option label=\"EUR\" value=\"EUR\"/>\n    <option label=\"USD\" value=\"USD\"/>\n    <option label=\"GBP\" value=\"GBP\"/>\n  </select>\n  <textarea label=\"Description\" name=\"descriptionReview\" data=\"description\" readonly=\"true\"/>\n  <textarea label=\"Finance Comments\" name=\"financeCommentsReview\" data=\"financeComments\" readonly=\"true\"/>\n  <textarea label=\"Manager Comments\" name=\"managerComments\"/>\n  <button name=\"clarify\" label=\"Request Employee Clarification\" transition=\"clarification\" color=\"warning\"/>\n  <button name=\"reject\" label=\"Reject\" transition=\"rejected\" color=\"danger\"/>\n  <button name=\"replyFinance\" label=\"Reply to Finance\" transition=\"replyFinance\" color=\"primary\"/>\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();\nList<TaskInstanceDTO> prevTasks = WorkflowUtils.getTaskInstances(piId, \"Manager Approval\");\n\nif (prevTasks != null && !prevTasks.isEmpty()) {\n  // Walk backwards to find the most recent completed actor\n  for (int i = prevTasks.size() - 1; i >= 0; i--) {\n    TaskInstanceDTO t = prevTasks.get(i);\n    if (t.getActor() != null && !t.getActor().isEmpty()) {\n      return t.getActor(); // Direct assignment — return String, not List\n    }\n  }\n}\n\n// Fallback: should not normally happen, Manager Approval always runs first\nreturn \"okmAdmin\";",
    "dueDate" : "",
    "repeat" : "",
    "notifyAssignment" : true,
    "notificationSubject" : "Workflow task assigment",
    "notificationBody" : "A workflow task has been assigned",
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 20,
    "type" : "action",
    "name" : "Set status - Pending Finance (Manager Reply)",
    "posX" : 946.3269595416497,
    "posY" : 1201.9161835990963,
    "description" : "",
    "sourcePosition" : "left",
    "targetPosition" : "right",
    "transitions" : [ {
      "id" : 23,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 20,
      "target" : 6
    } ],
    "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.*;\nimport java.util.*;\n\nOKMWebservices ws = WebservicesHelper.getInstance();\n\nString expenseRecordUuid = (String) context.get(\"expenseRecordUuid\");\nTextArea managerCommentsTextArea = (TextArea) context.get(\"managerComments\");\nString managerComments = managerCommentsTextArea != null ? managerCommentsTextArea.getValue() : \"\";\n\nMap<String, String> properties = new HashMap();\nproperties.put(\"okp:expense_report.status\", \"[\\\"pending_finance_validation\\\"]\");\nproperties.put(\"okp:expense_report.managerComments\", managerComments);\n\nws.propertyGroup.setProperties(expenseRecordUuid, \"okg:expense_report\", properties);\n\nFileLogger.info(\"expense-report-approval\", \"Manager replied to Finance, back to validation: \" + expenseRecordUuid);\n",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 21,
    "type" : "action",
    "name" : "Set status - Rejected by finance and manager",
    "posX" : 1531.8994365499316,
    "posY" : 1689.55046516178,
    "description" : "",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 24,
      "type" : "smoothstep",
      "name" : "",
      "color" : "#000000",
      "script" : "",
      "animated" : false,
      "source" : 21,
      "target" : 22
    } ],
    "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.*;\nimport java.util.*;\n\nOKMWebservices ws = WebservicesHelper.getInstance();\n\nString expenseRecordUuid = (String) context.get(\"expenseRecordUuid\");\nTextArea managerCommentsTextArea = (TextArea) context.get(\"managerComments\");\nString managerComments = managerCommentsTextArea != null ? managerCommentsTextArea.getValue() : \"\";\n\nMap<String, String> properties = new HashMap();\nproperties.put(\"okp:expense_report.status\", \"[\\\"rejected_manager\\\"]\");\nproperties.put(\"okp:expense_report.managerComments\", managerComments);\n\nws.propertyGroup.setProperties(expenseRecordUuid, \"okg:expense_report\", properties);\n\nFileLogger.info(\"expense-report-approval\", \"Expense rejected (final) by manager: \" + expenseRecordUuid);",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 22,
    "type" : "mail",
    "name" : "Mail - Final Rejection by finance and manager",
    "posX" : 1531.466590012813,
    "posY" : 1839.072768995413,
    "description" : "",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 25,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 22,
      "target" : 23
    } ],
    "script" : null,
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : "${initiator.email}",
    "subject" : "Your expense report ${expenseNumber.value} has been rejected",
    "body" : "<p>Hello ${initiator.name},</p>\n<p>Your expense report <strong>${expenseNumber.value}</strong> has been rejected by your manager.</p>\n<p>Reason: ${managerComments.value}</p>"
  }, {
    "id" : 23,
    "type" : "end",
    "name" : "End by finance and manager",
    "posX" : 1530.466590012813,
    "posY" : 1985.072768995413,
    "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" : 24,
    "type" : "action",
    "name" : "Set status - Clarification Requested",
    "posX" : 1665.902409821106,
    "posY" : 1135.4739547517236,
    "description" : "",
    "sourcePosition" : "right",
    "targetPosition" : "left",
    "transitions" : [ {
      "id" : 26,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 24,
      "target" : 12
    } ],
    "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.*;\nimport java.util.*;\n\nOKMWebservices ws = WebservicesHelper.getInstance();\n\nString expenseRecordUuid = (String) context.get(\"expenseRecordUuid\");\nTextArea managerCommentsTextArea = (TextArea) context.get(\"managerComments\");\nString managerComments = managerCommentsTextArea != null ? managerCommentsTextArea.getValue() : \"\";\n\nMap<String, String> properties = new HashMap();\nproperties.put(\"okp:expense_report.status\", \"[\\\"clarification_requested\\\"]\");\nproperties.put(\"okp:expense_report.managerComments\", managerComments);\n\nws.propertyGroup.setProperties(expenseRecordUuid, \"okg:expense_report\", properties);\n\nFileLogger.info(\"expense-report-approval\", \"Clarification requested for: \" + expenseRecordUuid);",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  } ]
}
