feat: configurable machine report export

This commit is contained in:
Esdras Renan 2025-11-18 15:54:49 -03:00
parent c1ce7f1ab9
commit a7f9191e1d
4 changed files with 414 additions and 33 deletions

View file

@ -204,7 +204,7 @@ function deriveMachineData(machine: MachineInventoryRecord): MachineDerivedData
}
}
function normalizeColumnConfig(columns?: DeviceInventoryColumnConfig[]): DeviceInventoryColumnConfig[] {
export function normalizeInventoryColumnConfig(columns?: DeviceInventoryColumnConfig[]): DeviceInventoryColumnConfig[] {
if (!columns || columns.length === 0) {
return [...DEFAULT_COLUMN_CONFIG]
}
@ -425,14 +425,7 @@ export function buildMachinesInventoryWorkbook(
): Buffer {
const generatedAt = options.generatedAt ?? new Date()
const summaryRows = buildSummaryRows(machines, options, generatedAt)
const columnConfig = normalizeColumnConfig(options.columns)
const derivedList = machines.map((machine) => deriveMachineData(machine))
const headers = columnConfig.map((column) => resolveColumnLabel(column, derivedList))
const columnWidths = columnConfig.map((column) => resolveColumnWidth(column.key))
const inventoryRows = machines.map((machine, index) => {
const derived = derivedList[index]
return columnConfig.map((column) => formatInventoryCell(resolveColumnValue(column.key, machine, derived)))
})
const inventorySheet = buildInventoryWorksheet(machines, options.columns)
const linksRows = buildLinkedUsersRows(machines)
const softwareRows = buildSoftwareRows(machines)
const partitionRows = buildPartitionRows(machines)
@ -454,14 +447,7 @@ export function buildMachinesInventoryWorkbook(
columnWidths: [28, 48],
})
sheets.push({
name: "Inventário",
headers,
rows: inventoryRows,
columnWidths,
freezePane: { rowSplit: 1 },
autoFilter: true,
})
sheets.push(inventorySheet)
sheets.push({
name: "Vínculos",
@ -583,6 +569,32 @@ export function buildMachinesInventoryWorkbook(
return buildXlsxWorkbook(sheets)
}
export function buildInventoryWorksheet(
machines: MachineInventoryRecord[],
columns?: DeviceInventoryColumnConfig[],
sheetName = "Inventário",
): WorksheetConfig {
const columnConfig = normalizeInventoryColumnConfig(columns)
const derivedList = machines.map((machine) => deriveMachineData(machine))
const headers = columnConfig.map((column) => resolveColumnLabel(column, derivedList))
const columnWidths = columnConfig.map((column) => resolveColumnWidth(column.key))
const inventoryRows = machines.map((machine, index) => {
const derived = derivedList[index]
return columnConfig.map((column) => formatInventoryCell(resolveColumnValue(column.key, machine, derived)))
})
const fallbackRows =
inventoryRows.length > 0 ? inventoryRows : [columnConfig.map(() => "—")]
return {
name: sheetName,
headers,
rows: fallbackRows,
columnWidths,
freezePane: { rowSplit: 1 },
autoFilter: inventoryRows.length > 0,
}
}
function buildSummaryRows(
machines: MachineInventoryRecord[],
options: WorkbookOptions,

View file

@ -4,9 +4,11 @@ import { ConvexHttpClient } from "convex/browser"
import { api } from "@/convex/_generated/api"
import type { Id } from "@/convex/_generated/dataModel"
import { buildXlsxWorkbook } from "@/lib/xlsx"
import { buildXlsxWorkbook, type WorksheetConfig } from "@/lib/xlsx"
import { REPORT_EXPORT_DEFINITIONS, type ReportExportKey } from "@/lib/report-definitions"
import { requireConvexUrl } from "@/server/convex-client"
import type { DeviceInventoryColumnConfig } from "@/lib/device-inventory-columns"
import { buildInventoryWorksheet, type MachineInventoryRecord } from "@/server/machines/inventory-export"
export type { ReportExportKey }
type ViewerIdentity = {
@ -205,7 +207,7 @@ export async function buildCategoryInsightsWorkbook(
export async function buildMachineCategoryWorkbook(
ctx: ConvexReportContext,
options: BaseOptions & { machineId?: string | null; userId?: string | null }
options: BaseOptions & { machineId?: string | null; userId?: string | null; columns?: DeviceInventoryColumnConfig[] }
): Promise<ReportArtifact> {
const response = await ctx.client.query(api.reports.ticketsByMachineAndCategory, {
tenantId: ctx.tenantId,
@ -274,7 +276,7 @@ export async function buildMachineCategoryWorkbook(
item.total,
])
const workbook = buildXlsxWorkbook([
const sheets: WorksheetConfig[] = [
{ name: "Resumo", headers: ["Item", "Valor"], rows: summaryRows },
{
name: "Máquinas",
@ -286,7 +288,29 @@ export async function buildMachineCategoryWorkbook(
headers: ["Data", "Máquina", "Empresa", "Categoria", "Total"],
rows: occurrencesRows.length > 0 ? occurrencesRows : [["—", "—", "—", "—", 0]],
},
])
]
if (options.columns && options.columns.length > 0) {
const machineIds = new Set<string>()
for (const item of items) {
if (item.machineId) {
machineIds.add(String(item.machineId))
}
}
if (machineIds.size > 0) {
const machines = (await ctx.client.query(api.devices.listByTenant, {
tenantId: ctx.tenantId,
includeMetadata: true,
})) as MachineInventoryRecord[]
const filteredMachines = machines.filter((machine) => machineIds.has(String(machine.id)))
if (filteredMachines.length > 0) {
const inventorySheet = buildInventoryWorksheet(filteredMachines, options.columns, "Máquinas detalhadas")
sheets.push(inventorySheet)
}
}
}
const workbook = buildXlsxWorkbook(sheets)
const fileName = `machine-category-${ctx.tenantId}-${options.range ?? response.rangeDays ?? "30"}d${
options.companyId ? `-${options.companyId}` : ""