revert(web): eliminar feature de reserva de numero en UI ADM-008
Eliminar secuencias.api.ts, useReservarNumero.ts, SecuenciasPanel.tsx, TipoComprobante enum y tipos ReservarNumeroResponse/ProximoNumeroResponse. Quitar SecuenciasPanel del PuntoDeVentaDetailPage.
This commit is contained in:
@@ -1,22 +0,0 @@
|
||||
import { axiosClient } from '@/api/axiosClient'
|
||||
import type { TipoComprobante, ReservarNumeroResponse, ProximoNumeroResponse } from '../types'
|
||||
|
||||
export async function reservarNumero(
|
||||
puntoDeVentaId: number,
|
||||
tipoComprobante: TipoComprobante,
|
||||
): Promise<ReservarNumeroResponse> {
|
||||
const response = await axiosClient.post<ReservarNumeroResponse>(
|
||||
`/api/v1/admin/puntos-de-venta/${puntoDeVentaId}/secuencias/${tipoComprobante}/reservar`,
|
||||
)
|
||||
return response.data
|
||||
}
|
||||
|
||||
export async function getProximoNumero(
|
||||
puntoDeVentaId: number,
|
||||
tipoComprobante: TipoComprobante,
|
||||
): Promise<ProximoNumeroResponse> {
|
||||
const response = await axiosClient.get<ProximoNumeroResponse>(
|
||||
`/api/v1/admin/puntos-de-venta/${puntoDeVentaId}/secuencias/${tipoComprobante}/proximo`,
|
||||
)
|
||||
return response.data
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
import { toast } from 'sonner'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
|
||||
import { TipoComprobante } from '../types'
|
||||
import { useReservarNumero, useProximoNumero } from '../hooks/useReservarNumero'
|
||||
|
||||
const TIPOS: Array<{ value: TipoComprobante; label: string }> = [
|
||||
{ value: TipoComprobante.FacturaA, label: 'Factura A' },
|
||||
{ value: TipoComprobante.FacturaB, label: 'Factura B' },
|
||||
{ value: TipoComprobante.FacturaC, label: 'Factura C' },
|
||||
{ value: TipoComprobante.NotaCreditoA, label: 'Nota Crédito A' },
|
||||
{ value: TipoComprobante.NotaCreditoB, label: 'Nota Crédito B' },
|
||||
{ value: TipoComprobante.NotaCreditoC, label: 'Nota Crédito C' },
|
||||
]
|
||||
|
||||
interface Props {
|
||||
puntoDeVentaId: number
|
||||
disabled: boolean
|
||||
}
|
||||
|
||||
export function SecuenciasPanel({ puntoDeVentaId, disabled }: Props) {
|
||||
return (
|
||||
<div className="rounded-md border border-border">
|
||||
<div className="border-b border-border px-4 py-3">
|
||||
<h2 className="text-sm font-semibold">Reserva de números de comprobante</h2>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Cada reserva incrementa el correlativo y devuelve el número asignado.
|
||||
</p>
|
||||
</div>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Tipo</TableHead>
|
||||
<TableHead className="text-right">Próximo número</TableHead>
|
||||
<TableHead className="text-right">Acción</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{TIPOS.map((tipo) => (
|
||||
<SecuenciaRow
|
||||
key={tipo.value}
|
||||
puntoDeVentaId={puntoDeVentaId}
|
||||
tipoValue={tipo.value}
|
||||
tipoLabel={tipo.label}
|
||||
disabled={disabled}
|
||||
/>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface RowProps {
|
||||
puntoDeVentaId: number
|
||||
tipoValue: TipoComprobante
|
||||
tipoLabel: string
|
||||
disabled: boolean
|
||||
}
|
||||
|
||||
function SecuenciaRow({ puntoDeVentaId, tipoValue, tipoLabel, disabled }: RowProps) {
|
||||
const proximo = useProximoNumero(puntoDeVentaId, tipoValue)
|
||||
const reservar = useReservarNumero(puntoDeVentaId)
|
||||
|
||||
const handleReservar = () => {
|
||||
reservar.mutate(tipoValue, {
|
||||
onSuccess: (data) => {
|
||||
toast.success(`${tipoLabel}: número ${data.numeroReservado} reservado`)
|
||||
},
|
||||
onError: (err: unknown) => {
|
||||
const apiError = err as { response?: { data?: { error?: string } } }
|
||||
const code = apiError.response?.data?.error ?? 'error'
|
||||
toast.error(`No se pudo reservar: ${code}`)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
<TableCell>{tipoLabel}</TableCell>
|
||||
<TableCell className="text-right font-mono">
|
||||
{proximo.isLoading ? '…' : proximo.data?.proximoNumero ?? '—'}
|
||||
</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
disabled={disabled || reservar.isPending}
|
||||
onClick={handleReservar}
|
||||
>
|
||||
{reservar.isPending ? 'Reservando…' : 'Reservar'}
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { reservarNumero, getProximoNumero } from '../api/secuencias.api'
|
||||
import type { TipoComprobante } from '../types'
|
||||
|
||||
// ─── Reservar ────────────────────────────────────────────────────────────────
|
||||
|
||||
export function useReservarNumero(puntoDeVentaId: number) {
|
||||
const queryClient = useQueryClient()
|
||||
return useMutation({
|
||||
mutationFn: (tipoComprobante: TipoComprobante) =>
|
||||
reservarNumero(puntoDeVentaId, tipoComprobante),
|
||||
onSuccess: (_data, tipoComprobante) => {
|
||||
// Invalidate the proximo query for this pdv+tipo so it refetches
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['puntos-de-venta', 'proximo', puntoDeVentaId, tipoComprobante],
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// ─── Próximo número (read-only) ──────────────────────────────────────────────
|
||||
|
||||
export function useProximoNumero(puntoDeVentaId: number, tipoComprobante: TipoComprobante) {
|
||||
return useQuery({
|
||||
queryKey: ['puntos-de-venta', 'proximo', puntoDeVentaId, tipoComprobante],
|
||||
queryFn: () => getProximoNumero(puntoDeVentaId, tipoComprobante),
|
||||
enabled: !!puntoDeVentaId,
|
||||
staleTime: 5_000,
|
||||
})
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import { useMedio } from '../../medios/hooks/useMedio'
|
||||
import { DeactivatePuntoDeVentaModal } from '../components/DeactivatePuntoDeVentaModal'
|
||||
import { MedioInactivoBanner } from '../components/MedioInactivoBanner'
|
||||
import { PdvInactivoBanner } from '../components/PdvInactivoBanner'
|
||||
import { SecuenciasPanel } from '../components/SecuenciasPanel'
|
||||
|
||||
function formatDate(iso: string | null): string {
|
||||
if (!iso) return '—'
|
||||
@@ -105,12 +104,6 @@ export function PuntoDeVentaDetailPage() {
|
||||
</div>
|
||||
</CanPerform>
|
||||
|
||||
<CanPerform permission="administracion:puntos_de_venta:gestionar">
|
||||
<SecuenciasPanel
|
||||
puntoDeVentaId={puntoDeVentaId}
|
||||
disabled={pdvInactivo || medioInactivo}
|
||||
/>
|
||||
</CanPerform>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
// ADM-008 — shared types for puntos-de-venta feature
|
||||
|
||||
export enum TipoComprobante {
|
||||
FacturaA = 1,
|
||||
FacturaB = 2,
|
||||
FacturaC = 3,
|
||||
NotaCreditoA = 4,
|
||||
NotaCreditoB = 5,
|
||||
NotaCreditoC = 6,
|
||||
}
|
||||
// NOTE: numeración AFIP (NumeroFactura, CAI) es asignada externamente por IMAC/Infogestión.
|
||||
// Un worker futuro (INT-001) polleará la vista de Infogestión para asociar
|
||||
// NumeroOrdenInterno ↔ NumeroFacturaAFIP + CAI. No se generan números aquí.
|
||||
|
||||
export interface PuntoDeVentaListItem {
|
||||
id: number
|
||||
@@ -53,16 +47,6 @@ export interface PuntosDeVentaQuery {
|
||||
activo?: boolean
|
||||
}
|
||||
|
||||
export interface ReservarNumeroResponse {
|
||||
tipoComprobante: TipoComprobante
|
||||
numeroReservado: number
|
||||
}
|
||||
|
||||
export interface ProximoNumeroResponse {
|
||||
tipoComprobante: TipoComprobante
|
||||
proximoNumero: number
|
||||
}
|
||||
|
||||
export interface PagedResult<T> {
|
||||
items: T[]
|
||||
page: number
|
||||
|
||||
Reference in New Issue
Block a user