电子签名API可以集成到Appsheet中吗?

问题描述 投票:0回答:1

几个月来,我一直在致力于一个集成电子签名 API 的项目,名为 Viafirma,该项目尚未被证明可以集成到 Appsheet 中。应该注意的是,我的应用程序生成的 PDF 文档将通过此集成发送进行签名,但由于此错误仍然存在,因此尚未实现:

https://sandbox.viafirma.com 请求失败,返回代码 404。截断的服务器响应:{“code”:404,“type”:“ERROR”,“message”:“HTTP 404 Not Found”, "trace":"1210a16cd6ad417ca238bb493428ed29"} (使用 muteHttpExceptions 选项检查完整响应)"

应该注意的是,开发中使用的协议是 oauth2 并且集成它请求来自 AppSheet 的回调,但我不知道如何在我的应用程序中搜索它以及在任何情况下 AppSheet 是否能够支持这种类型请求。

代码:

// Se Definen las Constantes de Autenticación y la URL Base
const OAUTH_CONSUMER_KEY = 'XXXX'; // 'tu_consumer_key' clave de consumidor de OAuth de Viafirma.
const OAUTH_CONSUMER_SECRET = 'XXXXXX'; // 'tu_consumer_secret' clave de consumidor de OAuth de Viafirma.
const VIAFIRMA_BASE_URL = 'https://sandbox.viafirma.com/documents/api/v3'; // URL base del entorno sandbox de Viafirma.
const FOLDER_ID = 'XXXXXXX'; // ID de la carpeta en Google Drive donde se almacenan los archivos

// Función para Obtener el Token OAuth
function obtenerTokenOAuth() {
  const OAUTH_TOKEN_URL = `${VIAFIRMA_BASE_URL}/oauth2/token`;
  
  const options = {
    method: 'post', // Método HTTP POST.
    contentType: 'application/x-www-form-urlencoded',
    headers: {
      'Authorization': 'Basic ' + Utilities.base64Encode(OAUTH_CONSUMER_KEY + ':' + OAUTH_CONSUMER_SECRET) // Base64 encode the client id and secret
    },
    payload: {
      'grant_type': 'client_credentials' // Tipo de concesión de OAuth.
    },
    muteHttpExceptions: true // Para obtener la respuesta completa en caso de error.
  };
  
  const response = UrlFetchApp.fetch(OAUTH_TOKEN_URL, options); // Se Realiza la solicitud para obtener el token.
  
  if (response.getResponseCode() !== 200) {
    Logger.log(response.getContentText()); // Registra el contenido de la respuesta
    throw new Error('Error al obtener el token OAuth: ' + response.getContentText());
  }
  
  const jsonResponse = JSON.parse(response.getContentText()); // Se Analiza la respuesta JSON.
  return jsonResponse.access_token; // Se Devuelve el token de acceso.
}

// Función para leer datos desde la hoja de cálculo y firmar documentos
function leerDatosYFirmarDocumentos() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('DATOS FORM'); // Nombre de tu hoja en Google Sheets.
  const data = sheet.getDataRange().getValues(); // Obtiene todos los datos de la hoja.
  
  for (let i = 1; i < data.length; i++) {
    const IDATS = data[i][0]; // Asume que la primera columna tiene el IDATS
    const DOCUMENTO = data[i][14]; // Asume que la segunda columna tiene la URL del documento

    if (IDATS && DOCUMENTO) {
      try {
        firmarDocumento(IDATS, DOCUMENTO);
      } catch (error) {
        Logger.log(`Error al firmar el documento con IDATS ${IDATS}: ${error.message}`);
      }
    } else {
      Logger.log(`IDATS o DOCUMENTO no definido para la fila ${i + 1}`);
    }
  }
}

// Crear un nuevo conjunto de documentos
function crearNuevoSet(token) {
  const payload = {
    "name": "Conjunto de Documentos a Firmar"
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      'Authorization': `Bearer ${token}`
    },
    payload: JSON.stringify(payload)
  };

  const response = UrlFetchApp.fetch(`${VIAFIRMA_BASE_URL}/sets`, options);
  const jsonResponse = JSON.parse(response.getContentText());
  return jsonResponse.id; // ID del nuevo conjunto de documentos
}

