{
  "processId" : 1,
  "id" : 1,
  "name" : "complaint-management",
  "locked" : false,
  "version" : 5,
  "active" : true,
  "nodes" : [ {
    "id" : 1,
    "type" : "start",
    "name" : "workflow.start",
    "posX" : 500.0,
    "posY" : 20.0,
    "description" : "",
    "sourcePosition" : "bottom",
    "targetPosition" : "none",
    "transitions" : [ {
      "id" : 1,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 1,
      "target" : 2
    } ],
    "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" : "action",
    "name" : "Generate Claim Reference and Initial Data",
    "posX" : 500.0,
    "posY" : 160.0,
    "description" : "Generates the case number and creates the complaint record from the run_config intake data, then attaches the process instance to it.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 2,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 2,
      "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.*;\nimport java.util.*;\nimport java.util.Calendar;\n\nOKMWebservices ws = WebservicesHelper.getInstance();\n\n// --- Generate a sequential claim reference (CLM-YYYY-NNN) ---\n// Requires the APP_COUNTER table (see script.sql) with a row counter_key='complaint'\nSqlQueryResults counterResult = ws.repository.executeSqlQuery(\n    \"SELECT counter_value FROM APP_COUNTER WHERE counter_key = 'complaint'\");\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 = 'complaint'\");\n\nint year = Calendar.getInstance().get(Calendar.YEAR);\nString caseNumber = String.format(\"CLM-%d-%03d\", year, currentValue);\nFileLogger.info(\"complaint-management\", \"Case number generated: \" + caseNumber);\n\n// --- Read the data entered by the user in the \"run_config\" intake form ---\nString contactName = WorkflowUtils.getFormElementValue(context, \"contactName\");\nString contactEmail = WorkflowUtils.getFormElementValue(context, \"contactEmail\");\nString contactPhone = WorkflowUtils.getFormElementValue(context, \"contactPhone\");\nString claimDescription = WorkflowUtils.getFormElementValue(context, \"claimDescription\");\n\n// --- Create a dedicated folder + record to hold this complaint case ---\n// TODO: adjust the base repository path to match your OpenKM folder structure.\nString yearFolderPath = \"/okm:root/Complaints/\" + year;\nif (!ws.repository.hasNode(yearFolderPath)) {\n  ws.folder.createMissingFolders(yearFolderPath);\n}\nString yearFolderUuid = ws.repository.getNodeUuid(yearFolderPath);\n\nString recordPath = yearFolderPath + \"/\" + caseNumber;\nif (!ws.repository.hasNode(recordPath)) {\n  ws.record.create(yearFolderUuid, caseNumber, \"\", 0);\n}\nString recordUuid = ws.repository.getNodeUuid(recordPath);\n\n// --- Attach this workflow process instance to the new complaint record ---\nWorkflowUtils.setProcessInstanceNode(context, recordUuid);\nFileLogger.info(\"complaint-management\", \"Process instance attached to record \" + recordUuid);\n\n// --- Create the okg:complaint metadata group with the intake data + case number ---\nMap<String,String> properties = new HashMap();\nproperties.put(\"okp:complaint.contact_name\", contactName);\nproperties.put(\"okp:complaint.contact_email\", contactEmail);\nproperties.put(\"okp:complaint.contact_phone\", contactPhone);\nproperties.put(\"okp:complaint.claim_description\", claimDescription);\nproperties.put(\"okp:complaint.case_number\", caseNumber);\nproperties.put(\"okp:complaint.status\", \"[\\\"new\\\"]\");\nif (!ws.propertyGroup.hasGroup(recordUuid, \"okg:complaint\")) {\n  ws.propertyGroup.addGroup(recordUuid, \"okg:complaint\", properties);\n} else {\n  ws.propertyGroup.setProperties(recordUuid, \"okg:complaint\", properties);\n}\n\n// --- Plain-string context variables (for Mail templates and other scripts) ---\ncontext.put(\"caseNumber\", caseNumber);\ncontext.put(\"contactName\", contactName);\ncontext.put(\"contactEmail\", contactEmail);\ncontext.put(\"contactPhone\", contactPhone);\ncontext.put(\"claimDescription\", claimDescription);\n\n// --- Typed objects to pre-fill readonly form fields (data=) ---\nInput caseNumberInput = new Input();\ncaseNumberInput.setValue(caseNumber);\ncontext.put(\"caseNumberData\", caseNumberInput);\n\nInput contactNameInput = new Input();\ncontactNameInput.setValue(contactName);\ncontext.put(\"contactNameData\", contactNameInput);\n\nInput contactEmailInput = new Input();\ncontactEmailInput.setValue(contactEmail);\ncontext.put(\"contactEmailData\", contactEmailInput);\n\nTextArea claimDescriptionInput = new TextArea();\nclaimDescriptionInput.setValue(claimDescription);\ncontext.put(\"claimDescriptionData\", claimDescriptionInput);\n\n// --- Prepare a folder to attach the resolution document later (task \"Resolution\") ---\nString resolutionFolderPath = recordPath + \"/resolution\";\nif (!ws.repository.hasNode(resolutionFolderPath)) {\n  ws.folder.createMissingFolders(resolutionFolderPath);\n}\nString resolutionFolderUuid = ws.repository.getNodeUuid(resolutionFolderPath);\ncontext.put(\"resolutionFolderUuid\", resolutionFolderUuid);\n\nUpload resolutionUpload = new Upload();\nresolutionUpload.setFolderUuid(resolutionFolderUuid);\ncontext.put(\"resolutionUploadParams\", resolutionUpload);\n",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 3,
    "type" : "mail",
    "name" : "Acknowledgement of Receipt",
    "posX" : 500.0,
    "posY" : 300.0,
    "description" : "Sends an automatic acknowledgement of receipt to the claimant.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 3,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 3,
      "target" : 4
    } ],
    "script" : null,
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : "${contactEmail}",
    "subject" : "We have received your complaint - Case ${caseNumber}",
    "body" : "<p>Dear ${contactName},</p><p>We confirm that we have received your complaint.</p><p><strong>Case number: ${caseNumber}</strong></p><p>Our team will review it and get back to you as soon as possible.</p><p>Please reference this case number in any further correspondence about this matter.</p><p>Kind regards,<br/>Customer Care Team</p>"
  }, {
    "id" : 4,
    "type" : "task",
    "name" : "Classification",
    "posX" : 453.2068965517242,
    "posY" : 476.62068965517244,
    "description" : "The triage team classifies the complaint by type, priority and department.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 4,
      "type" : "default",
      "name" : "classify",
      "color" : "#2196F3",
      "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  <text label=\"&lt;strong&gt;Complaint classification&lt;/strong&gt;\" name=\"headerClassification\" />\n  <input label=\"Case number\" name=\"caseNumberDisplay\" type=\"text\" readonly=\"true\" data=\"caseNumberData\" />\n  <input label=\"Claimant\" name=\"contactNameDisplay\" type=\"text\" readonly=\"true\" data=\"contactNameData\" />\n  <input label=\"Contact email\" name=\"contactEmailDisplay\" type=\"text\" readonly=\"true\" data=\"contactEmailData\" />\n  <textarea label=\"Complaint description\" name=\"claimDescriptionDisplay\" type=\"text\" readonly=\"true\" data=\"claimDescriptionData\" />\n  <select label=\"Complaint type\" name=\"claimType\" type=\"simple\">\n    <option label=\"Product\" value=\"product\"/>\n    <option label=\"Service\" value=\"service\"/>\n    <option label=\"Billing\" value=\"billing\"/>\n    <option label=\"Customer service\" value=\"customer_service\"/>\n    <option label=\"Delivery / lead time\" value=\"delivery\"/>\n    <option label=\"Other\" value=\"other\"/>\n    <validator type=\"req\"/>\n  </select>\n  <select label=\"Priority\" name=\"priority\" type=\"simple\">\n    <option label=\"Low\" value=\"low\"/>\n    <option label=\"Medium\" value=\"medium\" selected=\"true\"/>\n    <option label=\"High\" value=\"high\"/>\n    <validator type=\"req\"/>\n  </select>\n  <select label=\"Department\" name=\"department\" type=\"simple\">\n    <option label=\"Customer Care\" value=\"customer_care\"/>\n    <option label=\"Quality\" value=\"quality\"/>\n    <option label=\"Operations\" value=\"operations\"/>\n    <option label=\"Billing\" value=\"billing\"/>\n    <option label=\"Legal\" value=\"legal\"/>\n    <option label=\"Other\" value=\"other\"/>\n    <validator type=\"req\"/>\n  </select>\n  <textarea label=\"Classification comments\" name=\"classificationComments\" type=\"text\" />\n  <button label=\"Classify and continue\" name=\"classify\" transition=\"classify\" style=\"yes\" color=\"success\" 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.*;\nimport java.util.*;\n\n// TODO: adjust \"ROLE_CLAIMS_TRIAGE\" to the actual OpenKM role used by the team that classifies complaints.\nOKMWebservices ws = WebservicesHelper.getInstance();\nList<String> userList = new ArrayList();\nfor (CommonUser commonUser : ws.auth.getUsersByRole(\"ROLE_CLAIMS_TRIAGE\")) {\n  userList.add(commonUser.getId());\n}\nreturn userList;\n",
    "dueDate" : "",
    "repeat" : "",
    "notifyAssignment" : true,
    "notificationSubject" : "New complaint pending classification - ${caseNumber}",
    "notificationBody" : "<p>A new complaint (case ${caseNumber}) is pending classification.</p>",
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 5,
    "type" : "task",
    "name" : "Assignment",
    "posX" : 453.2068965517242,
    "posY" : 752.5862068965517,
    "description" : "The coordinator manually assigns the complaint to the responsible person.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 5,
      "type" : "default",
      "name" : "assign",
      "color" : "#2196F3",
      "script" : null,
      "animated" : false,
      "source" : 5,
      "target" : 6
    } ],
    "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;strong&gt;Complaint assignment&lt;/strong&gt;\" name=\"headerAssignment\" />\n  <input label=\"Case number\" name=\"caseNumberDisplay2\" type=\"text\" readonly=\"true\" data=\"caseNumberData\" />\n  <textarea label=\"Complaint description\" name=\"claimDescriptionDisplay3\" type=\"text\" readonly=\"true\" data=\"claimDescriptionData\" />\n  <select label=\"Complaint type\" name=\"claimType\" type=\"simple\" readonly=\"true\" data=\"claimType\">\n    <option label=\"Product\" value=\"product\"/>\n    <option label=\"Service\" value=\"service\"/>\n    <option label=\"Billing\" value=\"billing\"/>\n    <option label=\"Customer service\" value=\"customer_service\"/>\n    <option label=\"Delivery / lead time\" value=\"delivery\"/>\n    <option label=\"Other\" value=\"other\"/>\n  </select>\n  <select label=\"Priority\" name=\"priority\" type=\"simple\" readonly=\"true\" data=\"priority\">\n    <option label=\"Low\" value=\"low\"/>\n    <option label=\"Medium\" value=\"medium\"/>\n    <option label=\"High\" value=\"high\"/>\n  </select>\n  <select label=\"Department\" name=\"department\" type=\"simple\" readonly=\"true\" data=\"department\">\n    <option label=\"Customer Care\" value=\"customer_care\"/>\n    <option label=\"Quality\" value=\"quality\"/>\n    <option label=\"Operations\" value=\"operations\"/>\n    <option label=\"Billing\" value=\"billing\"/>\n    <option label=\"Legal\" value=\"legal\"/>\n    <option label=\"Other\" value=\"other\"/>\n  </select>\n  <textarea label=\"Classification comments\" name=\"classificationCommentsDisplay\" type=\"text\" readonly=\"true\" data=\"classificationComments\" />\n  <select label=\"Assignee\" name=\"assignee\" type=\"simple\"\n     className=\"com.openkm.plugin.form.values.OptionSelectUserList\">\n    <validator type=\"req\"/>\n  </select>\n  <textarea label=\"Assignment comments\" name=\"assignmentComments\" type=\"text\" />\n  <button label=\"Assign\" name=\"assign\" transition=\"assign\" style=\"yes\" color=\"success\" 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.*;\nimport java.util.*;\n\n// TODO: adjust \"ROLE_CLAIMS_COORDINATOR\" to the actual OpenKM role used by the dispatch/coordination team.\nOKMWebservices ws = WebservicesHelper.getInstance();\nList<String> userList = new ArrayList();\nfor (CommonUser commonUser : ws.auth.getUsersByRole(\"ROLE_CLAIMS_COORDINATOR\")) {\n  userList.add(commonUser.getId());\n}\nreturn userList;\n",
    "dueDate" : "",
    "repeat" : "",
    "notifyAssignment" : true,
    "notificationSubject" : "Complaint pending assignment - ${caseNumber}",
    "notificationBody" : "<p>A classified complaint (case ${caseNumber}) is pending assignment to a responsible person.</p>",
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 6,
    "type" : "action",
    "name" : "Save Classification and Assignment",
    "posX" : 502.0344827586207,
    "posY" : 1000.4137931034481,
    "description" : "Persists type, priority, department and assignee in the case metadata.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 6,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 6,
      "target" : 7
    } ],
    "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();\nString uuid = context.get(\"uuid\");\n\nSelect claimType = (Select) context.get(\"claimType\");\nSelect priority = (Select) context.get(\"priority\");\nSelect department = (Select) context.get(\"department\");\nSelect assignee = (Select) context.get(\"assignee\");\n\ncontext.put(\"assigneeId\", assignee.getValue());\n\nMap<String,String> properties = new HashMap();\nproperties.put(\"okp:complaint.claim_type\", \"[\\\"\" + claimType.getValue() + \"\\\"]\");\nproperties.put(\"okp:complaint.priority\", \"[\\\"\" + priority.getValue() + \"\\\"]\");\nproperties.put(\"okp:complaint.department\", \"[\\\"\" + department.getValue() + \"\\\"]\");\nproperties.put(\"okp:complaint.assigned_to\", assignee.getValue());\nproperties.put(\"okp:complaint.status\", \"[\\\"assigned\\\"]\");\nws.propertyGroup.setProperties(uuid, \"okg:complaint\", properties);\n\nFileLogger.info(\"complaint-management\", \"Classification and assignment saved for \" + context.get(\"caseNumber\"));\n",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 7,
    "type" : "task",
    "name" : "Investigation",
    "posX" : 455.24137931034477,
    "posY" : 1159.1178022641705,
    "description" : "The assignee investigates the complaint and decides whether it can be resolved or more information is needed.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 7,
      "type" : "default",
      "name" : "resolved",
      "color" : "#4CAF50",
      "script" : null,
      "animated" : false,
      "source" : 7,
      "target" : 16
    }, {
      "id" : 8,
      "type" : "default",
      "name" : "missing_info",
      "color" : "#FFC107",
      "script" : null,
      "animated" : false,
      "source" : 7,
      "target" : 8
    } ],
    "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;strong&gt;Investigation&lt;/strong&gt;\" name=\"headerInvestigation\" />\n  <input label=\"Case number\" name=\"caseNumberDisplay3\" type=\"text\" readonly=\"true\" data=\"caseNumberData\" />\n  <textarea label=\"Complaint description\" name=\"claimDescriptionDisplay2\" type=\"text\" readonly=\"true\" data=\"claimDescriptionData\" />\n  <textarea label=\"Additional information received (if any)\" name=\"infoReceivedDisplay\" type=\"text\" readonly=\"true\" data=\"infoReceivedData\" />\n  <textarea label=\"Investigation notes / findings\" name=\"investigationFindings\" type=\"text\">\n    <validator type=\"req\"/>\n  </textarea>\n  <button label=\"Investigation complete - move to resolution\" name=\"resolved\" transition=\"resolved\" style=\"yes\" color=\"success\" validate=\"true\" />\n  <button label=\"Missing information from claimant\" name=\"missing_info\" transition=\"missing_info\" style=\"change\" color=\"warning\" 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.okmflow.rest.dto.*;\nimport com.openkm.util.*;\nimport java.util.*;\n\n// If this task has already run before (re-entry after \"Register Received Information\"),\n// re-assign it to the same investigator.\ndef procIns = context.get(\"processInstance\");\nlong piId = procIns.getId();\nList<TaskInstanceDTO> prevTasks = WorkflowUtils.getTaskInstances(piId, \"Investigation\");\nif (prevTasks != null && !prevTasks.isEmpty()) {\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 the person chosen in \"Assignment\"\nString assigneeId = context.get(\"assigneeId\");\nreturn assigneeId;\n",
    "dueDate" : "",
    "repeat" : "",
    "notifyAssignment" : true,
    "notificationSubject" : "Complaint assigned - Investigation pending ${caseNumber}",
    "notificationBody" : "<p>You have been assigned to investigate complaint ${caseNumber}.</p>",
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 8,
    "type" : "action",
    "name" : "Request Additional Information",
    "posX" : 1175.024535471882,
    "posY" : 1460.0489215167156,
    "description" : "Sends an email to the claimant requesting additional information.",
    "sourcePosition" : "top",
    "targetPosition" : "left",
    "transitions" : [ {
      "id" : 9,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 8,
      "target" : 9
    } ],
    "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 contactEmail = context.get(\"contactEmail\");\nString contactName = context.get(\"contactName\");\nString caseNumber = context.get(\"caseNumber\");\ndef findings = context.get(\"investigationFindings\");\nString findingsText = (findings == null) ? \"\" : findings.getValue();\n\nString from = \"noreply@nomail.com\"; // TODO: adjust to the real sending address\nList<String> to = new ArrayList();\nto.add(contactEmail);\nString subject = \"We need more information about your complaint - Case \" + caseNumber;\n\nString body = \"Dear \" + contactName + \",<br/><br/>\";\nbody += \"We are reviewing your complaint with case number \" + caseNumber + \" and need additional information to continue the investigation.<br/><br/>\";\nif (!findingsText.equals(\"\")) {\n  body += \"Details of what we need:<br/>\" + findingsText + \"<br/><br/>\";\n}\nbody += \"Please reply to this email with the requested information, referencing the case number.<br/><br/>\";\nbody += \"Kind regards,<br/>Customer Care Team\";\n\nws.mail.sendMail(from, to, subject, body);\nFileLogger.info(\"complaint-management\", \"Additional information request sent for \" + caseNumber);",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 9,
    "type" : "task",
    "name" : "Register Received Information",
    "posX" : 1124.3448275862072,
    "posY" : 980.9655172413791,
    "description" : "The investigator records the information received from the claimant (by email, phone, etc.) or closes the case if there is no response.",
    "sourcePosition" : "left",
    "targetPosition" : "bottom",
    "transitions" : [ {
      "id" : 10,
      "type" : "default",
      "name" : "continue_investigation",
      "color" : "#4CAF50",
      "script" : null,
      "animated" : false,
      "source" : 9,
      "target" : 7
    }, {
      "id" : 11,
      "type" : "default",
      "name" : "close_no_response",
      "color" : "#F44336",
      "script" : null,
      "animated" : false,
      "source" : 9,
      "target" : 17
    } ],
    "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;strong&gt;Register received information&lt;/strong&gt;\" name=\"headerRegister\" />\n  <input label=\"Case number\" name=\"caseNumberDisplay4\" type=\"text\" readonly=\"true\" data=\"caseNumberData\" />\n  <textarea label=\"Previous investigation notes\" name=\"investigationFindingsDisplay\" type=\"text\" readonly=\"true\" data=\"investigationFindings\" />\n  <textarea label=\"Information received from the claimant\" name=\"infoReceived\" type=\"text\">\n    <validator type=\"req\"/>\n  </textarea>\n  <button label=\"Continue investigation\" name=\"continue_investigation\" transition=\"continue_investigation\" style=\"yes\" color=\"success\" validate=\"true\" />\n  <button label=\"Close - no response\" name=\"close_no_response\" transition=\"close_no_response\" confirmation=\"The claimant has not responded. Confirm you want to close the case without resolution?\" style=\"no\" color=\"danger\" 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.okmflow.rest.dto.*;\nimport com.openkm.util.*;\nimport java.util.*;\n\ndef procIns = context.get(\"processInstance\");\nlong piId = procIns.getId();\nList<TaskInstanceDTO> prevTasks = WorkflowUtils.getTaskInstances(piId, \"Investigation\");\nif (prevTasks != null && !prevTasks.isEmpty()) {\n  for (TaskInstanceDTO t : prevTasks) {\n    if (t.getActor() != null && !t.getActor().isEmpty()) {\n      return t.getActor();\n    }\n  }\n}\n// Should not normally happen: fall back to the assigned responsible\nString assigneeId = context.get(\"assigneeId\");\nreturn assigneeId;",
    "dueDate" : "",
    "repeat" : "",
    "notifyAssignment" : true,
    "notificationSubject" : "Additional information pending registration - ${caseNumber}",
    "notificationBody" : "<p>When you receive the additional information from the claimant for case ${caseNumber}, register it here to continue the investigation.</p>",
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 10,
    "type" : "task",
    "name" : "Resolution",
    "posX" : 459.26261930329804,
    "posY" : 1666.6914600483954,
    "description" : "The investigator resolves the complaint and writes the final message for the claimant.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 12,
      "type" : "default",
      "name" : "communicate",
      "color" : "#2196F3",
      "script" : null,
      "animated" : false,
      "source" : 10,
      "target" : 11
    } ],
    "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;strong&gt;Resolution&lt;/strong&gt;\" name=\"headerResolution\" />\n  <input label=\"Case number\" name=\"caseNumberDisplay5\" type=\"text\" readonly=\"true\" data=\"caseNumberData\" />\n  <textarea label=\"Investigation notes\" name=\"investigationFindingsDisplay2\" type=\"text\" readonly=\"true\" data=\"investigationFindings\" />\n  <select label=\"Resolution type\" name=\"resolutionType\" type=\"simple\">\n    <option label=\"Accepted\" value=\"accepted\"/>\n    <option label=\"Rejected\" value=\"rejected\"/>\n    <option label=\"Partially accepted\" value=\"partial\"/>\n    <validator type=\"req\"/>\n  </select>\n  <textarea label=\"Resolution text (will be sent to the claimant)\" name=\"resolutionText\" type=\"text\">\n    <validator type=\"req\"/>\n  </textarea>\n  <upload label=\"Resolution document (optional)\" name=\"resolutionDocument\" data=\"resolutionUploadParams\" allowedExtensions=\"pdf;doc;docx\" />\n  <button label=\"Finish and notify the claimant\" name=\"communicate\" transition=\"communicate\" style=\"yes\" color=\"success\" 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.okmflow.rest.dto.*;\nimport com.openkm.util.*;\nimport java.util.*;\n\n// The investigator resolves the complaint directly (no additional approval step):\n// re-assign to the same actor who completed \"Investigation\".\ndef procIns = context.get(\"processInstance\");\nlong piId = procIns.getId();\nList<TaskInstanceDTO> prevTasks = WorkflowUtils.getTaskInstances(piId, \"Investigation\");\nif (prevTasks != null && !prevTasks.isEmpty()) {\n  for (TaskInstanceDTO t : prevTasks) {\n    if (t.getActor() != null && !t.getActor().isEmpty()) {\n      return t.getActor();\n    }\n  }\n}\nString assigneeId = context.get(\"assigneeId\");\nreturn assigneeId;\n",
    "dueDate" : "",
    "repeat" : "",
    "notifyAssignment" : true,
    "notificationSubject" : "Complaint ready to be resolved - ${caseNumber}",
    "notificationBody" : "<p>The investigation for complaint ${caseNumber} has finished. Please record the resolution.</p>",
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 11,
    "type" : "action",
    "name" : "Communicate Resolution to Claimant",
    "posX" : 508.1379310344827,
    "posY" : 1940.4423413501904,
    "description" : "Sends the final resolution to the claimant, attaching the resolution document if one was uploaded.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 13,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 11,
      "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 contactEmail = context.get(\"contactEmail\");\nString contactName = context.get(\"contactName\");\nString caseNumber = context.get(\"caseNumber\");\nString resolutionFolderUuid = context.get(\"resolutionFolderUuid\");\n\nSelect resolutionTypeSelect = (Select) context.get(\"resolutionType\");\nString resolutionType = resolutionTypeSelect.getValue();\n\ndef resolutionTextField = context.get(\"resolutionText\");\nString resolutionText = resolutionTextField.getValue();\n\nString resolutionLabel;\nif (resolutionType.equals(\"accepted\")) {\n  resolutionLabel = \"Accepted\";\n} else if (resolutionType.equals(\"rejected\")) {\n  resolutionLabel = \"Rejected\";\n} else {\n  resolutionLabel = \"Partially accepted\";\n}\n\n// Check whether a resolution document was attached in the previous task\nList<String> docsId = new ArrayList();\nList<Document> resolutionDocs = ws.document.getChildren(resolutionFolderUuid);\nfor (Document d : resolutionDocs) {\n  docsId.add(d.getUuid());\n}\n\nList<String> to = new ArrayList();\nto.add(contactEmail);\nString from = \"noreply@nomail.com\"; // TODO: adjust to the real sending address\nString subject = \"Resolution of your complaint - Case \" + caseNumber;\n\nString body = \"Dear \" + contactName + \",<br/><br/>\";\nbody += \"We would like to inform you of the resolution of your complaint with case number \" + caseNumber + \".<br/><br/>\";\nbody += \"<strong>Outcome: \" + resolutionLabel + \"</strong><br/><br/>\";\nbody += resolutionText + \"<br/><br/>\";\nif (!docsId.isEmpty()) {\n  body += \"Please find attached documentation related to this resolution.<br/><br/>\";\n}\nbody += \"If you have any questions, please reply to this email referencing your case number.<br/><br/>\";\nbody += \"Kind regards,<br/>Customer Care Team\";\n\nif (docsId.isEmpty()) {\n  ws.mail.sendMail(from, to, subject, body);\n} else {\n  ws.mail.sendMailWithAttachments(from, to, new ArrayList(), new ArrayList(), new ArrayList(),\n      subject, body, docsId, resolutionFolderUuid);\n}\n\ncontext.put(\"resolutionLabel\", resolutionLabel);\nFileLogger.info(\"complaint-management\", \"Resolution communication sent for \" + caseNumber);\n",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 12,
    "type" : "action",
    "name" : "Close Claim",
    "posX" : 510.12468826881513,
    "posY" : 2105.09476207508,
    "description" : "Marks the case as closed and records the closing date.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 14,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 12,
      "target" : 13
    } ],
    "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;\nimport java.util.Date;\n\nOKMWebservices ws = WebservicesHelper.getInstance();\nString uuid = context.get(\"uuid\");\n\nSelect resolutionTypeSelect = (Select) context.get(\"resolutionType\");\n\nMap<String,String> closeProps = new HashMap();\ncloseProps.put(\"okp:complaint.resolution_type\", \"[\\\"\" + resolutionTypeSelect.getValue() + \"\\\"]\");\ncloseProps.put(\"okp:complaint.status\", \"[\\\"closed\\\"]\");\nSimpleDateFormat sdf = new SimpleDateFormat(\"yyyyMMddHHmmss\");\ncloseProps.put(\"okp:complaint.closed_date\", sdf.format(new Date()));\nws.propertyGroup.setProperties(uuid, \"okg:complaint\", closeProps);\n\nFileLogger.info(\"complaint-management\", \"Case closed: \" + context.get(\"caseNumber\"));\n",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 13,
    "type" : "end",
    "name" : "Closed",
    "posX" : 512.1114455031477,
    "posY" : 2253.614497303867,
    "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" : 14,
    "type" : "end",
    "name" : "Closed - No Response",
    "posX" : 915.1579617474813,
    "posY" : 1333.4180590901285,
    "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" : 15,
    "type" : "task",
    "name" : "run_config",
    "posX" : 1071.7555224114612,
    "posY" : 27.715109346045296,
    "description" : "Pre-start intake form: collects the claimant's contact details and the complaint description before the process instance is created.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ ],
    "script" : null,
    "form" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE workflow-form PUBLIC \"-//OpenKM//DTD Workflow Form 1.1//EN\"\n                                \"https://www.openkm.com/dtd/workflow-form-1.1.dtd\">\n<workflow-form>\n  <text label=\"&lt;strong&gt;New complaint / claim intake&lt;/strong&gt;\" name=\"headerIntake\" />\n  <input label=\"Claimant name\" name=\"contactName\" type=\"text\" timeFormat=\"none\">\n    <validator type=\"req\"/>\n  </input>\n  <input label=\"Contact email\" name=\"contactEmail\" type=\"text\" timeFormat=\"none\">\n    <validator type=\"req\"/>\n    <validator type=\"email\"/>\n  </input>\n  <input label=\"Contact phone\" name=\"contactPhone\" type=\"text\" timeFormat=\"none\" />\n  <textarea label=\"Complaint description\" name=\"claimDescription\" type=\"text\">\n    <validator type=\"req\"/>\n  </textarea>\n</workflow-form>",
    "assignExpr" : "\"\";",
    "dueDate" : "",
    "repeat" : "",
    "notifyAssignment" : true,
    "notificationSubject" : "Workflow task assignment",
    "notificationBody" : "A workflow task has been assigned",
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 16,
    "type" : "action",
    "name" : "Save Investigation Findings",
    "posX" : 505.6689308583123,
    "posY" : 1506.7551800272547,
    "description" : "Persists the investigation notes and updates the case status once the investigation is complete.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 15,
      "type" : "default",
      "name" : "",
      "color" : "#000000",
      "script" : null,
      "animated" : false,
      "source" : 16,
      "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.*;\n\nOKMWebservices ws = WebservicesHelper.getInstance();\nString uuid = context.get(\"uuid\");\n\ndef findings = context.get(\"investigationFindings\");\nString findingsText = (findings == null) ? \"\" : findings.getValue();\n\nMap<String,String> properties = new HashMap();\nproperties.put(\"okp:complaint.investigation_findings\", findingsText);\nproperties.put(\"okp:complaint.status\", \"[\\\"pending_resolution\\\"]\");\nws.propertyGroup.setProperties(uuid, \"okg:complaint\", properties);\n\nFileLogger.info(\"complaint-management\", \"Investigation findings saved for \" + context.get(\"caseNumber\"));\n",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  }, {
    "id" : 17,
    "type" : "action",
    "name" : "Close Claim - No Response",
    "posX" : 913.9126491954213,
    "posY" : 1196.7961742105879,
    "description" : "Marks the case as closed without a response from the claimant and records the closing date.",
    "sourcePosition" : "bottom",
    "targetPosition" : "top",
    "transitions" : [ {
      "id" : 16,
      "type" : "default",
      "name" : "",
      "color" : "#F44336",
      "script" : null,
      "animated" : false,
      "source" : 17,
      "target" : 14
    } ],
    "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;\nimport java.util.Date;\n\nOKMWebservices ws = WebservicesHelper.getInstance();\nString uuid = context.get(\"uuid\");\n\nMap<String,String> closeProps = new HashMap();\ncloseProps.put(\"okp:complaint.status\", \"[\\\"closed_no_response\\\"]\");\nSimpleDateFormat sdf = new SimpleDateFormat(\"yyyyMMddHHmmss\");\ncloseProps.put(\"okp:complaint.closed_date\", sdf.format(new Date()));\nws.propertyGroup.setProperties(uuid, \"okg:complaint\", closeProps);\n\nFileLogger.info(\"complaint-management\", \"Case closed without response: \" + context.get(\"caseNumber\"));\n",
    "form" : null,
    "assignExpr" : null,
    "dueDate" : null,
    "repeat" : null,
    "notifyAssignment" : true,
    "notificationSubject" : null,
    "notificationBody" : null,
    "recipients" : null,
    "subject" : null,
    "body" : null
  } ]
}
