Files
home-control/lib/database/database_helper.dart
2026-06-14 15:03:29 -04:00

194 lines
6.7 KiB
Dart

import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
import '../models/servicio.dart';
import '../models/factura.dart';
import '../models/configuracion.dart';
class DatabaseHelper {
static final DatabaseHelper instance = DatabaseHelper._init();
static Database? _database;
DatabaseHelper._init();
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDB('hogarcontrol.db');
return _database!;
}
Future<Database> _initDB(String filePath) async {
final dbPath = await getDatabasesPath();
final path = join(dbPath, filePath);
return await openDatabase(path, version: 1, onCreate: _createDB, onConfigure: _onConfigure);
}
Future _onConfigure(Database db) async {
await db.execute('PRAGMA foreign_keys = ON');
}
Future _createDB(Database db, int version) async {
await db.execute('''
CREATE TABLE servicios (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nombre TEXT NOT NULL,
icono TEXT NOT NULL,
color INTEGER NOT NULL,
dia_vencimiento INTEGER NOT NULL,
fecha_creacion TEXT NOT NULL
)
''');
await db.execute('''
CREATE TABLE facturas (
id INTEGER PRIMARY KEY AUTOINCREMENT,
servicio_id INTEGER NOT NULL,
monto REAL NOT NULL,
fecha_emision TEXT NOT NULL,
fecha_vencimiento TEXT NOT NULL,
estado TEXT NOT NULL DEFAULT 'Pendiente',
nota TEXT,
fecha_pago TEXT,
FOREIGN KEY (servicio_id) REFERENCES servicios(id) ON DELETE CASCADE
)
''');
await db.execute('''
CREATE TABLE configuracion (
id INTEGER PRIMARY KEY AUTOINCREMENT,
dias_recordatorio TEXT NOT NULL DEFAULT '7,3,1,0',
tema TEXT NOT NULL DEFAULT 'claro',
moneda TEXT NOT NULL DEFAULT 'USD'
)
''');
}
Future<int> insertServicio(Servicio servicio) async {
final db = await database;
return await db.insert('servicios', servicio.toMap()..remove('id'));
}
Future<List<Servicio>> getServicios() async {
final db = await database;
final maps = await db.query('servicios', orderBy: 'nombre ASC');
return maps.map((map) => Servicio.fromMap(map)).toList();
}
Future<int> updateServicio(Servicio servicio) async {
final db = await database;
return await db.update('servicios', servicio.toMap(), where: 'id = ?', whereArgs: [servicio.id]);
}
Future<int> deleteServicio(int id) async {
final db = await database;
return await db.delete('servicios', where: 'id = ?', whereArgs: [id]);
}
Future<int> insertFactura(Factura factura) async {
final db = await database;
return await db.insert('facturas', factura.toMap()..remove('id'));
}
Future<List<Factura>> getFacturas({String? estado, int? servicioId}) async {
final db = await database;
String? where;
List<dynamic>? whereArgs;
if (estado != null && servicioId != null) {
where = 'estado = ? AND servicio_id = ?';
whereArgs = [estado, servicioId];
} else if (estado != null) {
where = 'estado = ?';
whereArgs = [estado];
} else if (servicioId != null) {
where = 'servicio_id = ?';
whereArgs = [servicioId];
}
final maps = await db.query('facturas', where: where, whereArgs: whereArgs, orderBy: 'fecha_vencimiento DESC');
return maps.map((map) => Factura.fromMap(map)).toList();
}
Future<List<Factura>> getFacturasVencidas() async {
final db = await database;
final hoy = DateTime.now().toIso8601String().split('T')[0];
final maps = await db.query('facturas',
where: 'estado = ? AND fecha_vencimiento < ?', whereArgs: ['Pendiente', hoy], orderBy: 'fecha_vencimiento ASC');
return maps.map((map) => Factura.fromMap(map)).toList();
}
Future<List<Factura>> getFacturasPorMes(int year, int month) async {
final db = await database;
final mes = month.toString().padLeft(2, '0');
final maps = await db.query('facturas',
where: "fecha_vencimiento LIKE ?", whereArgs: ['$year-$mes%'], orderBy: 'fecha_vencimiento ASC');
return maps.map((map) => Factura.fromMap(map)).toList();
}
Future<List<Factura>> getFacturasPorRango(String inicio, String fin) async {
final db = await database;
final maps = await db.query('facturas',
where: 'fecha_vencimiento BETWEEN ? AND ?', whereArgs: [inicio, fin], orderBy: 'fecha_vencimiento ASC');
return maps.map((map) => Factura.fromMap(map)).toList();
}
Future<double> getTotalGastadoMes(int year, int month) async {
final db = await database;
final mes = month.toString().padLeft(2, '0');
final result = await db.rawQuery(
"SELECT COALESCE(SUM(monto), 0) as total FROM facturas WHERE estado = 'Pagada' AND fecha_pago LIKE ?",
['$year-$mes%']);
return (result.first['total'] as num).toDouble();
}
Future<Map<String, double>> getGastosPorServicio(int year, int month) async {
final db = await database;
final mes = month.toString().padLeft(2, '0');
final result = await db.rawQuery('''
SELECT s.nombre, COALESCE(SUM(f.monto), 0) as total
FROM facturas f
JOIN servicios s ON f.servicio_id = s.id
WHERE f.estado = 'Pagada' AND f.fecha_pago LIKE ?
GROUP BY s.nombre
''', ['$year-$mes%']);
final map = <String, double>{};
for (final row in result) {
map[row['nombre'] as String] = (row['total'] as num).toDouble();
}
return map;
}
Future<List<Map<String, dynamic>>> getGastoMensual(int year) async {
final db = await database;
return await db.rawQuery('''
SELECT strftime('%m', fecha_pago) as mes, COALESCE(SUM(monto), 0) as total
FROM facturas
WHERE estado = 'Pagada' AND fecha_pago LIKE ?
GROUP BY mes
ORDER BY mes
''', ['$year-%']);
}
Future<int> updateFactura(Factura factura) async {
final db = await database;
return await db.update('facturas', factura.toMap(), where: 'id = ?', whereArgs: [factura.id]);
}
Future<int> deleteFactura(int id) async {
final db = await database;
return await db.delete('facturas', where: 'id = ?', whereArgs: [id]);
}
Future<Configuracion?> getConfiguracion() async {
final db = await database;
final maps = await db.query('configuracion', limit: 1);
if (maps.isEmpty) return null;
return Configuracion.fromMap(maps.first);
}
Future<int> saveConfiguracion(Configuracion config) async {
final db = await database;
final existing = await getConfiguracion();
if (existing != null) {
return await db.update('configuracion', config.toMap()..remove('id'),
where: 'id = ?', whereArgs: [existing.id]);
}
return await db.insert('configuracion', config.toMap()..remove('id'));
}
}