Update: nueva version Horux Despachos

This commit is contained in:
consultoria-as
2026-04-27 22:09:36 -06:00
commit 6b36db1403
614 changed files with 125926 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import * as api from '../api/addons';
export function useMyAddons(contribuyenteId?: string) {
return useQuery({
queryKey: ['my-addons', contribuyenteId ?? 'all'],
queryFn: () => api.listMyAddons(contribuyenteId),
});
}
export function useSubscribeAddon() {
const qc = useQueryClient();
return useMutation({
mutationFn: api.subscribeAddon,
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['my-addons'] });
},
});
}
export function useCancelAddon() {
const qc = useQueryClient();
return useMutation({
mutationFn: api.cancelAddon,
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['my-addons'] });
},
});
}

View File

@@ -0,0 +1,73 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import * as alertasApi from '../api/alertas';
import type { AlertaCreate, AlertaUpdate } from '@horux/shared';
import { useContribuyenteStore } from '@/stores/contribuyente-store';
export function useAlertas(filters?: { leida?: boolean; resuelta?: boolean }) {
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['alertas', filters, selectedContribuyenteId],
queryFn: () => alertasApi.getAlertas({ ...filters, contribuyenteId: selectedContribuyenteId || undefined }),
});
}
export function useAlertasAutomaticas() {
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['alertas-automaticas', selectedContribuyenteId],
queryFn: () => alertasApi.getAlertasAutomaticas(selectedContribuyenteId || undefined),
});
}
export function useAlertasStats() {
return useQuery({
queryKey: ['alertas-stats'],
queryFn: alertasApi.getStats,
});
}
export function useCreateAlerta() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: AlertaCreate) => alertasApi.createAlerta(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['alertas'] });
queryClient.invalidateQueries({ queryKey: ['alertas-stats'] });
},
});
}
export function useUpdateAlerta() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: number; data: AlertaUpdate }) => alertasApi.updateAlerta(id, data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['alertas'] });
queryClient.invalidateQueries({ queryKey: ['alertas-stats'] });
},
});
}
export function useDeleteAlerta() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: number) => alertasApi.deleteAlerta(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['alertas'] });
queryClient.invalidateQueries({ queryKey: ['alertas-stats'] });
},
});
}
export function useMarkAllAsRead() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: alertasApi.markAllAsRead,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['alertas'] });
queryClient.invalidateQueries({ queryKey: ['alertas-stats'] });
},
});
}

View File

@@ -0,0 +1,12 @@
'use client';
import { useQuery } from '@tanstack/react-query';
import { listAuditLog, type AuditLogFilters } from '../api/audit-log';
export function useAuditLog(filters: AuditLogFilters) {
return useQuery({
queryKey: ['audit-log', filters],
queryFn: () => listAuditLog(filters),
staleTime: 30 * 1000,
});
}

View File

@@ -0,0 +1,39 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import * as bancosApi from '@/lib/api/bancos';
import { useTenantViewStore } from '@/stores/tenant-view-store';
import { useContribuyenteStore } from '@/stores/contribuyente-store';
function useBancosKey() {
const { viewingTenantId } = useTenantViewStore();
const { selectedContribuyenteId } = useContribuyenteStore();
const tenantKey = viewingTenantId || 'own';
return ['bancos', tenantKey, selectedContribuyenteId] as const;
}
export function useBancos() {
const key = useBancosKey();
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: key,
queryFn: () => bancosApi.getBancos(selectedContribuyenteId),
});
}
export function useCreateBanco() {
const qc = useQueryClient();
const { selectedContribuyenteId } = useContribuyenteStore();
return useMutation({
mutationFn: (data: { banco: string; terminacionCuenta: string }) =>
bancosApi.createBanco({ ...data, contribuyenteId: selectedContribuyenteId || undefined }),
onSuccess: () => qc.invalidateQueries({ queryKey: ['bancos'] }),
});
}
export function useDeleteBanco() {
const qc = useQueryClient();
const key = useBancosKey();
return useMutation({
mutationFn: bancosApi.deleteBanco,
onSuccess: () => qc.invalidateQueries({ queryKey: key }),
});
}

View File

