{
  "name": "Convalidaciones Acad\u00e9micas - Estructura Base",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "solicitud-convalidacion",
        "responseMode": "onReceived",
        "authentication": "basicAuth",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "application/json"
              }
            ]
          }
        }
      },
      "name": "Webhook - Recepci\u00f3n",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "// Validaci\u00f3n de campos requeridos\nconst requiredFields = ['nombre', 'carrera', 'materias', 'documentos'];\nconst errors = [];\n\nfor (const field of requiredFields) {\n  if (!$input.item.json[field]) {\n    errors.push(`Campo requerido: ${field}`);\n  }\n}\n\nif (errors.length > 0) {\n  return {\n    json: {\n      success: false,\n      errors: errors\n    }\n  };\n}\n\nreturn {\n  json: {\n    ...$input.item.json,\n    documentosCompletos: true,\n    fechaSolicitud: new Date().toISOString()\n  }\n};"
      },
      "name": "Function - Validar",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        450,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{$json.documentosCompletos}}",
              "value2": true
            }
          ]
        }
      },
      "name": "IF - Documentaci\u00f3n",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        650,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "// Comprueba que todos los archivos tengan extensi\u00f3n .pdf (case-insensitive)\nconst docs = $input.item.json.documentos || [];\nconst badFiles = [];\nfor (const d of docs) {\n  const fn = d.fileName || d.name || (d.url ? d.url.split('/').pop() : '');\n  if (!fn) continue;\n  if (!fn.toLowerCase().endsWith('.pdf')) {\n    badFiles.push(fn);\n  }\n}\nreturn { json: { ...$input.item.json, pdfsOk: badFiles.length === 0, badFiles } };"
      },
      "name": "Function - Check PDFs",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        800,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "// Registra el estado tras la validaci\u00f3n\nconst status = $json.success === false ? 'Validaci\u00f3n fallida' : 'Validado';\nconst details = $json.success === false ? ($json.errors || []).join('; ') : '';\nreturn { json: { ...$json, status, details, statusTimestamp: new Date().toISOString() } };"
      },
      "name": "Function - Status: Validaci\u00f3n",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        550,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "// Registra el resultado de la comprobacion de PDFs\nconst status = $json.pdfsOk ? 'PDFs OK' : 'PDFs inv\u00e1lidos';\nconst details = ($json.badFiles || []).join(', ');\nreturn { json: { ...$json, status, details, statusTimestamp: new Date().toISOString() } };"
      },
      "name": "Function - Status: PDF Check",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        900,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "// Estado: documentos almacenados\nreturn { json: { ...$input.item.json, status: 'Documentos almacenados', details: '', statusTimestamp: new Date().toISOString() } };"
      },
      "name": "Function - Status: Stored",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        1000,
        180
      ]
    },
    {
      "parameters": {
        "functionCode": "// Estado: registro creado\nreturn { json: { ...$input.item.json, status: 'Registro creado', details: '', statusTimestamp: new Date().toISOString() } };"
      },
      "name": "Function - Status: Registered",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        1000,
        420
      ]
    },
    {
      "parameters": {
        "functionCode": "// Estado: acta generada\nreturn { json: { ...$input.item.json, status: 'Acta generada', details: '', statusTimestamp: new Date().toISOString() } };"
      },
      "name": "Function - Status: Acta Generada",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        1750,
        260
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "sheetName": "Logs",
        "columns": [
          {
            "column": "Timestamp",
            "value": "={{$json.statusTimestamp || new Date().toISOString()}}"
          },
          {
            "column": "ID",
            "value": "={{$json.id || ''}}"
          },
          {
            "column": "Status",
            "value": "={{$json.status || ''}}"
          },
          {
            "column": "Details",
            "value": "={{$json.details || ''}}"
          }
        ]
      },
      "name": "DB - Log",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 1,
      "position": [
        1300,
        360
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "sheetName": "Logs",
        "columns": [
          {
            "column": "Timestamp",
            "value": "={{$json.statusTimestamp || new Date().toISOString()}}"
          },
          {
            "column": "ID",
            "value": "={{$json.id || ''}}"
          },
          {
            "column": "Status",
            "value": "={{$json.status || ''}}"
          },
          {
            "column": "Details",
            "value": "={{$json.details || ''}}"
          }
        ]
      },
      "name": "DB - Log - Validaci\u00f3n",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 1,
      "position": [
        950,
        300
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "sheetName": "Logs",
        "columns": [
          {
            "column": "Timestamp",
            "value": "={{$json.statusTimestamp || new Date().toISOString()}}"
          },
          {
            "column": "ID",
            "value": "={{$json.id || ''}}"
          },
          {
            "column": "Status",
            "value": "={{$json.status || ''}}"
          },
          {
            "column": "Details",
            "value": "={{$json.details || ''}}"
          }
        ]
      },
      "name": "DB - Log - PDFCheck",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 1,
      "position": [
        1150,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{$json.pdfsOk}}",
              "value2": true
            }
          ]
        }
      },
      "name": "IF - PDFs OK?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        1000,
        300
      ]
    },
    {
      "parameters": {
        "fromEmail": "sistema@ejemplo.com",
        "toEmail": "={{$json.estudianteEmail}}",
        "subject": "Archivo no v\u00e1lido",
        "text": "Estimado alumno, el archivo enviado no es del formato adecuado .PDF"
      },
      "name": "Email - Not PDF",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 1,
      "position": [
        1200,
        380
      ]
    },
    {
      "parameters": {
        "resource": "file",
        "operation": "upload"
      },
      "name": "Storage - Documentos",
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 1,
      "position": [
        850,
        200
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "sheetName": "Solicitudes",
        "columns": [
          {
            "column": "ID",
            "value": "={{$json.id}}"
          },
          {
            "column": "Fecha",
            "value": "={{$json.fechaSolicitud}}"
          },
          {
            "column": "Estudiante",
            "value": "={{$json.nombre}}"
          },
          {
            "column": "Estado",
            "value": "Pendiente"
          }
        ]
      },
      "name": "DB - Registro",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 1,
      "position": [
        850,
        400
      ]
    },
    {
      "parameters": {
        "fromEmail": "sistema@ejemplo.com",
        "toEmail": "={{$json.directorEmail}}",
        "subject": "Nueva Solicitud de Convalidaci\u00f3n",
        "text": "=Plantilla de correo con datos"
      },
      "name": "Email - Director",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 1,
      "position": [
        1050,
        300
      ]
    },
    {
      "parameters": {
        "httpMethod": "GET",
        "path": "decision-director",
        "responseMode": "onReceived"
      },
      "name": "Webhook - Decisi\u00f3n",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        1250,
        300
      ]
    },
    {
      "parameters": {
        "functionCode": "// Procesar decisi\u00f3n del director\n// Se espera que la llamada al webhook incluya query params: decision y id\nconst decision = $input.item.json.query && $input.item.json.query.decision ? $input.item.json.query.decision : ($input.item.json.decision || null);\nconst solicitudId = $input.item.json.query && $input.item.json.query.id ? $input.item.json.query.id : ($input.item.json.solicitudId || null);\n\nreturn [{\n  json: {\n    decision,\n    solicitudId,\n    timestamp: new Date().toISOString(),\n    ...$input.item.json\n  }\n}];"
      },
      "name": "Function - Procesar Decisi\u00f3n",
      "type": "n8n-nodes-base.function",
      "typeVersion": 1,
      "position": [
        1450,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{$json.decision}}",
              "operation": "equal",
              "value2": "Aceptada"
            },
            {
              "value1": "={{$json.decision}}",
              "operation": "equal",
              "value2": "Rechazada"
            },
            {
              "value1": "={{$json.decision}}",
              "operation": "equal",
              "value2": "Revisi\u00f3n Adicional"
            }
          ]
        }
      },
      "name": "Switch - Decision",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 1,
      "position": [
        1650,
        300
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "sheetName": "Solicitudes",
        "updateKey": "ID",
        "updateKeyColumn": "ID",
        "columns": [
          {
            "column": "Estado",
            "value": "Convalidada"
          }
        ]
      },
      "name": "Sheets - Update Aceptada",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 1,
      "position": [
        1850,
        220
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "sheetName": "Solicitudes",
        "updateKey": "ID",
        "updateKeyColumn": "ID",
        "columns": [
          {
            "column": "Estado",
            "value": "No Convalidada"
          }
        ]
      },
      "name": "Sheets - Update Rechazada",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 1,
      "position": [
        1850,
        360
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "sheetName": "Solicitudes",
        "updateKey": "ID",
        "updateKeyColumn": "ID",
        "columns": [
          {
            "column": "Estado",
            "value": "En revisi\u00f3n"
          }
        ]
      },
      "name": "Sheets - Update Revision",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 1,
      "position": [
        1850,
        440
      ]
    },
    {
      "parameters": {
        "fromEmail": "sistema@ejemplo.com",
        "toEmail": "={{$json.estudianteEmail}}",
        "subject": "Solicitud Aceptada - Convalidaci\u00f3n",
        "text": "Estimado/a {{$json.nombre}},\n\nSu solicitud ha sido ACEPTADA. Se adjunta el acta de convalidaci\u00f3n."
      },
      "name": "Email - Estudiante Aceptada",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 1,
      "position": [
        2050,
        220
      ]
    },
    {
      "parameters": {
        "fromEmail": "sistema@ejemplo.com",
        "toEmail": "={{$json.estudianteEmail}}",
        "subject": "Solicitud Rechazada - Convalidaci\u00f3n",
        "text": "Estimado/a {{$json.nombre}},\n\nSu solicitud ha sido RECHAZADA. Consulte las observaciones."
      },
      "name": "Email - Estudiante Rechazada",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 1,
      "position": [
        2050,
        360
      ]
    },
    {
      "parameters": {
        "fromEmail": "sistema@ejemplo.com",
        "toEmail": "comite@universidad.edu",
        "subject": "Solicitud para Revisi\u00f3n Adicional",
        "text": "Se solicita revisi\u00f3n adicional para la solicitud ID: {{$json.solicitudId}}"
      },
      "name": "Email - Comit\u00e9 Revision",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 1,
      "position": [
        2050,
        440
      ]
    },
    {
      "parameters": {
        "resource": "file",
        "operation": "create"
      },
      "name": "PDF - Generar Acta",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 1,
      "position": [
        1650,
        300
      ]
    },
    {
      "parameters": {
        "notes": "Recepci\u00f3n: Webhook que recibe solicitudes de convalidaci\u00f3n. Espera JSON con datos del estudiante y documentos."
      },
      "name": "Note - Recepci\u00f3n",
      "type": "n8n-nodes-base.comment",
      "typeVersion": 1,
      "position": [
        250,
        220
      ]
    },
    {
      "parameters": {
        "notes": "Validaci\u00f3n: Comprueba campos requeridos y marca la solicitud con fecha."
      },
      "name": "Note - Validaci\u00f3n",
      "type": "n8n-nodes-base.comment",
      "typeVersion": 1,
      "position": [
        450,
        220
      ]
    },
    {
      "parameters": {
        "notes": "Comprobaci\u00f3n de archivos: Verifica que todos los documentos tengan extensi\u00f3n .pdf. Si no, notifica y termina."
      },
      "name": "Note - PDF Check",
      "type": "n8n-nodes-base.comment",
      "typeVersion": 1,
      "position": [
        900,
        220
      ]
    },
    {
      "parameters": {
        "notes": "Almacenamiento y registro: Guarda documentos en Google Drive y registra la solicitud en Google Sheets."
      },
      "name": "Note - Storage & Registro",
      "type": "n8n-nodes-base.comment",
      "typeVersion": 1,
      "position": [
        950,
        120
      ]
    },
    {
      "parameters": {
        "notes": "Decisi\u00f3n del director: Se env\u00eda correo al director con enlaces/opciones. La decisi\u00f3n llega al webhook /decision-director."
      },
      "name": "Note - Decisi\u00f3n Director",
      "type": "n8n-nodes-base.comment",
      "typeVersion": 1,
      "position": [
        1250,
        220
      ]
    },
    {
      "parameters": {
        "notes": "Ramas de decisi\u00f3n: Aceptada -> genera acta y notifica; Rechazada -> notifica al estudiante; Revisi\u00f3n -> notifica comit\u00e9 y estudiante."
      },
      "name": "Note - Ramas Decision",
      "type": "n8n-nodes-base.comment",
      "typeVersion": 1,
      "position": [
        1750,
        360
      ]
    },
    {
      "parameters": {
        "fromEmail": "sistema@ejemplo.com",
        "toEmail": "={{$json.estudianteEmail}}",
        "subject": "Solicitud en revisi\u00f3n - Convalidaci\u00f3n",
        "text": "Estimado/a {{$json.nombre}},\n\nSu solicitud ha pasado a revisi\u00f3n adicional. Le notificaremos cuando haya una resoluci\u00f3n."
      },
      "name": "Email - Estudiante Revision",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 1,
      "position": [
        2050,
        380
      ]
    },
    {
      "parameters": {
        "operation": "append"
      },
      "name": "DB - Hist\u00f3rico",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 1,
      "position": [
        2050,
        300
      ]
    }
  ],
  "connections": {
    "Webhook - Recepci\u00f3n": {
      "main": [
        [
          {
            "node": "Function - Validar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function - Validar": {
      "main": [
        [
          {
            "node": "Function - Status: Validaci\u00f3n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function - Status: Validaci\u00f3n": {
      "main": [
        [
          {
            "node": "DB - Log - Validaci\u00f3n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DB - Log - Validaci\u00f3n": {
      "main": [
        [
          {
            "node": "IF - Documentaci\u00f3n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF - Documentaci\u00f3n": {
      "main": [
        [
          {
            "node": "Function - Check PDFs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function - Check PDFs": {
      "main": [
        [
          {
            "node": "Function - Status: PDF Check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function - Status: PDF Check": {
      "main": [
        [
          {
            "node": "DB - Log - PDFCheck",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DB - Log - PDFCheck": {
      "main": [
        [
          {
            "node": "IF - PDFs OK?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF - PDFs OK?": {
      "main": [
        [
          {
            "node": "Function - Status: Stored",
            "type": "main",
            "index": 0
          },
          {
            "node": "Function - Status: Registered",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Email - Not PDF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function - Status: Stored": {
      "main": [
        [
          {
            "node": "DB - Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function - Status: Registered": {
      "main": [
        [
          {
            "node": "DB - Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DB - Log": {
      "main": [
        [
          {
            "node": "Storage - Documentos",
            "type": "main",
            "index": 0
          },
          {
            "node": "DB - Registro",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Storage - Documentos": {
      "main": [
        [
          {
            "node": "Email - Director",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DB - Registro": {
      "main": [
        [
          {
            "node": "Email - Director",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email - Director": {
      "main": [
        [
          {
            "node": "Webhook - Decisi\u00f3n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook - Decisi\u00f3n": {
      "main": [
        [
          {
            "node": "Function - Procesar Decisi\u00f3n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function - Procesar Decisi\u00f3n": {
      "main": [
        [
          {
            "node": "Switch - Decision",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch - Decision": {
      "main": [
        [
          {
            "node": "Sheets - Update Aceptada",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Sheets - Update Rechazada",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Sheets - Update Revision",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sheets - Update Aceptada": {
      "main": [
        [
          {
            "node": "PDF - Generar Acta",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "PDF - Generar Acta": {
      "main": [
        [
          {
            "node": "Function - Status: Acta Generada",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function - Status: Acta Generada": {
      "main": [
        [
          {
            "node": "Email - Estudiante Aceptada",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email - Estudiante Aceptada": {
      "main": [
        [
          {
            "node": "DB - Hist\u00f3rico",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sheets - Update Rechazada": {
      "main": [
        [
          {
            "node": "Email - Estudiante Rechazada",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email - Estudiante Rechazada": {
      "main": [
        [
          {
            "node": "DB - Hist\u00f3rico",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sheets - Update Revision": {
      "main": [
        [
          {
            "node": "Email - Comit\u00e9 Revision",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email - Comit\u00e9 Revision": {
      "main": [
        [
          {
            "node": "Email - Estudiante Revision",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email - Estudiante Revision": {
      "main": [
        [
          {
            "node": "DB - Hist\u00f3rico",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {},
  "staticData": null,
  "tags": [
    "convalidaciones",
    "acad\u00e9mico"
  ],
  "triggerCount": 0
}