database_service.dart 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692
  1. import 'dart:convert';
  2. import 'package:intl/intl.dart';
  3. import 'package:path/path.dart';
  4. import 'package:path_provider/path_provider.dart';
  5. import 'package:sqflite/sqflite.dart';
  6. import 'api_response.dart';
  7. import '../models/models.dart';
  8. import 'services.dart';
  9. class DatabaseService<T> {
  10. static int dbVersion = 26;
  11. static String dbName = 'posTurquessaMesas.db';
  12. static const String id = Basico.identificadorWeb;
  13. static const String idLocal = Basico.identificadorLocal;
  14. static Database? _db;
  15. final Map<String, dynamic> contexto = {
  16. 'Categoria': CategoriaProducto(),
  17. 'Producto': Producto(),
  18. 'ProductoTopping': ProductoTopping(),
  19. 'Pedido': Pedido(productos: []),
  20. 'PedidoProducto': PedidoProducto(),
  21. 'PedidoProductoTopping': PedidoProductoTopping(),
  22. 'Sucursal': Sucursal(),
  23. 'Usuario': Usuario(),
  24. 'UsuarioPermiso': UsuarioPermiso(),
  25. 'Variable': Variable(),
  26. 'Descuento': Descuento(),
  27. 'Mesa': Mesa(),
  28. 'Propinas': Propinas(),
  29. };
  30. Future<Database?> get db async {
  31. if (_db != null) return _db;
  32. _db = await databaseInit();
  33. return _db;
  34. }
  35. Future<Database> databaseInit() async {
  36. String dir = (await getApplicationDocumentsDirectory()).path;
  37. String path = join(dir, dbName);
  38. return await openDatabase(
  39. path,
  40. version: dbVersion,
  41. onCreate: _onCreate,
  42. onUpgrade: _onUpgrade,
  43. );
  44. }
  45. _onCreate(Database db, int version) async {
  46. contexto.forEach((String nombre, dynamic modelo) async {
  47. Map<String, dynamic> model = json.decode(json.encode(modelo.toJson()));
  48. String sql =
  49. "CREATE TABLE ${modelo.runtimeType.toString()} (id INTEGER PRIMARY KEY AUTOINCREMENT";
  50. model.forEach((String key, dynamic value) {
  51. if (key != "id") {
  52. String tipo = value.runtimeType.toString();
  53. String sqlType = "";
  54. if (equals(tipo, 'int')) {
  55. sqlType = "INTEGER";
  56. } else if (equals(tipo, 'double')) {
  57. sqlType = "REAL";
  58. } else if (equals(tipo, 'bool')) {
  59. sqlType = "BOOLEAN";
  60. } else {
  61. sqlType = "TEXT";
  62. }
  63. sql += ", $key $sqlType";
  64. }
  65. });
  66. sql += ")";
  67. await db.execute(sql);
  68. });
  69. await db.insert('Variable', {
  70. 'nombre': 'Imprimir Ticket Cocina',
  71. 'clave': 'ticket_cocina',
  72. 'descripcion':
  73. 'Variable para imprimir ticket de cocina automaticamente al momento de generar un pedido',
  74. 'activo': 1,
  75. 'idLocal': -1,
  76. });
  77. await db.insert('Variable', {
  78. 'nombre': 'Imprimir Ticket Venta',
  79. 'clave': 'ticket_venta',
  80. 'descripcion':
  81. 'Variable para imprimir ticket de venta automaticamente al momento de generar un pedido',
  82. 'activo': 1,
  83. 'idLocal': -1,
  84. });
  85. await db.insert('Variable', {
  86. 'nombre': 'Mesas',
  87. 'clave': 'MESAS',
  88. 'descripcion': 'Uso de mesas en el punto de venta',
  89. 'activo': 1,
  90. 'idLocal': -1,
  91. });
  92. await db.insert('Descuento', {'porcentaje': 0});
  93. await db.insert('Descuento', {'porcentaje': 5});
  94. await db.insert('Descuento', {'porcentaje': 10});
  95. await db.insert('Descuento', {'porcentaje': 15});
  96. await db.insert('Descuento', {'porcentaje': 20});
  97. await db.insert('Descuento', {'porcentaje': 25});
  98. await db.insert('Descuento', {'porcentaje': 30});
  99. await db.execute('''
  100. CREATE TABLE Permiso (
  101. id TEXT PRIMARY KEY,
  102. idModulo TEXT,
  103. nombre TEXT,
  104. descripcion TEXT,
  105. eliminado TEXT,
  106. creado TEXT,
  107. modificado TEXT
  108. )
  109. ''');
  110. await db.execute('''
  111. CREATE TABLE CorteCaja (
  112. id TEXT PRIMARY KEY,
  113. fechaApertura TEXT,
  114. fechaCorte TEXT,
  115. idUsuario INTEGER,
  116. idSucursal INTEGER,
  117. fondo REAL,
  118. fondoDiaSig REAL,
  119. ventaPuntos REAL,
  120. ventaEfe REAL,
  121. ventaTrans REAL,
  122. ventaTarj REAL,
  123. gasto REAL,
  124. retiro REAL,
  125. deposito REAL,
  126. corteFinal REAL,
  127. creado TEXT,
  128. modificado TEXT,
  129. eliminado TEXT,
  130. idWeb TEXT,
  131. sincronizado TEXT
  132. )
  133. ''');
  134. await db.execute('''
  135. CREATE TABLE Deposito (
  136. id TEXT PRIMARY KEY,
  137. idCorteCaja TEXT,
  138. idSucursal INTEGER,
  139. idUsuario INTEGER,
  140. fechaDeposito TEXT,
  141. monto REAL,
  142. persona TEXT,
  143. descripcion TEXT,
  144. creado TEXT,
  145. modificado TEXT,
  146. eliminado TEXT,
  147. idWeb TEXT
  148. )
  149. ''');
  150. await db.execute('''
  151. CREATE TABLE Retiro (
  152. id TEXT PRIMARY KEY,
  153. idCorteCaja TEXT,
  154. idSucursal INTEGER,
  155. idUsuario INTEGER,
  156. fechaRetiro TEXT,
  157. monto REAL,
  158. persona TEXT,
  159. descripcion TEXT,
  160. creado TEXT,
  161. modificado TEXT,
  162. eliminado TEXT,
  163. sincronizado TEXT,
  164. idWeb TEXT
  165. )
  166. ''');
  167. await db.execute('''
  168. CREATE TABLE Gasto (
  169. id TEXT PRIMARY KEY,
  170. idCorteCaja TEXT,
  171. idSucursal INTEGER,
  172. idUsuario INTEGER,
  173. fechaGasto TEXT,
  174. monto REAL,
  175. persona TEXT,
  176. descripcion TEXT,
  177. creado TEXT,
  178. modificado TEXT,
  179. eliminado TEXT,
  180. idWeb TEXT,
  181. sincronizado TEXT
  182. )
  183. ''');
  184. }
  185. void _onUpgrade(Database db, int oldVersion, int newVersion) async {
  186. while (oldVersion < newVersion) {
  187. switch (oldVersion) {
  188. case 1:
  189. await db.execute(
  190. "ALTER TABLE CategoriaProducto ADD COLUMN esToping INTEGER DEFAULT 0");
  191. await db.execute(
  192. "ALTER TABLE CategoriaProducto ADD COLUMN descripcion TEXT DEFAULT ''");
  193. await db.execute(
  194. "ALTER TABLE CategoriaProducto ADD COLUMN maximo INTEGER");
  195. break;
  196. case 2:
  197. await db.execute('''
  198. CREATE TABLE ProductoTopping (
  199. id INTEGER PRIMARY KEY AUTOINCREMENT,
  200. idProducto INTEGER,
  201. idTopping INTEGER,
  202. FOREIGN KEY (idProducto) REFERENCES Producto(id),
  203. FOREIGN KEY (idTopping) REFERENCES Producto(id)
  204. )
  205. ''');
  206. break;
  207. case 3:
  208. await db.execute('''
  209. CREATE TABLE PedidoProductoTopping (
  210. id INTEGER PRIMARY KEY AUTOINCREMENT,
  211. idPedidoProducto INTEGER,
  212. idTopping INTEGER,
  213. FOREIGN KEY (idPedidoProducto) REFERENCES PedidoProducto(id),
  214. FOREIGN KEY (idTopping) REFERENCES Producto(id)
  215. )
  216. ''');
  217. break;
  218. case 4:
  219. await db.execute('''
  220. ALTER TABLE Pedido ADD COLUMN descuento INTEGER DEFAULT 0
  221. ''');
  222. break;
  223. case 5:
  224. await db.execute('''
  225. CREATE TABLE IF NOT EXISTS Descuento (
  226. id INTEGER PRIMARY KEY AUTOINCREMENT,
  227. porcentaje INTEGER
  228. )
  229. ''');
  230. await db.insert('Descuento', {'porcentaje': 0});
  231. await db.insert('Descuento', {'porcentaje': 5});
  232. await db.insert('Descuento', {'porcentaje': 10});
  233. await db.insert('Descuento', {'porcentaje': 15});
  234. await db.insert('Descuento', {'porcentaje': 20});
  235. await db.insert('Descuento', {'porcentaje': 25});
  236. await db.insert('Descuento', {'porcentaje': 30});
  237. break;
  238. case 6:
  239. await db.execute('''
  240. ALTER TABLE Pedido ADD COLUMN tipoPago TEXT DEFAULT '';
  241. ''');
  242. await db.execute('''
  243. ALTER TABLE Pedido ADD COLUMN cantEfectivo REAL DEFAULT 0;
  244. ''');
  245. await db.execute('''
  246. ALTER TABLE Pedido ADD COLUMN cantTarjeta REAL DEFAULT 0;
  247. ''');
  248. await db.execute('''
  249. ALTER TABLE Pedido ADD COLUMN cantTransferencia REAL DEFAULT 0;
  250. ''');
  251. break;
  252. case 7:
  253. await db.execute('''
  254. CREATE TABLE Variable (
  255. id INTEGER PRIMARY KEY AUTOINCREMENT,
  256. nombre TEXT,
  257. clave TEXT,
  258. descripcion TEXT,
  259. activo BOOLEAN,
  260. idLocal INTEGER,
  261. eliminado TEXT
  262. )
  263. ''');
  264. break;
  265. // case 8:
  266. // await db.execute('''
  267. // ALTER TABLE Producto ADD COLUMN toping INTEGER DEFAULT 0;
  268. // ''');
  269. // break;
  270. case 9:
  271. await db.execute('''
  272. ALTER TABLE Pedido ADD COLUMN idWeb INTEGER;
  273. ''');
  274. await db.execute('''
  275. ALTER TABLE Pedido ADD COLUMN sincronizado TEXT;
  276. ''');
  277. await db.execute('''
  278. ALTER TABLE PedidoProducto ADD COLUMN idWeb INTEGER;
  279. ''');
  280. await db.execute('''
  281. ALTER TABLE PedidoProducto ADD COLUMN sincronizado TEXT;
  282. ''');
  283. break;
  284. case 10:
  285. await db.execute('''
  286. update Pedido set sincronizado = null, peticion = strftime('%Y-%m-%dT%H:%M:%S',
  287. datetime(substr(peticion, 7, 4) || '-' ||
  288. substr(peticion, 4, 2) || '-' ||
  289. substr(peticion, 1, 2) || ' ' ||
  290. substr(peticion, 12, 8) || ' -07:00', 'localtime', '+07:00'))
  291. WHERE strftime('%Y-%m-%dT%H:%M:%S',
  292. datetime(substr(peticion, 7, 4) || '-' ||
  293. substr(peticion, 4, 2) || '-' ||
  294. substr(peticion, 1, 2) || ' ' ||
  295. substr(peticion, 12, 8) || ' -07:00', 'localtime', '+07:00')) is not null
  296. ''');
  297. break;
  298. case 11:
  299. await db.execute('DROP TABLE IF EXISTS Producto');
  300. //Se tiene que crear nuevamente para que precio sea Double
  301. await db.execute('''
  302. CREATE TABLE Producto (
  303. id INTEGER PRIMARY KEY AUTOINCREMENT,
  304. idCategoria INTEGER,
  305. idLocal INTEGER,
  306. nombre TEXT,
  307. descripcion TEXT,
  308. imagen TEXT,
  309. venta INTEGER,
  310. existencia INTEGER,
  311. precio REAL,
  312. verMenu INTEGER,
  313. codigo TEXT,
  314. descuento TEXT,
  315. toping INTEGER,
  316. creado TEXT,
  317. modificado TEXT,
  318. eliminado TEXT
  319. )
  320. ''');
  321. await db.execute('DELETE FROM CategoriaProducto');
  322. await db.execute('''
  323. ALTER TABLE CategoriaProducto ADD COLUMN creado TEXT;
  324. ''');
  325. await db.execute('''
  326. ALTER TABLE CategoriaProducto ADD COLUMN modificado TEXT;
  327. ''');
  328. break;
  329. case 12:
  330. await db.execute('''
  331. ALTER TABLE Producto ADD COLUMN activo INTEGER;
  332. ''');
  333. break;
  334. case 13:
  335. await db.execute('''
  336. ALTER TABLE Producto ADD COLUMN activo INTEGER;
  337. ''');
  338. break;
  339. case 14:
  340. await db.execute('''
  341. ALTER TABLE ProductoTopping ADD COLUMN idCategoria INTEGER;
  342. ''');
  343. await db.execute('''
  344. ALTER TABLE ProductoTopping ADD COLUMN creado text;
  345. ''');
  346. await db.execute('''
  347. ALTER TABLE ProductoTopping ADD COLUMN modificado text;
  348. ''');
  349. await db.execute('''
  350. ALTER TABLE ProductoTopping ADD COLUMN eliminado text;
  351. ''');
  352. break;
  353. case 15:
  354. await db.execute('''
  355. CREATE TABLE Sucursal (
  356. id INTEGER PRIMARY KEY AUTOINCREMENT,
  357. nombre TEXT,
  358. descripcion TEXT,
  359. direccion TEXT,
  360. ciudad TEXT,
  361. activo INTEGER,
  362. clave TEXT,
  363. eliminado TEXT,
  364. creado TEXT,
  365. modificado TEXT,
  366. idLocal INTEGER,
  367. seleccionado INTEGER
  368. )
  369. ''');
  370. break;
  371. case 16:
  372. await db.execute('''
  373. CREATE TABLE Usuario (
  374. id INTEGER PRIMARY KEY AUTOINCREMENT,
  375. nombre TEXT,
  376. apellidos TEXT,
  377. correo TEXT,
  378. celular TEXT,
  379. celularPersonal TEXT,
  380. rol INTEGER,
  381. genero BOOLEAN,
  382. estatus INTEGER,
  383. imagen TEXT,
  384. rfc TEXT,
  385. razonSocial TEXT,
  386. calle TEXT,
  387. numeroExterior TEXT,
  388. colonia TEXT,
  389. codigoPostal TEXT,
  390. idCiudad INTEGER,
  391. idEstado INTEGER,
  392. idSucursal INTEGER,
  393. turno TEXT,
  394. eliminado TEXT,
  395. creado TEXT,
  396. modificado TEXT,
  397. idLocal INTEGER
  398. )
  399. ''');
  400. await db.execute('''
  401. CREATE TABLE Permiso (
  402. id TEXT PRIMARY KEY,
  403. idModulo TEXT,
  404. nombre TEXT,
  405. descripcion TEXT,
  406. eliminado TEXT,
  407. creado TEXT,
  408. modificado TEXT
  409. )
  410. ''');
  411. await db.execute('''
  412. CREATE TABLE UsuarioPermiso (
  413. id INTEGER PRIMARY KEY AUTOINCREMENT,
  414. idUsuario INTEGER,
  415. idPermiso TEXT,
  416. asignado TEXT,
  417. modificado TEXT,
  418. eliminado TEXT,
  419. idLocal INTEGER
  420. )
  421. ''');
  422. await db.execute('''
  423. ALTER TABLE ProductoTopping ADD COLUMN idLocal INTEGER;
  424. ''');
  425. await db.execute('''
  426. ALTER TABLE PedidoProductoTopping ADD COLUMN idLocal INTEGER;
  427. ''');
  428. await db.execute('''
  429. ALTER TABLE PedidoProductoTopping ADD COLUMN idCategoria INTEGER;
  430. ''');
  431. break;
  432. case 17:
  433. await db.execute('''
  434. ALTER TABLE CategoriaProducto ADD COLUMN minimo INTEGER;
  435. ''');
  436. break;
  437. case 18:
  438. await db.execute('''
  439. ALTER TABLE Usuario ADD COLUMN clave TEXT;
  440. ''');
  441. break;
  442. case 19:
  443. await db.execute('DROP TABLE CorteCaja');
  444. await db.execute('DROP TABLE Deposito');
  445. await db.execute('DROP TABLE Gasto');
  446. await db.execute('''
  447. CREATE TABLE CorteCaja (
  448. id TEXT PRIMARY KEY,
  449. fechaApertura TEXT,
  450. fechaCorte TEXT,
  451. idUsuario INTEGER,
  452. idSucursal INTEGER,
  453. fondo REAL,
  454. fondoDiaSig REAL,
  455. ventaPuntos REAL,
  456. ventaEfe REAL,
  457. ventaTrans REAL,
  458. ventaTarj REAL,
  459. gasto REAL,
  460. retiro REAL,
  461. corteFinal REAL,
  462. creado TEXT,
  463. modificado TEXT,
  464. eliminado TEXT
  465. )
  466. ''');
  467. await db.execute('''
  468. CREATE TABLE Deposito (
  469. id TEXT PRIMARY KEY,
  470. idCorteCaja TEXT,
  471. idSucursal INTEGER,
  472. idUsuario INTEGER,
  473. fechaDeposito TEXT,
  474. monto REAL,
  475. persona TEXT,
  476. descripcion TEXT,
  477. creado TEXT,
  478. modificado TEXT,
  479. eliminado TEXT
  480. )
  481. ''');
  482. await db.execute('''
  483. CREATE TABLE Retiro (
  484. id TEXT PRIMARY KEY,
  485. idCorteCaja TEXT,
  486. idSucursal INTEGER,
  487. idUsuario INTEGER,
  488. fechaRetiro TEXT,
  489. monto REAL,
  490. persona TEXT,
  491. descripcion TEXT,
  492. creado TEXT,
  493. modificado TEXT,
  494. eliminado TEXT
  495. )
  496. ''');
  497. await db.execute('''
  498. CREATE TABLE Gasto (
  499. id TEXT PRIMARY KEY,
  500. idCorteCaja TEXT,
  501. idSucursal INTEGER,
  502. idUsuario INTEGER,
  503. fechaGasto TEXT,
  504. monto REAL,
  505. persona TEXT,
  506. descripcion TEXT,
  507. creado TEXT,
  508. modificado TEXT,
  509. eliminado TEXT
  510. )
  511. ''');
  512. await db.execute('''
  513. update Pedido set sincronizado = null where estatus = 'CANCELADO'
  514. ''');
  515. await db.insert('Variable', {
  516. 'nombre': 'Imprimir ticket PC/Tablet',
  517. 'clave': 'ticket_pc',
  518. 'descripcion':
  519. 'Al estar activo imprime ticket para pc, el estar desactivado imprime ticket para tablet',
  520. 'activo': 1,
  521. 'idLocal': -1,
  522. });
  523. break;
  524. case 20:
  525. await db.execute('''
  526. ALTER TABLE CorteCaja ADD COLUMN deposito REAL;
  527. ''');
  528. await db.execute('''
  529. ALTER TABLE CorteCaja ADD COLUMN idWeb TEXT;
  530. ''');
  531. await db.execute('''
  532. ALTER TABLE CorteCaja ADD COLUMN sincronizado TEXT;
  533. ''');
  534. await db.execute('''
  535. ALTER TABLE Gasto ADD COLUMN idWeb TEXT;
  536. ''');
  537. await db.execute('''
  538. ALTER TABLE Gasto ADD COLUMN sincronizado TEXT;
  539. ''');
  540. await db.execute('''
  541. ALTER TABLE Retiro ADD COLUMN idWeb TEXT;
  542. ''');
  543. await db.execute('''
  544. ALTER TABLE Retiro ADD COLUMN sincronizado TEXT;
  545. ''');
  546. await db.execute('''
  547. ALTER TABLE Deposito ADD COLUMN idWeb TEXT;
  548. ''');
  549. await db.execute('''
  550. ALTER TABLE Deposito ADD COLUMN sincronizado TEXT;
  551. ''');
  552. break;
  553. case 21:
  554. await db.execute('''
  555. CREATE TABLE Mesa (
  556. id INTEGER PRIMARY KEY AUTOINCREMENT,
  557. idLocal INTEGER,
  558. idSucursal INTEGER,
  559. nombre TEXT,
  560. clave TEXT,
  561. posicion TEXT,
  562. activa BOOLEAN,
  563. creado TEXT,
  564. modificado TEXT,
  565. eliminado TEXT
  566. )
  567. ''');
  568. break;
  569. case 22:
  570. await db.execute('''
  571. ALTER TABLE Usuario ADD COLUMN token TEXT;
  572. ''');
  573. await db.insert('Variable', {
  574. 'nombre': 'Mesas',
  575. 'clave': 'MESAS',
  576. 'descripcion': 'Uso de mesas en el punto de venta',
  577. 'activo': 1,
  578. 'idLocal': -1,
  579. });
  580. break;
  581. case 23:
  582. await db.execute('''
  583. ALTER TABLE Pedido ADD COLUMN uuid TEXT;
  584. ''');
  585. break;
  586. case 24:
  587. await db.execute('''
  588. CREATE TABLE Propinas (
  589. id INTEGER PRIMARY KEY AUTOINCREMENT,
  590. idLocal INTEGER,
  591. idPedido INTEGER,
  592. cantidad REAL,
  593. comentario TEXT,
  594. sincronizado TEXT,
  595. idWeb INTEGER,
  596. creado TEXT,
  597. modificado TEXT,
  598. eliminado TEXT
  599. )
  600. ''');
  601. break;
  602. case 25:
  603. await db.execute('''
  604. ALTER TABLE Pedido ADD COLUMN idCorteCaja TEXT;
  605. ''');
  606. await db.execute('''
  607. ALTER TABLE Producto ADD COLUMN idWeb INTEGER;
  608. ''');
  609. await db.execute('''
  610. ALTER TABLE Producto ADD COLUMN sincronizado TEXT;
  611. ''');
  612. await db.execute('''
  613. ALTER TABLE CategoriaProducto ADD COLUMN idWeb INTEGER;
  614. ''');
  615. await db.execute('''
  616. ALTER TABLE CategoriaProducto ADD COLUMN sincronizado TEXT;
  617. ''');
  618. break;
  619. }
  620. oldVersion++;
  621. }
  622. }
  623. Future<int> guardar(T model) async {
  624. try {
  625. // Convert the model to JSON for the database
  626. String modelo = json.encode(model, toEncodable: toEncodable);
  627. Map<String, dynamic> modelMap = json.decode(modelo);
  628. var dbClient = await db;
  629. String nombreTabla = model.runtimeType.toString();
  630. // Check if the model has a String ID or an int ID
  631. dynamic id = modelMap['id'];
  632. bool isStringId = id is String;
  633. bool isIntId = id is int;
  634. // If id is of type String (e.g., Permiso)
  635. if (isStringId) {
  636. if (id == null || (id as String).isEmpty) {
  637. throw Exception('El ID del modelo no puede ser nulo o vacío');
  638. }
  639. // Check for existing record with the String ID
  640. List<Map> existing = await dbClient!.query(
  641. nombreTabla,
  642. where: 'id = ?',
  643. whereArgs: [id],
  644. );
  645. if (existing.isNotEmpty) {
  646. await dbClient.update(
  647. nombreTabla,
  648. modelMap,
  649. where: 'id = ?',
  650. whereArgs: [id],
  651. );
  652. } else {
  653. print(
  654. "Insertando nuevo registro en la tabla $nombreTabla con ID: $id");
  655. await dbClient.insert(nombreTabla, modelMap);
  656. }
  657. return 1;
  658. } else if (isIntId) {
  659. // If id is of type int (e.g., other models)
  660. if (id == null || id == 0) {
  661. modelMap
  662. .remove('id'); // Remove id if it's null or 0 for auto-increment
  663. }
  664. List<Map> existing = (id != null && id > 0)
  665. ? await dbClient!
  666. .query(nombreTabla, where: 'id = ?', whereArgs: [id])
  667. : [];
  668. if (existing.isNotEmpty) {
  669. print("Actualizando registro existente con ID: $id");
  670. await dbClient!.update(
  671. nombreTabla,
  672. modelMap,
  673. where: 'id = ?',
  674. whereArgs: [id],
  675. );
  676. } else {
  677. print("Insertando nuevo registro en la tabla $nombreTabla");
  678. id = await dbClient!.insert(nombreTabla, modelMap);
  679. }
  680. return id as int;
  681. } else {
  682. throw Exception('Tipo de ID no soportado');
  683. }
  684. } catch (e) {
  685. print('Error al guardar en dynamic: $e');
  686. return 0;
  687. }
  688. }
  689. Future<int> guardarPedidoProducto(PedidoProducto pedidoProducto) async {
  690. try {
  691. var dbClient = await db;
  692. // Busca registros existentes
  693. List<Map<String, dynamic>> existingRecords = await dbClient!.query(
  694. 'PedidoProducto',
  695. where: 'idPedido = ? AND idProducto = ?',
  696. whereArgs: [pedidoProducto.idPedido, pedidoProducto.idProducto],
  697. );
  698. if (existingRecords.isNotEmpty) {
  699. // Obtiene el ID existente
  700. int existingId = existingRecords.first['id'] as int;
  701. // Clona el mapa JSON y elimina el campo 'id' para la actualización
  702. Map<String, dynamic> dataToUpdate = Map.from(pedidoProducto.toJson());
  703. dataToUpdate.remove('id');
  704. // Actualiza el registro
  705. await dbClient.update(
  706. 'PedidoProducto',
  707. dataToUpdate,
  708. where: 'id = ?',
  709. whereArgs: [existingId],
  710. );
  711. print(
  712. "Registro actualizado para idPedido: ${pedidoProducto.idPedido}, idProducto: ${pedidoProducto.idProducto}");
  713. return existingId;
  714. } else {
  715. // Inserta un nuevo registro eliminando el campo 'id' antes de insertar
  716. Map<String, dynamic> dataToInsert = Map.from(pedidoProducto.toJson());
  717. dataToInsert.remove('id');
  718. int id = await dbClient.insert('PedidoProducto', dataToInsert);
  719. print(
  720. "Registro insertado para idPedido: ${pedidoProducto.idPedido}, idProducto: ${pedidoProducto.idProducto}");
  721. return id;
  722. }
  723. } catch (e) {
  724. print('Error al guardar PedidoProducto: $e');
  725. return 0;
  726. }
  727. }
  728. Future<PedidoProducto?> obtenerPorIdPedidoYProducto({
  729. required int idPedido,
  730. required int idProducto,
  731. }) async {
  732. Database? dbClient = await db;
  733. List<Map<String, dynamic>> maps = await dbClient!.query(
  734. 'PedidoProducto',
  735. where: 'idPedido = ? AND idProducto = ?',
  736. whereArgs: [idPedido, idProducto],
  737. );
  738. if (maps.isNotEmpty) {
  739. return PedidoProducto.fromJson(Map<String, dynamic>.from(maps.first));
  740. }
  741. return null; // Retorna null si no se encuentra ningún registro
  742. }
  743. void asignarFechasLocalmente(Basico model) {
  744. DateTime ahora = DateTime.now();
  745. if (model.creado == null) {
  746. model.creado = ahora.toUtc();
  747. }
  748. model.modificado = ahora.toUtc();
  749. }
  750. Future<void> _guardarToppings(
  751. Database db, int idProducto, List<Producto>? topings) async {
  752. await db.delete('ProductoTopping',
  753. where: 'idProducto = ?', whereArgs: [idProducto]);
  754. if (topings != null) {
  755. for (var topping in topings) {
  756. await db.insert('ProductoTopping', {
  757. 'idProducto': idProducto,
  758. 'idTopping': topping.id,
  759. });
  760. }
  761. }
  762. }
  763. Future<int> guardarLocal(T model) async {
  764. var dbClient = await db;
  765. String nombreTabla = model.runtimeType.toString();
  766. String modelo = json.encode(model, toEncodable: toEncodable);
  767. Map<String, dynamic> modelMap = json.decode(modelo);
  768. if (nombreTabla == "PedidoProductoTopping") {
  769. modelMap.remove('idLocal');
  770. modelMap.remove('eliminado');
  771. }
  772. if (modelMap['id'] == null || modelMap['id'] == 0) {
  773. modelMap.remove('id');
  774. }
  775. int resultado;
  776. int? identificadorLocal = modelMap[Basico.identificadorLocal];
  777. if (identificadorLocal != null && identificadorLocal > 0) {
  778. resultado = await dbClient!.update(
  779. nombreTabla,
  780. modelMap,
  781. where: "$idLocal = ?",
  782. whereArgs: [identificadorLocal],
  783. );
  784. } else {
  785. resultado = await dbClient!.insert(nombreTabla, modelMap);
  786. var rawQuery =
  787. await dbClient.rawQuery("SELECT last_insert_rowid() as id");
  788. if (rawQuery.isNotEmpty) {
  789. resultado = int.parse(rawQuery.first["id"].toString());
  790. modelMap[Basico.identificadorLocal] = resultado;
  791. }
  792. }
  793. if (model is Pedido) {
  794. model.id = resultado;
  795. }
  796. if (model is Producto) {
  797. await _guardarToppings(dbClient!, model.id!, model.topings);
  798. }
  799. return resultado;
  800. }
  801. dynamic toEncodable(dynamic item) {
  802. return item.toJson();
  803. }
  804. Future<List<T>> obtenerTodos<T>({
  805. String where = 'eliminado IS NULL',
  806. List<dynamic>? whereArgs,
  807. String orderBy = 'id DESC',
  808. }) async {
  809. var db = await this.db;
  810. String tableName = T.toString();
  811. var result = await db!.query(
  812. tableName,
  813. where: where,
  814. whereArgs: whereArgs,
  815. orderBy: orderBy,
  816. );
  817. return result.map((map) => fromMap<T>(map)).toList();
  818. }
  819. T fromMap<T>(Map<String, dynamic> map) {
  820. switch (T) {
  821. case Pedido:
  822. return Pedido.fromJson(map) as T;
  823. case Producto:
  824. return Producto.fromJson(map) as T;
  825. case Usuario:
  826. return Usuario.fromJson(map) as T;
  827. case CorteCaja:
  828. return CorteCaja.fromJson(map) as T;
  829. case Propinas:
  830. return Propinas.fromJson(map) as T;
  831. default:
  832. throw Exception('Tipo no soportado');
  833. }
  834. }
  835. Future<Pedido?> obtenerPorId(int id) async {
  836. Database? dbClient = await db;
  837. List<Map> maps =
  838. await dbClient!.query('Pedido', where: 'id = ?', whereArgs: [id]);
  839. if (maps.isNotEmpty) {
  840. return Pedido.fromJson(Map<String, dynamic>.from(maps.first));
  841. }
  842. return null;
  843. }
  844. Future<List<PedidoProducto>> obtenerPorIdPedido(int idPedido) async {
  845. Database? dbClient = await db;
  846. List<Map> maps = await dbClient!
  847. .query('PedidoProducto', where: 'idPedido = ?', whereArgs: [idPedido]);
  848. return maps
  849. .map((map) => PedidoProducto.fromJson(Map<String, dynamic>.from(map)))
  850. .toList();
  851. }
  852. //CORTE CAJA
  853. Future<List<Pedido>> obtenerPedidosPorCorteCaja(String idCorteCaja) async {
  854. var dbClient = await db;
  855. List<Map<String, dynamic>> maps = await dbClient!.query(
  856. 'Pedido',
  857. where: 'idCorteCaja = ? AND eliminado IS NULL AND estatus != ?',
  858. whereArgs: [idCorteCaja, 'CANCELADO'],
  859. );
  860. return maps.map((map) => Pedido.fromJson(map)).toList();
  861. }
  862. Future<List<Deposito>> obtenerDepositosPorIdCorteCaja(
  863. String idCorteCaja) async {
  864. var dbClient = await db;
  865. List<Map<String, dynamic>> maps = await dbClient!.query(
  866. 'Deposito',
  867. where: 'idCorteCaja = ? AND eliminado IS NULL',
  868. whereArgs: [idCorteCaja],
  869. );
  870. return maps.map((map) => Deposito.fromJson(map)).toList();
  871. }
  872. Future<List<Retiro>> obtenerRetirosPorIdCorteCaja(String idCorteCaja) async {
  873. var dbClient = await db;
  874. List<Map<String, dynamic>> maps = await dbClient!.query(
  875. 'Retiro',
  876. where: 'idCorteCaja = ? AND eliminado IS NULL',
  877. whereArgs: [idCorteCaja],
  878. );
  879. return maps.map((map) => Retiro.fromJson(map)).toList();
  880. }
  881. Future<List<Gasto>> obtenerGastosPorIdCorteCaja(String idCorteCaja) async {
  882. var dbClient = await db;
  883. List<Map<String, dynamic>> maps = await dbClient!.query(
  884. 'Gasto',
  885. where: 'idCorteCaja = ? AND eliminado IS NULL',
  886. whereArgs: [idCorteCaja],
  887. );
  888. return maps.map((map) => Gasto.fromJson(map)).toList();
  889. }
  890. Future<int> contarPedidos() async {
  891. Database? dbClient = await db;
  892. var result = await dbClient!.rawQuery('SELECT COUNT(*) FROM Pedido');
  893. return Sqflite.firstIntValue(result) ?? 0;
  894. }
  895. Future<double?> obtenerFondoDiaSigDelUltimoCorte() async {
  896. var dbClient = await db;
  897. List<Map<String, dynamic>> result = await dbClient!.query(
  898. 'CorteCaja',
  899. orderBy: 'fechaApertura DESC',
  900. limit: 1,
  901. );
  902. if (result.isNotEmpty) {
  903. return result.first['fondoDiaSig'] as double?;
  904. }
  905. return null;
  906. }
  907. Future<List<Pedido>> obtenerPedidosPaginados(int limit, int offset) async {
  908. Database? dbClient = await db;
  909. List<Map<String, dynamic>> result = await dbClient!
  910. .query('Pedido', limit: limit, offset: offset, orderBy: 'id DESC');
  911. return result.map((map) => Pedido.fromJson(map)).toList();
  912. }
  913. Future<Producto?> obtenerProductoPorId(int idProducto) async {
  914. Database? dbClient = await db;
  915. List<Map> maps = await dbClient!
  916. .query('Producto', where: 'id = ?', whereArgs: [idProducto]);
  917. if (maps.isNotEmpty) {
  918. return Producto.fromJson(Map<String, dynamic>.from(maps.first));
  919. }
  920. return null;
  921. }
  922. Future<List<int>> obtenerToppingsPorProducto(int idProducto) async {
  923. var dbClient = await db;
  924. var result = await dbClient!.query(
  925. 'ProductoTopping',
  926. where: 'idProducto = ?',
  927. whereArgs: [idProducto],
  928. );
  929. return result.map((map) => map['idTopping'] as int).toList();
  930. }
  931. Future<List<PedidoProductoTopping>> obtenerToppingsPorPedidoProducto(
  932. int idPedidoProducto) async {
  933. var dbClient = await db;
  934. List<Map> maps = await dbClient!.query('PedidoProductoTopping',
  935. where: 'idPedidoProducto = ?', whereArgs: [idPedidoProducto]);
  936. if (maps.isNotEmpty) {
  937. return maps
  938. .map((map) =>
  939. PedidoProductoTopping.fromJson(Map<String, dynamic>.from(map)))
  940. .toList();
  941. }
  942. return [];
  943. }
  944. Future<int> obtenerProximoFolio() async {
  945. var dbClient = await db;
  946. var result = await dbClient!.rawQuery(
  947. 'SELECT MAX(CAST(folio AS INTEGER)) as last_folio FROM Pedido');
  948. if (result.isNotEmpty && result.first["last_folio"] != null) {
  949. return int.tryParse(result.first["last_folio"].toString())! + 1;
  950. }
  951. return 1;
  952. }
  953. Future<List<T>> buscarPorFolio(String folio) async {
  954. var dbClient = await db;
  955. List<Map<String, dynamic>> maps = await dbClient!.query(
  956. 'Pedido',
  957. where: 'folio LIKE ?',
  958. whereArgs: ['%$folio%'],
  959. );
  960. return maps.map((map) => fromMap<T>(map)).toList();
  961. }
  962. Future<List<Pedido>> buscarPorFecha(
  963. DateTime startDate, DateTime endDate) async {
  964. var dbClient = await db;
  965. String startDateString = startDate.toIso8601String();
  966. String endDateString = endDate.toIso8601String();
  967. print(
  968. 'Ejecutando consulta: SELECT * FROM Pedido WHERE peticion BETWEEN $startDateString AND $endDateString');
  969. List<Map<String, dynamic>> maps = await dbClient!.rawQuery('''
  970. SELECT * FROM Pedido
  971. WHERE peticion BETWEEN ? AND ?
  972. ''', [startDateString, endDateString]);
  973. print('Resultado de la consulta: ${maps.length} pedidos encontrados.');
  974. return maps.map((map) => Pedido.fromJson(map)).toList();
  975. }
  976. Future<List<CorteCaja>> buscarPorFechaCorte(
  977. DateTime startDate, DateTime endDate) async {
  978. var dbClient = await db;
  979. String startDateString = DateFormat('dd-MM-yyyy').format(startDate);
  980. String endDateString = DateFormat('dd-MM-yyyy 23:59:59').format(endDate);
  981. List<Map<String, dynamic>> maps = await dbClient!.query(
  982. 'CorteCaja',
  983. where: 'fecha BETWEEN ? AND ?',
  984. whereArgs: [startDateString, endDateString],
  985. );
  986. return maps.map((map) => CorteCaja.fromJson(map)).toList();
  987. }
  988. Future<void> eliminar<T>(int id) async {
  989. var dbClient = await db;
  990. String tableName = T.toString();
  991. await dbClient!.delete(tableName, where: 'id = ?', whereArgs: [id]);
  992. }
  993. Future<List<Descuento>> obtenerTodosDescuentos() async {
  994. var dbClient = await db;
  995. var result = await dbClient!.query('Descuento', orderBy: 'porcentaje ASC');
  996. return result.map((map) => Descuento.fromJson(map)).toList();
  997. }
  998. Future<int> guardarDescuento(Descuento descuento) async {
  999. var dbClient = await db;
  1000. if (descuento.id != null && descuento.id! > 0) {
  1001. return await dbClient!.update(
  1002. 'Descuento',
  1003. descuento.toJson(),
  1004. where: 'id = ?',
  1005. whereArgs: [descuento.id],
  1006. );
  1007. } else {
  1008. return await dbClient!.insert('Descuento', descuento.toJson());
  1009. }
  1010. }
  1011. Future<int> eliminarDescuento(int id) async {
  1012. var dbClient = await db;
  1013. return await dbClient!
  1014. .delete('Descuento', where: 'id = ?', whereArgs: [id]);
  1015. }
  1016. Future<Variable?> obtenerPorNombre(String nombre) async {
  1017. var dbClient = await db;
  1018. List<Map<String, dynamic>> maps = await dbClient!.query(
  1019. 'Variable',
  1020. where: 'nombre = ?',
  1021. whereArgs: [nombre],
  1022. );
  1023. if (maps.isNotEmpty) {
  1024. return Variable.fromJson(Map<String, dynamic>.from(maps.first));
  1025. }
  1026. return null;
  1027. }
  1028. Future<List<Pedido>> obtenerPedidosOrdenadosPorFecha() async {
  1029. var dbClient = await db;
  1030. String orderBy =
  1031. "datetime(substr(peticion, 7, 4) || '-' || substr(peticion, 4, 2) || '-' || substr(peticion, 1, 2) || ' ' || substr(peticion, 12)) ASC";
  1032. List<Map<String, dynamic>> result = await dbClient!.query(
  1033. 'Pedido',
  1034. where: 'sincronizado IS NULL',
  1035. orderBy: orderBy,
  1036. );
  1037. return result.map((map) => Pedido.fromJson(map)).toList();
  1038. }
  1039. Future<void> sincronizarCategorias(List<CategoriaProducto> categoriasApi,
  1040. {bool forzar = false}) async {
  1041. var db = await DatabaseService().db;
  1042. var categoriasLocalesQuery = await db!.query('CategoriaProducto');
  1043. List<CategoriaProducto> categoriasLocales = categoriasLocalesQuery
  1044. .map((e) => CategoriaProducto.fromJson(e))
  1045. .toList();
  1046. for (var categoriaApi in categoriasApi) {
  1047. var categoriaLocal = categoriasLocales.firstWhere(
  1048. (categoria) => categoria.id == categoriaApi.id,
  1049. orElse: () => CategoriaProducto(),
  1050. );
  1051. if (forzar ||
  1052. categoriaLocal.id != 0 &&
  1053. categoriaApi.modificado != null &&
  1054. (categoriaLocal.modificado == null ||
  1055. categoriaApi.modificado!
  1056. .isAfter(categoriaLocal.modificado!))) {
  1057. await DatabaseService().guardar(categoriaApi);
  1058. } else if (categoriaLocal.id == 0) {
  1059. await DatabaseService().guardar(categoriaApi);
  1060. }
  1061. }
  1062. }
  1063. Future<void> sincronizarProductos(List<Producto> productosApi,
  1064. {bool forzar = false}) async {
  1065. var db = await DatabaseService().db;
  1066. // // Print del JSON recibido
  1067. // print(
  1068. // "Productos API recibidos: ${productosApi.map((e) => e.toJson()).toList()}");
  1069. var productosLocalesQuery = await db!.query('Producto');
  1070. List<Producto> productosLocales =
  1071. productosLocalesQuery.map((e) => Producto.fromJson(e)).toList();
  1072. for (var productoApi in productosApi) {
  1073. // Validar que el ID del producto no sea nulo
  1074. if (productoApi.id == null) {
  1075. print("Producto con ID nulo, se omite: ${productoApi.nombre}");
  1076. continue; // Ignorar productos sin ID
  1077. }
  1078. // Buscar el producto localmente
  1079. var productoLocal = productosLocales.firstWhere(
  1080. (producto) => producto.id == productoApi.id,
  1081. orElse: () =>
  1082. Producto(), // Si no existe el producto, devolver uno nuevo con id 0
  1083. );
  1084. if (productoLocal.id == 0) {
  1085. print("Insertando nuevo producto: ${productoApi.nombre}");
  1086. await DatabaseService().guardar(productoApi);
  1087. } else if (forzar ||
  1088. productoApi.modificado != null &&
  1089. (productoLocal.modificado == null ||
  1090. productoApi.modificado!.isAfter(productoLocal.modificado!))) {
  1091. print("Actualizando producto: ${productoApi.nombre}");
  1092. await DatabaseService().guardar(productoApi);
  1093. } else {
  1094. // Producto sin cambios
  1095. // print(
  1096. // "Producto sin cambios o datos insuficientes: ${productoApi.nombre}");
  1097. }
  1098. }
  1099. }
  1100. Future<void> sincronizarProductoTopping(
  1101. List<ProductoTopping> toppingsApi) async {
  1102. var db = await DatabaseService().db;
  1103. await db!.delete('ProductoTopping');
  1104. for (var toppingApi in toppingsApi) {
  1105. await DatabaseService().guardar(toppingApi);
  1106. }
  1107. print("Todos los registros de ProductoTopping han sido sincronizados.");
  1108. }
  1109. Future<void> sincronizarSucursales(List<Sucursal> sucursalesApi,
  1110. {bool forzar = false}) async {
  1111. var db = await DatabaseService().db;
  1112. int? idSucursalSeleccionada = await obtenerIdSucursalSeleccionada();
  1113. var sucursalesLocalesQuery = await db!.query('Sucursal');
  1114. List<Sucursal> sucursalesLocales =
  1115. sucursalesLocalesQuery.map((e) => Sucursal.fromJson(e)).toList();
  1116. for (var sucursalApi in sucursalesApi) {
  1117. var sucursalLocal = sucursalesLocales.firstWhere(
  1118. (sucursal) => sucursal.id == sucursalApi.id,
  1119. orElse: () => Sucursal(),
  1120. );
  1121. sucursalApi.seleccionado =
  1122. (sucursalApi.id == idSucursalSeleccionada) ? 1 : 0;
  1123. if (forzar ||
  1124. sucursalLocal.id != 0 &&
  1125. sucursalApi.modificado != null &&
  1126. (sucursalLocal.modificado == null ||
  1127. sucursalApi.modificado!.isAfter(sucursalLocal.modificado!))) {
  1128. await DatabaseService().guardar(sucursalApi);
  1129. } else if (sucursalLocal.id == 0) {
  1130. await DatabaseService().guardar(sucursalApi);
  1131. }
  1132. }
  1133. }
  1134. Future<void> sincronizarPermisos(List<Permiso> permisosApi,
  1135. {bool forzar = false}) async {
  1136. var db = await DatabaseService().db;
  1137. var permisosLocalesQuery = await db!.query('Permiso');
  1138. List<Permiso> permisosLocales =
  1139. permisosLocalesQuery.map((e) => Permiso.fromJson(e)).toList();
  1140. for (var permisoApi in permisosApi) {
  1141. var permisoLocal = permisosLocales.firstWhere(
  1142. (permiso) => permiso.id == permisoApi.id,
  1143. orElse: () => Permiso(),
  1144. );
  1145. if (forzar ||
  1146. permisoLocal.id != null &&
  1147. permisoApi.modificado != null &&
  1148. (permisoLocal.modificado == null ||
  1149. permisoApi.modificado!.isAfter(permisoLocal.modificado!))) {
  1150. print('Actualizando permiso con ID: ${permisoApi.id}');
  1151. await DatabaseService().guardar(permisoApi);
  1152. } else if (permisoLocal.id == null) {
  1153. print('Insertando nuevo permiso con ID: ${permisoApi.id}');
  1154. await DatabaseService().guardar(permisoApi);
  1155. } else {
  1156. //print('Permiso sin cambios: ${permisoApi.id}');
  1157. }
  1158. }
  1159. }
  1160. Future<void> sincronizarUsuarios(List<Usuario> usuariosApi,
  1161. {bool forzar = false}) async {
  1162. var db = await DatabaseService().db;
  1163. var usuariosLocalesQuery = await db!.query('Usuario');
  1164. List<Usuario> usuariosLocales =
  1165. usuariosLocalesQuery.map((e) => Usuario.fromJson(e)).toList();
  1166. for (var usuarioApi in usuariosApi) {
  1167. var usuarioLocal = usuariosLocales.firstWhere(
  1168. (usuario) => usuario.id == usuarioApi.id,
  1169. orElse: () => Usuario(),
  1170. );
  1171. // Comprobar si realmente se necesita actualizar el usuario basado en la fecha de modificado
  1172. if (forzar ||
  1173. usuarioLocal.id != 0 &&
  1174. usuarioApi.modificado != null &&
  1175. (usuarioLocal.modificado == null ||
  1176. usuarioApi.modificado!.isAfter(usuarioLocal.modificado!))) {
  1177. print('Actualizando usuario con ID: ${usuarioApi.id}');
  1178. await DatabaseService().guardar(usuarioApi);
  1179. // Comparar permisos antes de actualizarlos
  1180. await _actualizarPermisosUsuario(
  1181. db, usuarioApi.id!, usuarioApi.permisos!);
  1182. } else if (usuarioLocal.id == 0) {
  1183. print('Insertando nuevo usuario con ID: ${usuarioApi.id}');
  1184. await DatabaseService().guardar(usuarioApi);
  1185. // Insertar los permisos correspondientes
  1186. await _guardarPermisosUsuario(db, usuarioApi.id!, usuarioApi.permisos!);
  1187. } else {
  1188. //print('Usuario sin cambios: ${usuarioApi.id}');
  1189. }
  1190. }
  1191. }
  1192. Future<void> _actualizarPermisosUsuario(
  1193. Database db, int idUsuario, List<String> permisosApi) async {
  1194. // Obtener los permisos actuales del usuario
  1195. var permisosLocalesQuery = await db.query(
  1196. 'UsuarioPermiso',
  1197. where: 'idUsuario = ?',
  1198. whereArgs: [idUsuario],
  1199. );
  1200. List<String> permisosLocales = permisosLocalesQuery
  1201. .map((permiso) => permiso['idPermiso'] as String)
  1202. .toList();
  1203. // Comparar los permisos del API con los locales
  1204. bool sonIguales = _listasIguales(permisosLocales, permisosApi);
  1205. if (!sonIguales) {
  1206. // Si los permisos no son iguales, actualizarlos
  1207. print('Actualizando permisos del usuario con ID: $idUsuario');
  1208. await _guardarPermisosUsuario(db, idUsuario, permisosApi);
  1209. } else {
  1210. print('Permisos del usuario con ID: $idUsuario no han cambiado.');
  1211. }
  1212. }
  1213. Future<void> _guardarPermisosUsuario(
  1214. Database db, int idUsuario, List<String> permisos) async {
  1215. // Eliminar los permisos actuales solo si hay cambios
  1216. await db.delete('UsuarioPermiso',
  1217. where: 'idUsuario = ?', whereArgs: [idUsuario]);
  1218. // Insertar los nuevos permisos
  1219. for (var idPermiso in permisos) {
  1220. await db.insert('UsuarioPermiso', {
  1221. 'idUsuario': idUsuario,
  1222. 'idPermiso': idPermiso,
  1223. });
  1224. }
  1225. }
  1226. bool _listasIguales(List<String> lista1, List<String> lista2) {
  1227. if (lista1.length != lista2.length) return false;
  1228. lista1.sort();
  1229. lista2.sort();
  1230. for (int i = 0; i < lista1.length; i++) {
  1231. if (lista1[i] != lista2[i]) return false;
  1232. }
  1233. return true;
  1234. }
  1235. Future<String?> obtenerClaveSucursalSeleccionada() async {
  1236. var db = await this.db;
  1237. List<Map<String, dynamic>> queryResult = await db!.query(
  1238. 'Sucursal',
  1239. where: 'seleccionado = ? AND eliminado IS NULL',
  1240. whereArgs: [1],
  1241. limit: 1,
  1242. );
  1243. if (queryResult.isNotEmpty) {
  1244. Sucursal sucursalSeleccionada = Sucursal.fromJson(queryResult.first);
  1245. return sucursalSeleccionada.clave;
  1246. }
  1247. return null;
  1248. }
  1249. Future<int?> obtenerIdSucursalSeleccionada() async {
  1250. var db = await this.db;
  1251. List<Map<String, dynamic>> queryResult = await db!.query(
  1252. 'Sucursal',
  1253. where: 'seleccionado = ? AND eliminado IS NULL',
  1254. whereArgs: [1],
  1255. limit: 1,
  1256. );
  1257. if (queryResult.isNotEmpty) {
  1258. return Sucursal.fromJson(queryResult.first).id;
  1259. }
  1260. return null;
  1261. }
  1262. Future<void> forzarSincronizacion() async {
  1263. String? claveSucursal = await obtenerClaveSucursalSeleccionada();
  1264. try {
  1265. // Sincronizar categorías
  1266. await sincronizarCategorias(
  1267. await fetchCategoriasApi(claveSucursal: claveSucursal),
  1268. forzar: true);
  1269. // Sincronizar productos
  1270. await sincronizarProductos(
  1271. await fetchProductosApi(claveSucursal: claveSucursal),
  1272. forzar: true);
  1273. // Sincronizar toppings de producto
  1274. await sincronizarProductoTopping(
  1275. await fetchProductoToppingApi(claveSucursal: claveSucursal));
  1276. // Sincronizar sucursales
  1277. await sincronizarSucursales(await fetchSucursalesApi(), forzar: true);
  1278. // Sincronizar permisos
  1279. await sincronizarPermisos(await fetchPermisosApi(), forzar: true);
  1280. // Sincronizar usuarios
  1281. await sincronizarUsuarios(await fetchUsuariosApi(), forzar: true);
  1282. print('Sincronización forzosa completada.');
  1283. } catch (e) {
  1284. print('Error en la sincronización forzosa: $e');
  1285. }
  1286. }
  1287. Future<List<CategoriaProducto>> fetchCategoriasApi(
  1288. {String? claveSucursal}) async {
  1289. Map<String, String> parametros = {
  1290. "claveSucursal": claveSucursal!,
  1291. "limite": "-1"
  1292. };
  1293. final response = ApiResponse(
  1294. await BaseService().get('/pos/categoria', queryParameters: parametros));
  1295. return response.isOk && response.resultados != null
  1296. ? response.resultados!
  1297. .map((json) => CategoriaProducto.fromApi(json))
  1298. .toList()
  1299. : [];
  1300. }
  1301. Future<List<Producto>> fetchProductosApi({String? claveSucursal}) async {
  1302. Map<String, String> parametros = {
  1303. "limite": "-1",
  1304. "claveSucursal": claveSucursal!,
  1305. "expand": "media"
  1306. };
  1307. final response = ApiResponse(
  1308. await BaseService().get('/pos/producto', queryParameters: parametros));
  1309. if (response.isOk && response.resultados != null) {
  1310. List<Producto> productosApi =
  1311. response.resultados!.map((json) => Producto.fromApi(json)).toList();
  1312. return productosApi;
  1313. }
  1314. return [];
  1315. }
  1316. Future<List<ProductoTopping>> fetchProductoToppingApi(
  1317. {String? claveSucursal}) async {
  1318. Map<String, String> parametros = {
  1319. "limite": "-1",
  1320. "claveSucursal": claveSucursal!,
  1321. };
  1322. final response = ApiResponse(await BaseService()
  1323. .get('/pos/producto-topping', queryParameters: parametros));
  1324. return response.isOk && response.resultados != null
  1325. ? response.resultados!
  1326. .map((json) => ProductoTopping.fromApi(json))
  1327. .toList()
  1328. : [];
  1329. }
  1330. Future<List<Sucursal>> fetchSucursalesApi() async {
  1331. Map<String, String> parametros = {
  1332. "limite": "-1",
  1333. };
  1334. final response = ApiResponse(
  1335. await BaseService().get('/pos/sucursal', queryParameters: parametros));
  1336. return response.isOk && response.resultados != null
  1337. ? response.resultados!.map((json) => Sucursal.fromApi(json)).toList()
  1338. : [];
  1339. }
  1340. Future<List<Permiso>> fetchPermisosApi() async {
  1341. Map<String, String> parametros = {
  1342. "limite": "-1",
  1343. };
  1344. final response = ApiResponse(
  1345. await BaseService().get('/pos/permiso', queryParameters: parametros));
  1346. return response.isOk && response.resultados != null
  1347. ? response.resultados!.map((json) => Permiso.fromJson(json)).toList()
  1348. : [];
  1349. }
  1350. Future<List<Usuario>> fetchUsuariosApi() async {
  1351. Map<String, String> parametros = {
  1352. "limite": "-1",
  1353. "expand": "permisos",
  1354. };
  1355. final response = ApiResponse(
  1356. await BaseService().get('/pos/usuario', queryParameters: parametros));
  1357. return response.isOk && response.resultados != null
  1358. ? response.resultados!.map((json) => Usuario.fromApi(json)).toList()
  1359. : [];
  1360. }
  1361. Future<void> sincronizarMesas(List<Mesa> mesasApi,
  1362. {bool forzar = false}) async {
  1363. var db = await DatabaseService().db;
  1364. // Obtener mesas locales
  1365. var mesasLocalesQuery = await db!.query('Mesa');
  1366. List<Mesa> mesasLocales =
  1367. mesasLocalesQuery.map((e) => Mesa.fromJson(e)).toList();
  1368. for (var mesaApi in mesasApi) {
  1369. // Buscar la mesa localmente
  1370. var mesaLocal = mesasLocales.firstWhere(
  1371. (mesa) => mesa.id == mesaApi.id,
  1372. orElse: () => Mesa(),
  1373. );
  1374. // Validar si es una nueva mesa o si necesita ser actualizada
  1375. if (mesaLocal.id == 0) {
  1376. print("Insertando nueva mesa: ${mesaApi.nombre}");
  1377. await DatabaseService().guardar(mesaApi);
  1378. } else if (forzar ||
  1379. mesaApi.modificado != null &&
  1380. (mesaLocal.modificado == null ||
  1381. mesaApi.modificado!.isAfter(mesaLocal.modificado!))) {
  1382. print("Actualizando mesa: ${mesaApi.nombre}");
  1383. await DatabaseService().guardar(mesaApi);
  1384. }
  1385. }
  1386. }
  1387. Future<List<Producto>>
  1388. obtenerProductosNoSincronizadosOrdenadosPorFecha() async {
  1389. var dbClient = await db;
  1390. List<Map<String, dynamic>> result = await dbClient!.query(
  1391. 'Producto',
  1392. where: 'sincronizado IS NULL AND eliminado IS NULL',
  1393. orderBy: 'creado ASC',
  1394. );
  1395. return result.map((map) => Producto.fromJson(map)).toList();
  1396. }
  1397. Future<List<CategoriaProducto>>
  1398. obtenerCategoriasNoSincronizadasOrdenadasPorFecha() async {
  1399. var dbClient = await db;
  1400. // Similar a productos, ordenando por 'modificado'
  1401. List<Map<String, dynamic>> result = await dbClient!.query(
  1402. 'CategoriaProducto',
  1403. where: 'sincronizado IS NULL AND eliminado IS NULL',
  1404. orderBy: 'creado ASC',
  1405. );
  1406. return result.map((map) => CategoriaProducto.fromJson(map)).toList();
  1407. }
  1408. Future<void> actualizarProductoSincronizado(
  1409. int idProducto, int idWeb, String sincronizado) async {
  1410. var dbClient = await db;
  1411. await dbClient!.update(
  1412. 'Producto',
  1413. {
  1414. 'idWeb': idWeb,
  1415. 'sincronizado': sincronizado,
  1416. },
  1417. where: 'id = ?',
  1418. whereArgs: [idProducto],
  1419. );
  1420. }
  1421. Future<void> actualizarCategoriaSincronizada(
  1422. int idCategoria, int idWeb, String sincronizado) async {
  1423. var dbClient = await db;
  1424. await dbClient!.update(
  1425. 'CategoriaProducto',
  1426. {
  1427. 'idWeb': idWeb,
  1428. 'sincronizado': sincronizado,
  1429. },
  1430. where: 'id = ?',
  1431. whereArgs: [idCategoria],
  1432. );
  1433. }
  1434. Future<List<Pedido>> obtenerPedidosConPropinasPorCorte(
  1435. String idCorteCaja) async {
  1436. Database? dbClient = await db;
  1437. List<Map<String, dynamic>> maps = await dbClient!.rawQuery('''
  1438. SELECT *
  1439. FROM Pedido
  1440. WHERE idCorteCaja = ?
  1441. AND estatus = 'TERMINADO'
  1442. AND eliminado IS NULL
  1443. AND id IN (
  1444. SELECT idPedido
  1445. FROM Propinas
  1446. WHERE eliminado IS NULL
  1447. )
  1448. ORDER BY id DESC
  1449. ''', [idCorteCaja]);
  1450. List<Pedido> pedidos = [];
  1451. for (var map in maps) {
  1452. Pedido pedido = Pedido.fromJson(map);
  1453. List<Propinas> propinas = await obtenerPropinasPorPedido(pedido.id!);
  1454. pedido.propinas = propinas;
  1455. pedidos.add(pedido);
  1456. }
  1457. return pedidos;
  1458. }
  1459. Future<List<Propinas>> obtenerPropinasPorPedido(int idPedido) async {
  1460. Database? dbClient = await db;
  1461. List<Map<String, dynamic>> maps = await dbClient!.query(
  1462. 'Propinas',
  1463. where: 'idPedido = ? AND eliminado IS NULL',
  1464. whereArgs: [idPedido],
  1465. );
  1466. return maps.map((map) => Propinas.fromJson(map)).toList();
  1467. }
  1468. }