@@ -0,0 +1,57 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import * as calendarioApi from '../api/calendario';
import { useTenantViewStore } from '@/stores/tenant-view-store';
import { useContribuyenteStore } from '@/stores/contribuyente-store';
import type { EventoCreate, EventoUpdate } from '@horux/shared';
function useTenantKey() {
const { viewingTenantId } = useTenantViewStore();
return viewingTenantId || 'own';
}
export function useEventos(año: number) {
const tenantKey = useTenantKey();
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['calendario', tenantKey, año, selectedContribuyenteId],
queryFn: () => calendarioApi.getEventos(año, selectedContribuyenteId),
});
}
export function useProximosEventos(dias = 30) {
const tenantKey = useTenantKey();
return useQuery({
queryKey: ['calendario-proximos', tenantKey, dias],
queryFn: () => calendarioApi.getProximos(dias),
});
}
export function useCreateEvento() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: EventoCreate) => calendarioApi.createEvento(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['calendario'] });
},
});
}
export function useUpdateEvento() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: number; data: EventoUpdate }) => calendarioApi.updateEvento(id, data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['calendario'] });
},
});
}
export function useDeleteEvento() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: number) => calendarioApi.deleteEvento(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['calendario'] });
},
});
}

View File

@@ -0,0 +1,62 @@
'use client';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import * as api from '@/lib/api/carteras';
export function useCarteras() {
return useQuery({
queryKey: ['carteras'],
queryFn: () => api.getCarteras().then(r => r.data),
});
}
export function useSupervisores() {
return useQuery({
queryKey: ['cartera-supervisores'],
queryFn: () => api.getSupervisores().then(r => r.data),
});
}
export function useCreateCartera() {
const qc = useQueryClient();
return useMutation({
mutationFn: api.createCartera,
onSuccess: () => qc.invalidateQueries({ queryKey: ['carteras'] }),
});
}
export function useDeleteCartera() {
const qc = useQueryClient();
return useMutation({
mutationFn: api.deleteCartera,
onSuccess: () => qc.invalidateQueries({ queryKey: ['carteras'] }),
});
}
export function useCarteraEntidades(carteraId: string | null) {
return useQuery({
queryKey: ['cartera-entidades', carteraId],
queryFn: () => api.getCarteraEntidades(carteraId!).then(r => r.data),
enabled: !!carteraId,
});
}
export function useSubcarteras(carteraId: string | null) {
return useQuery({
queryKey: ['subcarteras', carteraId],
queryFn: () => api.getSubcarteras(carteraId!).then(r => r.data),
enabled: !!carteraId,
});
}
export function useCreateSubcartera() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ carteraId, ...payload }: { carteraId: string; nombre: string; descripcion?: string; auxiliarUserId: string }) =>
api.createSubcartera(carteraId, payload),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['subcarteras'] });
qc.invalidateQueries({ queryKey: ['carteras'] });
},
});
}

View File

@@ -0,0 +1,72 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import * as cfdiApi from '@/lib/api/cfdi';
import type { CfdiFilters } from '@horux/shared';
import type { CreateCfdiData } from '@/lib/api/cfdi';
import { useContribuyenteStore } from '@/stores/contribuyente-store';
export function useCfdis(filters: CfdiFilters) {
const { selectedContribuyenteId } = useContribuyenteStore();
const filtersWithContribuyente: CfdiFilters = {
...filters,
contribuyenteId: selectedContribuyenteId || undefined,
};
return useQuery({
queryKey: ['cfdis', filters, selectedContribuyenteId],
queryFn: () => cfdiApi.getCfdis(filtersWithContribuyente),
});
}
export function useCfdi(id: string) {
return useQuery({
queryKey: ['cfdi', id],
queryFn: () => cfdiApi.getCfdiById(id),
enabled: !!id,
});
}
export function useResumenCfdi(año?: number, mes?: number) {
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['cfdi-resumen', año, mes, selectedContribuyenteId],
queryFn: () => cfdiApi.getResumenCfdi(año, mes, selectedContribuyenteId || undefined),
});
}
export function useCreateCfdi() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CreateCfdiData) => cfdiApi.createCfdi(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['cfdis'] });
queryClient.invalidateQueries({ queryKey: ['cfdi-resumen'] });
queryClient.invalidateQueries({ queryKey: ['dashboard'] });
},
});
}
export function useCreateManyCfdis() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (cfdis: CreateCfdiData[]) => cfdiApi.createManyCfdis(cfdis),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['cfdis'] });
queryClient.invalidateQueries({ queryKey: ['cfdi-resumen'] });
queryClient.invalidateQueries({ queryKey: ['dashboard'] });
},
});
}
export function useDeleteCfdi() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => cfdiApi.deleteCfdi(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['cfdis'] });
queryClient.invalidateQueries({ queryKey: ['cfdi-resumen'] });
queryClient.invalidateQueries({ queryKey: ['dashboard'] });
},
});
}

