feat(facturacion): fecha de emisión personalizable para I, E, T

- Frontend: input datetime-local visible solo para tipos I, E, T
  (no P). Default al día actual a las 12:00. Se resetea al cambiar tipo.
- Frontend: validación en handleSubmit: fecha ≤ ahora y ≥ ahora-72h
- Backend controller: validación idéntica antes de consumir timbre
- Backend servicios: pasa campo 'date' al payload de Facturapi
  cuando viene 'fechaEmision' en el body
- Build y deploy exitosos
This commit is contained in:
Horux Dev
2026-05-22 20:11:03 +00:00
parent 5ba31b7291
commit 1bde570035
5 changed files with 48 additions and 0 deletions

View File

@@ -303,6 +303,11 @@ export default function FacturacionPage() {
const [serie, setSerie] = useState('');
const [folio, setFolio] = useState('');
const [condiciones, setCondiciones] = useState('');
const [fechaEmision, setFechaEmision] = useState(() => {
const d = new Date();
d.setHours(12, 0, 0, 0);
return d.toISOString().slice(0, 16);
});
// Conceptos
const [conceptos, setConceptos] = useState<ConceptoForm[]>([{ ...emptyConcepto }]);
@@ -535,6 +540,10 @@ export default function FacturacionPage() {
// Resetear conceptos con unidad default según tipo
const defaultUnit = tipo === 'T' ? 'H87' : 'E48';
setConceptos([{ ...emptyConcepto, unitKey: defaultUnit }]);
// Resetear fecha de emisión al día actual (12:00)
const d = new Date();
d.setHours(12, 0, 0, 0);
setFechaEmision(d.toISOString().slice(0, 16));
};
// Unidades de servicio que no aplican para Traslado
@@ -651,6 +660,20 @@ export default function FacturacionPage() {
if (folio) data.folioNumber = parseInt(folio) || undefined;
if (condiciones) data.conditions = condiciones;
// Validar fecha de emisión para I, E, T
if (tipoComprobante !== 'P' && fechaEmision) {
const now = new Date();
const selected = new Date(fechaEmision);
const minDate = new Date(now.getTime() - 72 * 60 * 60 * 1000);
if (selected > now) {
alert('La fecha de emisión no puede ser a futuro'); return;
}
if (selected < minDate) {
alert('La fecha de emisión no puede ser mayor a 72 horas en el pasado'); return;
}
data.fechaEmision = selected.toISOString();
}
if (config.needsConceptos) {
if (conceptos.some(c => !c.description || !c.productKey)) {
alert('Completa todos los conceptos'); return;
@@ -1077,6 +1100,17 @@ export default function FacturacionPage() {
</p>
</div>
)}
{tipoComprobante !== 'P' && (
<div className="space-y-2">
<Label>Fecha de Emisión</Label>
<Input
type="datetime-local"
value={fechaEmision}
onChange={e => setFechaEmision(e.target.value)}
/>
<p className="text-xs text-muted-foreground">Máximo 72 horas en el pasado. No se permiten fechas a futuro.</p>
</div>
)}
<div className="space-y-2">
<Label>Serie (opcional)</Label>
<Input value={serie} onChange={e => setSerie(e.target.value.toUpperCase())} placeholder="P" maxLength={10} />

View File

@@ -69,6 +69,7 @@ export interface InvoiceData {
series?: string;
folioNumber?: number;
conditions?: string;
fechaEmision?: string;
}
export interface InvoiceResult {