Keep workers online during long-running downloads
@@ -0,0 +1,310 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { SpreadsheetFile, Workbook } from "@oai/artifact-tool";
|
||||
|
||||
const workspace = "C:/Users/erik1/Documents/IPSExtractor";
|
||||
const sourceDir = path.join(workspace, ".codex_tmp_apartments");
|
||||
const outputDir = path.join(workspace, "outputs", "apartamentos_rentpana_20260830");
|
||||
const outputPath = path.join(outputDir, "apartamentos_visibles_rentpana.xlsx");
|
||||
const pageSize = 50;
|
||||
|
||||
const pages = [];
|
||||
for (let pageIndex = 0; pageIndex < 3; pageIndex += 1) {
|
||||
const text = await fs.readFile(path.join(sourceDir, `page_${pageIndex}.json`), "utf8");
|
||||
const rows = JSON.parse(text);
|
||||
pages.push({ page: pageIndex + 1, offset: pageIndex * pageSize, rows });
|
||||
}
|
||||
|
||||
const apartments = pages.flatMap((page) => page.rows);
|
||||
if (apartments.length !== 101) throw new Error(`Se esperaban 101 registros y llegaron ${apartments.length}`);
|
||||
const ids = apartments.map((row) => row.id);
|
||||
if (new Set(ids).size !== apartments.length) throw new Error("Se detectaron IDs duplicados en la extracción");
|
||||
|
||||
const columns = Object.keys(apartments[0]);
|
||||
const expectedColumns = 34;
|
||||
if (columns.length !== expectedColumns) throw new Error(`Se esperaban ${expectedColumns} columnas y llegaron ${columns.length}`);
|
||||
|
||||
const normalize = (key, value) => {
|
||||
if (value === null || value === undefined) return null;
|
||||
if (key === "created_at" || key === "updated_at") {
|
||||
const date = new Date(`${value}T00:00:00Z`);
|
||||
return Number.isNaN(date.getTime()) ? String(value) : date;
|
||||
}
|
||||
if (Array.isArray(value)) return value.join(" | ");
|
||||
if (typeof value === "object") return JSON.stringify(value);
|
||||
return value;
|
||||
};
|
||||
|
||||
const colLetter = (oneBased) => {
|
||||
let n = oneBased;
|
||||
let result = "";
|
||||
while (n > 0) {
|
||||
const remainder = (n - 1) % 26;
|
||||
result = String.fromCharCode(65 + remainder) + result;
|
||||
n = Math.floor((n - 1) / 26);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const workbook = Workbook.create();
|
||||
const summary = workbook.worksheets.add("Resumen");
|
||||
const dataSheet = workbook.worksheets.add("Apartamentos");
|
||||
const photosSheet = workbook.worksheets.add("Fotos");
|
||||
const paginationSheet = workbook.worksheets.add("Paginacion");
|
||||
|
||||
const navy = "#123047";
|
||||
const teal = "#0F766E";
|
||||
const cyan = "#DFF4F1";
|
||||
const pale = "#F4F7F9";
|
||||
const gold = "#E8B44F";
|
||||
const white = "#FFFFFF";
|
||||
const ink = "#1F2937";
|
||||
const muted = "#60707D";
|
||||
const border = "#D8E1E7";
|
||||
|
||||
for (const sheet of [summary, dataSheet, photosSheet, paginationSheet]) {
|
||||
sheet.showGridLines = false;
|
||||
}
|
||||
|
||||
// Hoja principal con todos los campos devueltos por la API.
|
||||
const dataMatrix = [columns, ...apartments.map((row) => columns.map((key) => normalize(key, row[key])))];
|
||||
const dataEndCol = colLetter(columns.length);
|
||||
const dataEndRow = dataMatrix.length;
|
||||
dataSheet.getRange(`A1:${dataEndCol}${dataEndRow}`).values = dataMatrix;
|
||||
dataSheet.freezePanes.freezeRows(1);
|
||||
dataSheet.freezePanes.freezeColumns(2);
|
||||
const apartmentTable = dataSheet.tables.add(`A1:${dataEndCol}${dataEndRow}`, true, "ApartmentsTable");
|
||||
apartmentTable.style = "TableStyleMedium2";
|
||||
apartmentTable.showFilterButton = true;
|
||||
dataSheet.getRange(`A1:${dataEndCol}1`).format = {
|
||||
fill: navy,
|
||||
font: { bold: true, color: white },
|
||||
rowHeight: 28,
|
||||
verticalAlignment: "center",
|
||||
};
|
||||
dataSheet.getRange(`A2:${dataEndCol}${dataEndRow}`).format = {
|
||||
font: { color: ink, size: 10 },
|
||||
verticalAlignment: "top",
|
||||
};
|
||||
|
||||
const widths = {
|
||||
id: 36, user_id: 36, user_name: 22, user_phone: 16, address: 34, description: 60,
|
||||
bedrooms: 12, bathrooms: 12, area_m2: 12, monthly_rent: 16, available_rooms: 16,
|
||||
building_amenities: 38, apartment_features: 44, included_services: 36, photo_urls: 65,
|
||||
created_at: 14, updated_at: 14, show_phone: 12, show_profile: 13, is_visible: 12,
|
||||
priority: 11, listing_type: 14, city: 17, area: 24, short_id: 13,
|
||||
smart_rental_enabled: 20, parent_apartment_id: 36, tenant_user_id: 36,
|
||||
tenant_name: 20, tenant_phone: 16, tenant_gender: 15, tenant_age: 12,
|
||||
is_paid: 11, seo_slug: 38,
|
||||
};
|
||||
columns.forEach((key, index) => {
|
||||
const letter = colLetter(index + 1);
|
||||
dataSheet.getRange(`${letter}:${letter}`).format.columnWidth = widths[key] ?? 16;
|
||||
});
|
||||
for (const key of ["description", "building_amenities", "apartment_features", "included_services", "photo_urls"]) {
|
||||
const index = columns.indexOf(key) + 1;
|
||||
const letter = colLetter(index);
|
||||
dataSheet.getRange(`${letter}2:${letter}${dataEndRow}`).format.wrapText = true;
|
||||
}
|
||||
dataSheet.getRange(`A2:${dataEndCol}${dataEndRow}`).format.rowHeight = 42;
|
||||
for (const key of ["created_at", "updated_at"]) {
|
||||
const letter = colLetter(columns.indexOf(key) + 1);
|
||||
dataSheet.getRange(`${letter}2:${letter}${dataEndRow}`).format.numberFormat = "yyyy-mm-dd";
|
||||
}
|
||||
for (const key of ["bedrooms", "bathrooms", "area_m2", "available_rooms", "priority", "tenant_age"]) {
|
||||
const letter = colLetter(columns.indexOf(key) + 1);
|
||||
dataSheet.getRange(`${letter}2:${letter}${dataEndRow}`).format.numberFormat = "#,##0";
|
||||
}
|
||||
const rentLetter = colLetter(columns.indexOf("monthly_rent") + 1);
|
||||
dataSheet.getRange(`${rentLetter}2:${rentLetter}${dataEndRow}`).format.numberFormat = '"$"#,##0';
|
||||
|
||||
// Una fila por foto para facilitar filtros, descarga y revisión.
|
||||
const photoRows = [];
|
||||
for (const apartment of apartments) {
|
||||
const urls = Array.isArray(apartment.photo_urls) ? apartment.photo_urls : [];
|
||||
urls.forEach((url, index) => photoRows.push([
|
||||
apartment.id,
|
||||
apartment.short_id,
|
||||
apartment.city,
|
||||
Array.isArray(apartment.area) ? apartment.area.join(" | ") : apartment.area,
|
||||
apartment.address,
|
||||
index + 1,
|
||||
url,
|
||||
]));
|
||||
}
|
||||
const photoMatrix = [["apartment_id", "short_id", "city", "area", "address", "photo_index", "photo_url"], ...photoRows];
|
||||
photosSheet.getRange(`A1:G${photoMatrix.length}`).values = photoMatrix;
|
||||
photosSheet.freezePanes.freezeRows(1);
|
||||
photosSheet.freezePanes.freezeColumns(2);
|
||||
const photosTable = photosSheet.tables.add(`A1:G${photoMatrix.length}`, true, "PhotosTable");
|
||||
photosTable.style = "TableStyleMedium2";
|
||||
photosTable.showFilterButton = true;
|
||||
photosSheet.getRange("A1:G1").format = { fill: navy, font: { bold: true, color: white }, rowHeight: 28 };
|
||||
photosSheet.getRange(`A2:G${photoMatrix.length}`).format = { font: { color: ink, size: 10 }, rowHeight: 22 };
|
||||
photosSheet.getRange("A:A").format.columnWidth = 36;
|
||||
photosSheet.getRange("B:B").format.columnWidth = 13;
|
||||
photosSheet.getRange("C:C").format.columnWidth = 16;
|
||||
photosSheet.getRange("D:D").format.columnWidth = 24;
|
||||
photosSheet.getRange("E:E").format.columnWidth = 36;
|
||||
photosSheet.getRange("F:F").format.columnWidth = 12;
|
||||
photosSheet.getRange("G:G").format.columnWidth = 90;
|
||||
photosSheet.getRange(`F2:F${photoMatrix.length}`).format.numberFormat = "#,##0";
|
||||
|
||||
// Control detallado de las tres páginas consultadas.
|
||||
const paginationRows = pages.map((page) => {
|
||||
const from = page.offset;
|
||||
const to = page.offset + page.rows.length - 1;
|
||||
return [
|
||||
page.page,
|
||||
page.offset,
|
||||
pageSize,
|
||||
`${from}-${to}`,
|
||||
page.rows.length,
|
||||
"200 OK",
|
||||
page.rows[0]?.id ?? null,
|
||||
page.rows.at(-1)?.id ?? null,
|
||||
];
|
||||
});
|
||||
const paginationMatrix = [["pagina", "offset", "limite", "rango_respuesta", "filas", "estado_http", "primer_id", "ultimo_id"], ...paginationRows];
|
||||
paginationSheet.getRange("A1:H4").values = paginationMatrix;
|
||||
paginationSheet.getRange("A5:D5").merge();
|
||||
paginationSheet.getRange("A5:D5").values = [["Total descargado"]];
|
||||
paginationSheet.getRange("E5").formulas = [["=SUM(E2:E4)"]];
|
||||
paginationSheet.getRange("F5:H5").merge();
|
||||
paginationSheet.getRange("F5:H5").values = [["Validado contra Content-Range: 101"]];
|
||||
paginationSheet.getRange("A1:H1").format = { fill: navy, font: { bold: true, color: white }, rowHeight: 28 };
|
||||
paginationSheet.getRange("A2:H4").format = { fill: white, font: { color: ink }, rowHeight: 24 };
|
||||
paginationSheet.getRange("A5:H5").format = { fill: cyan, font: { bold: true, color: navy }, rowHeight: 26 };
|
||||
paginationSheet.getRange("A1:H5").format.borders = { preset: "all", style: "thin", color: border };
|
||||
paginationSheet.getRange("A2:F5").format.horizontalAlignment = "center";
|
||||
paginationSheet.getRange("A:C").format.columnWidth = 12;
|
||||
paginationSheet.getRange("D:D").format.columnWidth = 20;
|
||||
paginationSheet.getRange("E:E").format.columnWidth = 12;
|
||||
paginationSheet.getRange("F:F").format.columnWidth = 16;
|
||||
paginationSheet.getRange("G:H").format.columnWidth = 38;
|
||||
paginationSheet.getRange("A2:C5").format.numberFormat = "#,##0";
|
||||
paginationSheet.freezePanes.freezeRows(1);
|
||||
|
||||
// Resumen ejecutivo y trazabilidad de la extracción.
|
||||
summary.getRange("A1:F2").merge();
|
||||
summary.getRange("A1:F2").values = [["Apartamentos visibles · RentPana"]];
|
||||
summary.getRange("A1:F2").format = {
|
||||
fill: navy,
|
||||
font: { bold: true, color: white, size: 20 },
|
||||
horizontalAlignment: "left",
|
||||
verticalAlignment: "center",
|
||||
};
|
||||
summary.getRange("A3:F3").merge();
|
||||
summary.getRange("A3:F3").values = [["Extracción completa, paginada y validada contra el total informado por la API"]];
|
||||
summary.getRange("A3:F3").format = { fill: navy, font: { color: "#D9EDF2", size: 11 }, rowHeight: 24 };
|
||||
|
||||
summary.getRange("A5:B5").merge();
|
||||
summary.getRange("A5:B5").values = [["Apartamentos"]];
|
||||
summary.getRange("C5:D5").merge();
|
||||
summary.getRange("C5:D5").values = [["Páginas API"]];
|
||||
summary.getRange("E5:F5").merge();
|
||||
summary.getRange("E5:F5").values = [["Fotos"]];
|
||||
summary.getRange("A6:B7").merge();
|
||||
summary.getRange("A6:B7").formulas = [["=COUNTA('Apartamentos'!$A$2:$A$102)"]];
|
||||
summary.getRange("C6:D7").merge();
|
||||
summary.getRange("C6:D7").formulas = [["=COUNTA('Paginacion'!$A$2:$A$4)"]];
|
||||
summary.getRange("E6:F7").merge();
|
||||
summary.getRange("E6:F7").formulas = [[`=COUNTA('Fotos'!$A$2:$A$${photoMatrix.length})`]];
|
||||
summary.getRange("A5:F5").format = { fill: teal, font: { bold: true, color: white }, horizontalAlignment: "center", rowHeight: 24 };
|
||||
summary.getRange("A6:F7").format = { fill: cyan, font: { bold: true, color: navy, size: 20 }, horizontalAlignment: "center", verticalAlignment: "center" };
|
||||
summary.getRange("A5:F7").format.borders = { preset: "outside", style: "thin", color: border };
|
||||
|
||||
summary.getRange("A9:F9").merge();
|
||||
summary.getRange("A9:F9").values = [["Control de extracción"]];
|
||||
summary.getRange("A9:F9").format = { fill: teal, font: { bold: true, color: white }, rowHeight: 26 };
|
||||
const extractedAt = new Date();
|
||||
const controlRows = [
|
||||
["Fecha y hora (UTC)", extractedAt, null, null, null, null],
|
||||
["Origen", "https://srv99857.rentpana.com/rest/v1/apartments", null, null, null, null],
|
||||
["Filtro", "is_visible = true", null, null, null, null],
|
||||
["Orden estable", "id ascendente", null, null, null, null],
|
||||
["Tamaño de página", pageSize, null, null, null, null],
|
||||
["Total informado por API", 101, null, null, null, null],
|
||||
["IDs únicos validados", new Set(ids).size, null, null, null, null],
|
||||
["Duplicados detectados", apartments.length - new Set(ids).size, null, null, null, null],
|
||||
["Columnas de origen", columns.length, null, null, null, null],
|
||||
["Credenciales incluidas", "No", null, null, null, null],
|
||||
];
|
||||
summary.getRange("A10:F19").values = controlRows;
|
||||
for (let row = 10; row <= 19; row += 1) summary.getRange(`B${row}:F${row}`).merge();
|
||||
summary.getRange("A10:A19").format = { fill: pale, font: { bold: true, color: muted }, rowHeight: 24 };
|
||||
summary.getRange("B10:F19").format = { fill: white, font: { color: ink }, rowHeight: 24, wrapText: true, horizontalAlignment: "left" };
|
||||
summary.getRange("A10:F19").format.borders = { preset: "outside", style: "thin", color: border };
|
||||
summary.getRange("B10").format.numberFormat = "yyyy-mm-dd hh:mm:ss";
|
||||
summary.getRange("B14:B18").format.numberFormat = "#,##0";
|
||||
|
||||
summary.getRange("A21:F21").merge();
|
||||
summary.getRange("A21:F21").values = [["Contenido del archivo"]];
|
||||
summary.getRange("A21:F21").format = { fill: teal, font: { bold: true, color: white }, rowHeight: 26 };
|
||||
const contentsRows = [
|
||||
["Apartamentos", "Todos los 34 campos de origen; filtros activados y encabezado congelado."],
|
||||
["Fotos", "Una fila por URL de foto, vinculada por apartment_id y short_id."],
|
||||
["Paginacion", "Offset, límite, rango, filas, estado y IDs extremos por página."],
|
||||
];
|
||||
summary.getRange("A22:F24").values = contentsRows.map(([a, b]) => [a, b, null, null, null, null]);
|
||||
for (let row = 22; row <= 24; row += 1) summary.getRange(`B${row}:F${row}`).merge();
|
||||
summary.getRange("A22:A24").format = { fill: pale, font: { bold: true, color: navy }, rowHeight: 28 };
|
||||
summary.getRange("B22:F24").format = { fill: white, font: { color: ink }, wrapText: true, rowHeight: 28 };
|
||||
summary.getRange("A22:F24").format.borders = { preset: "outside", style: "thin", color: border };
|
||||
|
||||
summary.getRange("A:A").format.columnWidth = 24;
|
||||
summary.getRange("B:F").format.columnWidth = 18;
|
||||
summary.getRange("A1:F24").format.font.name = "Aptos";
|
||||
summary.freezePanes.freezeRows(3);
|
||||
|
||||
await fs.mkdir(outputDir, { recursive: true });
|
||||
|
||||
const checks = [];
|
||||
checks.push((await workbook.inspect({
|
||||
kind: "table",
|
||||
range: "Resumen!A1:F24",
|
||||
include: "values,formulas",
|
||||
tableMaxRows: 24,
|
||||
tableMaxCols: 6,
|
||||
maxChars: 6000,
|
||||
})).ndjson);
|
||||
checks.push((await workbook.inspect({
|
||||
kind: "table",
|
||||
range: "Paginacion!A1:H5",
|
||||
include: "values,formulas",
|
||||
tableMaxRows: 8,
|
||||
tableMaxCols: 8,
|
||||
maxChars: 3000,
|
||||
})).ndjson);
|
||||
checks.push((await workbook.inspect({
|
||||
kind: "match",
|
||||
searchTerm: "#REF!|#DIV/0!|#VALUE!|#NAME\\?|#N/A",
|
||||
options: { useRegex: true, maxResults: 300 },
|
||||
summary: "final formula error scan",
|
||||
})).ndjson);
|
||||
|
||||
const previews = [
|
||||
["Resumen", "A1:F24", "preview_resumen.png"],
|
||||
["Apartamentos", "A1:J10", "preview_apartamentos_1.png"],
|
||||
["Apartamentos", "K1:AH8", "preview_apartamentos_2.png"],
|
||||
["Fotos", "A1:G12", "preview_fotos.png"],
|
||||
["Paginacion", "A1:H5", "preview_paginacion.png"],
|
||||
];
|
||||
for (const [sheetName, range, fileName] of previews) {
|
||||
const blob = await workbook.render({ sheetName, range, scale: 1.4, format: "png" });
|
||||
await fs.writeFile(path.join(outputDir, fileName), new Uint8Array(await blob.arrayBuffer()));
|
||||
}
|
||||
|
||||
const output = await SpreadsheetFile.exportXlsx(workbook);
|
||||
await output.save(outputPath);
|
||||
|
||||
console.log(JSON.stringify({
|
||||
outputPath,
|
||||
apartments: apartments.length,
|
||||
uniqueIds: new Set(ids).size,
|
||||
photos: photoRows.length,
|
||||
pages: pages.length,
|
||||
columns: columns.length,
|
||||
checks,
|
||||
previews: previews.map((item) => path.join(outputDir, item[2])),
|
||||
}, null, 2));
|
||||
@@ -0,0 +1,22 @@
|
||||
HTTP/1.1 206 Partial Content
|
||||
Date: Sun, 30 Aug 2026 19:12:16 GMT
|
||||
Content-Type: application/json; charset=utf-8
|
||||
Content-Length: 108239
|
||||
Connection: keep-alive
|
||||
Server: cloudflare
|
||||
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
Content-Range: 0-49/101
|
||||
Content-Location: /apartments?is_visible=eq.true&limit=50&offset=0&order=id.asc&select=%2A
|
||||
Content-Profile: public
|
||||
Preference-Applied: count=exact
|
||||
Access-Control-Allow-Origin: *
|
||||
Access-Control-Expose-Headers: Content-Encoding, Content-Location, Content-Range, Content-Type, Date, Location, Server, Transfer-Encoding, Range-Unit
|
||||
X-Kong-Upstream-Latency: 12
|
||||
X-Kong-Proxy-Latency: 1
|
||||
Via: 1.1 kong/3.9.1
|
||||
X-Kong-Request-Id: 36d60653723f406a162c6535d728d27d
|
||||
cf-cache-status: DYNAMIC
|
||||
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=e%2FhgsmNUvfdXbxPGFrz%2FMjaXlkCiuYPlrQQ42rkkNFx4x%2BMdhLL3ImSLwz7rtCdYR1DHKjSIzEPLp4dHKjL0cypB8Z46vlG%2FHPjsRaBFF1ycsDO3VL4I73MtA5QRjQShWznGiKw38Qw%3D"}]}
|
||||
CF-RAY: a3361b23bd70dfba-MIA
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
HTTP/1.1 206 Partial Content
|
||||
Date: Sun, 30 Aug 2026 19:12:16 GMT
|
||||
Content-Type: application/json; charset=utf-8
|
||||
Content-Length: 110785
|
||||
Connection: keep-alive
|
||||
Server: cloudflare
|
||||
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
Content-Range: 50-99/101
|
||||
Content-Location: /apartments?is_visible=eq.true&limit=50&offset=50&order=id.asc&select=%2A
|
||||
Content-Profile: public
|
||||
Preference-Applied: count=exact
|
||||
Access-Control-Allow-Origin: *
|
||||
Access-Control-Expose-Headers: Content-Encoding, Content-Location, Content-Range, Content-Type, Date, Location, Server, Transfer-Encoding, Range-Unit
|
||||
X-Kong-Upstream-Latency: 18
|
||||
X-Kong-Proxy-Latency: 0
|
||||
Via: 1.1 kong/3.9.1
|
||||
X-Kong-Request-Id: 43005d3aa4dfd17006586b41c9903306
|
||||
cf-cache-status: DYNAMIC
|
||||
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=OXpuhJ8kF%2FzhCWI3QCdCE6R6ZZ33yEpgyPCVOIjJeIe4SC6LK%2BZp0Hoa%2FyYXkm49AUgc9W3NEB3RodHaby%2B3W8lVVfVUhYFlw392LbBZSINbEaP1olAo7Gd5CLHEl9fMltUYK%2F3FuZg%3D"}]}
|
||||
CF-RAY: a3361b26a99d8dc6-MIA
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
HTTP/1.1 206 Partial Content
|
||||
Date: Sun, 30 Aug 2026 19:12:16 GMT
|
||||
Content-Type: application/json; charset=utf-8
|
||||
Content-Length: 2399
|
||||
Connection: keep-alive
|
||||
Server: cloudflare
|
||||
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
Content-Range: 100-100/101
|
||||
Content-Location: /apartments?is_visible=eq.true&limit=50&offset=100&order=id.asc&select=%2A
|
||||
Content-Profile: public
|
||||
Preference-Applied: count=exact
|
||||
Access-Control-Allow-Origin: *
|
||||
Access-Control-Expose-Headers: Content-Encoding, Content-Location, Content-Range, Content-Type, Date, Location, Server, Transfer-Encoding, Range-Unit
|
||||
X-Kong-Upstream-Latency: 11
|
||||
X-Kong-Proxy-Latency: 0
|
||||
Via: 1.1 kong/3.9.1
|
||||
X-Kong-Request-Id: e5b9ec1e2e2ea72419eb096189826631
|
||||
cf-cache-status: DYNAMIC
|
||||
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=hs0K9bWUzpaTwFm4%2BZ2bo3c5Km2mVBEkNxHpE8aghdPj%2FqrUGgznk0IlCooLvaGKoFkvTUiyMIJq7CUi2tBqRFq%2B8XCjAsLBo3%2FbYXWL2lNJtjA8qv%2Fs0j5tFTYBGGd3RwD7dTbRWcw%3D"}]}
|
||||
CF-RAY: a3361b29ada95c66-MIA
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { SpreadsheetFile, Workbook } from "@oai/artifact-tool";
|
||||
|
||||
const workspace = "C:/Users/erik1/Documents/IPSExtractor";
|
||||
const visibleSample = JSON.parse(await fs.readFile(path.join(workspace, ".codex_tmp_apartments", "page_0.json"), "utf8"));
|
||||
const columns = Object.keys(visibleSample[0]);
|
||||
const outputDir = path.join(workspace, "outputs", "apartamentos_no_visibles_rentpana_20260830");
|
||||
const outputPath = path.join(outputDir, "apartamentos_no_visibles_rentpana.xlsx");
|
||||
|
||||
const colLetter = (oneBased) => {
|
||||
let n = oneBased;
|
||||
let result = "";
|
||||
while (n > 0) {
|
||||
const remainder = (n - 1) % 26;
|
||||
result = String.fromCharCode(65 + remainder) + result;
|
||||
n = Math.floor((n - 1) / 26);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const workbook = Workbook.create();
|
||||
const summary = workbook.worksheets.add("Resumen");
|
||||
const dataSheet = workbook.worksheets.add("Apartamentos");
|
||||
const photosSheet = workbook.worksheets.add("Fotos");
|
||||
const paginationSheet = workbook.worksheets.add("Paginacion");
|
||||
|
||||
const navy = "#123047";
|
||||
const teal = "#0F766E";
|
||||
const cyan = "#DFF4F1";
|
||||
const pale = "#F4F7F9";
|
||||
const white = "#FFFFFF";
|
||||
const ink = "#1F2937";
|
||||
const muted = "#60707D";
|
||||
const border = "#D8E1E7";
|
||||
|
||||
for (const sheet of [summary, dataSheet, photosSheet, paginationSheet]) sheet.showGridLines = false;
|
||||
|
||||
const endCol = colLetter(columns.length);
|
||||
dataSheet.getRange(`A1:${endCol}2`).values = [columns, columns.map(() => null)];
|
||||
dataSheet.freezePanes.freezeRows(1);
|
||||
dataSheet.freezePanes.freezeColumns(2);
|
||||
const apartmentTable = dataSheet.tables.add(`A1:${endCol}2`, true, "HiddenApartmentsTable");
|
||||
apartmentTable.style = "TableStyleMedium2";
|
||||
apartmentTable.showFilterButton = true;
|
||||
dataSheet.getRange(`A1:${endCol}1`).format = { fill: navy, font: { bold: true, color: white }, rowHeight: 28 };
|
||||
dataSheet.getRange(`A2:${endCol}2`).format = { fill: white, rowHeight: 24 };
|
||||
|
||||
const widths = {
|
||||
id: 36, user_id: 36, user_name: 22, user_phone: 16, address: 34, description: 60,
|
||||
bedrooms: 12, bathrooms: 12, area_m2: 12, monthly_rent: 16, available_rooms: 16,
|
||||
building_amenities: 38, apartment_features: 44, included_services: 36, photo_urls: 65,
|
||||
created_at: 14, updated_at: 14, show_phone: 12, show_profile: 13, is_visible: 12,
|
||||
priority: 11, listing_type: 14, city: 17, area: 24, short_id: 13,
|
||||
smart_rental_enabled: 20, parent_apartment_id: 36, tenant_user_id: 36,
|
||||
tenant_name: 20, tenant_phone: 16, tenant_gender: 15, tenant_age: 12,
|
||||
is_paid: 11, seo_slug: 38,
|
||||
};
|
||||
columns.forEach((key, index) => dataSheet.getRange(`${colLetter(index + 1)}:${colLetter(index + 1)}`).format.columnWidth = widths[key] ?? 16);
|
||||
|
||||
const photoHeaders = ["apartment_id", "short_id", "city", "area", "address", "photo_index", "photo_url"];
|
||||
photosSheet.getRange("A1:G2").values = [photoHeaders, photoHeaders.map(() => null)];
|
||||
photosSheet.freezePanes.freezeRows(1);
|
||||
photosSheet.freezePanes.freezeColumns(2);
|
||||
const photosTable = photosSheet.tables.add("A1:G2", true, "HiddenPhotosTable");
|
||||
photosTable.style = "TableStyleMedium2";
|
||||
photosTable.showFilterButton = true;
|
||||
photosSheet.getRange("A1:G1").format = { fill: navy, font: { bold: true, color: white }, rowHeight: 28 };
|
||||
photosSheet.getRange("A:A").format.columnWidth = 36;
|
||||
photosSheet.getRange("B:B").format.columnWidth = 13;
|
||||
photosSheet.getRange("C:C").format.columnWidth = 16;
|
||||
photosSheet.getRange("D:D").format.columnWidth = 24;
|
||||
photosSheet.getRange("E:E").format.columnWidth = 36;
|
||||
photosSheet.getRange("F:F").format.columnWidth = 12;
|
||||
photosSheet.getRange("G:G").format.columnWidth = 90;
|
||||
|
||||
paginationSheet.getRange("A1:H2").values = [
|
||||
["pagina", "offset", "limite", "content_range", "filas", "estado_http", "primer_id", "ultimo_id"],
|
||||
[1, 0, 50, "*/0", 0, "200 OK", null, null],
|
||||
];
|
||||
paginationSheet.getRange("A3:D3").merge();
|
||||
paginationSheet.getRange("A3:D3").values = [["Total descargado"]];
|
||||
paginationSheet.getRange("E3").formulas = [["=SUM(E2:E2)"]];
|
||||
paginationSheet.getRange("F3:H3").merge();
|
||||
paginationSheet.getRange("F3:H3").values = [["Validado contra Content-Range: */0"]];
|
||||
paginationSheet.getRange("A1:H1").format = { fill: navy, font: { bold: true, color: white }, rowHeight: 28 };
|
||||
paginationSheet.getRange("A2:H2").format = { fill: white, font: { color: ink }, rowHeight: 24 };
|
||||
paginationSheet.getRange("A3:H3").format = { fill: cyan, font: { bold: true, color: navy }, rowHeight: 26 };
|
||||
paginationSheet.getRange("A1:H3").format.borders = { preset: "all", style: "thin", color: border };
|
||||
paginationSheet.getRange("A2:F3").format.horizontalAlignment = "center";
|
||||
paginationSheet.getRange("A:C").format.columnWidth = 12;
|
||||
paginationSheet.getRange("D:D").format.columnWidth = 20;
|
||||
paginationSheet.getRange("E:E").format.columnWidth = 12;
|
||||
paginationSheet.getRange("F:F").format.columnWidth = 16;
|
||||
paginationSheet.getRange("G:H").format.columnWidth = 38;
|
||||
paginationSheet.freezePanes.freezeRows(1);
|
||||
|
||||
summary.getRange("A1:F2").merge();
|
||||
summary.getRange("A1:F2").values = [["Apartamentos no visibles · RentPana"]];
|
||||
summary.getRange("A1:F2").format = { fill: navy, font: { bold: true, color: white, size: 20 }, verticalAlignment: "center" };
|
||||
summary.getRange("A3:F3").merge();
|
||||
summary.getRange("A3:F3").values = [["Consulta independiente con is_visible = false"]];
|
||||
summary.getRange("A3:F3").format = { fill: navy, font: { color: "#D9EDF2", size: 11 }, rowHeight: 24 };
|
||||
|
||||
summary.getRange("A5:B5").merge();
|
||||
summary.getRange("C5:D5").merge();
|
||||
summary.getRange("E5:F5").merge();
|
||||
summary.getRange("A5:F5").values = [["Apartamentos", null, "Páginas consultadas", null, "Fotos", null]];
|
||||
summary.getRange("A6:B7").merge();
|
||||
summary.getRange("A6:B7").formulas = [["=COUNTA('Apartamentos'!$A$2:$A$2)"]];
|
||||
summary.getRange("C6:D7").merge();
|
||||
summary.getRange("C6:D7").formulas = [["=COUNTA('Paginacion'!$A$2:$A$2)"]];
|
||||
summary.getRange("E6:F7").merge();
|
||||
summary.getRange("E6:F7").formulas = [["=COUNTA('Fotos'!$A$2:$A$2)"]];
|
||||
summary.getRange("A5:F5").format = { fill: teal, font: { bold: true, color: white }, horizontalAlignment: "center", rowHeight: 24 };
|
||||
summary.getRange("A6:F7").format = { fill: cyan, font: { bold: true, color: navy, size: 20 }, horizontalAlignment: "center", verticalAlignment: "center" };
|
||||
summary.getRange("A5:F7").format.borders = { preset: "outside", style: "thin", color: border };
|
||||
|
||||
summary.getRange("A9:F9").merge();
|
||||
summary.getRange("A9:F9").values = [["Control de extracción"]];
|
||||
summary.getRange("A9:F9").format = { fill: teal, font: { bold: true, color: white }, rowHeight: 26 };
|
||||
const controlRows = [
|
||||
["Fecha y hora (UTC)", new Date()],
|
||||
["Origen", "https://srv99857.rentpana.com/rest/v1/apartments"],
|
||||
["Filtro", "is_visible = false"],
|
||||
["Orden estable", "id ascendente"],
|
||||
["Tamaño de página", 50],
|
||||
["Total informado por API", 0],
|
||||
["IDs únicos validados", 0],
|
||||
["Duplicados detectados", 0],
|
||||
["Columnas de origen", columns.length],
|
||||
["Resultado", "La API devolvió 0 registros para este filtro con la sesión suministrada."],
|
||||
["Credenciales incluidas", "No"],
|
||||
];
|
||||
summary.getRange("A10:F20").values = controlRows.map(([a, b]) => [a, b, null, null, null, null]);
|
||||
for (let row = 10; row <= 20; row += 1) summary.getRange(`B${row}:F${row}`).merge();
|
||||
summary.getRange("A10:A20").format = { fill: pale, font: { bold: true, color: muted }, rowHeight: 24 };
|
||||
summary.getRange("B10:F20").format = { fill: white, font: { color: ink }, rowHeight: 24, wrapText: true, horizontalAlignment: "left" };
|
||||
summary.getRange("A10:F20").format.borders = { preset: "outside", style: "thin", color: border };
|
||||
summary.getRange("B10").format.numberFormat = "yyyy-mm-dd hh:mm:ss";
|
||||
|
||||
summary.getRange("A22:F22").merge();
|
||||
summary.getRange("A22:F22").values = [["Contenido del archivo"]];
|
||||
summary.getRange("A22:F22").format = { fill: teal, font: { bold: true, color: white }, rowHeight: 26 };
|
||||
const contents = [
|
||||
["Apartamentos", "Estructura de 34 campos, lista para los registros devueltos por la consulta."],
|
||||
["Fotos", "Hoja normalizada para enlaces de fotos; actualmente sin filas."],
|
||||
["Paginacion", "Consulta, límite, rango, cantidad y estado HTTP documentados."],
|
||||
];
|
||||
summary.getRange("A23:F25").values = contents.map(([a, b]) => [a, b, null, null, null, null]);
|
||||
for (let row = 23; row <= 25; row += 1) summary.getRange(`B${row}:F${row}`).merge();
|
||||
summary.getRange("A23:A25").format = { fill: pale, font: { bold: true, color: navy }, rowHeight: 28 };
|
||||
summary.getRange("B23:F25").format = { fill: white, font: { color: ink }, wrapText: true, rowHeight: 28 };
|
||||
summary.getRange("A23:F25").format.borders = { preset: "outside", style: "thin", color: border };
|
||||
summary.getRange("A:A").format.columnWidth = 24;
|
||||
summary.getRange("B:F").format.columnWidth = 18;
|
||||
summary.getRange("A1:F25").format.font.name = "Aptos";
|
||||
summary.freezePanes.freezeRows(3);
|
||||
|
||||
await fs.mkdir(outputDir, { recursive: true });
|
||||
const checks = [
|
||||
(await workbook.inspect({ kind: "table", range: "Resumen!A1:F25", include: "values,formulas", tableMaxRows: 25, tableMaxCols: 6, maxChars: 6000 })).ndjson,
|
||||
(await workbook.inspect({ kind: "table", range: "Paginacion!A1:H3", include: "values,formulas", tableMaxRows: 5, tableMaxCols: 8, maxChars: 2500 })).ndjson,
|
||||
(await workbook.inspect({ kind: "match", searchTerm: "#REF!|#DIV/0!|#VALUE!|#NAME\\?|#N/A", options: { useRegex: true, maxResults: 300 }, summary: "final formula error scan" })).ndjson,
|
||||
];
|
||||
|
||||
const previews = [
|
||||
["Resumen", "A1:F25", "preview_resumen.png"],
|
||||
["Apartamentos", "A1:J2", "preview_apartamentos_1.png"],
|
||||
["Apartamentos", "K1:AH2", "preview_apartamentos_2.png"],
|
||||
["Fotos", "A1:G2", "preview_fotos.png"],
|
||||
["Paginacion", "A1:H3", "preview_paginacion.png"],
|
||||
];
|
||||
for (const [sheetName, range, fileName] of previews) {
|
||||
const blob = await workbook.render({ sheetName, range, scale: 1.4, format: "png" });
|
||||
await fs.writeFile(path.join(outputDir, fileName), new Uint8Array(await blob.arrayBuffer()));
|
||||
}
|
||||
|
||||
const output = await SpreadsheetFile.exportXlsx(workbook);
|
||||
await output.save(outputPath);
|
||||
console.log(JSON.stringify({ outputPath, rows: 0, pagesConsulted: 1, columns: columns.length, checks, previews: previews.map((item) => path.join(outputDir, item[2])) }, null, 2));
|
||||
@@ -0,0 +1,22 @@
|
||||
HTTP/1.1 200 OK
|
||||
Date: Sun, 30 Aug 2026 19:58:23 GMT
|
||||
Content-Type: application/json; charset=utf-8
|
||||
Content-Length: 2
|
||||
Connection: keep-alive
|
||||
Server: cloudflare
|
||||
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
Content-Range: */0
|
||||
Content-Location: /apartments?is_visible=not.is.true&limit=1&offset=0&order=id.asc&select=%2A
|
||||
Content-Profile: public
|
||||
Preference-Applied: count=exact
|
||||
Access-Control-Allow-Origin: *
|
||||
Access-Control-Expose-Headers: Content-Encoding, Content-Location, Content-Range, Content-Type, Date, Location, Server, Transfer-Encoding, Range-Unit
|
||||
X-Kong-Upstream-Latency: 4
|
||||
X-Kong-Proxy-Latency: 0
|
||||
Via: 1.1 kong/3.9.1
|
||||
X-Kong-Request-Id: ec6314205fccca4904d6d03407154c4a
|
||||
cf-cache-status: DYNAMIC
|
||||
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=8AohAv0A3ziLB3FtLIOhjzFdv85QxTqb1tAHIbT9ZaS8Azt0wu0aaZ%2FglV2Q18Z5XL%2F4QWsmSasuKWaPwKMMu7fkj6Ms1inrSl5uPbnKqH6JcOG66Cw%2FTMgdpHxGmOxLFIoMxU5F%2BdY%3D"}]}
|
||||
CF-RAY: a3365eb52dfced7d-MIA
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
HTTP/1.1 200 OK
|
||||
Date: Sun, 30 Aug 2026 19:58:22 GMT
|
||||
Content-Type: application/json; charset=utf-8
|
||||
Content-Length: 2
|
||||
Connection: keep-alive
|
||||
Server: cloudflare
|
||||
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
Content-Range: */0
|
||||
Content-Location: /apartments?is_visible=eq.false&limit=1&offset=0&order=id.asc&select=%2A
|
||||
Content-Profile: public
|
||||
Preference-Applied: count=exact
|
||||
Access-Control-Allow-Origin: *
|
||||
Access-Control-Expose-Headers: Content-Encoding, Content-Location, Content-Range, Content-Type, Date, Location, Server, Transfer-Encoding, Range-Unit
|
||||
X-Kong-Upstream-Latency: 7
|
||||
X-Kong-Proxy-Latency: 1
|
||||
Via: 1.1 kong/3.9.1
|
||||
X-Kong-Request-Id: fd33fa311539833f4a5ff50e90483a1a
|
||||
cf-cache-status: DYNAMIC
|
||||
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=NVKvV0awlCCGFLEGDS6qtWWoE1OawW5qkTusVN7UPmcUUz9ANiLsKREPkBGGlVgXtHV%2BhGfN2HE5KLVyYayaXmhi12828xkTJfNHfgC8loe5z3oA45mHEkThiTqq4qeMFFBk0z%2FF3jU%3D"}]}
|
||||
CF-RAY: a3365eb14b4920ce-MIA
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
HTTP/1.1 200 OK
|
||||
Date: Sun, 30 Aug 2026 19:58:23 GMT
|
||||
Content-Type: application/json; charset=utf-8
|
||||
Content-Length: 2
|
||||
Connection: keep-alive
|
||||
Server: cloudflare
|
||||
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
Content-Range: */0
|
||||
Content-Location: /apartments?is_visible=is.false&limit=1&offset=0&order=id.asc&select=%2A
|
||||
Content-Profile: public
|
||||
Preference-Applied: count=exact
|
||||
Access-Control-Allow-Origin: *
|
||||
Access-Control-Expose-Headers: Content-Encoding, Content-Location, Content-Range, Content-Type, Date, Location, Server, Transfer-Encoding, Range-Unit
|
||||
X-Kong-Upstream-Latency: 7
|
||||
X-Kong-Proxy-Latency: 3
|
||||
Via: 1.1 kong/3.9.1
|
||||
X-Kong-Request-Id: 788604537f4afd42a27dc7376de1cc0d
|
||||
cf-cache-status: DYNAMIC
|
||||
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=DBm2LKUWUatJi1DLvGFP6TkUGCAMtPwejSduHaNrdK9LQpD%2BUydLT5bIhe8CGGf6bMizlPvFkMbqIsb1pT4FZP2mGjvL570cJpUe%2BroGEy6Tw0RmL%2Bf4f7L4zZ1RGc8sH6wuBA29GMw%3D"}]}
|
||||
CF-RAY: a3365eb33e410cd1-MIA
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
HTTP/1.1 206 Partial Content
|
||||
Date: Sun, 30 Aug 2026 19:58:22 GMT
|
||||
Content-Type: application/json; charset=utf-8
|
||||
Content-Length: 2648
|
||||
Connection: keep-alive
|
||||
Server: cloudflare
|
||||
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
Content-Range: 0-0/101
|
||||
Content-Location: /apartments?limit=1&offset=0&order=id.asc&select=%2A
|
||||
Content-Profile: public
|
||||
Preference-Applied: count=exact
|
||||
Access-Control-Allow-Origin: *
|
||||
Access-Control-Expose-Headers: Content-Encoding, Content-Location, Content-Range, Content-Type, Date, Location, Server, Transfer-Encoding, Range-Unit
|
||||
X-Kong-Upstream-Latency: 12
|
||||
X-Kong-Proxy-Latency: 1
|
||||
Via: 1.1 kong/3.9.1
|
||||
X-Kong-Request-Id: 1a3b2b0fc9128a7fa1ec2840f5635327
|
||||
cf-cache-status: DYNAMIC
|
||||
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=vgZDSTap%2BSWUr7NuXZGQIE5Rn48TAu8OqXveTvdG3%2F9IkXH1NAXG%2Fb%2F9zcO6pXtFdmaBDsQyN%2F40uUjtH0SwwmDE1Pzrp2dR3CiiBqds5HJFAb9M8mngLuZqb330Fg3xhsv3VjGysLA%3D"}]}
|
||||
CF-RAY: a3365ead3d723405-MIA
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
HTTP/1.1 206 Partial Content
|
||||
Date: Sun, 30 Aug 2026 19:58:22 GMT
|
||||
Content-Type: application/json; charset=utf-8
|
||||
Content-Length: 2648
|
||||
Connection: keep-alive
|
||||
Server: cloudflare
|
||||
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
Content-Range: 0-0/101
|
||||
Content-Location: /apartments?is_visible=eq.true&limit=1&offset=0&order=id.asc&select=%2A
|
||||
Content-Profile: public
|
||||
Preference-Applied: count=exact
|
||||
Access-Control-Allow-Origin: *
|
||||
Access-Control-Expose-Headers: Content-Encoding, Content-Location, Content-Range, Content-Type, Date, Location, Server, Transfer-Encoding, Range-Unit
|
||||
X-Kong-Upstream-Latency: 4
|
||||
X-Kong-Proxy-Latency: 1
|
||||
Via: 1.1 kong/3.9.1
|
||||
X-Kong-Request-Id: 9b533b383646b2728617ef2a30e7d92f
|
||||
cf-cache-status: DYNAMIC
|
||||
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=%2BGmFgkGsDol59lrAXlrXdP4PeE7tfE4zwIcSf7NgeVi1KjsaibLlq%2B%2FPHaZ%2FQSeodYa5%2BQsYoh1nULeLCJU9%2FzkRS3wsXDrF1K5jDwyiS1fOKMcM%2Fl%2B%2F5k84tjozth%2B%2FMgZ6mhogkFo%3D"}]}
|
||||
CF-RAY: a3365eaf4e4e7bf9-MIA
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
HTTP/1.1 206 Partial Content
|
||||
Date: Sun, 30 Aug 2026 19:39:31 GMT
|
||||
Content-Type: application/json; charset=utf-8
|
||||
Content-Length: 2648
|
||||
Connection: keep-alive
|
||||
Server: cloudflare
|
||||
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
Content-Range: 0-0/101
|
||||
Content-Location: /apartments?limit=1&offset=0&order=id.asc&select=%2A
|
||||
Content-Profile: public
|
||||
Preference-Applied: count=exact
|
||||
Access-Control-Allow-Origin: *
|
||||
Access-Control-Expose-Headers: Content-Encoding, Content-Location, Content-Range, Content-Type, Date, Location, Server, Transfer-Encoding, Range-Unit
|
||||
X-Kong-Upstream-Latency: 45
|
||||
X-Kong-Proxy-Latency: 1
|
||||
Via: 1.1 kong/3.9.1
|
||||
X-Kong-Request-Id: 039e86122c46200cd717916b6e135842
|
||||
cf-cache-status: DYNAMIC
|
||||
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=BKv08O8bUUr4qDMLzEOxeINGc5VFoXdVQNNDhmT8Lc%2BM%2ByjJsGfjnkOfLuHtkIBeBsGh4kmOPlN%2FB3s2If%2BcmCNw6oZLjYg8bPKo1QNCO0AmTmYXSNoT5e7%2BzJochHeSxCsD1gW7m38%3D"}]}
|
||||
CF-RAY: a3364312bcedb887-MIA
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
HTTP/1.1 200 OK
|
||||
Date: Sun, 30 Aug 2026 19:39:32 GMT
|
||||
Content-Type: application/json; charset=utf-8
|
||||
Content-Length: 2
|
||||
Connection: keep-alive
|
||||
Server: cloudflare
|
||||
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
Content-Range: */0
|
||||
Content-Location: /apartments?is_visible=is.false&limit=1&offset=0&order=id.asc&select=%2A
|
||||
Content-Profile: public
|
||||
Preference-Applied: count=exact
|
||||
Access-Control-Allow-Origin: *
|
||||
Access-Control-Expose-Headers: Content-Encoding, Content-Location, Content-Range, Content-Type, Date, Location, Server, Transfer-Encoding, Range-Unit
|
||||
X-Kong-Upstream-Latency: 30
|
||||
X-Kong-Proxy-Latency: 2
|
||||
Via: 1.1 kong/3.9.1
|
||||
X-Kong-Request-Id: 9c2a57070a4b53249c28ac4c437d4b56
|
||||
cf-cache-status: DYNAMIC
|
||||
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=mAw%2BHylzVDcPCkK%2BIYK9f8zB9WEkfty7bMwyvjbyO%2B2IRzTN54jQAgofMSBrJOJOX6lxDDMScXE6iWe59XKESXlSDxYhmGLT%2FdwAHTAErXqgnYHCDtgCOh5GliHuDLBpf3o5zL8JJJE%3D"}]}
|
||||
CF-RAY: a3364315582aeeeb-MIA
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
HTTP/1.1 200 OK
|
||||
Date: Sun, 30 Aug 2026 19:39:31 GMT
|
||||
Content-Type: application/json; charset=utf-8
|
||||
Content-Length: 2
|
||||
Connection: keep-alive
|
||||
Server: cloudflare
|
||||
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
Content-Range: */0
|
||||
Content-Location: /apartments?is_visible=not.is.true&limit=1&offset=0&order=id.asc&select=%2A
|
||||
Content-Profile: public
|
||||
Preference-Applied: count=exact
|
||||
Access-Control-Allow-Origin: *
|
||||
Access-Control-Expose-Headers: Content-Encoding, Content-Location, Content-Range, Content-Type, Date, Location, Server, Transfer-Encoding, Range-Unit
|
||||
X-Kong-Upstream-Latency: 38
|
||||
X-Kong-Proxy-Latency: 3
|
||||
Via: 1.1 kong/3.9.1
|
||||
X-Kong-Request-Id: 252f2d0642d8464a133408069dfd8a5a
|
||||
cf-cache-status: DYNAMIC
|
||||
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=JhblutXOican2RX5cbcS8caKnc6WpdsodPvtjWOzwAml8Yomg3xKSs8m2aCpXaXkTzM7Jka8X1htOJh3Zj5uoGMPrpnsHEgm6tWSnKdytSugJz2OePeD8PoHh6m7%2B%2FPMXKhXEJwmcjQ%3D"}]}
|
||||
CF-RAY: a33643102b0e4fad-MIA
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
HTTP/1.1 200 OK
|
||||
Date: Sun, 30 Aug 2026 19:39:00 GMT
|
||||
Content-Type: application/json; charset=utf-8
|
||||
Content-Length: 2
|
||||
Connection: keep-alive
|
||||
Server: cloudflare
|
||||
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
|
||||
Content-Range: */0
|
||||
Content-Location: /apartments?is_visible=eq.false&limit=1&offset=0&order=id.asc&select=%2A
|
||||
Content-Profile: public
|
||||
Preference-Applied: count=exact
|
||||
Access-Control-Allow-Origin: *
|
||||
Access-Control-Expose-Headers: Content-Encoding, Content-Location, Content-Range, Content-Type, Date, Location, Server, Transfer-Encoding, Range-Unit
|
||||
X-Kong-Upstream-Latency: 28
|
||||
X-Kong-Proxy-Latency: 2
|
||||
Via: 1.1 kong/3.9.1
|
||||
X-Kong-Request-Id: 6d6ae32336046505b27faf4e2bca1a3f
|
||||
cf-cache-status: DYNAMIC
|
||||
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=kgZGlNNkVBjD7LKeaIEHFnIeOOcPvmxhdN%2FN4gUHg3RSwToezpIG%2B0CTGdk%2FFozCIHhg34IuG92GUhUHgI3iwQdgyEouvC1744S1aZVWHXicpXdcY6OJyfB%2BqGA2lza4%2B%2FVGt1jIW%2Fo%3D"}]}
|
||||
CF-RAY: a336424d59939aa6-MIA
|
||||
alt-svc: h3=":443"; ma=86400
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
BOT_API_TOKEN=dev-token-change-me
|
||||
BOT_API_URL=https://pys1.builker.xyz/bot-descarga
|
||||
|
||||
# Imaging (hostname interno; requiere VPN/DNS o IP alcanzable)
|
||||
BOT_IMAGING_URL=http://serviciosimaging:8180/
|
||||
# Imaging (requiere acceso a la red interna de Salud Total)
|
||||
BOT_IMAGING_URL=https://serviciosimaging.saludtotal.loc/
|
||||
|
||||
# MinIO — bucket pys-cuentas-medicas: sin credenciales (PutObject anónimo)
|
||||
MINIO_ENDPOINT=https://s3.builker.xyz
|
||||
|
||||
@@ -7,7 +7,7 @@ from pathlib import Path
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Settings:
|
||||
url_sistema: str = "http://serviciosimaging:8180/"
|
||||
url_sistema: str = "https://serviciosimaging.saludtotal.loc/"
|
||||
peso_minimo_bytes: int = 10_000
|
||||
max_intentos_click: int = 3
|
||||
max_intentos_pdf: int = 2
|
||||
|
||||
@@ -2,6 +2,7 @@ from __future__ import annotations
|
||||
|
||||
import socket
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
@@ -15,6 +16,9 @@ JOB_COMPLETED = "completed"
|
||||
JOB_FAILED = "failed"
|
||||
JOB_CANCELLED = "cancelled"
|
||||
|
||||
CONTROL_REQUEST_TIMEOUT_SECONDS = 5.0
|
||||
ACTIVE_JOB_HEARTBEAT_SECONDS = 10.0
|
||||
|
||||
|
||||
class RemoteApiClient:
|
||||
"""Cliente HTTP hacia la API en IPSExtractor (vía gateway). Sin puertos locales."""
|
||||
@@ -49,6 +53,7 @@ class RemoteApiClient:
|
||||
r = self._client.post(
|
||||
self._url("/workers/heartbeat"),
|
||||
json={"worker_id": worker_id},
|
||||
timeout=CONTROL_REQUEST_TIMEOUT_SECONDS,
|
||||
)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
@@ -70,11 +75,18 @@ class RemoteApiClient:
|
||||
return dest
|
||||
|
||||
def post_event(self, job_id: str, event: Dict[str, Any]) -> None:
|
||||
r = self._client.post(self._url(f"/jobs/{job_id}/events"), json=event)
|
||||
r = self._client.post(
|
||||
self._url(f"/jobs/{job_id}/events"),
|
||||
json=event,
|
||||
timeout=CONTROL_REQUEST_TIMEOUT_SECONDS,
|
||||
)
|
||||
r.raise_for_status()
|
||||
|
||||
def cancel_flag(self, job_id: str) -> bool:
|
||||
r = self._client.get(self._url(f"/jobs/{job_id}/cancel-flag"))
|
||||
r = self._client.get(
|
||||
self._url(f"/jobs/{job_id}/cancel-flag"),
|
||||
timeout=CONTROL_REQUEST_TIMEOUT_SECONDS,
|
||||
)
|
||||
r.raise_for_status()
|
||||
return bool(r.json().get("cancel_requested"))
|
||||
|
||||
@@ -93,12 +105,14 @@ class WorkerAgent:
|
||||
worker_id: str,
|
||||
token: str,
|
||||
poll_seconds: float = 8.0,
|
||||
heartbeat_seconds: float = ACTIVE_JOB_HEARTBEAT_SECONDS,
|
||||
staging_root: Optional[Path] = None,
|
||||
log_func=None,
|
||||
):
|
||||
self.api = RemoteApiClient(api_url, token)
|
||||
self.worker_id = worker_id
|
||||
self.poll_seconds = poll_seconds
|
||||
self.heartbeat_seconds = max(1.0, float(heartbeat_seconds))
|
||||
self.staging_root = staging_root or Path(tempfile.gettempdir()) / "bot_descarga"
|
||||
self.minio = WorkerMinioUploader(MinioSettings.from_env())
|
||||
self._running = True
|
||||
@@ -129,6 +143,25 @@ class WorkerAgent:
|
||||
self.api.close()
|
||||
self._log(f"[worker {self.worker_id}] detenido")
|
||||
|
||||
def _heartbeat_while_job_runs(self, stop_event: threading.Event) -> None:
|
||||
"""Mantiene al worker online mientras el procesamiento bloqueante continúa."""
|
||||
connection_failed = False
|
||||
while not stop_event.is_set():
|
||||
try:
|
||||
self.api.heartbeat(self.worker_id)
|
||||
if connection_failed:
|
||||
self._log(f"[worker {self.worker_id}] conexión con servidor restablecida")
|
||||
connection_failed = False
|
||||
except Exception as e:
|
||||
# Una caída temporal del gateway no debe cancelar la descarga local.
|
||||
if not connection_failed:
|
||||
self._log(
|
||||
f"[worker {self.worker_id}] heartbeat temporalmente no disponible: {e}; "
|
||||
"el job continúa"
|
||||
)
|
||||
connection_failed = True
|
||||
stop_event.wait(self.heartbeat_seconds)
|
||||
|
||||
def _run_job(self, job: dict) -> None:
|
||||
job_id = job["id"]
|
||||
downloads_prefix = (job.get("downloads_prefix") or "").strip() or f"downloads/{job_id}/"
|
||||
@@ -140,6 +173,15 @@ class WorkerAgent:
|
||||
|
||||
self._log(f"[worker {self.worker_id}] job {job_id} iniciado (prefix={downloads_prefix})")
|
||||
|
||||
heartbeat_stop = threading.Event()
|
||||
heartbeat_thread = threading.Thread(
|
||||
target=self._heartbeat_while_job_runs,
|
||||
args=(heartbeat_stop,),
|
||||
name=f"heartbeat-{self.worker_id}",
|
||||
daemon=True,
|
||||
)
|
||||
heartbeat_thread.start()
|
||||
|
||||
try:
|
||||
self.api.download_excel(job_id, excel_path)
|
||||
|
||||
@@ -265,3 +307,6 @@ class WorkerAgent:
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
finally:
|
||||
heartbeat_stop.set()
|
||||
heartbeat_thread.join(timeout=CONTROL_REQUEST_TIMEOUT_SECONDS + 1.0)
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
"""Construye un ZIP reproducible y limpio del Bot de Descarga."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
from zipfile import ZIP_DEFLATED, ZipFile, ZipInfo
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
DEFAULT_OUTPUT = ROOT.parent / "bot_descarga.zip"
|
||||
TOP_LEVEL_FILES = (
|
||||
".env.example",
|
||||
".gitignore",
|
||||
"README.md",
|
||||
"requirements.txt",
|
||||
"run_gui.py",
|
||||
"main.py",
|
||||
)
|
||||
EXCLUDED_PARTS = {"__pycache__", ".pytest_cache", ".venv", "data", "logs", "out"}
|
||||
EXCLUDED_SUFFIXES = {".pyc", ".pyo", ".log"}
|
||||
|
||||
|
||||
def package_files(root: Path) -> list[Path]:
|
||||
files: list[Path] = []
|
||||
for name in TOP_LEVEL_FILES:
|
||||
path = root / name
|
||||
if path.is_file():
|
||||
files.append(path)
|
||||
package_root = root / "bot_descarga"
|
||||
for path in package_root.rglob("*"):
|
||||
relative = path.relative_to(root)
|
||||
if not path.is_file() or any(part in EXCLUDED_PARTS for part in relative.parts):
|
||||
continue
|
||||
if path.suffix.lower() in EXCLUDED_SUFFIXES:
|
||||
continue
|
||||
files.append(path)
|
||||
return sorted(files, key=lambda path: path.relative_to(root).as_posix())
|
||||
|
||||
|
||||
def build_package(root: Path = ROOT, output: Path = DEFAULT_OUTPUT) -> Path:
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
with ZipFile(output, "w", compression=ZIP_DEFLATED, compresslevel=9) as archive:
|
||||
for source in package_files(root):
|
||||
relative = source.relative_to(root).as_posix()
|
||||
info = ZipInfo(f"bot_descarga/{relative}", date_time=(2020, 1, 1, 0, 0, 0))
|
||||
info.compress_type = ZIP_DEFLATED
|
||||
info.external_attr = 0o644 << 16
|
||||
archive.writestr(info, source.read_bytes())
|
||||
return output
|
||||
|
||||
|
||||
def sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as source:
|
||||
for chunk in iter(lambda: source.read(1024 * 1024), b""):
|
||||
digest.update(chunk)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--output", type=Path, default=DEFAULT_OUTPUT)
|
||||
args = parser.parse_args()
|
||||
target = build_package(output=args.output.resolve())
|
||||
print(f"Paquete: {target}")
|
||||
print(f"SHA256: {sha256(target)}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,66 @@
|
||||
"""Construye y publica el Bot de Descarga en el prefijo latest de MinIO."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import boto3
|
||||
from botocore.config import Config
|
||||
|
||||
from package_bot import DEFAULT_OUTPUT, build_package, sha256
|
||||
|
||||
|
||||
DEFAULT_ENDPOINT = "https://s3.builker.xyz"
|
||||
DEFAULT_BUCKET = "apps-versions"
|
||||
DEFAULT_KEY = "BotDescargaPYSCuentasMedicas/latest/bot_descarga.zip"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--output", type=Path, default=DEFAULT_OUTPUT)
|
||||
parser.add_argument("--build-only", action="store_true")
|
||||
args = parser.parse_args()
|
||||
artifact = build_package(output=args.output.resolve())
|
||||
print(f"Paquete validado: {artifact} ({sha256(artifact)})")
|
||||
if args.build_only:
|
||||
return 0
|
||||
|
||||
access = os.getenv("MINIO_ACCESS_KEY") or os.getenv("AWS_ACCESS_KEY_ID")
|
||||
secret = os.getenv("MINIO_SECRET_KEY") or os.getenv("AWS_SECRET_ACCESS_KEY")
|
||||
if not access or not secret:
|
||||
print("Faltan MINIO_ACCESS_KEY/MINIO_SECRET_KEY para publicar.", file=sys.stderr)
|
||||
return 2
|
||||
endpoint = os.getenv("MINIO_ENDPOINT", DEFAULT_ENDPOINT).rstrip("/")
|
||||
bucket = os.getenv("MINIO_APPS_BUCKET", DEFAULT_BUCKET)
|
||||
key = os.getenv("DOWNLOAD_PACKAGE_KEY", DEFAULT_KEY).strip("/")
|
||||
client = boto3.client(
|
||||
"s3",
|
||||
endpoint_url=endpoint,
|
||||
aws_access_key_id=access,
|
||||
aws_secret_access_key=secret,
|
||||
region_name=os.getenv("MINIO_REGION", "us-east-1"),
|
||||
config=Config(s3={"addressing_style": "path"}),
|
||||
)
|
||||
client.upload_file(
|
||||
str(artifact),
|
||||
bucket,
|
||||
key,
|
||||
ExtraArgs={"ContentType": "application/zip"},
|
||||
)
|
||||
remote = client.head_object(Bucket=bucket, Key=key)
|
||||
remote_size = int(remote.get("ContentLength") or 0)
|
||||
if remote_size != artifact.stat().st_size:
|
||||
print(
|
||||
f"La verificación remota falló: local={artifact.stat().st_size}, remoto={remote_size}.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 3
|
||||
print(f"Publicado: {endpoint}/{bucket}/{key}")
|
||||
print(f"Verificado: {remote_size} bytes")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -50,7 +50,7 @@ def test_browser_start_failure_sets_fatal_error(monkeypatch):
|
||||
svc = DownloadService(
|
||||
ruta_excel="dummy.xlsx",
|
||||
carpeta_descarga=".",
|
||||
settings=Settings(url_sistema="http://serviciosimaging:8180/"),
|
||||
settings=Settings(url_sistema="https://serviciosimaging.saludtotal.loc/"),
|
||||
event_callback=lambda e: events.append(e),
|
||||
)
|
||||
summary = svc.run()
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
import threading
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
import bot_descarga.worker.agent as agent_module
|
||||
from bot_descarga.models.resultado import RunSummary
|
||||
from bot_descarga.worker.agent import WorkerAgent
|
||||
|
||||
|
||||
class FakeApi:
|
||||
def __init__(self, failures: int = 0):
|
||||
self.calls = 0
|
||||
self.failures = failures
|
||||
|
||||
def heartbeat(self, worker_id: str) -> dict:
|
||||
self.calls += 1
|
||||
if self.calls <= self.failures:
|
||||
raise RuntimeError("gateway temporalmente no disponible")
|
||||
return {"worker_id": worker_id}
|
||||
|
||||
|
||||
def make_agent(api: FakeApi) -> WorkerAgent:
|
||||
agent = WorkerAgent.__new__(WorkerAgent)
|
||||
agent.api = api
|
||||
agent.worker_id = "zero0"
|
||||
agent.heartbeat_seconds = 0.01
|
||||
agent._log = lambda _message: None
|
||||
return agent
|
||||
|
||||
|
||||
def run_briefly(agent: WorkerAgent) -> threading.Thread:
|
||||
stop_event = threading.Event()
|
||||
thread = threading.Thread(
|
||||
target=agent._heartbeat_while_job_runs,
|
||||
args=(stop_event,),
|
||||
daemon=True,
|
||||
)
|
||||
thread.start()
|
||||
deadline = time.monotonic() + 1.0
|
||||
while agent.api.calls < 3 and time.monotonic() < deadline:
|
||||
time.sleep(0.01)
|
||||
stop_event.set()
|
||||
thread.join(timeout=1.0)
|
||||
return thread
|
||||
|
||||
|
||||
def test_active_job_sends_repeated_heartbeats() -> None:
|
||||
api = FakeApi()
|
||||
thread = run_briefly(make_agent(api))
|
||||
|
||||
assert api.calls >= 3
|
||||
assert not thread.is_alive()
|
||||
|
||||
|
||||
def test_transient_heartbeat_failure_does_not_stop_loop() -> None:
|
||||
api = FakeApi(failures=1)
|
||||
thread = run_briefly(make_agent(api))
|
||||
|
||||
assert api.calls >= 3
|
||||
assert not thread.is_alive()
|
||||
|
||||
|
||||
def test_successful_job_stays_completed_and_stops_heartbeat(monkeypatch, tmp_path: Path) -> None:
|
||||
class JobApi(FakeApi):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.patches = []
|
||||
|
||||
def download_excel(self, _job_id: str, dest: Path) -> Path:
|
||||
dest.parent.mkdir(parents=True, exist_ok=True)
|
||||
dest.write_bytes(b"xlsx")
|
||||
return dest
|
||||
|
||||
def cancel_flag(self, _job_id: str) -> bool:
|
||||
return False
|
||||
|
||||
def post_event(self, _job_id: str, _event: dict) -> None:
|
||||
return None
|
||||
|
||||
def patch_job(self, job_id: str, **body) -> dict:
|
||||
self.patches.append((job_id, body))
|
||||
return body
|
||||
|
||||
class FakeMinio:
|
||||
def write_manifest(self, *_args, **_kwargs) -> None:
|
||||
return None
|
||||
|
||||
class FakeDownloadService:
|
||||
def __init__(self, **_kwargs):
|
||||
pass
|
||||
|
||||
def run(self) -> RunSummary:
|
||||
return RunSummary(total=1, exitosos=1)
|
||||
|
||||
api = JobApi()
|
||||
agent = make_agent(api)
|
||||
agent.staging_root = tmp_path
|
||||
agent.minio = FakeMinio()
|
||||
agent._uploaded_keys = []
|
||||
monkeypatch.setattr(agent_module, "DownloadService", FakeDownloadService)
|
||||
|
||||
agent._run_job({"id": "job-1", "excel_key": "input.xlsx"})
|
||||
calls_after_job = api.calls
|
||||
time.sleep(0.03)
|
||||
|
||||
assert api.patches == [
|
||||
(
|
||||
"job-1",
|
||||
{
|
||||
"status": "completed",
|
||||
"result": {
|
||||
"total": 1,
|
||||
"exitosos": 1,
|
||||
"fallidos": 0,
|
||||
"cancelled": False,
|
||||
"downloads_prefix": "downloads/job-1/",
|
||||
"uploaded_count": 0,
|
||||
},
|
||||
"error": None,
|
||||
},
|
||||
)
|
||||
]
|
||||
assert api.calls == calls_after_job
|
||||
|
After Width: | Height: | Size: 237 KiB |
|
After Width: | Height: | Size: 175 KiB |
|
After Width: | Height: | Size: 901 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,18 @@
|
||||
# ADR 0001: Mantener el heartbeat durante trabajos de descarga
|
||||
|
||||
- Estado: Aceptada
|
||||
- Fecha: 2026-09-04
|
||||
|
||||
## Contexto
|
||||
|
||||
El bot de descarga ejecuta el procesamiento del Excel de forma bloqueante. Durante ese tiempo el ciclo principal no enviaba heartbeats y el servidor declaraba al worker desconectado después de 45 segundos, reclamando un trabajo que todavía seguía activo.
|
||||
|
||||
## Decisión
|
||||
|
||||
El worker enviará un heartbeat cada 10 segundos en un hilo auxiliar durante toda la ejecución del trabajo. Las llamadas de heartbeat, eventos y consulta de cancelación tendrán un timeout de 5 segundos y sus fallos temporales no detendrán la descarga local. El servidor esperará 180 segundos antes de reclamar un trabajo por desconexión.
|
||||
|
||||
## Consecuencias
|
||||
|
||||
- Los trabajos largos no serán reclamados solamente porque el ciclo principal esté ocupado.
|
||||
- Una interrupción breve del gateway no congelará el navegador durante un minuto por cada llamada de control.
|
||||
- Si un worker realmente se apaga, la recuperación automática puede tardar hasta tres minutos.
|
||||
@@ -0,0 +1,147 @@
|
||||
{"kind":"workbook","id":"wb/vpj3q6","sheets":4,"tables":4}
|
||||
{"kind":"sheet","id":"ws/85f3jb","name":"Resumen","index":0,"range":"A1:F25","address":"A1:F25","tables":1,"formulas":3}
|
||||
{"kind":"table","sheet":"Resumen","address":"A1:F25","rows":25,"cols":6,"values":[["Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana"],["Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana"],["Consulta independiente con is_visible = false","Consulta independiente con is_visible = false","Consulta independiente con is_visible = false","Consulta independiente con is_visible = false","Consulta independiente con is_visible = false","Consulta independiente con is_visible = false"],[null,null,null,null,null,null],["Apartamentos",null,"Páginas consultadas",null,"Fotos",null],[0,null,1,null,0,null],[null,null,null,null,null,null],[null,null,null,null,null,null],["Control de extracción","Control de extracción","Control de extracción","Control de extracción","Control de extracción","Control de extracción"],["Fecha y hora (UTC)","2026-08-30T19:41:16.075Z",null,null,null,null],["Origen","https://srv99857.rentpana.com/rest/v1/apartments",null,null,null,null],["Filtro","is_visible = false",null,null,null,null],["Orden estable","id ascendente",null,null,null,null],["Tamaño de página",50,null,null,null,null],["Total informado por API",0,null,null,null,null],["IDs únicos validados",0,null,null,null,null],["Duplicados detectados",0,null,null,null,null],["Columnas de origen",34,null,null,null,null],["Resultado","La API devolvió 0 registros para este filtro con la sesión suministrada.",null,null,null,null],["Credenciales incluidas","No",null,null,null,null],[null,null,null,null,null,null],["Contenido del archivo","Contenido del archivo","Contenido del archivo","Contenido del archivo","Contenido del archivo","Contenido del archivo"],["Apartamentos","Estructura de 34 campos, lista para los registros devueltos por la consulta.",null,null,null,null],["Fotos","Hoja normalizada para enlaces de fotos; actualmente sin filas.",null,null,null,null],["Paginacion","Consulta, límite, rango, cantidad y estado HTTP documentados.",null,null,null,null]]}
|
||||
{"kind":"region","sheet":"Resumen","address":"A9:F20","rows":12,"cols":6,"nonEmpty":28,"blank":44,"text":28,"maxTextLength":72,"preview":[["Control de extracción","Control de extracción","Control de extracción","Control de extracción","Control de extracción","Control de extracción"],["Fecha y hora (UTC)","46264.82032494213",null,null,null,null],["Origen","https://srv99857.rentpana.com/rest/v1/apartments",null,null,null,null],["Filtro","is_visible = false",null,null,null,null],["Orden estable","id ascendente",null,null,null,null]],"previewAddress":"A9:F13","previewRows":5,"previewCols":6}
|
||||
{"kind":"region","sheet":"Resumen","address":"A1:F3","rows":3,"cols":6,"nonEmpty":18,"text":18,"maxTextLength":45,"preview":[["Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana"],["Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana","Apartamentos no visibles · RentPana"],["Consulta independiente con is_visible = false","Consulta independiente con is_visible = false","Consulta independiente con is_visible = false","Consulta independiente con is_visible = false","Consulta independiente con is_visible = false","Consulta independiente con is_visible = false"]],"previewAddress":"A1:F3","previewRows":3,"previewCols":6}
|
||||
{"kind":"region","sheet":"Resumen","address":"A22:F25","rows":4,"cols":6,"nonEmpty":12,"blank":12,"text":12,"maxTextLength":76,"preview":[["Contenido del archivo","Contenido del archivo","Contenido del archivo","Contenido del archivo","Contenido del archivo","Contenido del archivo"],["Apartamentos","Estructura de 34 campos, lista para los registros devueltos por la consulta.",null,null,null,null],["Fotos","Hoja normalizada para enlaces de fotos; actualmente sin filas.",null,null,null,null],["Paginacion","Consulta, límite, rango, cantidad y estado HTTP documentados.",null,null,null,null]],"previewAddress":"A22:F25","previewRows":4,"previewCols":6}
|
||||
{"kind":"region","sheet":"Resumen","address":"A5:F6","rows":2,"cols":6,"nonEmpty":6,"blank":6,"text":6,"maxTextLength":19,"preview":[["Apartamentos",null,"Páginas consultadas",null,"Fotos",null],["0",null,"1",null,"0",null]],"previewAddress":"A5:F6","previewRows":2,"previewCols":6}
|
||||
{"kind":"formula","sheet":"Resumen","address":"A6","formula":"=COUNTA('Apartamentos'!$A$2:$A$2)"}
|
||||
{"kind":"formula","sheet":"Resumen","address":"C6","formula":"=COUNTA('Paginacion'!$A$2:$A$2)"}
|
||||
{"kind":"formula","sheet":"Resumen","address":"E6","formula":"=COUNTA('Fotos'!$A$2:$A$2)"}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":20,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":51}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":20,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":51}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"C1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":20,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":51}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"D1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":20,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":51}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"E1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":20,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":51}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"F1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":20,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":51}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A2","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":20,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":51}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B2","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":20,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":51}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"C2","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":20,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":51}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"D2","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":20,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":51}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"E2","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":20,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":51}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"F2","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":20,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":51}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A3","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"D9EDF2"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":52}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B3","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"D9EDF2"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":52}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"C3","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"D9EDF2"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":52}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"D3","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"D9EDF2"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":52}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"E3","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"D9EDF2"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":52}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"F3","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"D9EDF2"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":52}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A5","style":{"fill":{"type":1,"color":{"type":1,"value":"0F766E"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"center","styleId":54}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"C5","style":{"fill":{"type":1,"color":{"type":1,"value":"0F766E"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"center","styleId":55}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"E5","style":{"fill":{"type":1,"color":{"type":1,"value":"0F766E"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"center","styleId":55}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A6","style":{"fill":{"type":1,"color":{"type":1,"value":"DFF4F1"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":20,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]}},"border":{"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"center","styleId":57}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"C6","style":{"fill":{"type":1,"color":{"type":1,"value":"DFF4F1"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":20,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"center","styleId":58}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"E6","style":{"fill":{"type":1,"color":{"type":1,"value":"DFF4F1"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":20,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"center","styleId":58}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A9","style":{"fill":{"type":1,"color":{"type":1,"value":"0F766E"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":63}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B9","style":{"fill":{"type":1,"color":{"type":1,"value":"0F766E"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":63}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"C9","style":{"fill":{"type":1,"color":{"type":1,"value":"0F766E"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":63}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"D9","style":{"fill":{"type":1,"color":{"type":1,"value":"0F766E"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":63}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"E9","style":{"fill":{"type":1,"color":{"type":1,"value":"0F766E"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":63}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"F9","style":{"fill":{"type":1,"color":{"type":1,"value":"0F766E"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":63}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A10","style":{"fill":{"type":1,"color":{"type":1,"value":"F4F7F9"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"60707D"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":64}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B10","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"numberFormat":"yyyy-mm-dd hh:mm:ss","wrapText":true,"horizontalAlignment":"left","styleId":65}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A11","style":{"fill":{"type":1,"color":{"type":1,"value":"F4F7F9"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"60707D"},"gradientStops":[],"pictureEffects":[]}},"border":{"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":68}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B11","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":true,"horizontalAlignment":"left","styleId":69}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A12","style":{"fill":{"type":1,"color":{"type":1,"value":"F4F7F9"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"60707D"},"gradientStops":[],"pictureEffects":[]}},"border":{"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":68}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B12","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":true,"horizontalAlignment":"left","styleId":69}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A13","style":{"fill":{"type":1,"color":{"type":1,"value":"F4F7F9"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"60707D"},"gradientStops":[],"pictureEffects":[]}},"border":{"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":68}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B13","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":true,"horizontalAlignment":"left","styleId":69}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A14","style":{"fill":{"type":1,"color":{"type":1,"value":"F4F7F9"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"60707D"},"gradientStops":[],"pictureEffects":[]}},"border":{"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":68}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B14","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":true,"horizontalAlignment":"left","styleId":69}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A15","style":{"fill":{"type":1,"color":{"type":1,"value":"F4F7F9"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"60707D"},"gradientStops":[],"pictureEffects":[]}},"border":{"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":68}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B15","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":true,"horizontalAlignment":"left","styleId":69}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A16","style":{"fill":{"type":1,"color":{"type":1,"value":"F4F7F9"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"60707D"},"gradientStops":[],"pictureEffects":[]}},"border":{"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":68}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B16","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":true,"horizontalAlignment":"left","styleId":69}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A17","style":{"fill":{"type":1,"color":{"type":1,"value":"F4F7F9"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"60707D"},"gradientStops":[],"pictureEffects":[]}},"border":{"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":68}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B17","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":true,"horizontalAlignment":"left","styleId":69}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A18","style":{"fill":{"type":1,"color":{"type":1,"value":"F4F7F9"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"60707D"},"gradientStops":[],"pictureEffects":[]}},"border":{"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":68}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B18","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":true,"horizontalAlignment":"left","styleId":69}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A19","style":{"fill":{"type":1,"color":{"type":1,"value":"F4F7F9"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"60707D"},"gradientStops":[],"pictureEffects":[]}},"border":{"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":68}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B19","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":true,"horizontalAlignment":"left","styleId":69}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A20","style":{"fill":{"type":1,"color":{"type":1,"value":"F4F7F9"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"60707D"},"gradientStops":[],"pictureEffects":[]}},"border":{"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":71}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B20","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":true,"horizontalAlignment":"left","styleId":72}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A22","style":{"fill":{"type":1,"color":{"type":1,"value":"0F766E"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":63}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B22","style":{"fill":{"type":1,"color":{"type":1,"value":"0F766E"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":63}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"C22","style":{"fill":{"type":1,"color":{"type":1,"value":"0F766E"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":63}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"D22","style":{"fill":{"type":1,"color":{"type":1,"value":"0F766E"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":63}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"E22","style":{"fill":{"type":1,"color":{"type":1,"value":"0F766E"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":63}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"F22","style":{"fill":{"type":1,"color":{"type":1,"value":"0F766E"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":63}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A23","style":{"fill":{"type":1,"color":{"type":1,"value":"F4F7F9"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":74}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B23","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":true,"horizontalAlignment":"general","styleId":75}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A24","style":{"fill":{"type":1,"color":{"type":1,"value":"F4F7F9"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]}},"border":{"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":77}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B24","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":true,"horizontalAlignment":"general","styleId":78}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"A25","style":{"fill":{"type":1,"color":{"type":1,"value":"F4F7F9"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]}},"border":{"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":80}}
|
||||
{"kind":"computedStyle","sheet":"Resumen","for":"B25","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Aptos","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":true,"horizontalAlignment":"general","styleId":81}}
|
||||
{"kind":"sheet","id":"ws/ui1vde","name":"Apartamentos","index":1,"range":"A1:AH1","address":"A1:AH1","tables":1}
|
||||
{"kind":"table","sheet":"Apartamentos","address":"A1:AH1","rows":1,"cols":34,"values":[["id","user_id","user_name","user_phone","address","description","bedrooms","bathrooms","area_m2","monthly_rent","available_rooms","building_amenities","apartment_features","included_services","photo_urls","created_at","updated_at","show_phone","show_profile","is_visible","priority","listing_type","city","area","short_id","smart_rental_enabled","parent_apartment_id","tenant_user_id","tenant_name","tenant_phone","tenant_gender","tenant_age","is_paid","seo_slug"]]}
|
||||
{"kind":"region","sheet":"Apartamentos","address":"A1:AH1","rows":1,"cols":34,"nonEmpty":34,"text":34,"maxTextLength":20,"preview":[["id","user_id","user_name","user_phone","address","description"]],"previewAddress":"A1:F1","previewRows":1,"previewCols":6}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"A1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"B1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"C1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"D1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"E1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"F1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"G1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"H1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"I1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"J1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"K1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"L1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"M1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"N1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"O1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"P1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"Q1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"R1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"S1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"T1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"U1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"V1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"W1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"X1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"Y1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"Z1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"AA1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"AB1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"AC1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"AD1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"AE1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"AF1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"AG1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Apartamentos","for":"AH1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"sheet","id":"ws/x3rkxn","name":"Fotos","index":2,"range":"A1:G1","address":"A1:G1","tables":1}
|
||||
{"kind":"table","sheet":"Fotos","address":"A1:G1","rows":1,"cols":7,"values":[["apartment_id","short_id","city","area","address","photo_index","photo_url"]]}
|
||||
{"kind":"region","sheet":"Fotos","address":"A1:G1","rows":1,"cols":7,"nonEmpty":7,"text":7,"maxTextLength":12,"preview":[["apartment_id","short_id","city","area","address","photo_index"]],"previewAddress":"A1:F1","previewRows":1,"previewCols":6}
|
||||
{"kind":"computedStyle","sheet":"Fotos","for":"A1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Fotos","for":"B1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Fotos","for":"C1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Fotos","for":"D1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Fotos","for":"E1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Fotos","for":"F1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"computedStyle","sheet":"Fotos","for":"G1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{},"wrapText":false,"horizontalAlignment":"general","styleId":2}}
|
||||
{"kind":"sheet","id":"ws/ye6w3r","name":"Paginacion","index":3,"range":"A1:H3","address":"A1:H3","tables":1,"formulas":1}
|
||||
{"kind":"table","sheet":"Paginacion","address":"A1:H3","rows":3,"cols":8,"values":[["pagina","offset","limite","content_range","filas","estado_http","primer_id","ultimo_id"],[1,0,50,"*/0",0,"200 OK",null,null],["Total descargado","Total descargado","Total descargado","Total descargado",0,"Validado contra Content-Range: */0","Validado contra Content-Range: */0","Validado contra Content-Range: */0"]]}
|
||||
{"kind":"region","sheet":"Paginacion","address":"A1:H3","rows":3,"cols":8,"nonEmpty":22,"blank":2,"text":22,"maxTextLength":34,"preview":[["pagina","offset","limite","content_range","filas","estado_http"],["1","0","50","*/0","0","200 OK"],["Total descargado","Total descargado","Total descargado","Total descargado","0","Validado contra Content-Range: */0"]],"previewAddress":"A1:F3","previewRows":3,"previewCols":6}
|
||||
{"kind":"formula","sheet":"Paginacion","address":"E3","formula":"=SUM(E2:E2)"}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"A1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":7}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"B1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":7}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"C1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":7}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"D1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":7}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"E1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":7}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"F1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":7}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"G1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":7}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"H1","style":{"fill":{"type":1,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":7}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"A2","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"center","styleId":10}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"B2","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"center","styleId":10}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"C2","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"center","styleId":10}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"D2","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"center","styleId":10}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"E2","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"center","styleId":10}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"F2","style":{"fill":{"type":1,"color":{"type":1,"value":"FFFFFF"},"gradientStops":[],"pictureEffects":[]},"font":{"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"1F2937"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"center","styleId":10}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"A3","style":{"fill":{"type":1,"color":{"type":1,"value":"DFF4F1"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"center","styleId":11}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"B3","style":{"fill":{"type":1,"color":{"type":1,"value":"DFF4F1"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"center","styleId":11}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"C3","style":{"fill":{"type":1,"color":{"type":1,"value":"DFF4F1"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"center","styleId":11}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"D3","style":{"fill":{"type":1,"color":{"type":1,"value":"DFF4F1"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"center","styleId":11}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"E3","style":{"fill":{"type":1,"color":{"type":1,"value":"DFF4F1"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"center","styleId":11}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"F3","style":{"fill":{"type":1,"color":{"type":1,"value":"DFF4F1"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"center","styleId":11}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"G3","style":{"fill":{"type":1,"color":{"type":1,"value":"DFF4F1"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":9}}
|
||||
{"kind":"computedStyle","sheet":"Paginacion","for":"H3","style":{"fill":{"type":1,"color":{"type":1,"value":"DFF4F1"},"gradientStops":[],"pictureEffects":[]},"font":{"bold":true,"fontSize":11,"typeface":"Carlito","fill":{"type":0,"color":{"type":1,"value":"123047"},"gradientStops":[],"pictureEffects":[]}},"border":{"top":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"bottom":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"left":{"style":"thin","color":{"type":1,"value":"D8E1E7"}},"right":{"style":"thin","color":{"type":1,"value":"D8E1E7"}}},"wrapText":false,"horizontalAlignment":"general","styleId":9}}
|
||||
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 214 KiB |
|
After Width: | Height: | Size: 316 KiB |
|
After Width: | Height: | Size: 198 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 104 KiB |
@@ -1,4 +1,4 @@
|
||||
FROM python:3.11-slim
|
||||
FROM python:3.11-slim-bookworm
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
@@ -6,7 +6,8 @@ ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update \
|
||||
RUN sed -i 's|http://deb.debian.org|https://deb.debian.org|g' /etc/apt/sources.list.d/debian.sources \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM python:3.12-slim
|
||||
FROM python:3.12-slim-bookworm
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
@@ -6,7 +6,8 @@ ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update \
|
||||
RUN sed -i 's|http://deb.debian.org|https://deb.debian.org|g' /etc/apt/sources.list.d/debian.sources \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -26,7 +26,9 @@ from infrastructure.database import (
|
||||
)
|
||||
from infrastructure.storage_minio import downloads_prefix
|
||||
|
||||
HEARTBEAT_OFFLINE_SECONDS = 45
|
||||
# El worker procesa el navegador de forma bloqueante. Tres minutos toleran una
|
||||
# caída breve del gateway sin reclamar el mismo job mientras sigue descargando.
|
||||
HEARTBEAT_OFFLINE_SECONDS = 180
|
||||
# Un agent recién conectado no recibe jobs reclamados de otros workers.
|
||||
_FRESH_WORKER_GRACE_SECONDS = 45
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM python:3.12-slim
|
||||
FROM python:3.12-slim-bookworm
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
@@ -6,7 +6,8 @@ ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update \
|
||||
RUN sed -i 's|http://deb.debian.org|https://deb.debian.org|g' /etc/apt/sources.list.d/debian.sources \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM python:3.11-slim
|
||||
FROM python:3.11-slim-bookworm
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
@@ -6,7 +6,8 @@ ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update \
|
||||
RUN sed -i 's|http://deb.debian.org|https://deb.debian.org|g' /etc/apt/sources.list.d/debian.sources \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends libgl1 libglib2.0-0 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM python:3.12-slim
|
||||
FROM python:3.12-slim-bookworm
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ipsextractor-desktop",
|
||||
"version": "1.3.1",
|
||||
"version": "1.3.2",
|
||||
"private": true,
|
||||
"description": "Aplicación de escritorio Flujo IPS para automatizar procesos de cuentas médicas.",
|
||||
"main": "electron/main.cjs",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM python:3.11-slim
|
||||
FROM python:3.11-slim-bookworm
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
@@ -6,7 +6,8 @@ ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update \
|
||||
RUN sed -i 's|http://deb.debian.org|https://deb.debian.org|g' /etc/apt/sources.list.d/debian.sources \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends poppler-utils libgl1 libglib2.0-0 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM python:3.11-slim
|
||||
FROM python:3.11-slim-bookworm
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
|
||||
@@ -29,7 +29,22 @@ ENV GOMAXPROCS=2
|
||||
|
||||
WORKDIR /src
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
# La red hacia proxy.golang.org puede ser intermitente en Docker Desktop.
|
||||
# Reintentar conserva la verificación de go.sum; si el proxy oficial sigue
|
||||
# caído, la última tentativa descarga directamente desde el repositorio origen.
|
||||
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||
set -eu; \
|
||||
attempt=1; \
|
||||
while [ "$attempt" -le 3 ]; do \
|
||||
if GOPROXY=https://proxy.golang.org go mod download; then \
|
||||
exit 0; \
|
||||
fi; \
|
||||
echo "go mod download falló (intento ${attempt}/3); reintentando..."; \
|
||||
sleep $((attempt * 5)); \
|
||||
attempt=$((attempt + 1)); \
|
||||
done; \
|
||||
echo "proxy.golang.org no respondió; intentando descarga directa..."; \
|
||||
GOPROXY=direct go mod download
|
||||
|
||||
COPY . .
|
||||
|
||||
|
||||