View File

@@ -0,0 +1,37 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import * as conciliacionApi from '@/lib/api/conciliacion';
import { useContribuyenteStore } from '@/stores/contribuyente-store';
export function useCfdisConConciliacion(params: {
tipo: string;
fechaInicio?: string;
fechaFin?: string;
regimen?: string;
}) {
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['conciliacion', params, selectedContribuyenteId],
queryFn: () => conciliacionApi.getCfdisConConciliacion({
...params,
contribuyenteId: selectedContribuyenteId || undefined,
}),
enabled: !!params.tipo,
});
}
export function useConciliar() {
const qc = useQueryClient();
return useMutation({
mutationFn: conciliacionApi.conciliar,
onSuccess: () => qc.invalidateQueries({ queryKey: ['conciliacion'] }),
});
}
export function useDesconciliar() {
const qc = useQueryClient();
return useMutation({
mutationFn: conciliacionApi.desconciliar,
onSuccess: () => qc.invalidateQueries({ queryKey: ['conciliacion'] }),
});
}

View File

@@ -0,0 +1,42 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { listConstancias, consultarConstancia, descargarConstanciaPdf } from '../api/constancias';
import { useTenantViewStore } from '../../stores/tenant-view-store';
import { useContribuyenteStore } from '@/stores/contribuyente-store';
export function useConstancias() {
const viewingTenantId = useTenantViewStore((s) => s.viewingTenantId);
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['constancias', viewingTenantId, selectedContribuyenteId],
queryFn: () => listConstancias(selectedContribuyenteId || undefined),
});
}
export function useConsultarConstancia() {
const qc = useQueryClient();
const viewingTenantId = useTenantViewStore((s) => s.viewingTenantId);
return useMutation({
mutationFn: consultarConstancia,
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['constancias', viewingTenantId] });
qc.invalidateQueries({ queryKey: ['tenant-info'] });
qc.invalidateQueries({ queryKey: ['regimenes-activos'] });
},
});
}
export function useDescargarConstanciaPdf() {
return useMutation({
mutationFn: async (id: number) => {
const blob = await descargarConstanciaPdf(id);
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `constancia_${id}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
},
});
}

View File

@@ -0,0 +1,48 @@
'use client';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useAuthStore } from '@/stores/auth-store';
import * as api from '@/lib/api/contribuyentes';
export function useContribuyentes() {
const user = useAuthStore((s) => s.user);
return useQuery({
queryKey: ['contribuyentes', user?.tenantId],
queryFn: () => api.getContribuyentes().then((r) => r.data),
enabled: !!user,
});
}
export function useContribuyente(id: string | null) {
const user = useAuthStore((s) => s.user);
return useQuery({
queryKey: ['contribuyente', id, user?.tenantId],
queryFn: () => api.getContribuyente(id!),
enabled: !!user && !!id,
});
}
export function useCreateContribuyente() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: api.createContribuyente,
onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['contribuyentes'] }); },
});
}
export function useUpdateContribuyente() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: string; data: Partial<api.CreateContribuyenteData> }) =>
api.updateContribuyente(id, data),
onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['contribuyentes'] }); },
});
}
export function useDeactivateContribuyente() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: api.deactivateContribuyente,
onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['contribuyentes'] }); },
});
}

View File

@@ -0,0 +1,47 @@
import { useQuery } from '@tanstack/react-query';
import * as dashboardApi from '../api/dashboard';
import { useTenantViewStore } from '@/stores/tenant-view-store';
import { useContribuyenteStore } from '@/stores/contribuyente-store';
function useTenantKey() {
const { viewingTenantId } = useTenantViewStore();
return viewingTenantId || 'own';
}
export function useKpis(fechaInicio: string, fechaFin: string, conciliacion?: boolean) {
const tenantKey = useTenantKey();
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['kpis', tenantKey, fechaInicio, fechaFin, conciliacion, selectedContribuyenteId],
queryFn: () => dashboardApi.getKpis(fechaInicio, fechaFin, conciliacion, selectedContribuyenteId),
enabled: !!fechaInicio && !!fechaFin,
});
}
export function useIngresosEgresos(año?: number, conciliacion?: boolean) {
const tenantKey = useTenantKey();
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['ingresos-egresos', tenantKey, año, conciliacion, selectedContribuyenteId],
queryFn: () => dashboardApi.getIngresosEgresos(año, conciliacion, selectedContribuyenteId),
});
}
export function useRegimenesDelPeriodo(fechaInicio: string, fechaFin: string, conciliacion?: boolean) {
const tenantKey = useTenantKey();
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['regimenes-periodo', tenantKey, fechaInicio, fechaFin, conciliacion, selectedContribuyenteId],
queryFn: () => dashboardApi.getRegimenesDelPeriodo(fechaInicio, fechaFin, conciliacion, selectedContribuyenteId),
enabled: !!fechaInicio && !!fechaFin,
});
}
export function useAlertas(limit = 5) {
const tenantKey = useTenantKey();
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['alertas', tenantKey, limit, selectedContribuyenteId],
queryFn: () => dashboardApi.getAlertas(limit, selectedContribuyenteId),
});
}

View File

@@ -0,0 +1,67 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import {
listDeclaraciones,
createDeclaracion,
uploadComprobantePago,
deleteDeclaracion,
downloadDeclaracionPdf,
downloadBlob,
type CreateDeclaracionData,
} from '../api/declaraciones';
import { useTenantViewStore } from '../../stores/tenant-view-store';
export function useDeclaraciones(fechaDesde?: string, fechaHasta?: string, contribuyenteId?: string | null) {
const viewingTenantId = useTenantViewStore((s) => s.viewingTenantId);
return useQuery({
queryKey: ['declaraciones', fechaDesde, fechaHasta, contribuyenteId ?? 'all', viewingTenantId],
queryFn: () => listDeclaraciones(fechaDesde, fechaHasta, contribuyenteId),
});
}
export function useCreateDeclaracion() {
const qc = useQueryClient();
const viewingTenantId = useTenantViewStore((s) => s.viewingTenantId);
return useMutation({
mutationFn: (data: CreateDeclaracionData) => createDeclaracion(data),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['declaraciones'] });
qc.invalidateQueries({ queryKey: ['alertas'] });
qc.invalidateQueries({ queryKey: ['alertas-manuales'] });
qc.invalidateQueries({ queryKey: ['alertas-automaticas'] });
qc.invalidateQueries({ queryKey: ['eventos'] });
},
});
}
export function useUploadComprobantePago() {
const qc = useQueryClient();
const viewingTenantId = useTenantViewStore((s) => s.viewingTenantId);
return useMutation({
mutationFn: ({ id, pdfBase64, pdfFilename }: { id: number; pdfBase64: string; pdfFilename: string }) =>
uploadComprobantePago(id, pdfBase64, pdfFilename),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['declaraciones'] });
qc.invalidateQueries({ queryKey: ['alertas'] });
qc.invalidateQueries({ queryKey: ['alertas-manuales'] });
qc.invalidateQueries({ queryKey: ['alertas-automaticas'] });
qc.invalidateQueries({ queryKey: ['eventos'] });
},
});
}
export function useDeleteDeclaracion() {
const qc = useQueryClient();
return useMutation({
mutationFn: (id: number) => deleteDeclaracion(id),
onSuccess: () => qc.invalidateQueries({ queryKey: ['declaraciones'] }),
});
}
export function useDownloadDeclaracionPdf() {
return useMutation({
mutationFn: async ({ id, variant, filename }: { id: number; variant: 'declaracion' | 'liga' | 'pago'; filename: string }) => {
const blob = await downloadDeclaracionPdf(id, variant);
downloadBlob(blob, filename);
},
});
}

View File

@@ -0,0 +1,41 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { getOpiniones, descargarOpinionPdf, consultarOpinion } from '../api/documentos';
import { useTenantViewStore } from '../../stores/tenant-view-store';
import { useContribuyenteStore } from '@/stores/contribuyente-store';
export function useOpiniones() {
const viewingTenantId = useTenantViewStore((s) => s.viewingTenantId);
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['opiniones', viewingTenantId, selectedContribuyenteId],
queryFn: () => getOpiniones(selectedContribuyenteId || undefined),
});
}
export function useConsultarOpinion() {
const queryClient = useQueryClient();
const viewingTenantId = useTenantViewStore((s) => s.viewingTenantId);
const { selectedContribuyenteId } = useContribuyenteStore();
return useMutation({
mutationFn: () => consultarOpinion(selectedContribuyenteId || undefined),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['opiniones', viewingTenantId, selectedContribuyenteId] });
},
});
}
export function useDescargarPdf() {
return useMutation({
mutationFn: async (id: number) => {
const blob = await descargarOpinionPdf(id);
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `opinion_cumplimiento_${id}.pdf`;
a.click();
URL.revokeObjectURL(url);
},
});
}

View File

@@ -0,0 +1,53 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import * as facturacionApi from '../api/facturacion';
import * as catalogosApi from '../api/catalogos';
import { useTenantViewStore } from '@/stores/tenant-view-store';
function useTenantKey() {
const { viewingTenantId } = useTenantViewStore();
return viewingTenantId || 'own';
}
// Facturación
export function useOrgStatus() {
const tk = useTenantKey();
return useQuery({ queryKey: ['facturapi-org', tk], queryFn: facturacionApi.getOrgStatus });
}
export function useTimbres() {
const tk = useTenantKey();
return useQuery({ queryKey: ['facturapi-timbres', tk], queryFn: facturacionApi.getTimbres });
}
export function useEmitirFactura() {
const qc = useQueryClient();
return useMutation({
mutationFn: facturacionApi.emitirFactura,
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['facturapi-timbres'] });
qc.invalidateQueries({ queryKey: ['cfdi'] });
qc.invalidateQueries({ queryKey: ['kpis'] });
},
});
}
// Catálogos (se cachean globalmente, no dependen del tenant)
export function useFormasPago() {
return useQuery({ queryKey: ['cat-forma-pago'], queryFn: catalogosApi.getFormasPago, staleTime: Infinity });
}
export function useMetodosPago() {
return useQuery({ queryKey: ['cat-metodo-pago'], queryFn: catalogosApi.getMetodosPago, staleTime: Infinity });
}
export function useUsosCfdi() {
return useQuery({ queryKey: ['cat-uso-cfdi'], queryFn: catalogosApi.getUsosCfdi, staleTime: Infinity });
}
export function useMonedas() {
return useQuery({ queryKey: ['cat-moneda'], queryFn: catalogosApi.getMonedas, staleTime: Infinity });
}
export function useClavesUnidad() {
return useQuery({ queryKey: ['cat-clave-unidad'], queryFn: catalogosApi.getClavesUnidad, staleTime: Infinity });
}

View File

@@ -0,0 +1,65 @@
import { useQuery } from '@tanstack/react-query';
import * as impuestosApi from '@/lib/api/impuestos';
import { useTenantViewStore } from '@/stores/tenant-view-store';
import { useContribuyenteStore } from '@/stores/contribuyente-store';
function useTenantKey() {
const { viewingTenantId } = useTenantViewStore();
return viewingTenantId || 'own';
}
export function useIvaMensual(año?: number, conciliacion?: boolean, considerarActivos?: boolean, considerarNCs?: boolean) {
const tk = useTenantKey();
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['iva-mensual', tk, año, conciliacion, selectedContribuyenteId, considerarActivos, considerarNCs],
queryFn: () => impuestosApi.getIvaMensual(año, conciliacion, selectedContribuyenteId, considerarActivos, considerarNCs),
});
}
export function useResumenIva(fechaInicio: string, fechaFin: string, conciliacion?: boolean, considerarActivos?: boolean, considerarNCs?: boolean) {
const tk = useTenantKey();
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['iva-resumen', tk, fechaInicio, fechaFin, conciliacion, selectedContribuyenteId, considerarActivos, considerarNCs],
queryFn: () => impuestosApi.getResumenIva(fechaInicio, fechaFin, conciliacion, selectedContribuyenteId, considerarActivos, considerarNCs),
enabled: !!fechaInicio && !!fechaFin,
});
}
export function useCoeficiente(anio: number) {
const tk = useTenantKey();
return useQuery({
queryKey: ['coeficiente', tk, anio],
queryFn: () => impuestosApi.getCoeficiente(anio),
});
}
export function useIsrMensual(año?: number, conciliacion?: boolean, regimenClave?: string | null, considerarActivos?: boolean, considerarNCs?: boolean) {
const tk = useTenantKey();
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['isr-mensual', tk, año, conciliacion, selectedContribuyenteId, regimenClave, considerarActivos, considerarNCs],
queryFn: () => impuestosApi.getIsrMensual(año, conciliacion, selectedContribuyenteId, regimenClave, considerarActivos, considerarNCs),
});
}
export function useResumenIsr(fechaInicio: string, fechaFin: string, conciliacion?: boolean, considerarActivos?: boolean, considerarNCs?: boolean) {
const tk = useTenantKey();
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['isr-resumen', tk, fechaInicio, fechaFin, conciliacion, selectedContribuyenteId, considerarActivos, considerarNCs],
queryFn: () => impuestosApi.getResumenIsr(fechaInicio, fechaFin, conciliacion, selectedContribuyenteId, considerarActivos, considerarNCs),
enabled: !!fechaInicio && !!fechaFin,
});
}
export function useResumenIsrDesglosado(fechaFin: string, conciliacion?: boolean, considerarActivos?: boolean, considerarNCs?: boolean) {
const tk = useTenantKey();
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['isr-resumen-desglosado', tk, fechaFin, conciliacion, selectedContribuyenteId, considerarActivos, considerarNCs],
queryFn: () => impuestosApi.getResumenIsrDesglosado(fechaFin, conciliacion, selectedContribuyenteId, considerarActivos, considerarNCs),
enabled: !!fechaFin,
});
}

View File

@@ -0,0 +1,40 @@
'use client';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import * as api from '../api/platform-staff';
import type { PlatformRole } from '@horux/shared';
export function useStaff() {
return useQuery({
queryKey: ['platform-staff'],
queryFn: api.listStaff,
staleTime: 60 * 1000,
});
}
export function useSearchUsers(q: string) {
return useQuery({
queryKey: ['platform-staff-search', q],
queryFn: () => api.searchUsers(q),
enabled: q.length >= 2,
staleTime: 30 * 1000,
});
}
export function useGrantRole() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ userId, role }: { userId: string; role: PlatformRole }) =>
api.grantRole(userId, role),
onSuccess: () => qc.invalidateQueries({ queryKey: ['platform-staff'] }),
});
}
export function useRevokeRole() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ userId, role }: { userId: string; role: PlatformRole }) =>
api.revokeRole(userId, role),
onSuccess: () => qc.invalidateQueries({ queryKey: ['platform-staff'] }),
});
}

View File

@@ -0,0 +1,59 @@
import { useQuery } from '@tanstack/react-query';
import * as reportesApi from '../api/reportes';
import { useContribuyenteStore } from '@/stores/contribuyente-store';
export function useEstadoResultados(fechaInicio?: string, fechaFin?: string) {
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['estado-resultados', fechaInicio, fechaFin, selectedContribuyenteId],
queryFn: () => reportesApi.getEstadoResultados(fechaInicio, fechaFin, selectedContribuyenteId || undefined),
});
}
export function useFlujoEfectivo(fechaInicio?: string, fechaFin?: string) {
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['flujo-efectivo', fechaInicio, fechaFin, selectedContribuyenteId],
queryFn: () => reportesApi.getFlujoEfectivo(fechaInicio, fechaFin, selectedContribuyenteId || undefined),
});
}
export function useComparativo(año?: number) {
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['comparativo', año, selectedContribuyenteId],
queryFn: () => reportesApi.getComparativo(año, selectedContribuyenteId || undefined),
});
}
export function useConcentradoRfc(tipo: 'cliente' | 'proveedor', fechaInicio?: string, fechaFin?: string) {
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['concentrado-rfc', tipo, fechaInicio, fechaFin, selectedContribuyenteId],
queryFn: () => reportesApi.getConcentradoRfc(tipo, fechaInicio, fechaFin, selectedContribuyenteId || undefined),
});
}
export function useCuentasXPagar(fechaInicio: string, fechaFin: string, regimen?: string) {
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['cuentas-x-pagar', fechaInicio, fechaFin, regimen, selectedContribuyenteId],
queryFn: () => reportesApi.getCuentasXPagar(fechaInicio, fechaFin, regimen || undefined, selectedContribuyenteId || undefined),
enabled: !!fechaInicio && !!fechaFin,
});
}
export function useCuentasXCobrar(fechaInicio: string, fechaFin: string, regimen?: string) {
const { selectedContribuyenteId } = useContribuyenteStore();
return useQuery({
queryKey: ['cuentas-x-cobrar', fechaInicio, fechaFin, regimen, selectedContribuyenteId],
queryFn: () => reportesApi.getCuentasXCobrar(fechaInicio, fechaFin, regimen || undefined, selectedContribuyenteId || undefined),
enabled: !!fechaInicio && !!fechaFin,
});
}

View File

@@ -0,0 +1,133 @@
'use client';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import * as subscriptionApi from '../api/subscription';
export function useSubscription(tenantId: string | undefined) {
return useQuery({
queryKey: ['subscription', tenantId],
queryFn: () => subscriptionApi.getSubscription(tenantId!),
enabled: !!tenantId,
staleTime: 5 * 60 * 1000,
});
}
export function usePaymentHistory(tenantId: string | undefined) {
return useQuery({
queryKey: ['payments', tenantId],
queryFn: () => subscriptionApi.getPaymentHistory(tenantId!),
enabled: !!tenantId,
staleTime: 60 * 1000,
});
}
export function useGeneratePaymentLink() {
return useMutation({
mutationFn: (tenantId: string) => subscriptionApi.generatePaymentLink(tenantId),
});
}
export function useMarkAsPaid() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ tenantId, amount }: { tenantId: string; amount: number }) =>
subscriptionApi.markAsPaid(tenantId, amount),
onSuccess: (_, { tenantId }) => {
queryClient.invalidateQueries({ queryKey: ['subscription', tenantId] });
queryClient.invalidateQueries({ queryKey: ['payments', tenantId] });
},
});
}
// ============================================================================
// Self-serve hooks (actúan sobre el tenant del usuario autenticado)
// ============================================================================
export function usePlans() {
return useQuery({
queryKey: ['subscription-plans'],
queryFn: subscriptionApi.getPlans,
staleTime: 10 * 60 * 1000, // 10 min — los precios cambian poco
});
}
export function useStartTrial() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: subscriptionApi.startTrial,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['subscription'] });
},
});
}
export function useSubscribeMe() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: subscriptionApi.subscribeMe,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['subscription'] });
},
});
}
export function useChangeMyPlan() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: subscriptionApi.changeMyPlan,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['subscription'] });
},
});
}
export function useCancelMySubscription() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: subscriptionApi.cancelMySubscription,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['subscription'] });
},
});
}
export function useUpdatePlanPrice() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, amount }: { id: number; amount: number }) =>
subscriptionApi.updatePlanPrice(id, amount),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['subscription-plans'] });
},
});
}
export function useUpgradeMe() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (plan: string) => subscriptionApi.upgradeMe(plan),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['subscription'] });
},
});
}
export function useCancelPendingUpgrade() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: subscriptionApi.cancelPendingUpgrade,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['subscription'] });
},
});
}
export function useReactivateMe() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: subscriptionApi.reactivateMe,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['subscription'] });
},
});
}

View File

@@ -0,0 +1,42 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { getTenants, createTenant, updateTenant, deleteTenant, type CreateTenantData, type UpdateTenantData } from '@/lib/api/tenants';
export function useTenants() {
return useQuery({
queryKey: ['tenants'],
queryFn: getTenants,
});
}
export function useCreateTenant() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CreateTenantData) => createTenant(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['tenants'] });
},
});
}
export function useUpdateTenant() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: string; data: UpdateTenantData }) => updateTenant(id, data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['tenants'] });
},
});
}
export function useDeleteTenant() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => deleteTenant(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['tenants'] });
},
});
}

View File

@@ -0,0 +1,68 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import * as usuariosApi from '../api/usuarios';
import type { UserInvite, UserUpdate } from '@horux/shared';
export function useUsuarios() {
return useQuery({
queryKey: ['usuarios'],
queryFn: usuariosApi.getUsuarios,
});
}
export function useInviteUsuario() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: UserInvite) => usuariosApi.inviteUsuario(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['usuarios'] });
},
});
}
export function useUpdateUsuario() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: string; data: UserUpdate }) => usuariosApi.updateUsuario(id, data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['usuarios'] });
},
});
}
export function useDeleteUsuario() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => usuariosApi.deleteUsuario(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['usuarios'] });
},
});
}
// Hooks globales (admin global)
export function useAllUsuarios() {
return useQuery({
queryKey: ['usuarios', 'global'],
queryFn: usuariosApi.getAllUsuarios,
});
}
export function useUpdateUsuarioGlobal() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: string; data: UserUpdate }) => usuariosApi.updateUsuarioGlobal(id, data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['usuarios'] });
},
});
}
export function useDeleteUsuarioGlobal() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => usuariosApi.deleteUsuarioGlobal(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['usuarios'] });
},
});
}