{
  "updatedAt": "2026-03-25T17:05:27.000Z",
  "createdAt": "2026-01-05T04:35:09.412Z",
  "id": "93ZMYatYJvCIdKTJ",
  "name": "\ud611\ub825\uc0ac opem mall option \uc218\uc815",
  "description": null,
  "active": false,
  "isArchived": true,
  "nodes": [
    {
      "parameters": {},
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ],
      "id": "dd218ad6-46a7-42ff-8557-8ec83c23756a",
      "name": "When clicking \u2018Execute workflow\u2019"
    },
    {
      "parameters": {
        "fileSelector": "/home/node/vendor-automation/n8n_\uc635\uc158\ud06c\ub864\ub9c1_\ub124\uc774\ubc84_\uc644\ub8cc.xlsx",
        "options": {}
      },
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1,
      "position": [
        224,
        0
      ],
      "id": "67f58866-eaa1-4732-bde2-b8e6a0fdc50e",
      "name": "Read/Write Files from Disk"
    },
    {
      "parameters": {
        "operation": "xlsx",
        "options": {}
      },
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1.1,
      "position": [
        448,
        0
      ],
      "id": "b012afbf-cdc2-4c89-a647-e00c4d543b17",
      "name": "Extract from File"
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all();\n\n// product_variant_vendor_id\ub85c \uadf8\ub8f9\ud551 (\uc21c\uc11c \uc720\uc9c0)\nconst grouped = new Map();\n\nfor (const item of items) {\n  const data = item.json;\n  const pvvId = data.product_variant_vendor_id;\n  \n  if (!pvvId) continue;\n  \n  if (!grouped.has(pvvId)) {\n    grouped.set(pvvId, {\n      options: [],              // \uae30\ubcf8\uc635\uc158\n      additionalOptions: [],    // \ucd94\uac00\uc635\uc158\n      qtyPerUnit: data.open_mall_qty_per_unit || null,\n      needsManagerVerification: data.needs_manager_verification === true || data.needs_manager_verification === 'true' || data.needs_manager_verification === 'TRUE'\n    });\n  }\n  \n  if (data.option_title) {\n    const optionType = data.option_type || \"\uae30\ubcf8\uc635\uc158\";\n    \n    if (optionType === \"\ucd94\uac00\uc635\uc158\") {\n      // \ucd94\uac00\uc635\uc158 \u2192 \ud50c\ub7ab \ub9ac\uc2a4\ud2b8\n      grouped.get(pvvId).additionalOptions.push({\n        title: data.option_title,\n        value: data.option_value || \"\",\n        type: data.option_type_select || \"SELECT\"\n      });\n    } else {\n      // \uae30\ubcf8\uc635\uc158 \u2192 \uc138\ud2b8 \uadf8\ub8f9\n      grouped.get(pvvId).options.push({\n        title: data.option_title,\n        value: data.option_value || \"\",\n        type: data.option_type_select || \"SELECT\"\n      });\n    }\n  }\n}\n\n// GraphQL mutation input \ud615\uc2dd\uc73c\ub85c \ubcc0\ud658\nconst mutationInput = [];\n\nfor (const [pvvId, groupData] of grouped) {\n  const options = groupData.options;\n  const additionalOptions = groupData.additionalOptions;\n  \n  const encodedId = Buffer.from(`ProductVariantVendor:${pvvId}`).toString('base64');\n  \n  // \uae30\ubcf8\uc635\uc158: \uc138\ud2b8 \uad6c\uc870\ub85c \ubcc0\ud658\n  let optionSets = null;\n  if (options.length > 0) {\n    const uniqueTitles = [];\n    for (const opt of options) {\n      if (!uniqueTitles.includes(opt.title)) {\n        uniqueTitles.push(opt.title);\n      }\n    }\n    const groupSize = uniqueTitles.length;\n    \n    optionSets = [];\n    for (let i = 0; i < options.length; i += groupSize) {\n      const setOptions = options.slice(i, i + groupSize);\n      optionSets.push({ options: setOptions });\n    }\n  }\n  \n  const entry = {\n    productVariantVendorId: encodedId\n  };\n  \n  // \uae30\ubcf8\uc635\uc158\n  if (optionSets && optionSets.length > 0) {\n    entry.openMallOptions = optionSets;\n  }\n  \n  // \ucd94\uac00\uc635\uc158\n  if (additionalOptions.length > 0) {\n    entry.openMallAdditionalOptions = additionalOptions;\n  }\n  \n  // qtyPerUnit\n  if (groupData.qtyPerUnit) {\n    entry.openMallQtyPerUnit = parseInt(groupData.qtyPerUnit, 10) || null;\n  }\n  \n  // needsManagerVerification\n  if (groupData.needsManagerVerification) {\n    entry.needsManagerVerification = true;\n  }\n  \n  // \uc5c5\ub370\uc774\ud2b8\ud560 \ub0b4\uc6a9\uc774 \uc788\ub294 \uacbd\uc6b0\ub9cc \ucd94\uac00\n  const hasOptions = entry.openMallOptions && entry.openMallOptions.length > 0;\n  const hasAdditionalOptions = entry.openMallAdditionalOptions && entry.openMallAdditionalOptions.length > 0;\n  const hasQtyPerUnit = entry.openMallQtyPerUnit;\n  const hasVerification = entry.needsManagerVerification;\n  \n  if (hasOptions || hasAdditionalOptions || hasQtyPerUnit || hasVerification) {\n    mutationInput.push(entry);\n  }\n}\n\nreturn [{\n  json: {\n    query: `mutation ProductVariantVendorBulkUpdateOpenMall($input: [ProductVariantVendorBulkUpdateOpenMallInput!]!) {\n      productVariantVendorBulkUpdateOpenMall(input: $input) {\n        updatedCount\n        productErrors { code message }\n      }\n    }`,\n    variables: { input: mutationInput }\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        672,
        0
      ],
      "id": "16ac86ab-be2b-4de0-913f-0110391add37",
      "name": "\uc624\ud508\ubab0 \uc635\uc158 \uc7ac\uac00\uacf5"
    },
    {
      "parameters": {
        "endpoint": "={{ $env.GRAPHQL_URL }}",
        "query": "={{ $json.query }}",
        "variables": "={{ $json.variables }}",
        "headerParametersUi": {
          "parameter": [
            {
              "name": "Authorization",
              "value": "={{ $env.AUTH_TOKEN }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.graphql",
      "typeVersion": 1.1,
      "position": [
        896,
        0
      ],
      "id": "30a52690-fef1-4da7-97a5-9c9251d239ad",
      "name": "\uc81c\ud488 \ud611\ub825\uc0ac update mutation"
    }
  ],
  "connections": {
    "When clicking \u2018Execute workflow\u2019": {
      "main": [
        [
          {
            "node": "Read/Write Files from Disk",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read/Write Files from Disk": {
      "main": [
        [
          {
            "node": "Extract from File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract from File": {
      "main": [
        [
          {
            "node": "\uc624\ud508\ubab0 \uc635\uc158 \uc7ac\uac00\uacf5",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\uc624\ud508\ubab0 \uc635\uc158 \uc7ac\uac00\uacf5": {
      "main": [
        [
          {
            "node": "\uc81c\ud488 \ud611\ub825\uc0ac update mutation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "meta": null,
  "versionId": "c2d0afe7-0a74-482a-881d-a576d62e1e3f",
  "activeVersionId": null,
  "versionCounter": 23,
  "triggerCount": 0,
  "tags": [],
  "shared": [
    {
      "updatedAt": "2026-01-05T04:35:09.429Z",
      "createdAt": "2026-01-05T04:35:09.429Z",
      "role": "workflow:owner",
      "workflowId": "93ZMYatYJvCIdKTJ",
      "projectId": "PyrRNJYltDksNq22",
      "project": {
        "updatedAt": "2025-12-17T00:26:00.367Z",
        "createdAt": "2025-12-17T00:18:19.940Z",
        "id": "PyrRNJYltDksNq22",
        "name": "\ub3c4\ud604 \uae40 <dev-do@naver.com>",
        "type": "personal",
        "icon": null,
        "description": null
      }
    }
  ]
}