Initial commit
This commit is contained in:
126
lib/screens/crear_factura_screen.dart
Normal file
126
lib/screens/crear_factura_screen.dart
Normal file
@@ -0,0 +1,126 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../models/factura.dart';
|
||||
import '../providers/factura_provider.dart';
|
||||
import '../providers/servicio_provider.dart';
|
||||
|
||||
class CrearFacturaScreen extends StatefulWidget {
|
||||
const CrearFacturaScreen({super.key});
|
||||
|
||||
@override
|
||||
State<CrearFacturaScreen> createState() => _CrearFacturaScreenState();
|
||||
}
|
||||
|
||||
class _CrearFacturaScreenState extends State<CrearFacturaScreen> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
late TextEditingController _montoCtrl;
|
||||
late TextEditingController _notaCtrl;
|
||||
int? _servicioId;
|
||||
DateTime _fechaEmision = DateTime.now();
|
||||
DateTime _fechaVencimiento = DateTime.now().add(const Duration(days: 30));
|
||||
String _estado = 'Pendiente';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_montoCtrl = TextEditingController();
|
||||
_notaCtrl = TextEditingController();
|
||||
context.read<ServicioProvider>().cargarServicios();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_montoCtrl.dispose();
|
||||
_notaCtrl.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final servicioProv = context.watch<ServicioProvider>();
|
||||
final facturaProv = context.read<FacturaProvider>();
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Nueva factura')),
|
||||
body: Form(
|
||||
key: _formKey,
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
children: [
|
||||
DropdownButtonFormField<int>(
|
||||
value: _servicioId,
|
||||
decoration: const InputDecoration(labelText: 'Servicio', border: OutlineInputBorder()),
|
||||
items: servicioProv.servicios.map((s) => DropdownMenuItem(value: s.id, child: Text(s.nombre))).toList(),
|
||||
onChanged: (v) => setState(() => _servicioId = v),
|
||||
validator: (v) => v == null ? 'Selecciona un servicio' : null,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: _montoCtrl,
|
||||
decoration: const InputDecoration(labelText: 'Monto', border: OutlineInputBorder(), prefixText: '\$ '),
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
validator: (v) {
|
||||
if (v == null || v.isEmpty) return 'Ingresa el monto';
|
||||
if (double.tryParse(v) == null) return 'Monto inválido';
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
ListTile(
|
||||
title: const Text('Fecha de emisión'),
|
||||
subtitle: Text(DateFormat('yyyy-MM-dd').format(_fechaEmision)),
|
||||
trailing: const Icon(Icons.calendar_today),
|
||||
onTap: () async {
|
||||
final date = await showDatePicker(context: context, firstDate: DateTime(2020), lastDate: DateTime(2035), initialDate: _fechaEmision);
|
||||
if (date != null) setState(() => _fechaEmision = date);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Fecha de vencimiento'),
|
||||
subtitle: Text(DateFormat('yyyy-MM-dd').format(_fechaVencimiento)),
|
||||
trailing: const Icon(Icons.calendar_today),
|
||||
onTap: () async {
|
||||
final date = await showDatePicker(context: context, firstDate: DateTime(2020), lastDate: DateTime(2035), initialDate: _fechaVencimiento);
|
||||
if (date != null) setState(() => _fechaVencimiento = date);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: _notaCtrl,
|
||||
decoration: const InputDecoration(labelText: 'Nota (opcional)', border: OutlineInputBorder()),
|
||||
maxLines: 2,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SegmentedButton<String>(
|
||||
segments: const [
|
||||
ButtonSegment(value: 'Pendiente', label: Text('Pendiente')),
|
||||
ButtonSegment(value: 'Pagada', label: Text('Pagada')),
|
||||
],
|
||||
selected: {_estado},
|
||||
onSelectionChanged: (v) => setState(() => _estado = v.first),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
FilledButton(
|
||||
onPressed: () async {
|
||||
if (!_formKey.currentState!.validate()) return;
|
||||
final factura = Factura(
|
||||
servicioId: _servicioId!,
|
||||
monto: double.parse(_montoCtrl.text),
|
||||
fechaEmision: DateFormat('yyyy-MM-dd').format(_fechaEmision),
|
||||
fechaVencimiento: DateFormat('yyyy-MM-dd').format(_fechaVencimiento),
|
||||
estado: _estado,
|
||||
nota: _notaCtrl.text.isEmpty ? null : _notaCtrl.text,
|
||||
fechaPago: _estado == 'Pagada' ? DateFormat('yyyy-MM-dd').format(DateTime.now()) : null,
|
||||
);
|
||||
await facturaProv.agregarFactura(factura);
|
||||
if (context.mounted) Navigator.pop(context);
|
||||
},
|
||||
child: const Text('Guardar factura'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user