feat: tablero pagos muestra solo validos y errores aparte con motivo
This commit is contained in:
1 parent
c64e990dfa
commit
ba71c4daa6
2 files changed
+77
-13
No files matched your search
@@ -18,11 +18,15 @@ export async function GET(req: Request): Promise<Response> {
|
||||
const year = url.searchParams.get("year") ?? String(now.getFullYear());
|
||||
const m = Number(mes);
|
||||
const y = Number(year);
|
||||
const l = Number(url.searchParams.get("limite") ?? "200");
|
||||
if (!Number.isInteger(m) || m < 1 || m > 12 || !Number.isInteger(y) || y < 2000 || y > 2100) {
|
||||
return NextResponse.json({ error: "mes (1-12) y year válidos requeridos" }, { status: 400 });
|
||||
}
|
||||
if (!Number.isInteger(l) || l < 1 || l > 1000) {
|
||||
return NextResponse.json({ error: "limite (1-1000) requerido" }, { status: 400 });
|
||||
}
|
||||
const res = await fetch(
|
||||
`${SAM_API_URL}/api/Boletas/payments?mes=${m}&year=${y}`,
|
||||
`${SAM_API_URL}/api/Boletas/payments?mes=${m}&year=${y}&limite=${l}`,
|
||||
{ cache: "no-store" }
|
||||
);
|
||||
const text = await res.text();
|
||||
|
||||
+72
-12
@@ -67,6 +67,18 @@ interface Boleta {
|
||||
monto: number;
|
||||
tipo?: string;
|
||||
estado?: string;
|
||||
esValido?: boolean;
|
||||
errorMotivo?: string | null;
|
||||
}
|
||||
|
||||
// Fecha real = distinta de nula/vacía y del MinValue de .NET
|
||||
// (0001-01-01: la función PG no informó fecha de caja).
|
||||
function fechaReal(f: string | null | undefined): boolean {
|
||||
return !!f && !f.startsWith("0001-01-01");
|
||||
}
|
||||
|
||||
function fechaCorta(f: string | null | undefined): string {
|
||||
return fechaReal(f) ? String(f).slice(0, 10) : "—";
|
||||
}
|
||||
|
||||
function HelpdeskUsage() {
|
||||
@@ -229,7 +241,7 @@ function PagosUsage() {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const res = await fetch(`/api/portal/pagos-validados?mes=${m}&year=${y}`, {
|
||||
const res = await fetch(`/api/portal/pagos-validados?mes=${m}&year=${y}&limite=200`, {
|
||||
cache: "no-store",
|
||||
});
|
||||
const data = await res.json().catch(() => null);
|
||||
@@ -254,7 +266,13 @@ function PagosUsage() {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
const total = (rows ?? []).reduce((acc, r) => acc + (Number(r.monto) || 0), 0);
|
||||
const valid = (rows ?? []).filter(
|
||||
(r) => r.esValido !== false && fechaReal(r.fecha)
|
||||
);
|
||||
const errors = (rows ?? []).filter(
|
||||
(r) => r.esValido === false || !fechaReal(r.fecha)
|
||||
);
|
||||
const total = valid.reduce((acc, r) => acc + (Number(r.monto) || 0), 0);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -300,7 +318,9 @@ function PagosUsage() {
|
||||
</button>
|
||||
{rows && (
|
||||
<span className="ms-auto small text-muted align-self-center">
|
||||
{rows.length} pagos · Total ${total.toLocaleString("es-CL")}
|
||||
{valid.length} válidos
|
||||
{errors.length > 0 && ` · ${errors.length} observados`} · Total
|
||||
${total.toLocaleString("es-CL")}
|
||||
</span>
|
||||
)}
|
||||
</form>
|
||||
@@ -318,11 +338,11 @@ function PagosUsage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!error && !loading && rows && rows.length === 0 && (
|
||||
<p className="text-muted mb-0">Sin pagos validados para {mes}/{year}.</p>
|
||||
{!error && !loading && rows && valid.length === 0 && (
|
||||
<p className="text-muted mb-0">Sin pagos válidos para {mes}/{year}.</p>
|
||||
)}
|
||||
|
||||
{!error && !loading && rows && rows.length > 0 && (
|
||||
{!error && !loading && rows && valid.length > 0 && (
|
||||
<div className="table-responsive">
|
||||
<table className="table table-sm table-hover mb-0">
|
||||
<thead>
|
||||
@@ -335,7 +355,7 @@ function PagosUsage() {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.slice(0, 100).map((r, i) => (
|
||||
{valid.slice(0, 100).map((r, i) => (
|
||||
<tr key={`${r.folio}-${i}`}>
|
||||
<td>{r.folio}</td>
|
||||
<td className="small">
|
||||
@@ -344,20 +364,60 @@ function PagosUsage() {
|
||||
<span className="text-muted d-block">{r.alumnoRut}</span>
|
||||
) : null}
|
||||
</td>
|
||||
<td className="small">
|
||||
{r.fecha ? String(r.fecha).slice(0, 10) : "—"}
|
||||
</td>
|
||||
<td className="small">{fechaCorta(r.fecha)}</td>
|
||||
<td className="text-end">${Number(r.monto || 0).toLocaleString("es-CL")}</td>
|
||||
<td className="small">{r.estado || r.tipo || "—"}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
{rows.length > 100 && (
|
||||
<small className="text-muted">Mostrando 100 de {rows.length}.</small>
|
||||
{valid.length > 100 && (
|
||||
<small className="text-muted">Mostrando 100 de {valid.length}.</small>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{!error && !loading && rows && errors.length > 0 && (
|
||||
<details className="mt-3">
|
||||
<summary className="small text-warning fw-semibold" style={{ cursor: "pointer" }}>
|
||||
<i className="bx bx-error me-1" />
|
||||
{errors.length} registro{errors.length !== 1 ? "s" : ""} observado{
|
||||
errors.length !== 1 ? "s" : ""
|
||||
} (no son ventas válidas)
|
||||
</summary>
|
||||
<div className="table-responsive mt-2">
|
||||
<table className="table table-sm table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Folio</th>
|
||||
<th>Alumno</th>
|
||||
<th>Fecha</th>
|
||||
<th className="text-end">Monto</th>
|
||||
<th>Motivo</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{errors.slice(0, 100).map((r, i) => (
|
||||
<tr key={`err-${r.folio}-${i}`}>
|
||||
<td>{r.folio || "—"}</td>
|
||||
<td className="small">
|
||||
{r.alumnoNombre ?? "—"}
|
||||
{r.alumnoRut ? (
|
||||
<span className="text-muted d-block">{r.alumnoRut}</span>
|
||||
) : null}
|
||||
</td>
|
||||
<td className="small">{fechaCorta(r.fecha)}</td>
|
||||
<td className="text-end">${Number(r.monto || 0).toLocaleString("es-CL")}</td>
|
||||
<td className="small text-warning">{r.errorMotivo || "Sin fecha válida"}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
{errors.length > 100 && (
|
||||
<small className="text-muted">Mostrando 100 de {errors.length}.</small>
|
||||
)}
|
||||
</div>
|
||||
</details>
|
||||
)}
|
||||
<small className="text-muted d-block mt-2">
|
||||
Fuente: <code>GET /api/Boletas/payments?mes=&year=</code> (SAM.API).
|
||||
</small>
|
||||
|
||||
Reference in new issue
Block a user