import 'dart:convert'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; import 'package:sqflite/sqflite.dart'; import '../models/models.dart'; class RepoService { static int dbVersion = 1; static String dbName = 'joshipos023.db'; static const String id = Basico.identificadorWeb; static const String idLocal = Basico.identificadorLocal; static Database? _db; final Map contexto = { 'Categoria': CategoriaProducto(), 'Producto': Producto(), 'Pedido': Pedido(productos: []), 'PedidoProducto': PedidoProducto(), }; Future get db async { if (_db != null) return _db; _db = await databaseInit(); return _db; } Future databaseInit() async { String dir = (await getApplicationDocumentsDirectory()).path; String path = join(dir, dbName); return await openDatabase( path, version: dbVersion, onCreate: _onCreate, onUpgrade: _onUpgrade, ); } /// Crea la base de datos _onCreate(Database db, int version) async { contexto.forEach((String nombre, dynamic modelo) async { Map model = json.decode(json.encode(modelo.toJson())); String sql = "CREATE TABLE ${modelo.runtimeType.toString()} (id INTEGER PRIMARY KEY AUTOINCREMENT"; model.forEach((String key, dynamic value) { if (key != "id") { // No incluir la columna de identificador local de nuevo String tipo = value.runtimeType.toString(); String sqlType = ""; if (equals(tipo, 'int')) { sqlType = "INTEGER"; } else if (equals(tipo, 'double')) { sqlType = "REAL"; } else if (equals(tipo, 'bool')) { sqlType = "BOOLEAN"; } else { sqlType = "TEXT"; } // Añadir cada campo al SQL, asegurándose de no configurar AUTOINCREMENT en folio sql += ", $key $sqlType"; } }); sql += ")"; await db.execute(sql); }); } /// Actualiza la version de la base de datos _onUpgrade(Database db, int oldVersion, int newVersion) async { while (oldVersion <= newVersion) { switch (oldVersion) { case 100: /* await db.execute("DROP TABLE IF EXISTS Evidencia"); await db.execute('CREATE TABLE TABLAA (idLocal INTEGER PRIMARY KEY)'); List sueltos = [ "ALTER TABLE Evidencia ADD id INTEGER", ]; for(int i = 0; i < sueltos.length; i++) { try { String sql = sueltos.elementAt(i); await db.execute(sql); } catch (e) {} } */ break; } oldVersion++; } } /// Guarda un modelo de datos nuevo o modificado en el repositorio Future guardar(T model) async { var dbClient = await db; String nombreTabla = model.runtimeType.toString(); String modelo = json.encode(model, toEncodable: toEncodable); Map modelMap = json.decode(modelo); // Elimina 'id' si es 0 o null para evitar conflictos con AUTOINCREMENT if (modelMap['id'] == null || modelMap['id'] == 0) { modelMap.remove('id'); } int resultado; if (modelMap[Basico.identificadorLocal] > 0) { resultado = await dbClient!.update( nombreTabla, modelMap, where: "$idLocal = ?", whereArgs: [modelMap[Basico.identificadorLocal]], ); } else { resultado = await dbClient!.insert(nombreTabla, modelMap); var rawQuery = await dbClient.rawQuery("SELECT last_insert_rowid() as id"); if (rawQuery.isNotEmpty) { resultado = int.parse(rawQuery.first["id"].toString()); modelMap[Basico.identificadorLocal] = resultado; // Actualiza el ID del modelo } } if (model is Pedido) { // Asegúrate de actualizar el ID en el objeto Pedido después de guardar model.id = resultado; } return resultado; } dynamic toEncodable(dynamic item) { Map map = {}; item.toJson().forEach((key, value) { if (value is DateTime) { map[key] = value.toIso8601String(); } else { map[key] = value; } }); return map; } Future> obtenerTodos() async { var dbClient = await db; String tableName = T .toString(); // Obtiene el nombre del modelo, que asumimos coincide con el nombre de la tabla List> result = await dbClient!.query(tableName); return result.map((map) => fromMap(map)).toList(); } // Necesitarás una función que convierta un Map a un objeto de tipo T T fromMap(Map map) { switch (T) { case Pedido: return Pedido.fromJson(map) as T; case Producto: return Producto.fromJson(map) as T; // Añade más casos si tienes más tipos default: throw Exception('Tipo no soportado'); } } Future obtenerPorId(int id) async { Database? dbClient = await db; List maps = await dbClient!.query('Pedido', where: 'id = ?', // Asegúrate de que el nombre de la columna sea 'id' y no 'idLocal' whereArgs: [id]); if (maps.isNotEmpty) { return Pedido.fromJson(Map.from(maps.first)); } return null; } Future> obtenerPorIdPedido(int idPedido) async { Database? dbClient = await db; List maps = await dbClient! .query('PedidoProducto', where: 'idPedido = ?', whereArgs: [idPedido]); return maps .map((map) => PedidoProducto.fromJson(Map.from(map))) .toList(); } Future obtenerProductoPorId(int idProducto) async { Database? dbClient = await db; List maps = await dbClient! .query('Producto', where: 'id = ?', whereArgs: [idProducto]); if (maps.isNotEmpty) { return Producto.fromJson(Map.from(maps.first)); } return null; } Future obtenerProximoFolio() async { var dbClient = await db; var result = await dbClient!.rawQuery('SELECT MAX(folio) as last_folio FROM Pedido'); if (result.isNotEmpty && result.first["last_folio"] != null) { return int.tryParse(result.first["last_folio"].toString())! + 1; } return 1; // Retorna 1 si no hay registros anteriores } }