Discussions

Ask a Question
Back to All

Integracion con planilla de calculos

Estamos sincronizado el listado de propiedades a traves de un script en Google Shets para ser levantado por otro sistemas.

Segun la documentación de API el operations deberia arrojar currency, price, period (cuando es un temporal) y type (con valores 1 2 3, siendo 3 alquiler temporal). Pero esta arrojando solo los type currency, price y type 1 y 2.

No arroja type 3, no arroja period y en cambio arroja una nueva columna no mencionada en la documentacion llamada has_temporary_rent con los valores true o false.

Como hago para que me baje los valores type 3 y period para los alquileres temporales o de que manera sincronizo la informacion de los alquileres temporales.

Dejo copia del script


function obtenerPropiedades() {
const apiKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; //
const baseUrl = "https://www.tokkobroker.com/api/v1/property/?key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&format=json&lang=es_ar";
const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
const totalProperties = 500;
const limit = 50;

// Mapeo de traducciones al español para encabezados
const headerTranslations = {
"address": "Dirección1",
"age": "Antigüedad",
"bathroom_amount": "Cantidad de baños",
"depth_measure": "Medida de profundidad",
"description": "Descripción",
"development": "Emprendimiento / Inversion",
"disposition": "Disposición",
"expenses": "Expensas",
"floors_amount": "Cantidad de pisos",
"front_measure": "Medida del frente",
"id": "ID",
"location": "Zona / barrio / localidad",
"operation_currency": "Divisa",
"operation_price": "Precio",
"operation_type": "Tipo de operación",
"parking_lot_amount": "Cantidad de cocheras",
"producer": "Productor",
"property_condition": "Estado de la propiedad",
"public_url": "URL pública",
"publication_title": "Título",
"reference_code": "Código de referencia",
"roofed_surface": "Superficie cubierta",
"room_amount": "Ambientes",
"semiroofed_surface": "Superficie semicubierta",
"situation": "Situación",
"suite_amount": "Cantidad de habitaciones",
"surface": "Superficie",
"surface_measurement": "Medida de superficie",
"tags": "Caracteristicas",
"toilet_amount": "Cantidad de toilettes",
"total_surface": "Superficie total",
"transaction_requirements": "Requisitos de transacción",
"type": "Tipo de propiedad",
"unroofed_surface": "Superficie descubierta",
"videos": "Videos",
"zonification": "Zonificación",
"development_excel_extra_data": "Datos extra de desarrollo",
"extra_attributes": "Caracteristicas extra",
"fake_address": "Dirección",
"has_temporary_rent": "Tiene alquiler temporal"
};

// Mapeo de traducción de tipos de propiedad
const typeTranslations = {
"Apartment": "Departamento",
"Bussiness Permit": "Permiso de negocio",
"Bussiness Premises": "Local comercial",
"Condo": "Condominio",
"Countryside": "Campo",
"Garage": "Garaje",
"Hotel": "Hotel",
"House": "Casa",
"Land": "Terreno",
"Office": "Oficina",
"Warehouse": "Deposito",
"Weekend House": "Casa de fin de semana"
};

// Mapeo de traducciones al español para valores de tags
const translations = {
"Electricity": "Electricidad",
"Heater": "Calefacción",
"Service entrance": "Entrada de servicio",
"Moorings": "Muelle",
"Service Lift": "Ascensor de servicio",
"Refrigeration by forced air cooling": "Refrigeración por aire forzado",
"Basquet Field": "Campo de basquet",
"Balanced draft heating": "Calefacción por tiro balanceado",
"Linens": "Ropa de cama",
"PVC enclosures": "Cierres de PVC",
"Library": "Biblioteca",
"Scottish shower": "Ducha escocesa",
"Aluminium Carpentry": "Carpintería de aluminio",
"Individual boiler": "Caldera individual",
"Parking space": "Espacio de estacionamiento",
"Equestrian": "Ecuestre",
"central air conditioning": "Aire acondicionado central",
"Central water heater": "Calentador de agua central",
"Private hallway": "Pasillo privado",
"Mini": "Mini",
"cinema": "Cine",
"River view": "Vista al río",
"Double glazing windows": "Ventanas de doble acristalamiento",
"Children's game room": "Sala de juegos para niños",
"Heated Pool": "Piscina climatizada",
"Kitchen": "Cocina",
"Dining": "Comedor",
"Hall": "Vestíbulo",
"Living": "Living",
"Individual heating": "Calefacción individual",
"Cable": "Cable",
"Furniture": "Amoblado",
"Drinking water": "Agua potable",
"Wifi": "WiFi",
"Garden": "Jardín",
"Laundry": "Lavadero",
"Dining lounge": "Comedor diario",
"Pets allowed": "Se permiten mascotas",
"Work-friendly": "Apto para trabajar",
"Bright": "Luminoso",
"Gallery": "Galería",
"Suite": "Suite",
"Office": "Oficina",
"Individual air conditioner": "Aire acondicionado individual",
"Heating": "Calefacción",
"Pool": "Piscina",
"Balcony": "Balcón",
"Patio": "Patio",
"Air Heating": "Calefacción por aire",
"Alarm": "Alarma",
"Barbecue": "Parrilla",
"Security": "Seguridad"
};

// Mapeo para has_temporary_rent
const temporaryRentTranslations = {
"0": "-",
"1": "Por día",
"2": "Para fin de semana",
"3": "Por semana",
"4": "Quinceañera",
"5": "Yo",
"6": "1er quincena de enero",
"7": "2da quincena de enero",
"8": "1er quincena de febrero",
"9": "2da quincena de febrero",
"10": "1er quincena de marzo",
"11": "2da quincena de marzo",
"12": "Enero",
"13": "Febrero",
"14": "Marzo",
"15": "Abril",
"17": "Mayonesa",
"18": "Junio",
"19": "Julio",
"20": "Agosto",
"21": "Septiembre",
"22": "Octubre",
"23": "Noviembre",
"24": "Diciembre",
"25": "Por temporada",
"26": "Por año",
"27": "Fin de año",
"28": "Semana Santa",
"29": "1er quince de diciembre",
"30": "2da quincena de diciembre",
"false": "NO",
"true": "SI"
};

// Orden personalizado de las columnas
const headerOrder = [
"id",
"publication_title",
"type",
"fake_address",
"location",
"description",
"tags",
"extra_attributes",
"age",
"property_condition",
"floors_amount",
"suite_amount",
"room_amount",
"toilet_amount",
"bathroom_amount",
"parking_lot_amount",
"disposition",
"unroofed_surface",
"total_surface",
"surface",
"semiroofed_surface",
"roofed_surface",
"depth_measure",
"front_measure",
"development",
"development_excel_extra_data",
"operation_currency",
"operation_price",
"operation_type",
"expenses",
"has_temporary_rent",
"situation",
"transaction_requirements",
"zonification",
"producer",
"public_url",
"videos",
"reference_code"
];

// Limpiar la hoja
sheet.clear();

let offset = 0;
let firstPage = true;
let headers = [];

// Realizar solicitudes paginadas
while (offset < totalProperties) {
const url = ${baseUrl}&limit=${limit}&offset=${offset};
const options = {
method: "GET",
headers: {
"Authorization": apiKey,
},
};

const response = UrlFetchApp.fetch(url, options);
const data = JSON.parse(response.getContentText());

// Filtrar solo las propiedades con status = 2
const filteredData = {
  ...data,
  objects: data.objects.filter(item => item.status === 2)
};

if (firstPage) {
  // Filtrar las columnas no deseadas y excluir 'operations'
  headers = Object.keys(filteredData.objects[0]).filter(
    (header) => ![
      "branch", "created_at", "deleted_at", "files", "geo_lat", "geo_long",
      "gm_location_type", "occupation", "orientation", "portal_footer", "status",
      "web_price", "custom1", "is_denounced", "is_starred_on_web", "legally_checked",
      "real_address", "custom_tags", "address", "ID", "surface_measurement", "internal_data",
      "footer", "description_only", "photos", "rich_description", "operations"
    ].includes(header)
  );

  // Agregar las nuevas columnas de operaciones
  headers.push("operation_currency");
  headers.push("operation_price");
  headers.push("operation_type");

  // Ordenar headers según el orden personalizado
  headers.sort((a, b) => {
    return headerOrder.indexOf(a) - headerOrder.indexOf(b);
  });

  // Obtener encabezados traducidos y agregarlos a la hoja
  const translatedHeaders = headers.map(
    (header) => headerTranslations[header] || header
  );
  sheet.appendRow(translatedHeaders);
  firstPage = false;
}

// Insertar datos en la hoja
filteredData.objects.forEach((item) => {
  const row = headers.map((header) => {
    // Procesar las columnas de operaciones
    if (["operation_currency", "operation_price", "operation_type"].includes(header)) {
      if (Array.isArray(item.operations) && item.operations.length > 0) {
        const firstOperation = item.operations[0];
        const priceInfo = firstOperation.prices?.[0];

        if (header === "operation_currency") {
          return priceInfo?.currency || "";
        } else if (header === "operation_price") {
          return priceInfo?.price || "";
        } else if (header === "operation_type") {
          let operationType = firstOperation.operation_type;
          // Convertir a número si es posible
          const operationTypeNum = parseInt(operationType);
          if (!isNaN(operationTypeNum)) {
            // Si es un número, usar el mapeo numérico
            switch (operationTypeNum) {
              case 1: return "venta";
              case 2: return "alquiler";
              case 3: return "alquiler temporal";
              default: return operationType || "";
            }
          } else {
            // Mantener el mapeo de strings por compatibilidad
            if (operationType === "Sale") return "venta";
            if (operationType === "Rent") return "alquiler";
            return operationType || "";
          }
        }
      }
      return "";
    }

    const value = item[header];

    // Procesar age según los nuevos requerimientos
    if (header === "age") {
      if (value === -1) return "en construccion";
      if (value === 0) return "a estrenar";
      return value ? `${value} años` : "";
    }

    if (header === "location" && typeof value === "object" && value !== null) {
      return value.full_location || "";
    }
    else if (header === "type" && typeof value === "object" && value !== null) {
      return typeTranslations[value.name] || value.name;
    }
    else if (header === "has_temporary_rent") {
      // Manejar tanto valores numéricos como booleanos
      const rentValue = String(value);
      Logger.log(`has_temporary_rent valor original: ${value}, tipo: ${typeof value}`);
      return temporaryRentTranslations[rentValue] || "-";
    }
    else if (header === "property_condition") {
      if (value === "Excellent") return "Excelente";
      if (value === "Good") return "Bueno";
      if (value === "Very good") return "Muy bueno";
      if (value === "To refurbish") return "A refaccionar";
      return value;
    }
    else if (header === "situation") {
      if (value === "In use") return "En uso";
      if (value === "Empty") return "Vacío";
      return value;
    }
    else if (
      header === "depth_measure" ||
      header === "front_measure" ||
      header === "surface_measurement"
    ) {
      return value ? `${value} mt.` : "";
    }
    else if (
      header === "roofed_surface" ||
      header === "semiroofed_surface" ||
      header === "surface" ||
      header === "total_surface" ||
      header === "unroofed_surface"
    ) {
      return value ? `${value} mts2` : "";
    }
    else if (header === "development") {
      return value ? "SI" : "NO";
    }
    else if (header === "disposition") {
      switch (value) {
        case "Front": return "Frente";
        case "Internal": return "Interno";
        case "BackFront": return "Contrafrente";
        default: return value;
      }
    }
    else if (header === "expenses") {
      return value ? `$${value}` : "";
    }
    else if (header === "videos" && Array.isArray(value)) {
      return value.map(video => video.url).join(" - ");
    }
    else if (header === "extra_attributes" && Array.isArray(value)) {
      return value
        .map(attribute => `${attribute.name.trim()} ${attribute.value || ""}`.trim())
        .join(" - ");
    }
    else if (header === "tags" && Array.isArray(value)) {
      return value
        .map(tag => translations[tag.name] || tag.name)
        .join(" - ");
    }
    else if (Array.isArray(value)) {
      return value.map(obj => JSON.stringify(obj)).join(", ");
    }
    else {
      return value;
    }
  });
  sheet.appendRow(row);
});

offset += limit;

if (filteredData.objects.length < limit) {
  break;
}

}
}