8
n8n 한국어amn8n.com

GLPI 지원 성능 보고서 생성(SLA 추적 및 이메일 발송)

고급

이것은Content Creation, Multimodal AI분야의자동화 워크플로우로, 20개의 노드를 포함합니다.주로 Set, Code, Html, Gmail, SplitOut 등의 노드를 사용하며. GLPI 지원 성능 보고서 생성, SLA 추적 및 이메일 전송 기능 포함

사전 요구사항
  • Google 계정 및 Gmail API 인증 정보
  • 대상 API의 인증 정보가 필요할 수 있음
워크플로우 미리보기
노드 연결 관계를 시각적으로 표시하며, 확대/축소 및 이동을 지원합니다
워크플로우 내보내기
다음 JSON 구성을 복사하여 n8n에 가져오면 이 워크플로우를 사용할 수 있습니다
{
  "meta": {
    "instanceId": "6fe840c9f744c9e44a1c50b6467124995157353b1fc80f3a8dd173276e4fc270",
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "d17beade-5e8d-482f-ad6a-d3f692b3ddc0",
      "name": "Variables",
      "type": "n8n-nodes-base.set",
      "position": [
        -448,
        32
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "ea290016-88f0-4287-be92-7a3f8c7046d6",
              "name": "Server URL",
              "type": "string",
              "value": "https://server_glpi.com/"
            },
            {
              "id": "5cd7f69c-f079-4155-b887-c4b5e6e1cb64",
              "name": "App Token",
              "type": "string",
              "value": "\"You app token\""
            },
            {
              "id": "4c2a3325-1547-4333-805a-c74b711e3bc5",
              "name": "Entity name",
              "type": "string",
              "value": "\"name_entity\""
            },
            {
              "id": "96765e53-2275-41e9-a297-b64207fa4a79",
              "name": "WORK_START",
              "type": "string",
              "value": "8"
            },
            {
              "id": "4c04dfd8-64ef-4ae0-8375-e3108222a4b8",
              "name": "LUNCH_START",
              "type": "string",
              "value": "12"
            },
            {
              "id": "b76f06aa-405f-421d-b64f-7468222ddfb8",
              "name": "LUNCH_END",
              "type": "string",
              "value": "13"
            },
            {
              "id": "1a1a5672-226e-439e-8121-bb48fbe46f67",
              "name": "WORK_END",
              "type": "string",
              "value": "18"
            },
            {
              "id": "b8ee7859-6533-4642-861b-d0e0136c3b39",
              "name": "SLA_LIMIT_HOURS",
              "type": "string",
              "value": "24"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "3042ce97-b7b8-47c0-b702-905a31114297",
      "name": "Edit Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        416,
        32
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "5a116716-658c-425a-9817-b84cfa462819",
              "name": "Ticket_id",
              "type": "string",
              "value": "={{ $json[\"2\"] }}"
            },
            {
              "id": "6deaea47-3c4a-4a2f-80de-a790f4dcd417",
              "name": "Title",
              "type": "string",
              "value": "={{ $json[\"1\"] }}"
            },
            {
              "id": "a710ff8c-c898-435d-91eb-c67e71ddc5f7",
              "name": "technical_id",
              "type": "string",
              "value": "={{ $json[\"5\"] }}"
            },
            {
              "id": "0ee2215d-760e-433e-9f1f-3237a8d0860c",
              "name": "Entity",
              "type": "string",
              "value": "={{ $json[\"80\"] }}"
            },
            {
              "id": "7b02dcbd-49df-43f9-b4e4-01b7d93a9a8e",
              "name": "Opening date",
              "type": "string",
              "value": "={{ $json[\"15\"] }}"
            },
            {
              "id": "62e29ecb-0dc2-4e94-ada5-c9e076dc596d",
              "name": "Solution date",
              "type": "string",
              "value": "={{ $json[\"17\"] }}"
            },
            {
              "id": "9741e21c-b42a-42e7-a58b-68947b24f29e",
              "name": "Closing date",
              "type": "string",
              "value": "={{ $json[\"16\"] }}"
            },
            {
              "id": "06abb1e0-7d26-4ac1-bd5e-a1c3b1823e3e",
              "name": "Status",
              "type": "string",
              "value": "={{ $json[\"12\"] }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "7cf4932f-9afd-4fb4-94e7-22f2f7c634a9",
      "name": "분할 출력",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        192,
        32
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "data"
      },
      "typeVersion": 1
    },
    {
      "id": "e583f78f-0288-4166-b930-ebb39a88f7ef",
      "name": "Send a message",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1056,
        -176
      ],
      "webhookId": "4bee6d0c-8e87-46ff-90f0-a3539439b8cf",
      "parameters": {
        "sendTo": "info@example.com",
        "message": "={{ $json.html }}",
        "options": {},
        "subject": "=Report - {{ $('Date range').first().json.month }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "1vGUy7BPigbNRllM",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "0cd4a9c1-5e1e-47b8-ba4c-92ffbdfef6d2",
      "name": "Get tickets",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -16,
        -176
      ],
      "parameters": {
        "url": "={{ $('Variables').item.json[\"Server URL\"] }}apirest.php/search/Ticket",
        "options": {},
        "sendQuery": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "criteria[0][field]",
              "value": "15"
            },
            {
              "name": "criteria[0][searchtype]",
              "value": "morethan"
            },
            {
              "name": "criteria[0][value]",
              "value": "={{ $('Date range').item.json.startDate }}"
            },
            {
              "name": "criteria[1][link]",
              "value": "AND"
            },
            {
              "name": "criteria[1][field]",
              "value": "15"
            },
            {
              "name": "criteria[1][searchtype]",
              "value": "lessthan"
            },
            {
              "name": "criteria[1][value]",
              "value": "={{ $('Date range').item.json.endDate }}"
            },
            {
              "name": "criteria[2][link]",
              "value": "AND"
            },
            {
              "name": "criteria[2][field]",
              "value": "80"
            },
            {
              "name": "criteria[2][searchtype]",
              "value": "contains"
            },
            {
              "name": "criteria[2][value]",
              "value": "={{ $('Variables').item.json[\"Entity name\"] }}"
            },
            {
              "name": "order",
              "value": "DESC"
            },
            {
              "name": "range",
              "value": "0-999"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "Session-Token",
              "value": "={{ $json.session_token }}"
            },
            {
              "name": "App-Token",
              "value": "={{ $('Variables').item.json[\"App Token\"] }}"
            }
          ]
        }
      },
      "credentials": {
        "httpBasicAuth": {
          "id": "1ri8MpwPvPOW9M8n",
          "name": "Api GLPI"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "0dc82824-be50-485d-b49a-398fff0dd4e1",
      "name": "일정 트리거",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -464,
        -544
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "months",
              "triggerAtDayOfMonth": 6
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "3b5061f5-6fb0-4620-8d1d-d699f973e755",
      "name": "Get session token",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -208,
        32
      ],
      "parameters": {
        "url": "={{ $json[\"Server URL\"] }}apirest.php/initSession",
        "options": {},
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {
              "name": "App-Token",
              "value": "={{ $json[\"App Token\"] }}"
            }
          ]
        }
      },
      "credentials": {
        "httpBasicAuth": {
          "id": "1ri8MpwPvPOW9M8n",
          "name": "Api GLPI"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "06ea7bb1-1347-4e14-8499-8df9c4b0619b",
      "name": "End session",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1232,
        -176
      ],
      "parameters": {
        "url": "={{ $('Variables').first().json[\"Server URL\"] }}apirest.php/killSession",
        "options": {},
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Session-Token",
              "value": "={{ $('Get session token').first().json.session_token }}"
            },
            {
              "name": "App-Token",
              "value": "={{ $('Variables').first().json[\"App Token\"] }}"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "5af4ce0e-c957-49a0-a081-7e5c9b84a714",
      "name": "작업 없음, do nothing",
      "type": "n8n-nodes-base.noOp",
      "position": [
        1408,
        -176
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "51e2a4d5-d133-4ba7-9013-e24e10529a15",
      "name": "Date range",
      "type": "n8n-nodes-base.code",
      "position": [
        -464,
        -272
      ],
      "parameters": {
        "jsCode": "// Get the date from the Schedule Trigger\nconst today = new Date($input.item.json.timestamp);\n\n// Calculate the previous month\nconst previousMonth = new Date(today.getFullYear(), today.getMonth() - 1, 1);\n\n// Start date: last day of the month before the previous month\nconst startDate = new Date(previousMonth.getFullYear(), previousMonth.getMonth(), 0);\n\n// End date: first day of the month after the previous month\nconst endDate = new Date(previousMonth.getFullYear(), previousMonth.getMonth() + 1, 1);\n\n// Format as YYYY-MM-DD\nconst startDateStr = startDate.toISOString().split('T')[0];\nconst endDateStr = endDate.toISOString().split('T')[0];\n\n// Get the report month and year\nconst monthNames = [\n  'January', 'February', 'March', 'April', 'May', 'June',\n  'July', 'August', 'September', 'October', 'November', 'December'\n];\nconst reportMonth = monthNames[previousMonth.getMonth()];\nconst reportYear = previousMonth.getFullYear();\n\nreturn {\n  json: {\n    month: `${reportMonth} ${reportYear}`,\n    startDate: startDateStr,\n    endDate: endDateStr\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "1946b065-da80-413f-aaee-0d23ce11eb6f",
      "name": "메모",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -864,
        -720
      ],
      "parameters": {
        "color": 4,
        "width": 544,
        "height": 304,
        "content": "## Schedule\n\nThe configuration is set to start on the 6th day of each month to ensure accurate SLA measurement. This is because if the cut-off date were set to the last day of the month, cases opened in the days immediately prior would not be measured correctly, negatively impacting the SLA calculation."
      },
      "typeVersion": 1
    },
    {
      "id": "1d5b834b-be04-4c55-9282-33586fd9a6a6",
      "name": "메모1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -864,
        -400
      ],
      "parameters": {
        "width": 544,
        "height": 288,
        "content": "## Data range \nThe month prior to the execution month is identified, and the range covering all days of that month is determined.\n\nExample:\n\nmonth: September 2025\nstartDate: 2025-08-31\nendDate: 2025-10-01\n\ndays\": 30,\ndates\": [\"2025-09-01\", \"...\", \"2025-09-30\"]\n"
      },
      "typeVersion": 1
    },
    {
      "id": "1284666f-52b4-49c0-b398-5e028eb80823",
      "name": "메모2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -864,
        -96
      ],
      "parameters": {
        "color": 3,
        "width": 544,
        "height": 400,
        "content": "## Variables\n\nIn this node, the connection parameters to the GLPI server are updated:\n\nGLPI server URL: https://server_glpi.com/\n\nGLPI API App-Token: Here_App-Token\n\nGLPI entity name: name_entity\n\n\n\nSetting working hours \n\n(WORK_START, LUNCH_START, LUNCH_END, WORK_END) and SLA limit in hours (SLA_LIMIT_HOURS)"
      },
      "typeVersion": 1
    },
    {
      "id": "9ec74986-a8f0-43ec-935b-e26f16e45376",
      "name": "메모4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -256,
        -368
      ],
      "parameters": {
        "color": 5,
        "width": 480,
        "height": 320,
        "content": "## Get tickets\n\nThe node retrieves GLPI cases based on the defined entity, applying the date range configured in Data range to filter by opening date. By default, the query is limited to a range of 0–999 cases, which can be adjusted as needed."
      },
      "typeVersion": 1
    },
    {
      "id": "f38ad03a-8f49-4169-94da-ae3765796acc",
      "name": "메모3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        256,
        -576
      ],
      "parameters": {
        "width": 544,
        "height": 528,
        "content": "## Get report\nhe node calculates the effective working hours between ticket opening and resolution/closure, considering only business hours (8:00–12:00 and 13:00–16:00, excluding weekends).\n\nChecks SLA compliance based on SLA_LIMIT_HOURS (default: 24 hours).\n\n- Classifies tickets by status (open, in progress, resolved, closed).\n- Sums total working hours and calculates the average hours per ticket.\n- Determines the SLA compliance percentage.\n\n\n### Generates two reports:\n- General Report: metrics for all incidents.\n- Report by Technician: metrics per technician.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "15df2869-8142-46b3-98f5-ef58bb750794",
      "name": "Metrics",
      "type": "n8n-nodes-base.code",
      "position": [
        544,
        -176
      ],
      "parameters": {
        "jsCode": "// n8n Function Node - GLPI Report with Case Totals\n// =================================================\n\n// Business hours configuration\nconst WORK_START = $('Variables').first().json.WORK_START;   // 8 AM\nconst LUNCH_START = $('Variables').first().json.LUNCH_START; // 12 PM\nconst LUNCH_END = $('Variables').first().json.WORK_END;   // 1 PM\nconst WORK_END = $('Variables').first().json.WORK_END;    // 6 PM\n\n// SLA configuration\nconst SLA_LIMIT_HOURS = $('Variables').first().json.SLA_LIMIT_HOURS; // cambiar aquí según SLA\n\nfunction toDate(str) {\n  return str ? new Date(str.replace(\" \", \"T\")) : null;\n}\n\nfunction isWeekend(date) {\n  const day = date.getDay();\n  return day === 0 || day === 6;\n}\n\n// Calculate effective working hours within business schedule\nfunction businessHoursDiff(start, end) {\n  if (!start || !end) return 0;\n  if (end < start) return 0;\n\n  let totalHours = 0;\n  let current = new Date(start);\n\n  while (current < end) {\n    if (isWeekend(current)) {\n      current.setDate(current.getDate() + 1);\n      current.setHours(WORK_START, 0, 0, 0);\n      continue;\n    }\n\n    const workMorningStart = new Date(current.setHours(WORK_START, 0, 0, 0));\n    const workMorningEnd = new Date(current.setHours(LUNCH_START, 0, 0, 0));\n    const workAfternoonStart = new Date(current.setHours(LUNCH_END, 0, 0, 0));\n    const workAfternoonEnd = new Date(current.setHours(WORK_END, 0, 0, 0));\n\n    const dayStart = start > workMorningStart ? start : workMorningStart;\n    const dayEnd = end < workAfternoonEnd ? end : workAfternoonEnd;\n\n    if (dayStart < workMorningEnd) {\n      totalHours += Math.max(0, (Math.min(dayEnd, workMorningEnd) - dayStart) / 3600000);\n    }\n    if (dayEnd > workAfternoonStart) {\n      totalHours += Math.max(0, (dayEnd - Math.max(dayStart, workAfternoonStart)) / 3600000);\n    }\n\n    current.setDate(current.getDate() + 1);\n    current.setHours(WORK_START, 0, 0, 0);\n  }\n\n  return totalHours;\n}\n\n// Convert decimal → \"Xh Ym\"\nfunction decimalToHM(decimal) {\n  const hours = Math.floor(decimal);\n  const minutes = Math.round((decimal - hours) * 60);\n  return `${hours}h ${minutes}m`;\n}\n\n// Initialize metrics\nlet general = { open: 0, in_progress: 0, solved: 0, closed: 0, hours: 0, sla_ok: 0, total: 0 };\nlet byTechnician = {};\n\n// Process tickets\nfor (const item of items) {\n  const t = item.json;\n\n  const opening = toDate(t[\"Opening date\"]);\n  const solution = toDate(t[\"Solution date\"]);\n  const closing = toDate(t[\"Closing date\"]);\n  const technician = t.technical_id || \"Unassigned\";\n  const status = parseInt(t.Status, 10);\n\n  const end = solution || closing;\n  const hours = end ? businessHoursDiff(opening, end) : 0;\n  const sla_ok = solution ? (hours <= SLA_LIMIT_HOURS ? 1 : 0) : 0;\n\n  // General report\n  if (status === 1) general.open++;\n  if (status === 2) general.in_progress++;\n  if (status === 5) general.solved++;\n  if (status === 6) general.closed++;\n  general.hours += hours;\n  general.sla_ok += sla_ok;\n  general.total++;\n\n  // Report by technician\n  if (!byTechnician[technician]) {\n    byTechnician[technician] = { open: 0, in_progress: 0, solved: 0, closed: 0, hours: 0, sla_ok: 0, total: 0 };\n  }\n  if (status === 1) byTechnician[technician].open++;\n  if (status === 2) byTechnician[technician].in_progress++;\n  if (status === 5) byTechnician[technician].solved++;\n  if (status === 6) byTechnician[technician].closed++;\n  byTechnician[technician].hours += hours;\n  byTechnician[technician].sla_ok += sla_ok;\n  byTechnician[technician].total++;\n}\n\n// Function to build summary\nfunction summary(data) {\n  return {\n    \"Total cases\": data.total,\n    \"Open cases\": data.open,\n    \"Cases in progress\": data.in_progress,\n    \"Solved cases\": data.solved,\n    \"Closed cases\": data.closed,\n    \"Total hours (decimal)\": data.hours.toFixed(2),\n    \"Total hours (formatted)\": decimalToHM(data.hours),\n    \"Average hours (decimal)\": data.total > 0 ? (data.hours / data.total).toFixed(2) : 0,\n    \"Average hours (formatted)\": data.total > 0 ? decimalToHM(data.hours / data.total) : \"0h 0m\",\n    \"SLA compliance\": data.total > 0 ? ((data.sla_ok / data.total) * 100).toFixed(2) + \"%\" : \"0%\"\n  };\n}\n\n// Final output\nreturn [\n  {\n    json: {\n      \"General Report\": summary(general),\n      \"Report by Technician\": Object.fromEntries(\n        Object.entries(byTechnician).map(([tech, data]) => [tech, summary(data)])\n      )\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "4dc2fc78-aedc-44ac-9c12-8343dee0ef20",
      "name": "Generate report",
      "type": "n8n-nodes-base.html",
      "position": [
        880,
        -176
      ],
      "parameters": {
        "html": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"/>\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n    <title>Case Report - Technical Support</title>\n    <style>\n        /* Reset styles */\n        body { margin: 0; padding: 0; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }\n        table { border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; }\n        img { border: 0; height: auto; line-height: 100%; outline: none; text-decoration: none; -ms-interpolation-mode: bicubic; }\n        \n        /* Responsive styles */\n        @media only screen and (max-width: 620px) {\n            .wrapper { width: 100% !important; }\n            .container { width: 100% !important; min-width: 100% !important; }\n            .mobile-padding { padding-left: 15px !important; padding-right: 15px !important; }\n            .metric-card { display: block !important; width: 100% !important; margin-bottom: 10px !important; }\n            .metric-row td { display: block !important; width: 100% !important; padding-bottom: 10px !important; }\n            .hide-mobile { display: none !important; }\n            .table-responsive { font-size: 12px !important; }\n            .table-responsive td { padding: 8px 4px !important; }\n        }\n    </style>\n</head>\n<body style=\"margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; background-color: #f3f4f6;\">\n    <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" role=\"presentation\" style=\"background-color: #f3f4f6; padding: 20px;\" class=\"wrapper\">\n        <tr>\n            <td align=\"center\">\n                <table width=\"600\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" role=\"presentation\" style=\"background-color: #ffffff; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); max-width: 600px;\" class=\"container\">\n                    \n                    <!-- Header -->\n                    <tr>\n                        <td style=\"background: linear-gradient(135deg, #2F3F64 0%, #1a2744 100%); background-color: #2F3F64; padding: 40px 30px; text-align: center;\" class=\"mobile-padding\">\n                            <h1 style=\"margin: 0; color: #ffffff; font-size: 26px; font-weight: bold; line-height: 1.3;\">\n                                📊 Technical Support Case Report - {{ $('Date range').first().json.month }}\n                            </h1>\n                            <p style=\"margin: 8px 0 0 0; color: #e2e8f0; font-size: 14px;\">\n                                Complete analysis of performance and case status\n                            </p>\n                        </td>\n                    </tr>\n                    \n                    <!-- Content -->\n                    <tr>\n                        <td style=\"padding: 30px;\" class=\"mobile-padding\">\n                            \n                            <!-- Section Title -->\n                            <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" role=\"presentation\" style=\"margin-bottom: 20px;\">\n                                <tr>\n                                    <td style=\"border-left: 4px solid #2F3F64; padding-left: 12px;\">\n                                        <h2 style=\"margin: 0; font-size: 18px; color: #0f172a; font-weight: bold;\">\n                                            📈 General Summary\n                                        </h2>\n                                    </td>\n                                </tr>\n                            </table>\n                            \n                            <!-- Metrics Row 1 -->\n                            <table width=\"100%\" cellpadding=\"8\" cellspacing=\"0\" border=\"0\" role=\"presentation\" style=\"margin-bottom: 12px;\" class=\"metric-row\">\n                                <tr>\n                                    <!-- Total Cases -->\n                                    <td width=\"25%\" style=\"background-color: #f8fafc; border-left: 4px solid #3b82f6; border-radius: 8px; padding: 16px; vertical-align: top;\" class=\"metric-card\">\n                                        <div style=\"font-size: 10px; color: #64748b; font-weight: bold; text-transform: uppercase; margin-bottom: 8px; letter-spacing: 0.5px;\">\n                                            TOTAL CASES\n                                        </div>\n                                        <div style=\"font-size: 26px; color: #0f172a; font-weight: bold; line-height: 1;\">\n                                            {{$json[\"General Report\"][\"Total cases\"]}}\n                                        </div>\n                                    </td>\n                                    \n                                    <td width=\"2%\" class=\"hide-mobile\"></td>\n                                    \n                                    <!-- Open Cases -->\n                                    <td width=\"25%\" style=\"background-color: #f8fafc; border-left: 4px solid #f59e0b; border-radius: 8px; padding: 16px; vertical-align: top;\" class=\"metric-card\">\n                                        <div style=\"font-size: 10px; color: #64748b; font-weight: bold; text-transform: uppercase; margin-bottom: 8px; letter-spacing: 0.5px;\">\n                                            OPEN CASES\n                                        </div>\n                                        <div style=\"font-size: 26px; color: #0f172a; font-weight: bold; line-height: 1;\">\n                                            {{$json[\"General Report\"][\"Open cases\"]}}\n                                        </div>\n                                    </td>\n                                    \n                                    <td width=\"2%\" class=\"hide-mobile\"></td>\n                                    \n                                    <!-- In Progress with Alert -->\n                                    <td width=\"23%\" style=\"background-color: #f8fafc; border-left: 4px solid #8b5cf6; border-radius: 8px; padding: 16px; vertical-align: top; position: relative;\" class=\"metric-card\">\n                                        <div style=\"font-size: 10px; color: #64748b; font-weight: bold; text-transform: uppercase; margin-bottom: 8px; letter-spacing: 0.5px;\">\n                                            IN PROGRESS\n                                        </div>\n                                        <div style=\"font-size: 26px; color: #0f172a; font-weight: bold; line-height: 1;\">\n                                            {{$json[\"General Report\"][\"Cases in progress\"]}}\n                                        </div>\n                                        {{parseInt($json[\"General Report\"][\"Cases in progress\"]) > 100 ? `\n                                        <div style=\"margin-top: 8px; padding: 4px 8px; background-color: #fef3c7; border-radius: 4px; font-size: 10px; color: #92400e; font-weight: bold;\">\n                                            ⚠️ HIGH VOLUME\n                                        </div>\n                                        ` : ''}}\n                                    </td>\n                                    \n                                    <td width=\"2%\" class=\"hide-mobile\"></td>\n                                    \n                                    <!-- Resolved -->\n                                    <td width=\"23%\" style=\"background-color: #f8fafc; border-left: 4px solid #10b981; border-radius: 8px; padding: 16px; vertical-align: top;\" class=\"metric-card\">\n                                        <div style=\"font-size: 10px; color: #64748b; font-weight: bold; text-transform: uppercase; margin-bottom: 8px; letter-spacing: 0.5px;\">\n                                            RESOLVED\n                                        </div>\n                                        <div style=\"font-size: 26px; color: #0f172a; font-weight: bold; line-height: 1;\">\n                                            {{$json[\"General Report\"][\"Solved cases\"]}}\n                                        </div>\n                                    </td>\n                                </tr>\n                            </table>\n                            \n                            <!-- Metrics Row 2 -->\n                            <table width=\"100%\" cellpadding=\"8\" cellspacing=\"0\" border=\"0\" role=\"presentation\" style=\"margin-bottom: 30px;\" class=\"metric-row\">\n                                <tr>\n                                    <!-- Closed -->\n                                    <td width=\"25%\" style=\"background-color: #f8fafc; border-left: 4px solid #6b7280; border-radius: 8px; padding: 16px; vertical-align: top;\" class=\"metric-card\">\n                                        <div style=\"font-size: 10px; color: #64748b; font-weight: bold; text-transform: uppercase; margin-bottom: 8px; letter-spacing: 0.5px;\">\n                                            CLOSED\n                                        </div>\n                                        <div style=\"font-size: 26px; color: #0f172a; font-weight: bold; line-height: 1;\">\n                                            {{$json[\"General Report\"][\"Closed cases\"]}}\n                                        </div>\n                                    </td>\n                                    \n                                    <td width=\"2%\" class=\"hide-mobile\"></td>\n                                    \n                                    <!-- Total Hours -->\n                                    <td width=\"25%\" style=\"background-color: #f8fafc; border-left: 4px solid #3b82f6; border-radius: 8px; padding: 16px; vertical-align: top;\" class=\"metric-card\">\n                                        <div style=\"font-size: 10px; color: #64748b; font-weight: bold; text-transform: uppercase; margin-bottom: 8px; letter-spacing: 0.5px;\">\n                                            TOTAL HOURS\n                                        </div>\n                                        <div style=\"font-size: 20px; color: #0f172a; font-weight: bold; line-height: 1;\">\n                                            {{$json[\"General Report\"][\"Total hours (formatted)\"]}}\n                                        </div>\n                                    </td>\n                                    \n                                    <td width=\"2%\" class=\"hide-mobile\"></td>\n                                    \n                                    <!-- Average -->\n                                    <td width=\"23%\" style=\"background-color: #f8fafc; border-left: 4px solid #f59e0b; border-radius: 8px; padding: 16px; vertical-align: top;\" class=\"metric-card\">\n                                        <div style=\"font-size: 10px; color: #64748b; font-weight: bold; text-transform: uppercase; margin-bottom: 8px; letter-spacing: 0.5px;\">\n                                            AVERAGE\n                                        </div>\n                                        <div style=\"font-size: 20px; color: #0f172a; font-weight: bold; line-height: 1;\">\n                                            {{$json[\"General Report\"][\"Average hours (formatted)\"]}}\n                                        </div>\n                                    </td>\n                                    \n                                    <td width=\"2%\" class=\"hide-mobile\"></td>\n                                    \n                                    <!-- SLA Compliance with Dynamic Color -->\n                                    <td width=\"23%\" style=\"background-color: #f8fafc; border-radius: 8px; padding: 16px; vertical-align: top;\" class=\"metric-card\">\n                                        {{(() => {\n                                            const sla = parseFloat($json[\"General Report\"][\"SLA compliance\"]);\n                                            const borderColor = sla >= 80 ? '#10b981' : sla >= 50 ? '#f59e0b' : '#ef4444';\n                                            return `<div style=\"border-left: 4px solid ${borderColor}; padding-left: 12px;\">\n                                                <div style=\"font-size: 10px; color: #64748b; font-weight: bold; text-transform: uppercase; margin-bottom: 8px; letter-spacing: 0.5px;\">\n                                                    SLA COMPLIANCE\n                                                </div>\n                                                <div style=\"font-size: 22px; color: #0f172a; font-weight: bold; line-height: 1;\">\n                                                    ${$json[\"General Report\"][\"SLA compliance\"]}\n                                                </div>\n                                            </div>`;\n                                        })()}}\n                                    </td>\n                                </tr>\n                            </table>\n                            \n                            <!-- Alert Section for Critical SLA -->\n                            {{parseFloat($json[\"General Report\"][\"SLA compliance\"]) < 50 ? `\n                            <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" role=\"presentation\" style=\"margin-bottom: 20px;\">\n                                <tr>\n                                    <td style=\"background-color: #fef2f2; border-left: 4px solid #dc2626; border-radius: 8px; padding: 16px;\">\n                                        <div style=\"font-size: 14px; color: #991b1b; font-weight: bold; margin-bottom: 4px;\">\n                                            ⚠️ CRITICAL ALERT\n                                        </div>\n                                        <div style=\"font-size: 13px; color: #7f1d1d; line-height: 1.5;\">\n                                            SLA compliance is below 50%. Immediate action required to improve service levels.\n                                        </div>\n                                    </td>\n                                </tr>\n                            </table>\n                            ` : ''}}\n                            \n                            <!-- Divider -->\n                            <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" role=\"presentation\" style=\"margin: 30px 0;\">\n                                <tr>\n                                    <td style=\"border-bottom: 1px solid #e2e8f0;\"></td>\n                                </tr>\n                            </table>\n                            \n                            <!-- Section Title 2 -->\n                            <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" role=\"presentation\" style=\"margin-bottom: 20px;\">\n                                <tr>\n                                    <td style=\"border-left: 4px solid #2F3F64; padding-left: 12px;\">\n                                        <h2 style=\"margin: 0; font-size: 18px; color: #0f172a; font-weight: bold;\">\n                                            👥 Technician Details\n                                        </h2>\n                                    </td>\n                                </tr>\n                            </table>\n                            \n                            <!-- Table -->\n                            <table width=\"100%\" cellpadding=\"12\" cellspacing=\"0\" border=\"0\" role=\"presentation\" style=\"border: 1px solid #e2e8f0; border-radius: 8px; overflow: hidden;\" class=\"table-responsive\">\n                                <thead>\n                                    <tr style=\"background-color: #f8fafc;\">\n                                        <th style=\"text-align: left; font-size: 11px; color: #475569; font-weight: bold; text-transform: uppercase; padding: 12px; border-bottom: 1px solid #e2e8f0;\">Technician</th>\n                                        <th style=\"text-align: center; font-size: 11px; color: #475569; font-weight: bold; text-transform: uppercase; padding: 12px; border-bottom: 1px solid #e2e8f0;\">Total</th>\n                                        <th style=\"text-align: center; font-size: 11px; color: #475569; font-weight: bold; text-transform: uppercase; padding: 12px; border-bottom: 1px solid #e2e8f0;\" class=\"hide-mobile\">Open</th>\n                                        <th style=\"text-align: center; font-size: 11px; color: #475569; font-weight: bold; text-transform: uppercase; padding: 12px; border-bottom: 1px solid #e2e8f0;\">Progress</th>\n                                        <th style=\"text-align: center; font-size: 11px; color: #475569; font-weight: bold; text-transform: uppercase; padding: 12px; border-bottom: 1px solid #e2e8f0;\" class=\"hide-mobile\">Solved</th>\n                                        <th style=\"text-align: center; font-size: 11px; color: #475569; font-weight: bold; text-transform: uppercase; padding: 12px; border-bottom: 1px solid #e2e8f0;\">Closed</th>\n                                        <th style=\"text-align: center; font-size: 11px; color: #475569; font-weight: bold; text-transform: uppercase; padding: 12px; border-bottom: 1px solid #e2e8f0;\" class=\"hide-mobile\">Total Hrs</th>\n                                        <th style=\"text-align: center; font-size: 11px; color: #475569; font-weight: bold; text-transform: uppercase; padding: 12px; border-bottom: 1px solid #e2e8f0;\" class=\"hide-mobile\">Average</th>\n                                        <th style=\"text-align: center; font-size: 11px; color: #475569; font-weight: bold; text-transform: uppercase; padding: 12px; border-bottom: 1px solid #e2e8f0;\">SLA</th>\n                                    </tr>\n                                </thead>\n                                <tbody>\n                                    {{($json[\"Report by Technician\"] && Object.keys($json[\"Report by Technician\"]).length > 0) \n                                        ? Object.keys($json[\"Report by Technician\"]).map(techId => {\n                                            const tech = $json[\"Report by Technician\"][techId];\n                                            const sla = parseFloat(tech[\"SLA compliance\"]);\n                                            const bgColor = sla >= 80 ? '#d1fae5' : sla >= 50 ? '#fef3c7' : '#fee2e2';\n                                            const textColor = sla >= 80 ? '#065f46' : sla >= 50 ? '#92400e' : '#991b1b';\n                                            const inProgress = parseInt(tech[\"Cases in progress\"]);\n                                            const progressAlert = inProgress > 100 ? 'background-color: #fef3c7;' : '';\n                                            \n                                            return `\n                                            <tr style=\"${progressAlert}\">\n                                                <td style=\"padding: 12px; font-size: 14px; color: #0f172a; font-weight: bold; border-bottom: 1px solid #f1f5f9;\">\n                                                    Technician #${techId}\n                                                </td>\n                                                <td style=\"padding: 12px; font-size: 14px; color: #334155; border-bottom: 1px solid #f1f5f9; text-align: center;\">\n                                                    ${tech[\"Total cases\"]}\n                                                </td>\n                                                <td style=\"padding: 12px; font-size: 14px; color: #334155; border-bottom: 1px solid #f1f5f9; text-align: center;\" class=\"hide-mobile\">\n                                                    ${tech[\"Open cases\"]}\n                                                </td>\n                                                <td style=\"padding: 12px; font-size: 14px; border-bottom: 1px solid #f1f5f9; text-align: center;\">\n                                                    <span style=\"${inProgress > 100 ? 'font-weight: bold; color: #92400e;' : 'color: #334155;'}\">\n                                                        ${tech[\"Cases in progress\"]}${inProgress > 100 ? ' ⚠️' : ''}\n                                                    </span>\n                                                </td>\n                                                <td style=\"padding: 12px; font-size: 14px; color: #334155; border-bottom: 1px solid #f1f5f9; text-align: center;\" class=\"hide-mobile\">\n                                                    ${tech[\"Solved cases\"]}\n                                                </td>\n                                                <td style=\"padding: 12px; font-size: 14px; color: #334155; border-bottom: 1px solid #f1f5f9; text-align: center;\">\n                                                    ${tech[\"Closed cases\"]}\n                                                </td>\n                                                <td style=\"padding: 12px; font-size: 14px; color: #334155; border-bottom: 1px solid #f1f5f9; text-align: center;\" class=\"hide-mobile\">\n                                                    ${tech[\"Total hours (formatted)\"]}\n                                                </td>\n                                                <td style=\"padding: 12px; font-size: 14px; color: #334155; border-bottom: 1px solid #f1f5f9; text-align: center;\" class=\"hide-mobile\">\n                                                    ${tech[\"Average hours (formatted)\"]}\n                                                </td>\n                                                <td style=\"padding: 12px; font-size: 14px; border-bottom: 1px solid #f1f5f9; text-align: center;\">\n                                                    <span style=\"display: inline-block; padding: 6px 12px; background-color: ${bgColor}; color: ${textColor}; font-size: 12px; font-weight: bold; border-radius: 12px; white-space: nowrap;\">\n                                                        ${tech[\"SLA compliance\"]}\n                                                    </span>\n                                                </td>\n                                            </tr>\n                                            `;\n                                        }).join('')\n                                        : '<tr><td colspan=\"9\" style=\"padding: 30px; text-align: center; color: #64748b; font-style: italic; border-bottom: 1px solid #f1f5f9;\">No technician data available</td></tr>'\n                                    }}\n                                </tbody>\n                            </table>\n                            \n                        </td>\n                    </tr>\n                    \n                    <!-- Footer -->\n                    <tr>\n                        <td style=\"background-color: #f8fafc; padding: 20px; text-align: center; border-top: 1px solid #e2e8f0;\">\n                            <p style=\"margin: 0 0 8px 0; color: #64748b; font-size: 12px;\">\n                                Report automatically generated by the technical support system\n                            </p>\n                            <p style=\"margin: 0; color: #94a3b8; font-size: 11px;\">\n                                Generated on: {{new Date().toLocaleString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', timeZone: 'America/Bogota' })}}\n                            </p>\n                        </td>\n                    </tr>\n                    \n                </table>\n            </td>\n        </tr>\n    </table>\n</body>\n</html>"
      },
      "typeVersion": 1.2
    },
    {
      "id": "b8578b10-7ce4-4bcc-945b-b938cfbd2fb7",
      "name": "메모5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -368,
        -1280
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 304,
        "content": "## Create GLPI API Credentials in n8n\n## Node https request\nSet up your GLPI credentials before configuring the workflow:\nCredential Name: Api GLPI (or your preferred name)\n\nAuthentication: Generic Credential Type → Basic Auth\nGeneric Auth Type: Basic Auth\nUsername: Your GLPI API username\nPassword: Your GLPI API password"
      },
      "typeVersion": 1
    },
    {
      "id": "dcfed78e-cb52-4a20-87b9-41e1699743b8",
      "name": "메모6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -864,
        -1280
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 304,
        "content": "## Tickets panel GLPI\nConfigure the tickets module in Assistance > Tickets with the following items using the tool icon.\n\nID\nTitle\nStatus\nOpening Date\nClosing Date\nResolution Date\nPriority\nRequester - Requester\nAssigned To - Technician"
      },
      "typeVersion": 1
    },
    {
      "id": "5623a271-7c94-40cb-9043-b9e6c2f35c71",
      "name": "메모7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1008,
        -320
      ],
      "parameters": {
        "width": 192,
        "height": 128,
        "content": "## Email\nAdd your email account"
      },
      "typeVersion": 1
    }
  ],
  "pinData": {},
  "connections": {
    "15df2869-8142-46b3-98f5-ef58bb750794": {
      "main": [
        [
          {
            "node": "4dc2fc78-aedc-44ac-9c12-8343dee0ef20",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out": {
      "main": [
        [
          {
            "node": "3042ce97-b7b8-47c0-b702-905a31114297",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "d17beade-5e8d-482f-ad6a-d3f692b3ddc0": {
      "main": [
        [
          {
            "node": "3b5061f5-6fb0-4620-8d1d-d699f973e755",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "51e2a4d5-d133-4ba7-9013-e24e10529a15": {
      "main": [
        [
          {
            "node": "d17beade-5e8d-482f-ad6a-d3f692b3ddc0",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3042ce97-b7b8-47c0-b702-905a31114297": {
      "main": [
        [
          {
            "node": "15df2869-8142-46b3-98f5-ef58bb750794",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "06ea7bb1-1347-4e14-8499-8df9c4b0619b": {
      "main": [
        [
          {
            "node": "No Operation, do nothing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "0cd4a9c1-5e1e-47b8-ba4c-92ffbdfef6d2": {
      "main": [
        [
          {
            "node": "Split Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "e583f78f-0288-4166-b930-ebb39a88f7ef": {
      "main": [
        [
          {
            "node": "06ea7bb1-1347-4e14-8499-8df9c4b0619b",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4dc2fc78-aedc-44ac-9c12-8343dee0ef20": {
      "main": [
        [
          {
            "node": "e583f78f-0288-4166-b930-ebb39a88f7ef",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "51e2a4d5-d133-4ba7-9013-e24e10529a15",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3b5061f5-6fb0-4620-8d1d-d699f973e755": {
      "main": [
        [
          {
            "node": "0cd4a9c1-5e1e-47b8-ba4c-92ffbdfef6d2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
자주 묻는 질문

이 워크플로우를 어떻게 사용하나요?

위의 JSON 구성 코드를 복사하여 n8n 인스턴스에서 새 워크플로우를 생성하고 "JSON에서 가져오기"를 선택한 후, 구성을 붙여넣고 필요에 따라 인증 설정을 수정하세요.

이 워크플로우는 어떤 시나리오에 적합한가요?

고급 - 콘텐츠 제작, 멀티모달 AI

유료인가요?

이 워크플로우는 완전히 무료이며 직접 가져와 사용할 수 있습니다. 다만, 워크플로우에서 사용하는 타사 서비스(예: OpenAI API)는 사용자 직접 비용을 지불해야 할 수 있습니다.

워크플로우 정보
난이도
고급
노드 수20
카테고리2
노드 유형9
난이도 설명

고급 사용자를 위한 16+개 노드의 복잡한 워크플로우

저자
Luis Hernandez

Luis Hernandez

@integropen

I like solving problems and have a true passion for no-code automation. I'm thoughtful by nature and enjoy finding ways to optimize processes, always guided by my principles and values.

외부 링크
n8n.io에서 보기

이 워크플로우 공유

카테고리

카테고리: 34