import { API_URL, conAuth, manejar401 } from './auth' // ─── Tipos ────────────────────────────────────────────────────────── export interface CampoDef { campo: string tipo: string label: string options?: string[] /** Campo de fecha emparejado (solo booleanos de Obra) */ conFecha?: string } export interface ResumenDepartamento { departamento: string camposTotales: number camposLlenos: number porcentaje: number } export type DatosCaptura = Record> // ─── Departamentos y campos (espejo del backend) ──────────────────── export const DEPARTAMENTOS = ['OBRA', 'VENTAS', 'ESCRITURACION', 'FINANZAS', 'POSTVENTA'] as const export type DepartamentoId = (typeof DEPARTAMENTOS)[number] export const CAMPOS_POR_DEPARTAMENTO: Record = { OBRA: [ { campo: 'certificacion_gas', tipo: 'boolean', label: 'Certificación Gas', conFecha: 'certificacion_gas_fecha' }, { campo: 'certificacion_gas_fecha', tipo: 'date', label: 'Fecha Certificación Gas' }, { campo: 'to_c4_fianza', tipo: 'boolean', label: 'TO y C4-Fianza', conFecha: 'to_c4_fianza_fecha' }, { campo: 'to_c4_fianza_fecha', tipo: 'date', label: 'Fecha TO y C4-Fianza' }, { campo: 'regimen_inscrito', tipo: 'boolean', label: 'Régimen Inscrito', conFecha: 'regimen_inscrito_fecha' }, { campo: 'regimen_inscrito_fecha', tipo: 'date', label: 'Fecha Régimen Inscrito' }, { campo: 'no_oficial', tipo: 'boolean', label: 'No. Oficial', conFecha: 'no_oficial_fecha' }, { campo: 'no_oficial_fecha', tipo: 'date', label: 'Fecha No. Oficial' }, { campo: 'clave_catastral', tipo: 'boolean', label: 'Clave Catastral', conFecha: 'clave_catastral_fecha' }, { campo: 'clave_catastral_fecha', tipo: 'date', label: 'Fecha Clave Catastral' }, { campo: 'listas_avaluo', tipo: 'boolean', label: 'Listas para Avaluo', conFecha: 'listas_avaluo_fecha' }, { campo: 'listas_avaluo_fecha', tipo: 'date', label: 'Fecha Listas para Avaluo' }, { campo: 'habitabilidad', tipo: 'date', label: 'Habitabilidad a partir de' }, { campo: 'comentarios_obra', tipo: 'text', label: 'Comentarios' }, ], VENTAS: [ { campo: 'cliente_id', tipo: 'text', label: 'Cliente ID' }, { campo: 'nombre_cliente', tipo: 'text', label: 'Nombre Cliente' }, { campo: 'ubicacion', tipo: 'text', label: 'Ubicación/Unidad' }, { campo: 'modelo', tipo: 'text', label: 'Modelo' }, { campo: 'tipo_credito', tipo: 'select', label: 'Tipo Crédito', options: ['BANCARIO', 'COFINAVIT', 'INFONAVIT', 'SANTANDER', 'HSBC', 'BBVA', 'FOVISSSTE', 'CONTADO'] }, { campo: 'estatus', tipo: 'select', label: 'Estatus', options: ['DISPONIBLE', 'APARTADO', 'VENDIDO', 'ESCRITURADO'] }, { campo: 'fecha_apartado', tipo: 'date', label: 'Fecha Apartado' }, { campo: 'fecha_venta', tipo: 'date', label: 'Fecha Venta' }, { campo: 'fecha_vencimiento', tipo: 'date', label: 'Fecha Vencimiento Contrato' }, { campo: 'precio_venta', tipo: 'number', label: 'Precio Venta' }, ], ESCRITURACION: [ { campo: 'inicio_obra', tipo: 'boolean', label: 'Inicio Obra', conFecha: 'inicio_obra_fecha' }, { campo: 'inicio_obra_fecha', tipo: 'date', label: 'Fecha Inicio Obra' }, { campo: 'entrega_programada', tipo: 'boolean', label: 'Entrega Programada', conFecha: 'entrega_programada_fecha' }, { campo: 'entrega_programada_fecha', tipo: 'date', label: 'Fecha Programada Entrega Vivienda' }, { campo: 'entrega_reprogramada', tipo: 'boolean', label: 'Entrega Reprogramada', conFecha: 'entrega_reprogramada_fecha' }, { campo: 'entrega_reprogramada_fecha', tipo: 'date', label: 'Fecha Reprogramada Entrega Vivienda' }, { campo: 'fecha_autorizacion', tipo: 'date', label: 'Fecha Autorización' }, { campo: 'fecha_firma', tipo: 'date', label: 'Fecha Firma' }, { campo: 'notaria', tipo: 'text', label: 'Notaría' }, { campo: 'fecha_pago_banco', tipo: 'date', label: 'Fecha Pago Banco' }, { campo: 'fecha_pago_infonavit', tipo: 'date', label: 'Fecha Pago Infonavit' }, { campo: 'fecha_pago_fovissste', tipo: 'date', label: 'Fecha Pago Fovissste' }, ], FINANZAS: [ { campo: 'otros_ingresos', tipo: 'number', label: 'Otros Ingresos' }, { campo: 'pagado_transferencia', tipo: 'number', label: 'Pagado Transferencia' }, { campo: 'infonavit', tipo: 'number', label: 'Infonavit' }, { campo: 'bancario', tipo: 'number', label: 'Bancario' }, { campo: 'fovissste', tipo: 'number', label: 'Fovissste' }, { campo: 'credito_puente', tipo: 'number', label: 'Crédito Puente' }, { campo: 'saldo_favor', tipo: 'number', label: 'Saldo a Favor' }, ], POSTVENTA: [ { campo: 'entrega_sac', tipo: 'boolean', label: 'Entrega a SAC' }, { campo: 'comentarios_entrega', tipo: 'text', label: 'Comentarios' }, ], } export const DESARROLLOS = ['SENDA', 'ATELIER', 'ESTANZA', 'DIAGONAL', 'SOLANA', 'SOLE', 'MUTUO'] as const /** Labels legibles para cada departamento */ export const DEPARTAMENTO_LABELS: Record = { OBRA: 'Obra', VENTAS: 'Ventas', ESCRITURACION: 'Escrituración', FINANZAS: 'Finanzas', POSTVENTA: 'Postventa', } // ─── Permisos por rol ─────────────────────────────────────────────── /** * Departamentos visibles/editables por cada rol. * Director y admin ven todos. */ export const DEPARTAMENTOS_POR_ROL: Record = { admin: [...DEPARTAMENTOS], director: [...DEPARTAMENTOS], director_ventas: [...DEPARTAMENTOS], vendedor: ['VENTAS'], escrituracion: ['ESCRITURACION'], cobranza: ['FINANZAS'], postventa: ['POSTVENTA'], obra: ['OBRA'], } // ─── API calls ────────────────────────────────────────────────────── /** GET /api/captura?desarrollo=X — datos agrupados por unidad */ export async function obtenerCaptura( desarrollo: string, departamento?: string, ): Promise { const params = new URLSearchParams({ desarrollo }) if (departamento) params.set('departamento', departamento) const resp = await fetch(`${API_URL}/captura?${params}`, conAuth()) manejar401(resp) if (!resp.ok) throw new Error(`HTTP ${resp.status}`) return (await resp.json()) as DatosCaptura } /** GET /api/captura/unidades?desarrollo=X — lista de códigos de unidad */ export async function obtenerUnidadesCaptura(desarrollo: string): Promise { const params = new URLSearchParams({ desarrollo }) const resp = await fetch(`${API_URL}/captura/unidades?${params}`, conAuth()) manejar401(resp) if (!resp.ok) throw new Error(`HTTP ${resp.status}`) return (await resp.json()) as string[] } /** GET /api/captura/resumen?desarrollo=X — avance por departamento */ export async function obtenerResumenCaptura(desarrollo: string): Promise { const params = new URLSearchParams({ desarrollo }) const resp = await fetch(`${API_URL}/captura/resumen?${params}`, conAuth()) manejar401(resp) if (!resp.ok) throw new Error(`HTTP ${resp.status}`) return (await resp.json()) as ResumenDepartamento[] } /** POST /api/captura — guardar campo individual */ export async function guardarCampo(data: { desarrollo: string unidad: string departamento: string campo: string valor: string | null }): Promise { const resp = await fetch( `${API_URL}/captura`, conAuth({ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ desarrollo: data.desarrollo, unidadCodigo: data.unidad, departamento: data.departamento, campo: data.campo, valor: data.valor, }), }), ) manejar401(resp) if (!resp.ok) { const cuerpo = (await resp.json().catch(() => null)) as { error?: string } | null throw new Error(cuerpo?.error ?? `HTTP ${resp.status}`) } } /** POST /api/captura/bulk — guardar múltiples campos */ export async function guardarBulk(data: { desarrollo: string departamento: string registros: { unidad: string; campo: string; valor: string | null }[] }): Promise { const resp = await fetch( `${API_URL}/captura/bulk`, conAuth({ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ desarrollo: data.desarrollo, departamento: data.departamento, registros: data.registros, }), }), ) manejar401(resp) if (!resp.ok) { const cuerpo = (await resp.json().catch(() => null)) as { error?: string } | null throw new Error(cuerpo?.error ?? `HTTP ${resp.status}`) } }