{
  "id": "EnNQafbUKMybv70w",
  "name": "Automatically lock Redmine, Gitlab accounts for employees after their last shift",
  "tags": [
    {
      "id": "HyLSX6V7QZs5MrZy",
      "name": "Odoo",
      "createdAt": "2025-03-24T01:54:27.030Z",
      "updatedAt": "2025-03-24T01:54:27.030Z"
    },
    {
      "id": "ROlM2EPm0TCikpBv",
      "name": "Redmine 6",
      "createdAt": "2025-03-26T07:11:53.633Z",
      "updatedAt": "2025-03-26T07:11:53.633Z"
    }
  ],
  "nodes": [
    {
      "id": "29e11f4a-6af3-4fcb-ac2f-0e287ce1f036",
      "name": "END",
      "type": "n8n-nodes-base.noOp",
      "position": [
        224,
        912
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "365d76e7-f556-4a20-9f30-9060b42fe747",
      "name": "Step2: Handle get today",
      "type": "n8n-nodes-base.code",
      "position": [
        -224,
        672
      ],
      "parameters": {
        "jsCode": "const today = new Date();\n\nconst formatDate = (date) => {\n  const year = date.getFullYear();\n  const month = String(date.getMonth() + 1).padStart(2, '0');\n  const day = String(date.getDate()).padStart(2, '0');\n  return `${year}-${month}-${day}`;\n};\nconst getDayOfWeek = (date) => {\n  const days = [\"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\", \"Sunday\"];\n  return days[date.getDay()];\n};\n\nreturn [\n  {\n    date: formatDate(today),\n    dayOfWeek: getDayOfWeek(today)\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "b388dae5-6b64-4f90-a24d-ebcec5639469",
      "name": "Step3: Set Variables",
      "type": "n8n-nodes-base.set",
      "position": [
        -432,
        912
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "={\n  \"redmine6_Url\": \"\",\n  \"odooUrl\": \"\",\n  \"limit\": 100,\n  \"web_search_read_api\": \"\",\n  \"web_read_api\": \"\",\n  \"gitlab_Url\": \"\"\n}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "d2a4f72b-e694-4604-b3b3-f21eaf13a177",
      "name": "Step5: If total_count is not equal to 0 = true",
      "type": "n8n-nodes-base.if",
      "position": [
        -16,
        784
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "40359ca9-0845-423c-9a96-58f06c9155df",
              "operator": {
                "type": "number",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.result.length }}",
              "rightValue": "={{ 0 }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "8a870043-42f4-4f41-b7de-d4f98e990b6e",
      "name": "Step6: Check if there is a valid record.",
      "type": "n8n-nodes-base.code",
      "position": [
        224,
        672
      ],
      "parameters": {
        "jsCode": "const inputData = $input.all();\nconst records = inputData[0].json.result.records;\n\nconst today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD\n\nconst filteredRecords = records.filter(record => record.state !== \"draft\" && record.state !== \"cancel\");\n\nconst result = filteredRecords\n  .filter(record => record.expected_revealing_date === today)\n  .map(record => ({ id: record.employee_id.id }));\n\nreturn result;\n"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "8228a302-6dff-4216-b043-b41656fcce68",
      "name": "Step7: If hasRecords is empty==> true",
      "type": "n8n-nodes-base.if",
      "position": [
        432,
        784
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "49b970b3-6c1f-4e8d-b165-6abdcb8b0079",
              "operator": {
                "type": "object",
                "operation": "empty",
                "singleValue": true
              },
              "leftValue": "={{ $json }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "2630d71f-971b-416f-bd38-6fe61a6fb8eb",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -496,
        512
      ],
      "parameters": {
        "width": 1068,
        "height": 584,
        "content": "## Step 1 --> 4: The flow will automatically run daily at 17:00 and check if any members are working their last shift on the current day.\n* Step 5: If there are no records, the flow will end. If there are records, it will filter the records that are NOT in draft or canceled state."
      },
      "typeVersion": 1
    },
    {
      "id": "73449f33-b4c1-4c5e-b3ae-4fd8da50bce7",
      "name": "Step1: Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -432,
        672
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1,
                2,
                3,
                4,
                5
              ],
              "triggerAtHour": "={{ 17 }}",
              "triggerAtMinute": "={{ 0 }}"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "2d3de564-bb63-4765-9663-5586c908b4f8",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        656,
        400
      ],
      "parameters": {
        "color": 4,
        "width": 832,
        "height": 488,
        "content": "## Loop Over Items\n- Get the information of that member on Odoo, then extract their work email.\n- Use that email to find that user on RM6.\n  + If found, take the user's ID and lock the user."
      },
      "typeVersion": 1
    },
    {
      "id": "d79b45c4-1f2a-40b9-b472-9d32123423ac",
      "name": "Step8: Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        672,
        688
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "9a50191b-a20a-4cdb-a461-47da8b8baafa",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1616,
        448
      ],
      "parameters": {
        "color": 5,
        "width": 1308,
        "height": 672,
        "content": "## Lock, remove all group, delete membership in project on RM6"
      },
      "typeVersion": 1
    },
    {
      "id": "245da7d1-8cf3-44f7-b56e-009c1087012d",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1632,
        1232
      ],
      "parameters": {
        "color": 2,
        "width": 1224,
        "height": 320,
        "content": "## Check block a user on Gitlab"
      },
      "typeVersion": 1
    },
    {
      "id": "71fc8048-ea59-4e1c-a6c5-73627aaa5205",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -272,
        1168
      ],
      "parameters": {
        "height": 80,
        "content": "## Use APIkey Odoo 18"
      },
      "typeVersion": 1
    },
    {
      "id": "3dbbadf8-4d27-49ef-afa4-bef8f35d63a6",
      "name": "END1",
      "type": "n8n-nodes-base.noOp",
      "position": [
        672,
        528
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "68681c9a-ae82-4b60-b9c5-5aab983cc712",
      "name": "Step11: Get user info in RM6",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1328,
        688
      ],
      "parameters": {
        "url": "={{ $node['Step3: Set Variables'].json.redmine6_Url}}users.json?name={{ $node['Step10: Handle work_email'].json.work_email }}",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 4.2
    },
    {
      "id": "cafcc135-283d-4d3b-ae21-6e9005637625",
      "name": "Step12:  Check if there is a record or not?",
      "type": "n8n-nodes-base.if",
      "position": [
        1568,
        688
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "557ae5fd-116a-4bc5-aac2-7343bc7e3eb8",
              "operator": {
                "type": "number",
                "operation": "equals"
              },
              "leftValue": "={{ $json.total_count }}",
              "rightValue": "={{ 1 }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "288bec11-508c-4ecb-8c9a-d319b595e496",
      "name": "Step13: Update the user's status to \"locked\" on RM6",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1792,
        608
      ],
      "parameters": {
        "url": "={{ $node['Step3: Set Variables'].json.redmine6_Url}}users/{{ $node['Step12:  Check if there is a record or not?'].json.users[0].id }}.json",
        "method": "PUT",
        "options": {},
        "jsonBody": "={\"user\": {\"status\": 3}}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "0dcb4fcd-c5ab-45bc-90e2-292b032af1b0",
      "name": "Step14: Remove the user from all groups in RM 6",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2000,
        608
      ],
      "parameters": {
        "url": "={{ $node['Step3: Set Variables'].json.redmine6_Url}}users/{{ $node['Step12:  Check if there is a record or not?'].json.users[0].id }}.json",
        "method": "PUT",
        "options": {},
        "jsonBody": "={\n  \"user\": {\n    \"group_ids\": []\n  }\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 4.2
    },
    {
      "id": "b30b26f1-5e2e-4d30-924e-6a0dca67456a",
      "name": "Step15: Get membership list of user in RM 6",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2224,
        608
      ],
      "parameters": {
        "url": "={{ $node['Step3: Set Variables'].json.redmine6_Url}}users/{{ $node['Step12:  Check if there is a record or not?'].json.users[0].id }}.json?include=memberships",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 4.2
    },
    {
      "id": "07847913-2ab6-4082-b804-e6d5cbe6e5f0",
      "name": "Step16: Get memberships_id",
      "type": "n8n-nodes-base.code",
      "position": [
        2432,
        608
      ],
      "parameters": {
        "jsCode": "const inputData = $input.all();\nconst membershipsProject = inputData[0].json.user.memberships;\nconst result = membershipsProject\n  .map(record => ({ id: record.id }));\n\nreturn result;\n"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "bb6be057-56e8-46d2-b1ee-092116f2f652",
      "name": "Step17: Loop Over memberships_id",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        2624,
        608
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "958a44fd-f6d6-4462-9d1a-97287532ec6f",
      "name": "Step18: Delete membership in project on RM 6",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        2800,
        704
      ],
      "parameters": {
        "url": "={{ $node['Step3: Set Variables'].json.redmine6_Url}}memberships/{{ $json.id }}.json",
        "method": "DELETE",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 4.2,
      "alwaysOutputData": true
    },
    {
      "id": "c82a9c18-1419-44bb-be44-ac216633fd73",
      "name": "Step19: Get user information in Gitlab",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1664,
        1344
      ],
      "parameters": {
        "url": "={{ $node['Step3: Set Variables'].json.gitlab_Url}}api/v4/users?search={{ $node['Step10: Handle work_email'].json.username }}",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": true
    },
    {
      "id": "fe50b2d0-7437-4272-97de-08f99ec45cd3",
      "name": "Step20:  Check if there is a record = true",
      "type": "n8n-nodes-base.if",
      "position": [
        1920,
        1328
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "557ae5fd-116a-4bc5-aac2-7343bc7e3eb8",
              "operator": {
                "type": "object",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $node['Step19: Get user information in Gitlab'].json }}",
              "rightValue": "={{ 1 }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "3ba6b5e4-a344-4021-89f0-59e2318dc557",
      "name": "Step21: Check if the user is not blocked = true",
      "type": "n8n-nodes-base.if",
      "position": [
        2160,
        1296
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "08948f8d-0661-4106-86a0-3f0b07214e94",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $node['Step19: Get user information in Gitlab'].json.state}}",
              "rightValue": "=blocked"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "eff03657-4a4a-467c-8a6c-87e78b85fc1a",
      "name": "Step22: Check if the user is not deactivate = true",
      "type": "n8n-nodes-base.if",
      "position": [
        2384,
        1280
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "abf4625d-6a78-4da6-a704-82fb8b83f152",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $node['Step19: Get user information in Gitlab'].json.state}}",
              "rightValue": "=banned"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "12ef1a30-ecba-4e4a-9d72-8eeaa2f442a5",
      "name": "Step23: Block a user in Gitlab",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2688,
        1328
      ],
      "parameters": {
        "url": "={{ $node['Step3: Set Variables'].json.gitlab_Url}}api/v4/users/{{ $node['Step20:  Check if there is a record = true'].json.id}}/block",
        "method": "POST",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": true
    },
    {
      "id": "e28de410-2e4a-47a0-8ac2-43e95049b077",
      "name": "Step24: Get user information in Gitlab",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1792,
        784
      ],
      "parameters": {
        "url": "={{ $node['Step3: Set Variables'].json.gitlab_Url}}api/v4/users?search={{ $node['Step10: Handle work_email'].json.username }}",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": true
    },
    {
      "id": "bda33ccf-b67b-4c09-996d-e86db238c771",
      "name": "Step25:  Check if there is a record = true",
      "type": "n8n-nodes-base.if",
      "position": [
        2000,
        784
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "557ae5fd-116a-4bc5-aac2-7343bc7e3eb8",
              "operator": {
                "type": "object",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $node['Step24: Get user information in Gitlab'].json }}",
              "rightValue": "={{ 1 }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "37324328-c131-4f3f-a8a3-4b635f580bd9",
      "name": "Step26: Check if the user is not blocked = true",
      "type": "n8n-nodes-base.if",
      "position": [
        2224,
        864
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "08948f8d-0661-4106-86a0-3f0b07214e94",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $node['Step24: Get user information in Gitlab'].json.state}}",
              "rightValue": "=blocked"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "2250c2c1-dfc1-4873-8600-51e829b2f688",
      "name": "Step27: Check if the user is not deactivate = true",
      "type": "n8n-nodes-base.if",
      "position": [
        2432,
        912
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "abf4625d-6a78-4da6-a704-82fb8b83f152",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $node['Step24: Get user information in Gitlab'].json.state}}",
              "rightValue": "=banned"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "1380048c-2981-4d07-9e63-3d6bf62f9e37",
      "name": "Step28: Block a user in Gitlab",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2688,
        960
      ],
      "parameters": {
        "url": "={{ $node['Step3: Set Variables'].json.gitlab_Url}}api/v4/users/{{ $node['Step25:  Check if there is a record = true'].json.id}}/block",
        "method": "POST",
        "options": {},
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "alwaysOutputData": true
    },
    {
      "id": "b218ac6d-1695-4e22-99f0-b8e93f52f368",
      "name": "Code",
      "type": "n8n-nodes-base.code",
      "position": [
        2800,
        480
      ],
      "parameters": {
        "jsCode": "return [\n  {}\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "87ad0556-fde3-47f6-b07a-ea545209db3e",
      "name": "Step9: Get employee information in Odoo 18",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        912,
        688
      ],
      "parameters": {
        "url": "={{ $node['Step3: Set Variables'].json.web_read_api}}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"id\": 26,\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"call\",\n  \"params\": {\n    \"model\": \"hr.employee\",\n    \"method\": \"web_read\",\n    \"args\": [\n      [\n        {{ $json.id }}\n      ]\n    ],\n    \"kwargs\": {\n      \"context\": {\n        \"lang\": \"en_US\",\n        \"tz\": \"Asia/Bangkok\",\n        \"allowed_company_ids\": [\n          1\n        ],\n        \"bin_size\": true,\n        \"params\": {\n          \"action\": \"employees\",\n          \"actionStack\": [\n            {\n              \"action\": \"employees\"\n            }\n          ]\n        },\n        \"chat_icon\": true\n      },\n      \"specification\": {\n        \"active\": {},\n        \"user_id\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n\n        \"work_email\": {}\n      }\n    }\n  }\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 4.2,
      "alwaysOutputData": false
    },
    {
      "id": "274c6f67-bfd6-4c2d-8ff5-a48dda3ed130",
      "name": "Step4: Get Employee Resignation in Odoo 18",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -224,
        912
      ],
      "parameters": {
        "url": "={{ $node['Step3: Set Variables'].json.web_search_read_api}}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"id\": 6,\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"call\",\n  \"params\": {\n    \"model\": \"hr.resignation\",\n    \"method\": \"web_search_read\",\n    \"args\": [],\n    \"kwargs\": {\n      \"specification\": {\n        \"employee_id\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"department_id\": {\n          \"fields\": {\n            \"display_name\": {}\n          }\n        },\n        \"employee_contract\": {},\n        \"joined_date\": {},\n        \"expected_revealing_date\": {},\n        \"approved_revealing_date\": {},\n        \"resignation_type\": {},\n        \"notice_period\": {},\n        \"state\": {}\n      },\n      \"offset\": 0,\n      \"order\": \"\",\n      \"limit\": {{ $node['Step3: Set Variables'].json.limit }},\n      \"context\": {\n        \"lang\": \"en_US\",\n        \"tz\": \"Asia/Bangkok\",\n        \"allowed_company_ids\": [\n          1\n        ],\n        \"bin_size\": true,\n        \"params\": {\n          \"action\": \"resignation\",\n          \"actionStack\": [\n            {\n              \"action\": \"resignation\"\n            }\n          ]\n        },\n        \"current_company_id\": 1\n      },\n      \"count_limit\": 10001,\n      \"domain\": [\n        [\n          \"state\",\n          \"in\",\n          [\n            \"draft\",\n            \"confirm\",\n            \"manager_approved\",\n            \"handed_over\",\n            \"cancel\"\n          ]\n        ]\n      ]\n    }\n  }\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 4.2,
      "alwaysOutputData": false
    },
    {
      "id": "ece600ac-63a2-4eef-9d6d-649110803be1",
      "name": "Step10: Handle work_email",
      "type": "n8n-nodes-base.code",
      "position": [
        1104,
        688
      ],
      "parameters": {
        "jsCode": "const inputData = $input.all();\nconst work_email = inputData[0].json.result[0].work_email.split('@')[0];\nconst username = work_email.split('.')[0];\nreturn {work_email, username};\n"
      },
      "executeOnce": false,
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "d39321ea-115d-4351-b8c0-4302668a3457",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1328,
        368
      ],
      "parameters": {
        "width": 800,
        "height": 1056,
        "content": "## Automatically lock Redmine, Gitlab accounts for employees after their last shift\nThis workflow is designed for IT Ops, HR, and Security teams automating employee offboarding. Zero manual work: Disable access to Redmine, GitLab, and more- right after their last day. Boost security, cut risks, and stay compliant.\n\n### \ud83d\udccc The Problem It Solves\nOffboarding is messy and slow:\n- HR flags ending contracts.\n- IT hunts down accounts manually (Redmine, GitLab, etc.).\n- Misses happen, risks linger.\n\nThis n8n workflow queries Odoo 18 daily, spots offboardees, and locks accounts automatically.\n\n### \ud83d\udccc What It Does\n- **Triggers** daily (e.g., 5 PM weekdays).\n- **Queries** Odoo 18 for employees ending today.\n- **Filters** active users needing offboarding.\n- **Checks & Locks** Redmine accounts via API.\n- **Checks & Revokes** GitLab access via API.\n- **Notifies** via Slack/Teams/email with summary.\n- **Handles Errors**: Retries failures, logs issues.\n\n### \ud83d\udccc Quick setup\n1. Odoo 18 API (read employee end dates/last shifts).\n2. Redmine Admin API key.\n3. GitLab Admin token (for locking users).\n4. Slack/Teams webhook or SMTP for alerts.\n5. Cron schedule (e.g., daily 5 PM weekdays, skip weekends).\n\n### \ud83d\udccc Customize It\n- **Add Systems**: Jira, Confluence, LDAP\u2014easy toggles.\n- **Notification**: Full reports or alerts-only.\n- **Error Rules**: Retries, escalations.\n- **Audit Logs**: Save to DB, S3, Sheets, or dashboard.\n\n### \ud83d\udccc Results\n100% automated: Accounts locked on exit day. No orphans, no workload, full compliance.\n\n### \ud83d\udccc Workflow in Action\n1. Schedule trigger fires.\n2. Pull Odoo offboardees.\n3. API checks & disables Redmine/GitLab.\n4. Logs + summary notification."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "c77edf40-edd5-45ae-bd93-ee3796cb3c58",
  "connections": {
    "END": {
      "main": [
        []
      ]
    },
    "Code": {
      "main": [
        [
          {
            "node": "Step19: Get user information in Gitlab",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step3: Set Variables": {
      "main": [
        [
          {
            "node": "Step4: Get Employee Resignation in Odoo 18",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step8: Loop Over Items": {
      "main": [
        [],
        [
          {
            "node": "Step9: Get employee information in Odoo 18",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step1: Schedule Trigger": {
      "main": [
        [
          {
            "node": "Step2: Handle get today",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step2: Handle get today": {
      "main": [
        [
          {
            "node": "Step3: Set Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step10: Handle work_email": {
      "main": [
        [
          {
            "node": "Step11: Get user info in RM6",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step16: Get memberships_id": {
      "main": [
        [
          {
            "node": "Step17: Loop Over memberships_id",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step11: Get user info in RM6": {
      "main": [
        [
          {
            "node": "Step12:  Check if there is a record or not?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step23: Block a user in Gitlab": {
      "main": [
        [
          {
            "node": "Step8: Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step28: Block a user in Gitlab": {
      "main": [
        [
          {
            "node": "Step8: Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step17: Loop Over memberships_id": {
      "main": [
        [
          {
            "node": "Code",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step18: Delete membership in project on RM 6",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step7: If hasRecords is empty==> true": {
      "main": [
        [
          {
            "node": "END1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step8: Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step19: Get user information in Gitlab": {
      "main": [
        [
          {
            "node": "Step20:  Check if there is a record = true",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step24: Get user information in Gitlab": {
      "main": [
        [
          {
            "node": "Step25:  Check if there is a record = true",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step6: Check if there is a valid record.": {
      "main": [
        [
          {
            "node": "Step7: If hasRecords is empty==> true",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step20:  Check if there is a record = true": {
      "main": [
        [
          {
            "node": "Step21: Check if the user is not blocked = true",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step8: Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step25:  Check if there is a record = true": {
      "main": [
        [
          {
            "node": "Step26: Check if the user is not blocked = true",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step8: Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step4: Get Employee Resignation in Odoo 18": {
      "main": [
        [
          {
            "node": "Step5: If total_count is not equal to 0 = true",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step9: Get employee information in Odoo 18": {
      "main": [
        [
          {
            "node": "Step10: Handle work_email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step12:  Check if there is a record or not?": {
      "main": [
        [
          {
            "node": "Step13: Update the user's status to \"locked\" on RM6",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step24: Get user information in Gitlab",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step15: Get membership list of user in RM 6": {
      "main": [
        [
          {
            "node": "Step16: Get memberships_id",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step18: Delete membership in project on RM 6": {
      "main": [
        [
          {
            "node": "Step17: Loop Over memberships_id",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step5: If total_count is not equal to 0 = true": {
      "main": [
        [
          {
            "node": "Step6: Check if there is a valid record.",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "END",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step14: Remove the user from all groups in RM 6": {
      "main": [
        [
          {
            "node": "Step15: Get membership list of user in RM 6",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step21: Check if the user is not blocked = true": {
      "main": [
        [
          {
            "node": "Step22: Check if the user is not deactivate = true",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step8: Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step26: Check if the user is not blocked = true": {
      "main": [
        [
          {
            "node": "Step27: Check if the user is not deactivate = true",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step8: Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step22: Check if the user is not deactivate = true": {
      "main": [
        [
          {
            "node": "Step23: Block a user in Gitlab",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step8: Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step27: Check if the user is not deactivate = true": {
      "main": [
        [
          {
            "node": "Step28: Block a user in Gitlab",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Step8: Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Step13: Update the user's status to \"locked\" on RM6": {
      "main": [
        [
          {
            "node": "Step14: Remove the user from all groups in RM 6",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}