@horizon-modules/jetimob-crm-integration
Version:
Integração CRM Jetimob para conversão de dados imobiliários para property-model-v3
1,347 lines (1,336 loc) • 189 kB
JavaScript
"use strict";
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
JetimobApiClient: () => JetimobApiClient,
JetimobDownloader: () => JetimobDownloader,
ProfilerService: () => ProfilerService,
convertJetimobToPropertyV3: () => convertJetimobToPropertyV3,
fakeData: () => fakeData
});
module.exports = __toCommonJS(index_exports);
// src/converter/discoverers/discoverOperation.ts
function discoverOperation(imovel) {
if (imovel.contrato) {
return [imovel.contrato];
}
return [];
}
// src/converter/discoverers/discoverAttributes.ts
function discoverAttributes(imovel) {
const attributes = {};
const operacao = discoverOperation(imovel);
if (operacao.length > 0) attributes.operacao = operacao;
if (imovel.valor_venda) {
const valor = Number(imovel.valor_venda);
if (!isNaN(valor) && valor > 0) attributes.valor_venda = valor;
}
if (imovel.valor_locacao && imovel.valor_locacao_visivel) {
const valor = Number(imovel.valor_locacao);
if (!isNaN(valor) && valor > 0) attributes.valor_aluguel = valor;
}
if (imovel.valor_temporada && imovel.valor_temporada_visivel) {
const valor = Number(imovel.valor_temporada);
if (!isNaN(valor) && valor > 0) attributes.valor_temporada = valor;
}
if (imovel.valor_condominio && imovel.valor_condominio_visivel) {
const valor = Number(imovel.valor_condominio);
if (!isNaN(valor) && valor >= 0) attributes.valor_condominio = valor;
}
if (imovel.valor_iptu && imovel.valor_iptu_visivel) {
const valor = Number(imovel.valor_iptu);
if (!isNaN(valor) && valor >= 0) attributes.valor_iptu = valor;
}
if (imovel.area_total) {
const area = Number(imovel.area_total);
if (!isNaN(area) && area > 0) attributes.area_total = area;
}
if (imovel.area_privativa) {
const area = Number(imovel.area_privativa);
if (!isNaN(area) && area > 0) attributes.area_privativa = area;
}
if (imovel.dormitorios) attributes.dormitorios = Number(imovel.dormitorios);
if (imovel.suites) attributes.suites = Number(imovel.suites);
if (imovel.banheiros) attributes.banheiros = Number(imovel.banheiros);
if (imovel.garagens) attributes.vagas_garagem = Number(imovel.garagens);
if (imovel.tipo) attributes.finalidade = imovel.tipo;
if (imovel.subtipo) attributes.tipo = imovel.subtipo;
if (imovel.endereco_cep) attributes.endereco_cep = imovel.endereco_cep;
if (imovel.endereco_estado) attributes.endereco_estado = imovel.endereco_estado;
if (imovel.endereco_cidade) attributes.endereco_cidade = imovel.endereco_cidade;
if (imovel.endereco_bairro) attributes.endereco_bairro = imovel.endereco_bairro;
if (imovel.endereco_logradouro) attributes.endereco_logradouro = imovel.endereco_logradouro;
if (imovel.endereco_numero) attributes.endereco_numero = imovel.endereco_numero;
if (imovel.endereco_complemento) attributes.endereco_complemento = imovel.endereco_complemento;
if (imovel.endereco_referencia) attributes.endereco_referencia = imovel.endereco_referencia;
if (imovel.andar) attributes.andar = Number(imovel.andar);
const geoValue = imovel.geoposicionamento_visivel ? Number(imovel.geoposicionamento_visivel) : 0;
if (imovel.latitude && imovel.longitude && geoValue !== 0) {
const lat = Number(imovel.latitude);
const lng = Number(imovel.longitude);
if (!isNaN(lat) && !isNaN(lng) && lat !== 0 && lng !== 0) {
attributes.latitude = lat;
attributes.longitude = lng;
}
}
if (String(imovel.mobiliado) === "1" || String(imovel.mobiliado) === "true") {
attributes.mobiliado = true;
}
if (String(imovel.financiavel) === "1" || String(imovel.financiavel) === "true") {
attributes.financiavel = true;
}
if (String(imovel.exclusividade) === "true" || String(imovel.exclusividade) === "1") {
attributes.exclusividade = true;
}
if (String(imovel.permuta) === "true" || String(imovel.permuta) === "1") {
attributes.permuta = true;
}
if (String(imovel.seguro_fianca) === "true" || String(imovel.seguro_fianca) === "1") {
attributes.seguro_fianca = true;
}
if (imovel.imovel_comodidades) {
const comodidadesArray = String(imovel.imovel_comodidades).split(",").map((c) => c.trim()).filter((c) => c.length > 0);
if (comodidadesArray.length > 0) {
attributes.comodidades = comodidadesArray;
}
}
if (imovel.situacao) attributes.situacao = imovel.situacao;
if (imovel.destaque && imovel.destaque !== "Sem destaque") {
if (imovel.destaque === "Destaque" || imovel.destaque === "true" || String(imovel.destaque) === "true") {
attributes.destaque = true;
}
}
if (imovel.distancia_mar) attributes.distancia_mar = Number(imovel.distancia_mar);
if (imovel.posicao_solar) attributes.posicao_solar = imovel.posicao_solar;
if (imovel.id_corretor) attributes.corretor_id = String(imovel.id_corretor);
if (imovel.updated_at) attributes.data_atualizacao = imovel.updated_at;
if (imovel.tags) attributes.tags = imovel.tags;
if (imovel.status) attributes.status = imovel.status;
if (imovel.valor_seguro_incendio) {
const valor = Number(imovel.valor_seguro_incendio);
if (!isNaN(valor) && valor >= 0) attributes.valor_seguro_incendio = valor;
}
if (imovel.valor_taxa_limpeza) {
const valor = Number(imovel.valor_taxa_limpeza);
if (!isNaN(valor) && valor >= 0) attributes.valor_taxa_limpeza = valor;
}
if (imovel.calendario_temporada) attributes.calendario_temporada = imovel.calendario_temporada;
if (imovel.condominio_comodidades) attributes.condominio_comodidades = imovel.condominio_comodidades;
return attributes;
}
// src/converter/discoverers/discoverMedia.ts
function discoverMedias(imovel) {
const images = imovel.imagens?.map((imagem, index) => ({
full: imagem.link,
md: imagem.link_thumb || imagem.link,
sm: imagem.link_thumb || imagem.link,
cover: index === 0
// primeira imagem como cover
})) ?? [];
const videos = imovel.videos && imovel.videos.length > 0 ? imovel.videos.map((url) => generateVideo(url)) : [];
const virtual_tours = imovel.tour360 ? [{ embed_url: imovel.tour360 }] : [];
const documents = imovel.plantas && imovel.plantas.length > 0 ? imovel.plantas.map((plantaUrl, index) => ({
name: `Planta ${index + 1}`,
url: plantaUrl
})) : [];
const result = {};
if (images.length > 0) result.images = images;
if (videos.length > 0) result.videos = videos;
if (virtual_tours.length > 0) result.virtual_tours = virtual_tours;
if (documents.length > 0) result.documents = documents;
return result;
}
function generateVideo(url) {
try {
const parsed = new URL(url);
const host = parsed.hostname;
if (host.includes("youtube.com") || host.includes("youtu.be")) {
const id = parsed.searchParams.get("v") || parsed.pathname.split("/").pop();
return {
provider: "youtube",
id: id || void 0,
embed_url: `https://www.youtube.com/embed/${id}`
};
}
return {
embed_url: url
};
} catch (e) {
return {
embed_url: url
};
}
}
// src/converter/discoverers/discoverSettings.ts
function discoverSettings(imovel) {
return {
currency_unit: "BRL",
// sempre BRL no Jetimob
area_unit: imovel.medida === "m\xB2" ? "m2" : imovel.medida || "m2",
// mapeia m² -> m2
distance_unit: "meters",
exibir_no_mapa: true
};
}
// src/converter/discoverers/discoverSEO.ts
function discoverSEO(imovel) {
const seo = {};
if (imovel.meta_title) {
seo.meta_title = imovel.meta_title;
}
if (imovel.meta_description) {
seo.meta_description = imovel.meta_description;
}
if (Object.keys(seo).length > 0) {
return seo;
}
return void 0;
}
// src/converter/index.ts
function convertJetimobToPropertyV3(imovel) {
const seo = discoverSEO(imovel);
return {
// Identificação básica
reference: imovel.codigo ?? "",
title: imovel.titulo_anuncio ?? "",
description: imovel.observacoes ?? "",
// SEO (apenas se houver dados)
...seo && { seo },
// Descoberta de atributos complexos (inclui operação)
attributes: discoverAttributes(imovel),
// Descoberta de mídias (imagens)
media_assets: discoverMedias(imovel),
// Descoberta de configurações e visibilidade
settings: discoverSettings(imovel),
// Data de atualização
updated_at: imovel.updated_at || (/* @__PURE__ */ new Date()).toISOString()
};
}
// src/services/JetimobApiClient.ts
var JetimobApiClient = class {
constructor(config) {
this.webserviceKey = config.webserviceKey;
this.baseUrl = config.baseUrl || "https://api.jetimob.com";
}
async request(endpoint) {
const url = `${this.baseUrl}${endpoint}`;
console.log(`\u{1F517} Requisi\xE7\xE3o para: ${url}`);
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 1e4);
const response = await fetch(url, {
signal: controller.signal
});
clearTimeout(timeoutId);
console.log(`\u{1F4CA} Status: ${response.status}`);
if (!response.ok) {
const errorText = await response.text();
throw new Error(
`Erro na requisi\xE7\xE3o: ${response.status} - ${response.statusText} - ${errorText}`
);
}
return response.json();
}
async getImoveis(page = 1, pageSize = 50) {
return this.request(
`/webservice/${this.webserviceKey}/imoveis?v=4&page=${page}&pageSize=${pageSize}`
);
}
async getImovel(id) {
return this.request(`/webservice/${this.webserviceKey}/imoveis/${id}`);
}
async testConnection() {
try {
console.log("\u{1F680} Testando conex\xE3o com API Jetimob...");
console.log(`\u{1F4CD} Base URL: ${this.baseUrl}`);
console.log(`\u{1F511} Webservice Key: ${this.webserviceKey.substring(0, 10)}...`);
const result = await this.getImoveis(1, 1);
console.log("\u2705 Conex\xE3o bem sucedida!");
return result;
} catch (error) {
console.error("\u274C Erro na conex\xE3o:", error);
throw error;
}
}
};
// src/services/JetimobDownloader.ts
var import_fs = require("fs");
var import_path = require("path");
var JetimobDownloader = class {
constructor(config) {
this.apiClient = new JetimobApiClient({
webserviceKey: config.webserviceKey,
baseUrl: config.baseUrl || "https://api.jetimob.com"
});
this.outputDir = config.outputDir;
}
async ensureOutputDir() {
try {
await import_fs.promises.access(this.outputDir);
} catch {
await import_fs.promises.mkdir(this.outputDir, { recursive: true });
}
}
async savePageData(page, data) {
const properties = data?.data || data;
if (!Array.isArray(properties) || properties.length === 0) {
console.log(` \u{1F4C4} P\xE1gina ${page} vazia, n\xE3o salvando arquivo`);
return false;
}
const fileName = `page-${page}.json`;
const filePath = (0, import_path.join)(this.outputDir, fileName);
await import_fs.promises.writeFile(filePath, JSON.stringify(properties, null, 2), "utf8");
return true;
}
async downloadPage(page, pageSize = 100) {
await this.ensureOutputDir();
const response = await this.apiClient.getImoveis(page, pageSize);
await this.savePageData(page, response);
}
async downloadPages(options = {}) {
const {
startPage = 1,
endPage,
maxPages,
pageSize = 100
} = options;
await this.ensureOutputDir();
const errors = [];
let totalPages = 0;
let totalItems = 0;
let downloadedItems = 0;
try {
console.log(`\u{1F50D} Descobrindo total de p\xE1ginas dispon\xEDveis...`);
const firstPageResponse = await this.apiClient.getImoveis(1, pageSize);
const firstPage = firstPageResponse?.data || firstPageResponse;
if (!Array.isArray(firstPage) || firstPage.length === 0) {
console.log(`\u26A0\uFE0F Primeira p\xE1gina vazia, finalizando download`);
return {
totalPages: 1,
totalItems: 0,
downloadedItems: 0,
errors
};
}
totalPages = firstPageResponse?.totalPages || 0;
totalItems = firstPageResponse?.total || firstPage.length;
console.log(`\u{1F4CA} Total de p\xE1ginas: ${totalPages}`);
console.log(`\u{1F4CA} Total de im\xF3veis: ${totalItems}`);
if (startPage === 1) {
const saved = await this.savePageData(1, firstPageResponse);
if (saved) {
downloadedItems += firstPage.length;
console.log(` \u{1F4C4} P\xE1gina 1: ${firstPage.length} im\xF3veis salvos`);
}
}
let currentPage = Math.max(startPage, 2);
let hasMorePages = true;
const finalEndPage = endPage || (maxPages ? Math.min(startPage + maxPages - 1, totalPages) : totalPages);
while (hasMorePages && currentPage <= finalEndPage) {
try {
console.log(`\u{1F504} Baixando p\xE1gina ${currentPage}...`);
const response = await this.apiClient.getImoveis(currentPage, pageSize);
const properties = response?.data || response;
if (!Array.isArray(properties) || properties.length === 0) {
console.log(`\u26A0\uFE0F P\xE1gina ${currentPage} vazia, finalizando download`);
hasMorePages = false;
break;
}
const saved = await this.savePageData(currentPage, response);
if (saved) {
downloadedItems += properties.length;
console.log(` \u{1F4C4} P\xE1gina ${currentPage}: ${properties.length} im\xF3veis salvos`);
}
currentPage++;
totalPages = currentPage - 1;
await new Promise((resolve) => setTimeout(resolve, 200));
} catch (error) {
const errorMsg = `Erro ao baixar p\xE1gina ${currentPage}: ${error instanceof Error ? error.message : String(error)}`;
errors.push(errorMsg);
console.error(` \u274C ${errorMsg}`);
try {
console.log(`\u{1F504} Tentando novamente p\xE1gina ${currentPage}...`);
await new Promise((resolve) => setTimeout(resolve, 1e3));
const response = await this.apiClient.getImoveis(currentPage, pageSize);
if (Array.isArray(response) && response.length > 0) {
const saved = await this.savePageData(currentPage, response);
if (saved) {
downloadedItems += response.length;
totalItems += response.length;
console.log(` \u{1F4C4} P\xE1gina ${currentPage}: ${response.length} im\xF3veis salvos (retry)`);
}
currentPage++;
totalPages = currentPage - 1;
} else {
hasMorePages = false;
}
} catch (retryError) {
const retryErrorMsg = `Erro na segunda tentativa p\xE1gina ${currentPage}: ${retryError instanceof Error ? retryError.message : String(retryError)}`;
errors.push(retryErrorMsg);
console.error(` \u274C ${retryErrorMsg}`);
hasMorePages = false;
}
}
}
} catch (error) {
const errorMsg = `Erro geral no download: ${error instanceof Error ? error.message : String(error)}`;
errors.push(errorMsg);
console.error(`\u274C ${errorMsg}`);
}
console.log(`
\u{1F4CA} RESUMO DO DOWNLOAD:`);
console.log(`\u{1F4C4} Total de p\xE1ginas: ${totalPages}`);
console.log(`\u{1F4E6} Total de im\xF3veis: ${totalItems}`);
console.log(`\u2705 Im\xF3veis baixados: ${downloadedItems}`);
if (errors.length > 0) {
console.log(`\u274C Erros: ${errors.length}`);
}
return {
totalPages,
totalItems,
downloadedItems,
errors
};
}
async downloadAll(pageSize = 100) {
console.log(`\u{1F680} Iniciando download completo da API Jetimob...`);
console.log(`\u{1F4C4} Tamanho da p\xE1gina: ${pageSize} im\xF3veis`);
return this.downloadPages({ pageSize });
}
async uploadToApi(uploadConfig) {
const { endpoint, headers = {}, convertData = true } = uploadConfig;
const errors = [];
let totalProcessed = 0;
let totalSent = 0;
let totalErrors = 0;
try {
const files = await import_fs.promises.readdir(this.outputDir);
const jsonFiles = files.filter((file) => file.endsWith(".json")).sort((a, b) => {
const numA = parseInt(a.match(/page-(\d+)/)?.[1] || "0");
const numB = parseInt(b.match(/page-(\d+)/)?.[1] || "0");
return numA - numB;
});
console.log(`
\u{1F4C1} Encontrados ${jsonFiles.length} arquivos para processar`);
for (const file of jsonFiles) {
console.log(`
\u{1F4C4} Processando ${file}...`);
try {
const filePath = (0, import_path.join)(this.outputDir, file);
const content = await import_fs.promises.readFile(filePath, "utf8");
const pageData = JSON.parse(content);
if (!Array.isArray(pageData) || pageData.length === 0) {
console.log(" \u{1F4C4} Arquivo vazio, pulando...");
continue;
}
const properties = pageData;
console.log(` \u{1F4CA} ${properties.length} im\xF3veis encontrados`);
totalProcessed += properties.length;
try {
let payload;
if (convertData) {
payload = { properties, source: "jetimob" };
} else {
payload = { properties };
}
const response = await fetch(endpoint, {
method: "PUT",
headers: {
"Content-Type": "application/json",
...headers
},
body: JSON.stringify(payload)
});
if (response.ok) {
const result = await response.json();
totalSent += properties.length;
console.log(` \u2705 Sucesso: ${properties.length} im\xF3veis enviados`);
console.log(` \u{1F4DD} ${result.message || "Processado com sucesso"}`);
} else {
const errorText = await response.text();
totalErrors += properties.length;
const errorMsg = `Erro ${response.status} ao enviar arquivo ${file}: ${errorText}`;
errors.push(errorMsg);
console.log(` \u274C ${errorMsg}`);
break;
}
} catch (error) {
totalErrors += properties.length;
const errorMsg = `Erro de rede ao enviar arquivo ${file}: ${error instanceof Error ? error.message : String(error)}`;
errors.push(errorMsg);
console.error(` \u274C ${errorMsg}`);
break;
}
await new Promise((resolve) => setTimeout(resolve, 500));
} catch (error) {
const errorMsg = `Erro ao processar arquivo ${file}: ${error instanceof Error ? error.message : String(error)}`;
errors.push(errorMsg);
console.error(` \u274C ${errorMsg}`);
}
}
} catch (error) {
const errorMsg = `Erro ao acessar diret\xF3rio ${this.outputDir}: ${error instanceof Error ? error.message : String(error)}`;
errors.push(errorMsg);
console.error(`\u274C ${errorMsg}`);
}
console.log("\n\u{1F389} RESUMO FINAL DO UPLOAD:");
console.log(`\u{1F4CA} Total processado: ${totalProcessed} im\xF3veis`);
console.log(`\u2705 Sucessos: ${totalSent} im\xF3veis`);
console.log(`\u274C Erros: ${totalErrors} im\xF3veis`);
if (totalProcessed > 0) {
console.log(`\u{1F4C8} Taxa de sucesso: ${Math.round(totalSent / totalProcessed * 100)}%`);
}
return {
totalProcessed,
totalSent,
totalErrors,
errors
};
}
async downloadAndUpload(downloadOptions, uploadConfig) {
console.log(`\u{1F680} Iniciando processo completo: Download + Upload`);
const downloadResult = await this.downloadPages(downloadOptions);
if (downloadResult.downloadedItems > 0) {
console.log(`
\u{1F4E4} Iniciando upload de ${downloadResult.downloadedItems} im\xF3veis...`);
const uploadResult = await this.uploadToApi(uploadConfig);
return {
downloadResult,
uploadResult
};
} else {
console.log(`\u26A0\uFE0F Nenhum im\xF3vel foi baixado, pulando upload`);
return {
downloadResult,
uploadResult: {
totalProcessed: 0,
totalSent: 0,
totalErrors: 0,
errors: ["Nenhum dado para enviar"]
}
};
}
}
};
// src/services/ProfilerService.ts
var fs2 = __toESM(require("fs"));
var path = __toESM(require("path"));
var ProfilerService = class {
constructor(config) {
this.fieldData = /* @__PURE__ */ new Map();
this.fieldExamples = /* @__PURE__ */ new Map();
this.config = {
outputFileName: "profiling-report.json",
defaultMaxExamples: 10,
verbose: false,
uniqueField: "id",
dataLabel: "items",
serviceLabel: "Data",
...config
};
}
async profile() {
if (this.config.verbose) {
console.log(`\u{1F4CA} Iniciando profiling dos dados ${this.config.serviceLabel}...`);
}
if (!fs2.existsSync(this.config.inputDir)) {
throw new Error(`Diret\xF3rio de entrada n\xE3o encontrado: ${this.config.inputDir}`);
}
const data = await this.loadData();
this.processData(data);
const result = this.generateResult();
await this.saveResult(result);
return result;
}
async loadData() {
const files = fs2.readdirSync(this.config.inputDir).filter((file) => file.endsWith(".json")).sort();
if (this.config.verbose) {
console.log(`\u{1F4C1} Carregando ${files.length} arquivos ${this.config.serviceLabel}...`);
}
const allData = [];
for (const file of files) {
const filePath = path.join(this.config.inputDir, file);
const content = fs2.readFileSync(filePath, "utf8");
const fileData = JSON.parse(content);
if (Array.isArray(fileData)) {
allData.push(...fileData);
if (this.config.verbose) {
console.log(` \u2705 ${file}: ${fileData.length} ${this.config.dataLabel}`);
}
} else if (fileData.data && Array.isArray(fileData.data)) {
allData.push(...fileData.data);
if (this.config.verbose) {
console.log(` \u2705 ${file}: ${fileData.data.length} ${this.config.dataLabel}`);
}
}
}
if (this.config.verbose) {
console.log(`\u{1F50D} Analisando ${allData.length} ${this.config.dataLabel} ${this.config.serviceLabel}...`);
}
return allData;
}
processData(data) {
data.forEach((item, index) => {
if (this.config.verbose && (index + 1) % 100 === 0) {
console.log(` Processando ${index + 1}/${data.length}...`);
}
this.processObject(item, "");
});
}
processObject(obj, prefix) {
for (const [key, value] of Object.entries(obj)) {
const fieldName = prefix ? `${prefix}.${key}` : key;
if (value === null || value === void 0) {
continue;
}
if (Array.isArray(value)) {
this.processArrayField(fieldName, value);
} else if (typeof value === "object") {
this.processObject(value, fieldName);
} else {
this.processSimpleField(fieldName, value);
}
}
}
processArrayField(fieldName, array) {
for (const item of array) {
if (item !== null && item !== void 0) {
if (typeof item === "object") {
this.processObject(item, fieldName);
} else {
this.processSimpleField(fieldName, item);
}
}
}
}
processSimpleField(fieldName, value) {
if (!this.fieldData.has(fieldName)) {
this.fieldData.set(fieldName, /* @__PURE__ */ new Set());
this.fieldExamples.set(fieldName, []);
}
const valueSet = this.fieldData.get(fieldName);
const examples = this.fieldExamples.get(fieldName);
valueSet.add(value);
const fieldConfig = this.config.fieldConfigs?.[fieldName] || {};
const maxExamples = fieldConfig.maxExamples ?? this.config.defaultMaxExamples;
if (!examples.includes(value) && examples.length < maxExamples) {
examples.push(value);
}
}
generateResult() {
const result = {};
const sortedFields = Array.from(this.fieldData.keys()).sort();
for (const fieldName of sortedFields) {
const examples = this.fieldExamples.get(fieldName) || [];
const sortedExamples = examples.sort((a, b) => {
const aStr = String(a);
const bStr = String(b);
return aStr.localeCompare(bStr);
});
result[fieldName] = sortedExamples;
}
return result;
}
async saveResult(result) {
if (!fs2.existsSync(this.config.outputDir)) {
fs2.mkdirSync(this.config.outputDir, { recursive: true });
}
const outputPath = path.join(this.config.outputDir, this.config.outputFileName);
const jsonContent = JSON.stringify(result, null, 2);
fs2.writeFileSync(outputPath, jsonContent, "utf8");
if (this.config.verbose) {
const sizeKB = (jsonContent.length / 1024).toFixed(1);
console.log(`\u2705 Profiling ${this.config.serviceLabel} salvo em: ${outputPath} (${sizeKB}KB)`);
console.log(`\u{1F4CA} Total de campos analisados: ${Object.keys(result).length}`);
}
}
/**
* Método para analisar apenas dados únicos
* Remove duplicatas baseado no campo configurado em uniqueField
*/
async profileUnique() {
const allData = await this.loadData();
const uniqueData = Array.from(
new Map(allData.map((item) => [item[this.config.uniqueField], item])).values()
);
if (this.config.verbose) {
console.log(`\u{1F50D} Removidas ${allData.length - uniqueData.length} duplicatas`);
console.log(`\u{1F4CA} Analisando ${uniqueData.length} ${this.config.dataLabel} \xFAnicos...`);
}
this.processData(uniqueData);
const result = this.generateResult();
await this.saveResult(result);
return result;
}
};
// src/data/fake-data/apartamentos.json
var apartamentos_default = [
{
codigo: "FAKE_APARTAMENTOS_001",
titulo_anuncio: "Apartamento Centro - 2 dorm, 2 su\xEDtes, 165m\xB2, 1 vaga",
observacoes: "Apartamento com vista para o mar em Torres, a praia mais linda do RS.",
contrato: "Compra",
tipo: "Residencial",
subtipo: "Apartamento",
mobiliado: 0,
financiavel: 0,
exclusividade: false,
medida: "m\xB2",
endereco_estado: "Rio Grande do Sul",
endereco_cidade: "Torres",
data_cadastro: "2024-01-06 13:26:01",
data_update: "2025-03-03 00:46:23",
data_atualizacao: "2025-03-16 10:42:00",
updated_at: "2025-03-19 08:18:57",
dormitorios: 2,
suites: 2,
banheiros: 3,
garagens: 1,
area_total: 150,
area_privativa: 165,
andar: 1,
valor_venda: 28e4,
endereco_bairro: "Vila S\xE3o Jo\xE3o",
endereco_logradouro: "Rua J\xFAlio de Castilhos",
endereco_numero: "491",
endereco_cep: "95560-070",
endereco_complemento: "Apto 1",
latitude: -29.342936776054497,
longitude: -49.72035923955464,
imovel_comodidades: "Sacada,Pr\xF3ximo \xE0 praia,\xC1rea de servi\xE7o,Churrasqueira,Lavabo",
imagens: [
{
link: "https://images.unsplash.com/photo-1565183997392-2f6f122e5912?w=800&q=80",
titulo: "1.jpg",
link_thumb: "https://images.unsplash.com/photo-1565183997392-2f6f122e5912?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=800&q=80",
titulo: "2.jpg",
link_thumb: "https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1568605117036-5fe5e7bab0b7?w=800&q=80",
titulo: "3.jpg",
link_thumb: "https://images.unsplash.com/photo-1568605117036-5fe5e7bab0b7?w=400&q=80"
}
],
videos: [],
tour360: [],
plantas: [],
valor_venda_visivel: true,
valor_locacao_visivel: false,
valor_temporada_visivel: false,
valor_condominio_visivel: false,
valor_iptu_visivel: false,
endereco_estado_visivel: true,
endereco_cidade_visivel: false,
endereco_bairro_visivel: false,
endereco_logradouro_visivel: false,
endereco_numero_visivel: false,
endereco_complemento_visivel: false
},
{
codigo: "FAKE_APARTAMENTOS_002",
titulo_anuncio: "Apartamento Centro - 4 dorm, 3 su\xEDtes, 165m\xB2, 3 vagas",
observacoes: "Unidade moderna pr\xF3xima ao Centro Hist\xF3rico e ao Farol de Torres.",
contrato: "Compra",
tipo: "Residencial",
subtipo: "Apartamento",
mobiliado: 0,
financiavel: 0,
exclusividade: false,
medida: "m\xB2",
endereco_estado: "Rio Grande do Sul",
endereco_cidade: "Torres",
data_cadastro: "2024-03-10 02:20:33",
data_update: "2025-05-18 22:01:44",
data_atualizacao: "2025-04-13 15:23:31",
updated_at: "2025-01-14 22:31:12",
dormitorios: 4,
suites: 3,
banheiros: 3,
garagens: 3,
area_total: 105,
area_privativa: 165,
andar: 10,
valor_venda: 85e4,
endereco_bairro: "Vila S\xE3o Jo\xE3o",
endereco_logradouro: "Rua Jo\xE3o Neves da Fontoura",
endereco_numero: "882",
endereco_cep: "95560-020",
endereco_complemento: "",
latitude: -29.326109044782587,
longitude: -49.72886046595862,
imovel_comodidades: "\xC1rea gourmet,\xC1rea de servi\xE7o,Lavabo,Hidromassagem",
imagens: [
{
link: "https://images.unsplash.com/photo-1493663284031-b7e3aefcae8e?w=800&q=80",
titulo: "1.jpg",
link_thumb: "https://images.unsplash.com/photo-1493663284031-b7e3aefcae8e?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1493663284031-b7e3aefcae8e?w=800&q=80",
titulo: "2.jpg",
link_thumb: "https://images.unsplash.com/photo-1493663284031-b7e3aefcae8e?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1560185127-6ed189bf02f4?w=800&q=80",
titulo: "3.jpg",
link_thumb: "https://images.unsplash.com/photo-1560185127-6ed189bf02f4?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1560185127-6ed189bf02f4?w=800&q=80",
titulo: "4.jpg",
link_thumb: "https://images.unsplash.com/photo-1560185127-6ed189bf02f4?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=800&q=80",
titulo: "5.jpg",
link_thumb: "https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=400&q=80"
}
],
videos: [],
tour360: [],
plantas: [],
valor_venda_visivel: true,
valor_locacao_visivel: false,
valor_temporada_visivel: false,
valor_condominio_visivel: false,
valor_iptu_visivel: false,
endereco_estado_visivel: true,
endereco_cidade_visivel: false,
endereco_bairro_visivel: false,
endereco_logradouro_visivel: false,
endereco_numero_visivel: false,
endereco_complemento_visivel: false
},
{
codigo: "FAKE_APARTAMENTOS_003",
titulo_anuncio: "Apartamento Centro - 3 dorm, 115m\xB2, 3 vagas",
observacoes: "Im\xF3vel com excelente localiza\xE7\xE3o e acabamentos de primeira linha.",
contrato: "Compra",
tipo: "Residencial",
subtipo: "Apartamento",
mobiliado: 0,
financiavel: 0,
exclusividade: false,
medida: "m\xB2",
endereco_estado: "Rio Grande do Sul",
endereco_cidade: "Torres",
data_cadastro: "2025-07-23 02:33:46",
data_update: "2024-06-18 14:20:49",
data_atualizacao: "2025-05-26 22:11:42",
updated_at: "2025-07-18 14:46:17",
dormitorios: 3,
suites: 0,
banheiros: 3,
garagens: 3,
area_total: 45,
area_privativa: 115,
andar: 15,
valor_venda: 85e4,
endereco_bairro: "Praia Grande",
endereco_logradouro: "Rua Senador Pinheiro Machado",
endereco_numero: "430",
endereco_cep: "95560-060",
endereco_complemento: "Apto 2",
latitude: -29.336375878338483,
longitude: -49.72503985134924,
imovel_comodidades: "Ar condicionado,Varanda,\xC1rea gourmet,\xC1rea de servi\xE7o",
imagens: [
{
link: "https://images.unsplash.com/photo-1502672260266-1c1ef2d93688?w=800&q=80",
titulo: "1.jpg",
link_thumb: "https://images.unsplash.com/photo-1502672260266-1c1ef2d93688?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1493663284031-b7e3aefcae8e?w=800&q=80",
titulo: "2.jpg",
link_thumb: "https://images.unsplash.com/photo-1493663284031-b7e3aefcae8e?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1522708323590-d24dbb6b0267?w=800&q=80",
titulo: "3.jpg",
link_thumb: "https://images.unsplash.com/photo-1522708323590-d24dbb6b0267?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1560185127-6ed189bf02f4?w=800&q=80",
titulo: "4.jpg",
link_thumb: "https://images.unsplash.com/photo-1560185127-6ed189bf02f4?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1586023492125-27b2c045efd7?w=800&q=80",
titulo: "5.jpg",
link_thumb: "https://images.unsplash.com/photo-1586023492125-27b2c045efd7?w=400&q=80"
}
],
videos: [],
tour360: [],
plantas: [],
valor_venda_visivel: true,
valor_locacao_visivel: false,
valor_temporada_visivel: false,
valor_condominio_visivel: false,
valor_iptu_visivel: false,
endereco_estado_visivel: true,
endereco_cidade_visivel: false,
endereco_bairro_visivel: false,
endereco_logradouro_visivel: false,
endereco_numero_visivel: false,
endereco_complemento_visivel: false
},
{
codigo: "FAKE_APARTAMENTOS_004",
titulo_anuncio: "Apartamento Centro - 3 dorm, 2 su\xEDtes, 140m\xB2, 1 vaga",
observacoes: "Im\xF3vel com excelente localiza\xE7\xE3o e acabamentos de primeira linha.",
contrato: "Compra",
tipo: "Residencial",
subtipo: "Apartamento",
mobiliado: 0,
financiavel: 0,
exclusividade: false,
medida: "m\xB2",
endereco_estado: "Rio Grande do Sul",
endereco_cidade: "Torres",
data_cadastro: "2025-01-12 05:21:57",
data_update: "2025-07-10 14:50:25",
data_atualizacao: "2024-10-07 07:40:13",
updated_at: "2025-05-05 10:51:02",
dormitorios: 3,
suites: 2,
banheiros: 1,
garagens: 1,
area_total: 65,
area_privativa: 140,
andar: 12,
valor_venda: 85e4,
endereco_bairro: "Jardim Ubatuba",
endereco_logradouro: "Rua Senador Pinheiro Machado",
endereco_numero: "427",
endereco_cep: "95560-020",
endereco_complemento: "Apto 6",
latitude: -29.339157171441027,
longitude: -49.72632203630522,
imovel_comodidades: "Ar condicionado,Jardim,Garagem coberta,Terra\xE7o,Sacada,Pr\xF3ximo \xE0 praia",
imagens: [
{
link: "https://images.unsplash.com/photo-1560448204-e02f11c3d0e2?w=800&q=80",
titulo: "1.jpg",
link_thumb: "https://images.unsplash.com/photo-1560448204-e02f11c3d0e2?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1522708323590-d24dbb6b0267?w=800&q=80",
titulo: "2.jpg",
link_thumb: "https://images.unsplash.com/photo-1522708323590-d24dbb6b0267?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1568605117036-5fe5e7bab0b7?w=800&q=80",
titulo: "3.jpg",
link_thumb: "https://images.unsplash.com/photo-1568605117036-5fe5e7bab0b7?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1556909114-f6e7ad7d3136?w=800&q=80",
titulo: "4.jpg",
link_thumb: "https://images.unsplash.com/photo-1556909114-f6e7ad7d3136?w=400&q=80"
}
],
videos: [],
tour360: [],
plantas: [],
valor_venda_visivel: true,
valor_locacao_visivel: false,
valor_temporada_visivel: false,
valor_condominio_visivel: false,
valor_iptu_visivel: false,
endereco_estado_visivel: true,
endereco_cidade_visivel: false,
endereco_bairro_visivel: false,
endereco_logradouro_visivel: false,
endereco_numero_visivel: false,
endereco_complemento_visivel: false
},
{
codigo: "FAKE_APARTAMENTOS_005",
titulo_anuncio: "Apartamento Centro - 3 dorm, 3 su\xEDtes, 55m\xB2, 2 vagas",
observacoes: "Apartamento com sacada, a poucos metros da Praia Grande.",
contrato: "Compra",
tipo: "Residencial",
subtipo: "Apartamento",
mobiliado: 0,
financiavel: 0,
exclusividade: false,
medida: "m\xB2",
endereco_estado: "Rio Grande do Sul",
endereco_cidade: "Torres",
data_cadastro: "2024-05-08 10:23:39",
data_update: "2024-09-18 14:42:42",
data_atualizacao: "2024-01-07 03:13:44",
updated_at: "2025-02-09 06:49:29",
dormitorios: 3,
suites: 3,
banheiros: 4,
garagens: 2,
area_total: 180,
area_privativa: 55,
andar: 12,
valor_venda: 18e4,
endereco_bairro: "Prainha",
endereco_logradouro: "Rua Bar\xE3o do Rio Branco",
endereco_numero: "526",
endereco_cep: "95560-060",
endereco_complemento: "",
latitude: -29.33708529462322,
longitude: -49.73430782637095,
imovel_comodidades: "Lareira,Varanda",
imagens: [
{
link: "https://images.unsplash.com/photo-1522708323590-d24dbb6b0267?w=800&q=80",
titulo: "1.jpg",
link_thumb: "https://images.unsplash.com/photo-1522708323590-d24dbb6b0267?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1502672260266-1c1ef2d93688?w=800&q=80",
titulo: "2.jpg",
link_thumb: "https://images.unsplash.com/photo-1502672260266-1c1ef2d93688?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1493663284031-b7e3aefcae8e?w=800&q=80",
titulo: "3.jpg",
link_thumb: "https://images.unsplash.com/photo-1493663284031-b7e3aefcae8e?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1581858726788-75bc0f6a952d?w=800&q=80",
titulo: "4.jpg",
link_thumb: "https://images.unsplash.com/photo-1581858726788-75bc0f6a952d?w=400&q=80"
}
],
videos: [],
tour360: [],
plantas: [],
valor_venda_visivel: true,
valor_locacao_visivel: false,
valor_temporada_visivel: false,
valor_condominio_visivel: false,
valor_iptu_visivel: false,
endereco_estado_visivel: true,
endereco_cidade_visivel: false,
endereco_bairro_visivel: false,
endereco_logradouro_visivel: false,
endereco_numero_visivel: false,
endereco_complemento_visivel: false
},
{
codigo: "FAKE_APARTAMENTOS_006",
titulo_anuncio: "Apartamento Centro - 4 dorm, 2 su\xEDtes, 55m\xB2, 3 vagas",
observacoes: "Apartamento com vista para o mar em Torres, a praia mais linda do RS.",
contrato: "Compra",
tipo: "Residencial",
subtipo: "Apartamento",
mobiliado: 0,
financiavel: 0,
exclusividade: false,
medida: "m\xB2",
endereco_estado: "Rio Grande do Sul",
endereco_cidade: "Torres",
data_cadastro: "2025-06-12 10:45:18",
data_update: "2024-09-07 03:24:40",
data_atualizacao: "2024-12-04 16:01:29",
updated_at: "2024-07-27 13:34:42",
dormitorios: 4,
suites: 2,
banheiros: 4,
garagens: 3,
area_total: 105,
area_privativa: 55,
andar: 12,
valor_venda: 62e4,
endereco_bairro: "Residencial Quinta da Colina",
endereco_logradouro: "Rua Crist\xF3v\xE3o Colombo",
endereco_numero: "52",
endereco_cep: "95560-010",
endereco_complemento: "",
latitude: -29.3424800569058,
longitude: -49.71831372337415,
imovel_comodidades: "Churrasqueira,Vista para o mar,Garagem coberta,Ar condicionado",
imagens: [
{
link: "https://images.unsplash.com/photo-1574362848149-11496d93a7c7?w=800&q=80",
titulo: "1.jpg",
link_thumb: "https://images.unsplash.com/photo-1574362848149-11496d93a7c7?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1565183997392-2f6f122e5912?w=800&q=80",
titulo: "2.jpg",
link_thumb: "https://images.unsplash.com/photo-1565183997392-2f6f122e5912?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1581858726788-75bc0f6a952d?w=800&q=80",
titulo: "3.jpg",
link_thumb: "https://images.unsplash.com/photo-1581858726788-75bc0f6a952d?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1560185127-6ed189bf02f4?w=800&q=80",
titulo: "4.jpg",
link_thumb: "https://images.unsplash.com/photo-1560185127-6ed189bf02f4?w=400&q=80"
}
],
videos: [],
tour360: [],
plantas: [],
valor_venda_visivel: true,
valor_locacao_visivel: false,
valor_temporada_visivel: false,
valor_condominio_visivel: false,
valor_iptu_visivel: false,
endereco_estado_visivel: true,
endereco_cidade_visivel: false,
endereco_bairro_visivel: false,
endereco_logradouro_visivel: false,
endereco_numero_visivel: false,
endereco_complemento_visivel: false
},
{
codigo: "FAKE_APARTAMENTOS_007",
titulo_anuncio: "Apartamento Centro - 2 dorm, 3 su\xEDtes, 35m\xB2, 2 vagas",
observacoes: "Apartamento com sacada, a poucos metros da Praia Grande.",
contrato: "Compra",
tipo: "Residencial",
subtipo: "Apartamento",
mobiliado: 0,
financiavel: 0,
exclusividade: false,
medida: "m\xB2",
endereco_estado: "Rio Grande do Sul",
endereco_cidade: "Torres",
data_cadastro: "2024-10-27 12:03:54",
data_update: "2025-03-07 19:18:00",
data_atualizacao: "2024-07-30 07:14:20",
updated_at: "2024-08-20 11:51:48",
dormitorios: 2,
suites: 3,
banheiros: 3,
garagens: 2,
area_total: 180,
area_privativa: 35,
andar: 15,
valor_venda: 18e4,
endereco_bairro: "Vila Aparecida",
endereco_logradouro: "Avenida Paraguassu",
endereco_numero: "501",
endereco_cep: "95560-001",
endereco_complemento: "",
latitude: -29.32939553045724,
longitude: -49.72914491690439,
imovel_comodidades: "Hidromassagem,Garagem coberta,\xC1rea de servi\xE7o",
imagens: [
{
link: "https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=800&q=80",
titulo: "1.jpg",
link_thumb: "https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=800&q=80",
titulo: "2.jpg",
link_thumb: "https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1502672260266-1c1ef2d93688?w=800&q=80",
titulo: "3.jpg",
link_thumb: "https://images.unsplash.com/photo-1502672260266-1c1ef2d93688?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1586023492125-27b2c045efd7?w=800&q=80",
titulo: "4.jpg",
link_thumb: "https://images.unsplash.com/photo-1586023492125-27b2c045efd7?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1556909114-f6e7ad7d3136?w=800&q=80",
titulo: "5.jpg",
link_thumb: "https://images.unsplash.com/photo-1556909114-f6e7ad7d3136?w=400&q=80"
}
],
videos: [],
tour360: [],
plantas: [],
valor_venda_visivel: true,
valor_locacao_visivel: false,
valor_temporada_visivel: false,
valor_condominio_visivel: false,
valor_iptu_visivel: false,
endereco_estado_visivel: true,
endereco_cidade_visivel: false,
endereco_bairro_visivel: false,
endereco_logradouro_visivel: false,
endereco_numero_visivel: false,
endereco_complemento_visivel: false
},
{
codigo: "FAKE_APARTAMENTOS_008",
titulo_anuncio: "Apartamento Centro - 4 dorm, 3 su\xEDtes, 75m\xB2, 3 vagas",
observacoes: "Apartamento com sacada, a poucos metros da Praia Grande.",
contrato: "Compra",
tipo: "Residencial",
subtipo: "Apartamento",
mobiliado: 0,
financiavel: 0,
exclusividade: false,
medida: "m\xB2",
endereco_estado: "Rio Grande do Sul",
endereco_cidade: "Torres",
data_cadastro: "2024-08-09 15:10:05",
data_update: "2024-11-13 10:58:00",
data_atualizacao: "2024-06-27 21:22:25",
updated_at: "2024-04-26 14:12:51",
dormitorios: 4,
suites: 3,
banheiros: 4,
garagens: 3,
area_total: 105,
area_privativa: 75,
andar: 12,
valor_venda: 18e4,
endereco_bairro: "Prainha",
endereco_logradouro: "Avenida Beira Mar",
endereco_numero: "573",
endereco_cep: "95560-010",
endereco_complemento: "Apto 13",
latitude: -29.33017236005315,
longitude: -49.7229083304007,
imovel_comodidades: "Churrasqueira,\xC1rea gourmet,Terra\xE7o,Vista para o mar",
imagens: [
{
link: "https://images.unsplash.com/photo-1560448204-e02f11c3d0e2?w=800&q=80",
titulo: "1.jpg",
link_thumb: "https://images.unsplash.com/photo-1560448204-e02f11c3d0e2?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=800&q=80",
titulo: "2.jpg",
link_thumb: "https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1560185127-6ed189bf02f4?w=800&q=80",
titulo: "3.jpg",
link_thumb: "https://images.unsplash.com/photo-1560185127-6ed189bf02f4?w=400&q=80"
}
],
videos: [],
tour360: [],
plantas: [],
valor_venda_visivel: true,
valor_locacao_visivel: false,
valor_temporada_visivel: false,
valor_condominio_visivel: false,
valor_iptu_visivel: false,
endereco_estado_visivel: true,
endereco_cidade_visivel: false,
endereco_bairro_visivel: false,
endereco_logradouro_visivel: false,
endereco_numero_visivel: false,
endereco_complemento_visivel: false
},
{
codigo: "FAKE_APARTAMENTOS_009",
titulo_anuncio: "Apartamento Centro - 4 dorm, 95m\xB2, 1 vaga",
observacoes: "Im\xF3vel com excelente localiza\xE7\xE3o e acabamentos de primeira linha.",
contrato: "Compra",
tipo: "Residencial",
subtipo: "Apartamento",
mobiliado: 0,
financiavel: 0,
exclusividade: false,
medida: "m\xB2",
endereco_estado: "Rio Grande do Sul",
endereco_cidade: "Torres",
data_cadastro: "2025-02-11 23:09:26",
data_update: "2024-06-21 03:00:28",
data_atualizacao: "2024-02-08 04:56:29",
updated_at: "2024-07-04 12:24:44",
dormitorios: 4,
suites: 0,
banheiros: 4,
garagens: 1,
area_total: 150,
area_privativa: 95,
andar: 8,
valor_venda: 28e4,
endereco_bairro: "Vila S\xE3o Jo\xE3o",
endereco_logradouro: "Rua Benjamin Constant",
endereco_numero: "967",
endereco_cep: "95560-020",
endereco_complemento: "",
latitude: -29.338789575624848,
longitude: -49.736857533133374,
imovel_comodidades: "Garagem coberta,Ar condicionado,Lareira,Churrasqueira",
imagens: [
{
link: "https://images.unsplash.com/photo-1493663284031-b7e3aefcae8e?w=800&q=80",
titulo: "1.jpg",
link_thumb: "https://images.unsplash.com/photo-1493663284031-b7e3aefcae8e?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=800&q=80",
titulo: "2.jpg",
link_thumb: "https://images.unsplash.com/photo-1545324418-cc1a3fa10c00?w=400&q=80"
},
{
link: "https://images.unsplash.com/photo-1556909114-f6e7ad7d3136?w=800&q=80",
titulo: "3.jpg",
link_thumb: "https://images.unsplash.com/photo-1556909114-f6e7ad7d3136?w=400&q=80"
}
],
videos: [],
tour360: [],
plantas: [],
valor_venda_visivel: true,
valor_locacao_visivel: false,
valor_temporada_visivel: false,
valor_condominio_visivel: false,
valor_iptu_visivel: false,
endereco_estado_visivel: true,
endereco_cidade_visivel: false,
endereco_bairro_visivel: false,
endereco_logradouro_visivel: false,
endereco_numero_visivel: false,
endereco_complemento_visivel: false
},
{
codigo: "FAKE_APARTAMENTOS_010",
titulo_anuncio: "Apartamento Centro - 3 dorm, 55m\xB2, 2 vagas",
observacoes: "Im\xF3vel com excelente localiza\xE7\xE3o e acabamentos de primeira linha.",
contrato: "Compra",
tipo: "Residencial",
subtipo: "Apartamento",
mobiliado: 0,
financiavel: 0,
exclusividade: false,
medida: "m\xB2",
endereco_estado: "Rio Grande do Sul