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 year = url.searchParams.get("year") ?? String(now.getFullYear());
|
||||||
const m = Number(mes);
|
const m = Number(mes);
|
||||||
const y = Number(year);
|
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) {
|
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 });
|
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(
|
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" }
|
{ cache: "no-store" }
|
||||||
);
|
);
|
||||||
const text = await res.text();
|
const text = await res.text();
|
||||||
|
|||||||
+72
-12
@@ -67,6 +67,18 @@ interface Boleta {
|
|||||||
monto: number;
|
monto: number;
|
||||||
tipo?: string;
|
tipo?: string;
|
||||||
estado?: 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() {
|
function HelpdeskUsage() {
|
||||||
@@ -229,7 +241,7 @@ function PagosUsage() {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
try {
|
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",
|
cache: "no-store",
|
||||||
});
|
});
|
||||||
const data = await res.json().catch(() => null);
|
const data = await res.json().catch(() => null);
|
||||||
@@ -254,7 +266,13 @@ function PagosUsage() {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// 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 (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -300,7 +318,9 @@ function PagosUsage() {
|
|||||||
</button>
|
</button>
|
||||||
{rows && (
|
{rows && (
|
||||||
<span className="ms-auto small text-muted align-self-center">
|
<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>
|
</span>
|
||||||
)}
|
)}
|
||||||
</form>
|
</form>
|
||||||
@@ -318,11 +338,11 @@ function PagosUsage() {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!error && !loading && rows && rows.length === 0 && (
|
{!error && !loading && rows && valid.length === 0 && (
|
||||||
<p className="text-muted mb-0">Sin pagos validados para {mes}/{year}.</p>
|
<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">
|
<div className="table-responsive">
|
||||||
<table className="table table-sm table-hover mb-0">
|
<table className="table table-sm table-hover mb-0">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -335,7 +355,7 @@ function PagosUsage() {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{rows.slice(0, 100).map((r, i) => (
|
{valid.slice(0, 100).map((r, i) => (
|
||||||
<tr key={`${r.folio}-${i}`}>
|
<tr key={`${r.folio}-${i}`}>
|
||||||
<td>{r.folio}</td>
|
<td>{r.folio}</td>
|
||||||
<td className="small">
|
<td className="small">
|
||||||
@@ -344,20 +364,60 @@ function PagosUsage() {
|
|||||||
<span className="text-muted d-block">{r.alumnoRut}</span>
|
<span className="text-muted d-block">{r.alumnoRut}</span>
|
||||||
) : null}
|
) : null}
|
||||||
</td>
|
</td>
|
||||||
<td className="small">
|
<td className="small">{fechaCorta(r.fecha)}</td>
|
||||||
{r.fecha ? String(r.fecha).slice(0, 10) : "—"}
|
|
||||||
</td>
|
|
||||||
<td className="text-end">${Number(r.monto || 0).toLocaleString("es-CL")}</td>
|
<td className="text-end">${Number(r.monto || 0).toLocaleString("es-CL")}</td>
|
||||||
<td className="small">{r.estado || r.tipo || "—"}</td>
|
<td className="small">{r.estado || r.tipo || "—"}</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{rows.length > 100 && (
|
{valid.length > 100 && (
|
||||||
<small className="text-muted">Mostrando 100 de {rows.length}.</small>
|
<small className="text-muted">Mostrando 100 de {valid.length}.</small>
|
||||||
)}
|
)}
|
||||||
</div>
|
</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">
|
<small className="text-muted d-block mt-2">
|
||||||
Fuente: <code>GET /api/Boletas/payments?mes=&year=</code> (SAM.API).
|
Fuente: <code>GET /api/Boletas/payments?mes=&year=</code> (SAM.API).
|
||||||
</small>
|
</small>
|
||||||
|
|||||||
Reference in new issue
Block a user