{
  "name": "VNTANA: Sync Translations from Attachment",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "vntana-sync-attachment",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "webhook",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [240, 300],
      "webhookId": "vntana-sync-attachment",
      "notes": "Receives: { productUuid, clientUuid, org, workspace }"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api-platform.vntana.com/v1/auth/login",
        "sendBody": true,
        "contentType": "json",
        "body": {
          "email": "={{ $vars.VNTANA_EMAIL }}",
          "password": "={{ $vars.VNTANA_PASSWORD }}"
        },
        "options": {}
      },
      "id": "auth",
      "name": "Auth",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [460, 300]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api-platform.vntana.com/v1/attachments/search",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            { "name": "X-AUTH-TOKEN", "value": "={{ $node['Auth'].json.response.token }}" },
            { "name": "Content-Type",  "value": "application/json" }
          ]
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            { "name": "productUuid", "value": "={{ $node['Webhook'].json.body.productUuid }}" },
            { "name": "entityType",  "value": "PRODUCT" }
          ]
        },
        "sendBody": true,
        "contentType": "json",
        "body": { "page": 1, "size": 20 },
        "options": {}
      },
      "id": "searchAttachments",
      "name": "Search Attachments",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [680, 300]
    },
    {
      "parameters": {
        "jsCode": "// Find the most recent .xlsx attachment\nconst attachments = $input.first().json.response?.grid ?? [];\nconst xlsx = attachments\n  .filter(a => (a.name ?? '').toLowerCase().endsWith('.xlsx'))\n  .sort((a, b) => new Date(b.created ?? 0) - new Date(a.created ?? 0))[0];\n\nif (!xlsx) throw new Error('No .xlsx attachment found on this product. Attach a spreadsheet first.');\n\nreturn [{ json: { blobId: xlsx.blobId, name: xlsx.name, uuid: xlsx.uuid } }];"
      },
      "id": "findXlsx",
      "name": "Find XLSX",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [900, 300]
    },
    {
      "parameters": {
        "url": "=https://api-platform.vntana.com/v1/storage/load/asset/model?blobId={{ $json.blobId }}&clientUuid={{ $node['Webhook'].json.body.clientUuid }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            { "name": "X-AUTH-TOKEN", "value": "={{ $node['Auth'].json.response.token }}" }
          ]
        },
        "options": {
          "response": { "response": { "responseFormat": "file", "outputPropertyName": "data" } }
        }
      },
      "id": "downloadFile",
      "name": "Download XLSX",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [1120, 300],
      "notes": "Downloads the xlsx blob. If this returns 404, try /v1/products/{productUuid}/download/asset/{blobId} instead."
    },
    {
      "parameters": {
        "operation": "toJson",
        "binaryPropertyName": "data",
        "options": { "sheetName": "Sheet1" }
      },
      "id": "parseSpreadsheet",
      "name": "Parse Spreadsheet",
      "type": "n8n-nodes-base.spreadsheetFile",
      "typeVersion": 2,
      "position": [1340, 300]
    },
    {
      "parameters": {
        "jsCode": "// Transform spreadsheet rows into hotspot_translations_{lang} attribute objects\nconst rows = $input.all().map(i => i.json);\nconst langs = ['fr', 'es', 'de'];\nconst translations = {};\n\nfor (const row of rows) {\n  const uuid = String(row['Hotspot UUID'] ?? '').trim();\n  if (!uuid) continue;\n  for (const lang of langs) {\n    const title       = String(row[`${lang.toUpperCase()} Title`]       ?? '').trim();\n    const description = String(row[`${lang.toUpperCase()} Description`] ?? '').trim();\n    if (!title && !description) continue;\n    if (!translations[lang]) translations[lang] = {};\n    translations[lang][uuid] = { title, description };\n  }\n}\n\n// Pass along with product context from the webhook\nconst body = $node['Webhook'].json.body;\nreturn [{ json: { ...body, translations } }];"
      },
      "id": "transformData",
      "name": "Transform to Translations",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [1560, 300]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "=https://api.vntana.com/products/{{ $json.productUuid }}/organizations/{{ $json.org }}/clients/{{ $json.workspace }}",
        "options": {}
      },
      "id": "getProduct",
      "name": "Get Product",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [1780, 300]
    },
    {
      "parameters": {
        "jsCode": "// Merge new translations into existing attributes\nconst product = $node['Get Product'].json.response;\nconst newTranslations = $node['Transform to Translations'].json.translations;\nconst existingAttrs = product.attributes ?? [];\n\n// Build updated attributes array, upserting translation keys\nconst attrMap = {};\nfor (const a of existingAttrs) {\n  attrMap[a.name ?? a.key] = a.value;\n}\n\nfor (const [lang, data] of Object.entries(newTranslations)) {\n  attrMap[`hotspot_translations_${lang}`] = JSON.stringify(data);\n}\n\nconst mergedAttributes = Object.entries(attrMap).map(([key, value]) => ({ name: key, value }));\n\nreturn [{\n  json: {\n    uuid: product.uuid,\n    name: product.name,\n    attributes: mergedAttributes\n  }\n}];"
      },
      "id": "mergeAttributes",
      "name": "Merge Attributes",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [2000, 300]
    },
    {
      "parameters": {
        "method": "PUT",
        "url": "https://api-platform.vntana.com/v1/products",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            { "name": "X-AUTH-TOKEN", "value": "={{ $node['Auth'].json.response.token }}" },
            { "name": "Content-Type",  "value": "application/json" }
          ]
        },
        "sendBody": true,
        "contentType": "json",
        "body": "={{ JSON.stringify($json) }}",
        "options": {}
      },
      "id": "writeAttributes",
      "name": "Write Attributes",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [2220, 300]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify({ success: $json.success ?? true, message: 'Translations synced from attachment' }) }}"
      },
      "id": "respond",
      "name": "Respond",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [2440, 300]
    }
  ],
  "connections": {
    "Webhook":                  { "main": [[{ "node": "Auth",                       "type": "main", "index": 0 }]] },
    "Auth":                     { "main": [[{ "node": "Search Attachments",         "type": "main", "index": 0 }]] },
    "Search Attachments":       { "main": [[{ "node": "Find XLSX",                  "type": "main", "index": 0 }]] },
    "Find XLSX":                { "main": [[{ "node": "Download XLSX",              "type": "main", "index": 0 }]] },
    "Download XLSX":            { "main": [[{ "node": "Parse Spreadsheet",          "type": "main", "index": 0 }]] },
    "Parse Spreadsheet":        { "main": [[{ "node": "Transform to Translations",  "type": "main", "index": 0 }]] },
    "Transform to Translations":{ "main": [[{ "node": "Get Product",               "type": "main", "index": 0 }]] },
    "Get Product":              { "main": [[{ "node": "Merge Attributes",           "type": "main", "index": 0 }]] },
    "Merge Attributes":         { "main": [[{ "node": "Write Attributes",           "type": "main", "index": 0 }]] },
    "Write Attributes":         { "main": [[{ "node": "Respond",                   "type": "main", "index": 0 }]] }
  },
  "settings": { "executionOrder": "v1" },
  "staticData": null,
  "meta": {
    "templateId": "vntana-sync-attachment",
    "description": "Reads the .xlsx file attached to a VNTANA product, parses hotspot translations, and writes them as product attributes. Requires VNTANA_EMAIL and VNTANA_PASSWORD n8n variables. One note: the Download XLSX node uses /v1/storage/load/asset/model — if that returns 404 for attachment blobs, switch the URL to /v1/products/{productUuid}/download/asset/{blobId}."
  }
}