// Función para Firmar el Documento
function firmarDocumento(IDATS, DOCUMENTO) {
  if (!DOCUMENTO) {
    throw new Error('La ruta del archivo no está definida');
  }
  const token = obtenerTokenOAuth(); // Obtén el token de acceso OAuth.

  // Paso 1: Se crea un nuevo conjunto de documentos
  const setId = crearNuevoSet(token);

  // Paso 2: Se Agrega el documento al conjunto
  agregarDocumentoAlSet(token, setId, IDATS, DOCUMENTO);

  // Paso 3: Se Envia el conjunto para firma
  enviarSetParaFirma(token, setId);

  // Se guarda la URL del documento firmado en Google Sheets (puede necesitar ajustes)
  guardarSignedUrlEnSheet(IDATS, `https://sandbox.viafirma.com/documents/api/v3/sets/${setId}`);
}


// Agregar un documento al conjunto
function agregarDocumentoAlSet(token, setId, IDATS, DOCUMENTO) {
  const filePath = DOCUMENTO.split('/').pop(); // Extrae solo el nombre del archivo
  const fileId = obtenerFileId(filePath);

  const payload = {
    "name": IDATS, // Nombre del documento (ID o nombre identificativo).
    "contentType": "application/pdf", // Tipo de contenido del documento.
    "content": obtenerContenidoBase64(fileId) // Contenido del documento en base64.
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      'Authorization': `Bearer ${token}`
    },
    payload: JSON.stringify(payload)
  };

  const response = UrlFetchApp.fetch(`${VIAFIRMA_BASE_URL}/sets/${setId}/documents`, options);
  const jsonResponse = JSON.parse(response.getContentText());
  return jsonResponse.id; // ID del documento agregado al conjunto
}

// Enviar el conjunto para firma
function enviarSetParaFirma(token, setId) {
  const payload = {
    "recipients": [
      {
        "type": "SIGNER",
        "identifier": {
          "type": "EMAIL",
          "value": "[email protected]" // Reemplaza con el email del firmante
        },
        "name": "Firmante Ejemplo"
      }
    ],
    "callback": {
      "url": "https://tudominio.com/callback" // Reemplaza con tu URL de callback
    }
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      'Authorization': `Bearer ${token}`
    },
    payload: JSON.stringify(payload)
  };

  const response = UrlFetchApp.fetch(`${VIAFIRMA_BASE_URL}/sets/${setId}/send`, options);
  const jsonResponse = JSON.parse(response.getContentText());
  return jsonResponse;
}

function obtenerFileId(filePath) {
  if (!filePath) {
    throw new Error('La ruta del archivo no está definida');
  }

  // Extraer el ID del archivo de la ruta
  const folderId = FOLDER_ID; // Se Reemplaza con el ID del DRIVE
  const folder = DriveApp.getFolderById(folderId); // Se Reemplaza 'FOLDER_ID' con el ID de la carpeta donde se almacenan los archivos
  const fileName = filePath.split('/').pop(); // Se obtiene el archivo por nombre

  const files = folder.getFilesByName(fileName);

  if (files.hasNext()) {
    return files.next().getId();
  } else {
    throw new Error('Archivo no encontrado: ' + filePath);
  }
}

// Función para Obtener el Contenido en Base64
function obtenerContenidoBase64(fileId) {
  const file = DriveApp.getFileById(fileId); // Se Realiza la solicitud para obtener el contenido del archivo.
  const blob = file.getBlob(); // Se Obtiene el blob del archivo.
  return Utilities.base64Encode(blob.getBytes()); // Se Codifica el blob en base64 y lo devuelve.
}

// Función para Guardar la URL Firmada en Google Sheets
function guardarSignedUrlEnSheet(IDATS, signedUrl) {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('DATOS FORM'); // Reemplaza 'NombreDeTuHoja' con el nombre de tu hoja en Google Sheets.
  const data = sheet.getDataRange().getValues(); // Obtiene todos los datos de la hoja.
  
  for (let i = 1; i < data.length; i++) {
    if (data[i][0] === IDATS) {  // Busca el ID del documento en la primera columna.
      sheet.getRange(i + 1, 16).setValue(signedUrl);  // Guarda la URL firmada en la columna 16.
      break;
    }
  }
}

// Llama a la función para leer datos y firmar documentos
leerDatosYFirmarDocumentos();

如果您能告诉我这种类型的集成是否可行,或者在任何情况下如果我的代码中存在某种类型的错误,请告诉我,我将非常感激。我愿意继续学习并听取您的意见。

google-sheets google-apps-script google-appsheet
1个回答
0
投票

在 Google Apps 脚本项目中,包含称为顶级/全局作用域的函数可能会导致问题。

尽管可能存在其他问题,但应删除以下代码行

// Llama a la función para leer datos y firmar documentos
leerDatosYFirmarDocumentos();
© www.soinside.com 2019 - 2024. All rights reserved.