From 7fdf31f02a2944bede172239a9b10eb78075fc5d Mon Sep 17 00:00:00 2001 From: Jose Alberto Guerra Ugalde Date: Wed, 31 Jan 2024 16:53:55 -0600 Subject: [PATCH] Commit Inicial --- .gitignore | 2 + B4A/B4XMainPage.bas | 85 + B4A/C_Principal.bas | 966 +++++++++++ B4A/DBRequestManager.bas | 277 ++++ B4A/Files/candado.png | Bin 0 -> 17760 bytes B4A/Files/durakelo.png | Bin 0 -> 7098 bytes B4A/Files/engrane.png | Bin 0 -> 1860 bytes B4A/Files/engranes.png | Bin 0 -> 2735 bytes B4A/Files/kmt.db | Bin 0 -> 66560 bytes B4A/Files/login.bal | Bin 0 -> 11863 bytes B4A/Files/logo.png | Bin 0 -> 6777 bytes B4A/Files/mainpage.bal | Bin 0 -> 1584 bytes B4A/Files/mesasitem.bal | Bin 0 -> 2460 bytes B4A/Files/principal.bal | Bin 0 -> 28832 bytes B4A/Files/proditem.bal | Bin 0 -> 5149 bytes B4A/Files/proditemcarrito.bal | Bin 0 -> 5859 bytes B4A/Files/usuario.png | Bin 0 -> 17227 bytes ...solated-on-white_12833309-[convertido].png | Bin 0 -> 14983 bytes B4A/MarketPlace.b4a | 123 ++ B4A/MarketPlace.b4a.meta | 24 + B4A/Starter.bas | 120 ++ B4A/Subs.bas | 1408 +++++++++++++++++ B4A/errorManager.bas | 167 ++ gitpull.bat | 1 + 24 files changed, 3173 insertions(+) create mode 100644 .gitignore create mode 100644 B4A/B4XMainPage.bas create mode 100644 B4A/C_Principal.bas create mode 100644 B4A/DBRequestManager.bas create mode 100644 B4A/Files/candado.png create mode 100644 B4A/Files/durakelo.png create mode 100644 B4A/Files/engrane.png create mode 100644 B4A/Files/engranes.png create mode 100644 B4A/Files/kmt.db create mode 100644 B4A/Files/login.bal create mode 100644 B4A/Files/logo.png create mode 100644 B4A/Files/mainpage.bal create mode 100644 B4A/Files/mesasitem.bal create mode 100644 B4A/Files/principal.bal create mode 100644 B4A/Files/proditem.bal create mode 100644 B4A/Files/proditemcarrito.bal create mode 100644 B4A/Files/usuario.png create mode 100644 B4A/Files/vecteezy_white-diagonal-stripes-with-red-line-isolated-on-white_12833309-[convertido].png create mode 100644 B4A/MarketPlace.b4a create mode 100644 B4A/MarketPlace.b4a.meta create mode 100644 B4A/Starter.bas create mode 100644 B4A/Subs.bas create mode 100644 B4A/errorManager.bas create mode 100644 gitpull.bat diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..af94e9d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +**/Objects +**/AutoBackups \ No newline at end of file diff --git a/B4A/B4XMainPage.bas b/B4A/B4XMainPage.bas new file mode 100644 index 0000000..7ee2745 --- /dev/null +++ b/B4A/B4XMainPage.bas @@ -0,0 +1,85 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Class +Version=9.85 +@EndOfDesignText@ +#Region Shared Files + 'Ctrl + click to sync files: ide://run?file=%WINDIR%\System32\Robocopy.exe&args=..\..\Shared+Files&args=..\Files&FilesSync=True + '########################################################################################################### + '###################### PULL ############################################################# + 'Ctrl + click ide://run?file=%WINDIR%\System32\cmd.exe&Args=/c&Args=git&Args=pull + '########################################################################################################### + '###################### PUSH ############################################################# + 'Ctrl + click ide://run?file=%WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe&Args=github&Args=..\..\ + '########################################################################################################### + '###################### PUSH TORTOISE GIT ######################################################### + 'Ctrl + click ide://run?file=%WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe&Args=TortoiseGitProc&Args=/command:commit&Args=/path:"./../../"&Args=/closeonend:2 + '########################################################################################################### +#End Region + +'Ctrl + click to export as zip: ide://run?File=%B4X%\Zipper.jar&Args=Project.zip + +Sub Class_Globals + Private Root As B4XView + Private xui As XUI + Public principal As C_Principal + Private i_logo As ImageView + Private p_configuracion As Panel + Private p_login As Panel + Private b_regresar As Button + Private b_entrar As Button + Private b_envioBD As Button + Private B_SERVER As Button + Private ImageView4 As ImageView + Private ImageView2 As ImageView + Private Panel3 As Panel + Private Label1 As Label +End Sub + +Public Sub Initialize +' B4XPages.GetManager.LogEvents = True +End Sub + +'This event will be called once, before the page becomes visible. +Private Sub B4XPage_Created (Root1 As B4XView) + Root = Root1 + Root.LoadLayout("login") + principal.Initialize + B4XPages.AddPage("Principal", principal) + p_login.Width = Root.Width + p_login.Height = Root.Height + Subs.agregaColumna("cat_gunaprod", "CAT_PT_DESC", "TEXT") + Subs.agregaColumna("cat_gunaprod", "CAT_PS_DESC", "TEXT") + Subs.agregaColumna("cat_gunaprod", "CAT_PS_DESC", "TEXT") + Subs.agregaColumna("cat_gunaprod", "CAT_GP_FECHA", "TEXT") + Subs.agregaColumna("cat_gunaprod", "CAT_GP_FECHA_MOD", "TEXT") + Starter.skmt.ExecNonQuery("delete from cuentaa") + Starter.skmt.ExecNonQuery("insert into cuentaa (cuenta) values ('123456')") + Starter.skmt.ExecNonQuery("delete from cat_almacen") + Starter.skmt.ExecNonQuery("insert into cat_almacen (id_almacen) values ('1')") +End Sub + +'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage. + +Private Sub i_logo_Click + p_configuracion.Width = Root.Width + p_configuracion.Height = Root.Height + Subs.panelVisible(p_configuracion, 0, 0) +End Sub + +Private Sub b_regresar_Click + Subs.panelVisible(p_login, 0, 0) +End Sub + +Private Sub b_entrar_Click + B4XPages.ShowPage("principal") +End Sub + +Private Sub B_SERVER_Click + +End Sub + +Private Sub b_envioBD_Click + +End Sub \ No newline at end of file diff --git a/B4A/C_Principal.bas b/B4A/C_Principal.bas new file mode 100644 index 0000000..600a077 --- /dev/null +++ b/B4A/C_Principal.bas @@ -0,0 +1,966 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Class +Version=12.2 +@EndOfDesignText@ +Sub Class_Globals + Private Root As B4XView 'ignore + Private xui As XUI 'ignore + Private p_principal As Panel + Private WobbleMenu1 As WobbleMenu + Dim PCLV, PCLVM As PreoptimizedCLV + Private p_productos As Panel + Private clv_prods_ll, clv_carrito, clv As CustomListView + Dim prodsMap As Map + Private p_botonesVenta As Panel + Private b_continuar As Button + Private lfila As Label + Private et_busca As EditText + Private b_buscar As Button + Dim etCantHasFocus, hayPedido As Boolean 'ignore + Dim ticketId As String + Dim rutaUsuario, folio As String 'ignore + Dim query As String + Dim listaProds, listaHints, listaHintsM, list_prodsPedido As List + Dim reiniciarlistaProds As Boolean = False 'ignore + Dim forzarBusqueda As Boolean = False +' Private lv_promos As ListView + Private b_prodMenos As Button + Private et_pCant As EditText + Private l_pCant As Label + Private b_prodMas As Button + Private p_botMasMen As Panel + Private l_prodX As Label + Private i_prod As ImageView + Private p_prods As Panel + Private p_mesas As Panel +' Private lv_carrito As ListView + Private p_carrito As Panel + Private p_botonesCarrito As Panel + Private b_terminar As Button + Private p_historial As Panel +' Private p_botonesHist As Panel + Private l_compraTerminada As Label + Private l_carritoVacio As Label + Private b_borrar As Button + Private l_totalCarrito As Label + Private l_historialVacio As Label + Private lv_historial As ListView + Private clv_mesas As CustomListView + Private l_mesaX As Label + Private l_estatus As Label + Private l_mesa As Label + Private p_mesa As Panel + Private b_abrirMesa As Button + Private cb_comensales As B4XComboBox + Private cb_mesero As B4XComboBox + Private l_mesero As Label + Private l_comensales As Label + Private l_pago As Label + Private cb_pago As B4XComboBox + Private p_mesaCampos As Panel + Private p_mesasItem As Panel + Private l_comensalesAbierta2 As Label + Private l_meseroAbierta2 As Label + Private b_mesaEditar As Button + Private b_mesaCerrar As Button + Private p_mesaAbierta As Panel + Private lv_categorias As ListView + Private p_pago As Panel + Private Label1 As Label + Private b_pagoCerrar As Button +End Sub + +'You can add more parameters here. +Public Sub Initialize As Object + Return Me +End Sub + +'This event will be called once, before the page becomes visible. +Private Sub B4XPage_Created (Root1 As B4XView) + Root = Root1 + 'load the layout to Root + Root.LoadLayout("principal") +' p_principal.Width = Root.Width +' p_principal.Height = Root.Height + Subs.panelWH(p_principal, Root.Width, Root.Height) + Subs.panelWH(p_mesa, Root.Width, Root.Height - WobbleMenu1.Height) + If File.Exists(Starter.ruta, "kmt.db") = False Then + File.Copy(File.DirAssets, "kmt.db", Starter.ruta, "kmt.db") + End If + PCLV.Initialize(Me, "PCLV", clv_prods_ll) + PCLVM.Initialize(Me, "PCLVM", clv_mesas) + WobbleMenu1.SetTabTextIcon(1,"Mesas", Chr(0xF0C0), Typeface.FONTAWESOME) + WobbleMenu1.SetTabTextIcon(2,"Productos", Chr(0xF007), Typeface.FONTAWESOME) + WobbleMenu1.SetTabTextIcon(3,"Carrito", Chr(0xF2BE), Typeface.FONTAWESOME) + WobbleMenu1.SetTabTextIcon(4,"Historial", Chr(0xF21B), Typeface.FONTAWESOME) +' WobbleMenu1.SetTabTextIcon(5,"Cinco", Chr(0xF29D), Typeface.FONTAWESOME) + p_principal.Width = Root.Width + p_principal.Height = Root.Height + clv_prods_ll.GetBase.SetLayoutAnimated(0, 5dip, (l_meseroAbierta2.Top + l_meseroAbierta2.Height + 5), Root.Width + 10, Root.Height * 0.55) 'Cambiamos el tamaño y posición de la lista de productos. + clv_prods_ll.Base_Resize(clv_prods_ll.GetBase.Width, clv_prods_ll.GetBase.Height) 'Cambiamos el tamaño del panel interno de la lista para que se ajuste al nuevo tamaño. + clv_carrito.GetBase.SetLayoutAnimated(0, 5dip, 80dip, Root.Width - 20, Root.Height * 0.65) 'Cambiamos el tamaño y posición de la lista del carrito. + clv_carrito.Base_Resize(clv_carrito.GetBase.Width, clv_carrito.GetBase.Height) 'Cambiamos el tamaño del panel interno del carrito para que se ajuste al nuevo tamaño. + clv_mesas.GetBase.SetLayoutAnimated(0, 5dip, 80dip, Root.Width - 20, Root.Height * 0.80) 'Cambiamos el tamaño y posición de la lista de mesas. + clv_mesas.Base_Resize(clv_mesas.GetBase.Width, clv_mesas.GetBase.Height) 'Cambiamos el tamaño del panel interno de las mesas para que se ajuste al nuevo tamaño. + p_productos.Width = Root.Width + p_productos.Height = Root.Height - WobbleMenu1.Height + p_carrito.Width = Root.Width + p_carrito.Height = Root.Height - WobbleMenu1.Height + p_mesas.Width = Root.Width + p_mesaAbierta.Height = Root.Height + p_mesas.Height = Root.Height - WobbleMenu1.Height + p_historial.Width = Root.Width + p_historial.Height = Root.Height - WobbleMenu1.Height + p_botonesVenta.Top = Root.Height - p_botonesVenta.Height - WobbleMenu1.Height + 10 + p_botonesCarrito.Top = Root.Height - p_botonesCarrito.Height - WobbleMenu1.Height + 10 + Subs.centraPanel(p_pago, p_mesaAbierta.Width) + Subs.centraBoton(b_abrirMesa, Root.Width) + b_mesaCerrar.Top = clv_prods_ll.AsView.top + clv_prods_ll.AsView.Height + 15 ' - b_mesaCerrar.Height +' Subs.centraEtiqueta(l_mesa, Root.Width) +' Subs.centraEtiqueta(l_comensales, Root.Width) +' Subs.centraEtiqueta(l_mesero, Root.Width) + Subs.centraPanel(p_mesaCampos, Root.Width) + Subs.centraPanel(p_mesaAbierta, Root.Width) + Dim ri As Cursor = Starter.skmt.ExecQuery($"select count(*) as cuantos from cat_gunaprod"$) + ri.Position = 0 + If ri.GetString("cuantos") = "0" Then 'Si no hay productos, los descargamos + Starter.reqManager.Initialize(Me, Starter.server) + Dim cmd As DBCommand + cmd.Initialize + cmd.Name = "selectPedigree" + cmd.Parameters = Array As Object(DateTime.Date(DateTime.Now)) + Log($"Traemos productos, ${DateTime.Date(DateTime.Now)}"$) + Starter.reqManager.ExecuteQuery(cmd , 0, "descargaProds") + End If + query = "cat_gunaprod" + prodsMap.Initialize + listaProds.Initialize + listaHints.Initialize + listaHintsM.Initialize + p_mesas.Width = Root.Width +' Log(p_productos.Width) + Subs.panelVisible(p_mesas, 0, 0) + cb_comensales.SetItems(Array As String(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)) + cb_pago.SetItems(Array As String("Efectivo", "Tarjeta")) + cb_mesero.SetItems(Subs.traeMeserosLista) +End Sub + +Sub B4XPage_Appear +' ticketId = Subs.traeTicket +' rutaUsuario = Subs.traeMesa +' Log($"${clv_carrito.AsView.Width}, ${Root.Width}"$) + clv = clv_prods_ll + cuentaProds +' LlenaProdsLL(Null, Null) + LlenaMesas(Null, Null) + LlenaProdsLL(Null, Null) + PCLV.lblHint.SetTextSizeAnimated(0,13) + PCLV.B4XSeekBar1.Color1=Colors.DarkGray + PCLV.B4XSeekBar1.Color2=Colors.DarkGray + PCLV.B4XSeekBar1.ThumbColor=Colors.red + PCLV.B4XSeekBar1.Radius1 = 15 + PCLV.B4XSeekBar1.Radius2 = 20 + PCLV.B4XSeekBar1.mBase.Left=Root.Width * 0.85 + PCLV.B4XSeekBar1.mBase.Width=50dip +' PCLV.B4XSeekBar1.mBase.Top=-50 + PCLV.B4XSeekBar1.mBase.Height=clv_prods_ll.AsView.Height + PCLV.pnlOverlay.Height = clv_prods_ll.AsView.Height + PCLV.pnlOverlay.Width = clv_prods_ll.AsView.Width + PCLV.B4XSeekBar1.Update + If clv_mesas.Size > 0 Then + clv_mesas.JumpToItem(0) 'Vamos al primer artículo de la lista. + End If + PCLVM.lblHint.SetTextSizeAnimated(0,13) + PCLVM.B4XSeekBar1.Color1=Colors.DarkGray + PCLVM.B4XSeekBar1.Color2=Colors.DarkGray + PCLVM.B4XSeekBar1.ThumbColor=Colors.red + PCLVM.B4XSeekBar1.Radius1 = 15 + PCLVM.B4XSeekBar1.Radius2 = 20 + PCLVM.B4XSeekBar1.mBase.Left=Root.Width * 0.88 +' PCLVM.B4XSeekBar1.mBase.Top=-50 + PCLVM.B4XSeekBar1.mBase.Height=clv_mesas.AsView.Height + PCLVM.pnlOverlay.Height = clv_mesas.AsView.Height + PCLVM.pnlOverlay.Width = clv_mesas.AsView.Width + PCLVM.B4XSeekBar1.Update + p_productos.Height = Root.Height - WobbleMenu1.Height + If et_busca.Text <> "" Then et_busca.Text ="" +End Sub + +Sub B4XPage_CloseRequest As ResumableSub + ' BACK key pressed + 'Return True to close, False to cancel + Log(1) + If p_mesa.Visible Then + p_mesa.Visible = False + p_mesas.Visible = True + LlenaMesas(Null, Null) + Else if p_carrito.Visible Then +' p_carrito.Visible = False +' p_mesas.Visible = True + WobbleMenu1_Tab1Click + WobbleMenu1.SetCurrentTab(1) +' Else +' Subs.iniciaActividad("Login") + End If + Return False +End Sub + +Sub JobDone(Job As HttpJob) + If Starter.Logger Then LogColor("Principal - JobDone", Colors.Magenta) + If Job.Success = False Then +' ToastMessageShow("Error: " & Job.ErrorMessage, True) + Else + If Starter.Logger Then LogColor("JobDone: '" & Starter.reqManager.HandleJob(Job).tag & "' - Registros: " & Starter.reqManager.HandleJob(Job).Rows.Size, Colors.Green) 'Mod por CHV - 211110 + If Job.JobName = "DBRequest" Then + Dim result As DBResult = Starter.reqManager.HandleJob(Job) + If result.Tag = "descargaProds" Then 'query tag +' If Starter.Logger Then Subs.logJobDoneResultados(result) + Starter.skmt.BeginTransaction + For Each records() As Object In result.Rows + Log($"ID: ${records(result.Columns.Get("CAT_GP_ID"))}, NOM: ${records(result.Columns.Get("CAT_GP_NOMBRE"))}"$) + Dim CAT_GP_ID As String = records(result.Columns.Get("CAT_GP_ID")) + Dim CAT_GP_NOMBRE As String = records(result.Columns.Get("CAT_GP_NOMBRE")) + Dim CAT_GP_PRECIO As String = records(result.Columns.Get("CAT_GP_PRECIO")) + Dim CAT_GP_ALMACEN As String = records(result.Columns.Get("CAT_GP_ALMACEN")) + Dim CAT_PT_DESC As String = records(result.Columns.Get("CAT_PT_DESC")) + Dim CAT_PS_DESC As String = records(result.Columns.Get("CAT_PS_DESC")) + Dim CAT_GP_IMG() As Byte = records(result.Columns.Get("CAT_GP_IMG")) + Dim CAT_GP_FECHA As String = records(result.Columns.Get("CAT_GP_FECHA")) + Dim CAT_GP_FECHA_MOD As String = records(result.Columns.Get("CAT_GP_FECHA_MOD")) + Dim CAT_GP_CLASIF As String = records(result.Columns.Get("CAT_GP_CLASIF")) + Starter.skmt.ExecNonQuery2("INSERT INTO CAT_GUNAPROD(CAT_GP_ID,CAT_GP_NOMBRE,CAT_GP_PRECIO,CAT_GP_ALMACEN,CAT_PT_DESC,CAT_PS_DESC,CAT_GP_IMG,CAT_GP_FECHA,CAT_GP_FECHA_MOD, CAT_GP_CLASIF) VALUES (?,?,?,?,?,?,?,?,?,?)", Array As Object (CAT_GP_ID,CAT_GP_NOMBRE,CAT_GP_PRECIO,CAT_GP_ALMACEN,CAT_PT_DESC,CAT_PS_DESC,CAT_GP_IMG,CAT_GP_FECHA,CAT_GP_FECHA_MOD,CAT_GP_CLASIF)) + Next +' Starter.skmt.ExecNonQuery2("INSERT INTO kmt_info(CAT_CL_CODIGO,CAT_CL_RUTA,CAT_CL_NOMBRE,CAT_CL_ATIENDE1,CAT_CL_ATIENTE2,CAT_CL_TELEFONO,CAT_CL_EMAIL,CAT_CL_CALLE,CAT_CL_NOEXT,CAT_CL_NOINT,CAT_CL_CALLE1,CAT_CL_CALLE2,CAT_CL_COLONIA,CAT_CL_MUNI,CAT_CL_EDO,CAT_CL_CP,CAT_CL_LONG,CAT_CL_LAT,CAT_CL_BFACTURA,CAT_CL_BCREDITO,CAT_CL_MTOCOMPRA,CAT_CL_NUM_SERIEFISICO,CAT_CL_DIAS_VISITA, gestion, IMPRESION) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,0,0,0,?,0,0) ",Array As Object ("0",e_ruta.TEXT, "VENTA ABORDO","null","null","null","null","null","null","null","null","null","null","null","null","NULL","null","null","NULL","NULL")) + Starter.skmt.TransactionSuccessful 'Si no se pone TransactionSuccessful no se escribe NADA!! + Starter.skmt.EndTransaction +' LlenaProdsLL(Null, Null) + End If + End If + End If + Job.Release +End Sub + +Sub b_prodMenos_Click + etCantHasFocus = False + If WobbleMenu1.GetCurrentTab = 3 Then clv = clv_carrito Else clv = clv_prods_ll +' Log(Sender.As(Button).text & "|" & Sender.As(Button).tag) + Private buttonTag As String = Sender.As(Button).tag + LogColor("b_prodMenos_Click", Colors.Magenta) + Dim index As Int = clv.GetItemFromView(Sender) + LogColor(clv.GetValue(index), Colors.Magenta) + Private inv As Int = clv.GetValue(index).As(Map).Get("almacen") + Dim pnl0 As B4XView = clv.GetPanel(index) + Log(pnl0.As(Panel)) + Dim pnl As B4XView = pnl0.GetView(0) + Dim laCant As B4XView = pnl.GetView(2).GetView(2) +' Log(pnl.GetView(0).NumberOfViews) + Dim elNombre As B4XView = pnl.GetView(1) + If WobbleMenu1.GetCurrentTab = 3 Then laCant = pnl.GetView(2).GetView(4) + Log($"${pnl.GetView(1)}${CRLF}${pnl.GetView(2).GetView(2)}${CRLF}${pnl.GetView(2).GetView(3)}${CRLF}${pnl.GetView(2).GetView(4)}"$) +' Log($"precio|stock:${laCant.tag}"$) +' Log("lacant.text="&laCant.text & "|" & buttonTag) + If buttonTag = "vendido" And laCant.Text > 0 Then + Log(clv.GetValue(index).As(Map)) + clv.GetValue(index).As(Map).Put("almacen",inv + 1) + Log(clv.GetValue(index).As(Map)) +' clv.GetValue(index).As(Map).Get("almacen") = clv.GetValue(index).As(Map).Get("almacen") + 1 + End If + If laCant.Text = "" Then laCant.Text = 0 + Log($"|${laCant.Text}|"$) + laCant.Text = $"$1.0{laCant.Text-1}"$ + If laCant.Text < 0 Then laCant.Text = 0 + Private tmpMap As Map = clv.GetValue(index).As(Map) + Private precio As String = clv.GetValue(index).As(Map).Get("precio") + Private id As String=clv.GetValue(index).As(Map).Get("id") + Private tmpMap As Map = CreateMap("precio":precio, "cant":laCant.Text, "almacen":Subs.traeAlmacen) +' Log(tmpMap) + prodsMap.Put(id, tmpMap) + If laCant.Text = 0 Then prodsMap.Remove(id) +' LogColor("prodsMap="&prodsMap, Colors.blue) +' (Subs.traeAlmacen, p1.Get("precio"), p1.Get("cant"), pn, p, ticketId, Subs.traeFecha, Subs.traeUsuarioDeBD, rutaUsuario, 0, B4XPages.MainPage.tipo_venta) + Private almacenX As String = Subs.traeAlmacen + Private nombreX As String = Subs.traeProdNombre(id) + Subs.actualizaProducto(almacenX, precio, laCant.text, nombreX, id, Starter.ticketActual, Subs.traeFecha, Subs.traeUsuarioDeBD, Starter.mesaActual, 0, Starter.tipov) + cuentaProds + Dim cs As CSBuilder + cs.Initialize + If WobbleMenu1.GetCurrentTab = 3 Then + Private elTexto As String = clv.GetValue(index).As(Map).Get("prod") + Private elPrecioU As String = clv.GetValue(index).As(Map).Get("precio") + Private elTotal As String = elPrecioU * laCant.text + elNombre.Text = cs.Color(Colors.red).append(elTexto).pop.append(CRLF).Color(0xFF017F01).Append($"Precio $${NumberFormat2(elTotal, 1, 2, 2, True)}"$).Popall + End If +' Log($"Total Prods: ${totalProds}, Total Compra: $$1.2{totalCompra}"$) +End Sub + +Sub b_prodMas_Click + etCantHasFocus = False + If WobbleMenu1.GetCurrentTab = 3 Then clv = clv_carrito Else clv = clv_prods_ll + Private buttonTag As String = Sender.As(Button).tag + Dim index As Int = clv.GetItemFromView(Sender) + LogColor("b_prodMas_Click", Colors.Magenta) + Dim pnl0 As B4XView = clv.GetPanel(index) + Dim pnl As B4XView = pnl0.GetView(0) + Dim laCant As B4XView = pnl.GetView(2).GetView(2) + Dim elNombre As B4XView = pnl.GetView(1) + If WobbleMenu1.GetCurrentTab = 3 Then laCant = pnl.GetView(2).GetView(4) + Log($"${pnl.GetView(2).GetView(1)}${CRLF}${pnl.GetView(2).GetView(2)}${CRLF}${pnl.GetView(2).GetView(3)}${CRLF}${pnl.GetView(2).GetView(4)}"$) + If laCant.Text = "" Then laCant.Text = 0 +' Private tmpMap As Map = clv.GetValue(index).As(Map) + Private precio As String=clv.GetValue(index).As(Map).Get("precio") + Private inv As Int = clv.GetValue(index).As(Map).Get("almacen") + Log($"|${laCant.Text}, ${inv}"$) + If buttonTag = "vendido" Then + If inv > 0 And (laCant.Text + 1 <= inv) Then +' Log(clv.GetValue(index).As(Map)) + clv.GetValue(index).As(Map).Put("almacen", (inv - 1)) + inv = inv - 1 + laCant.Text = $"$1.0{laCant.Text+1}"$ +' Log(clv.GetValue(index).As(Map)) + End If + else If laCant.Text + 1 <= inv And lfila.Text = "PRODUCTOS" Then +' LogColor(inv, Colors.blue) + laCant.Text = $"$1.0{laCant.Text + 1}"$ + Log(Subs.totalPedido) + End If + Private id As String=clv.GetValue(index).As(Map).Get("id") + Private almacenX As String = Subs.traeAlmacen + Private nombreX As String = Subs.traeProdNombre(id) + Private precioX As String = precio + Subs.actualizaProducto(almacenX, precioX, laCant.text, nombreX, id, Starter.ticketActual, Subs.traeFecha, Subs.traeUsuarioDeBD, Starter.mesaActual, 0, Starter.tipov) + cuentaProds + Dim cs As CSBuilder + cs.Initialize + If WobbleMenu1.GetCurrentTab = 3 Then + Private elTexto As String = clv.GetValue(index).As(Map).Get("prod") + Private elPrecioU As String = clv.GetValue(index).As(Map).Get("precio") + Private elTotal As String = elPrecioU * laCant.text + elNombre.Text = cs.Color(Colors.red).append(elTexto).pop.append(CRLF).Color(0xFF017F01).Append($"Precio $${NumberFormat2(elTotal, 1, 2, 2, True)}"$).Popall + End If +' Log($"Total Prods: ${totalProds}, Total Compra: $$1.2{totalCompra}"$) +End Sub + +Sub cuentaProds + 'LogColor($"Productos de la orden: ${c_prodsX.GetString("cantProds")}, Total: ${c_prodsX.GetString("costoTotal")}"$, Colors.red) +' Log("===========================") + Private c As Cursor = Starter.skmt.ExecQuery($"select sum(PE_COSTO_TOT) as total, sum(PE_CANT) as cant from PEDIDO where PE_TICKET IN (Select cuenta from cuentaa)"$) +' LogColor("TIEMPO cuentaProds =" & ((DateTime.Now-inicioContador)/1000), Colors.Red) +' LogColor(prodsMap, Colors.Magenta) + p_botonesVenta.Visible = True + p_botonesVenta.BringToFront + c.Position=0 +' Log(Subs.totalPedido) + Private cant0 As String = "0" + Private total0 As String = "0" + + If c.GetString("cant") <> Null And c.GetString("cant") <> "null" Then cant0 = c.GetString("cant") + If c.GetString("total") <> Null And c.GetString("total") <> "null" Then total0 = c.GetString("total") + +' Log($"Total Prods: ${cant0}, Total Compra: $$1.2{total0}"$) + l_totalCarrito.text = $"Total: $${NumberFormat2(total0,1,2,2,True)}"$ + c.Close + If WobbleMenu1.GetCurrentTab = 3 Then LlenaProdsLL(Null, Null) + If Subs.hayPedido Then WobbleMenu1.SetBadge(3, 1, Colors.white, Colors.red) Else WobbleMenu1.RemoveBadge(3) +End Sub + +Sub LlenaProdsLL(p As ResultSet, extra As String) +' Log("LlenaProdsLL") + listaProds.Initialize + hayPedido = Subs.hayPedido +' Log($"HAYPEDIDO: ${hayPedido}"$) + If hayPedido Then 'Si hay pedido obtenemos las cantidades de los productos para agregarlos al CLV. + Dim cantsMap As Map + cantsMap.Initialize + Dim pe As ResultSet = Starter.skmt.ExecQuery($"select PE_PROID, PE_CANT from PEDIDO where PE_TICKET = '${Starter.ticketActual}' and PE_CEDIS = '${Subs.traeAlmacen}'"$) + 'Si EXTRA es igual a rmi, entonces regresamos los RMIs existentes. + If extra = "rmi" Then pe = Starter.skmt.ExecQuery($"select PE_PROID, PE_CANT from PEDIDO where PE_TICKET = '${Starter.ticketActual}' and PE_CEDIS = 'DUR'"$) +' LogColor("Ponemos productos de pedido anterior: "&pe.RowCount, Colors.red) + Do While pe.NextRow + Private cant As Int = 0 + cantsMap.put(pe.GetString("PE_PROID"), pe.GetString("PE_CANT")) + Loop +' Log($"Con pedido: ${pe.RowCount}"$) +' Log("CANTSMAP: " & cantsMap) + pe.Close + End If +' Log(p.IsInitialized) + If query = "" Or query = Null Then query = "cat_gunaprod2" + If p.IsInitialized Then + Log($"YA HAY RESULSET ${p.RowCount}"$) + Else +' Log("NO HAY RESULSET") + Dim p As ResultSet = Starter.skmt.ExecQuery($"select CAT_GP_ID, CAT_GP_NOMBRE, CAT_GP_ALMACEN, CAT_GP_PRECIO, CAT_GP_TIPOPROD, CAT_GP_IMG from cat_gunaprod where CAT_GP_PRECIO > 0 And CAT_GP_CLASIF <> 'PROMOS' order by CAT_GP_NOMBRE"$) + End If +' Log(p.RowCount) + Do While p.NextRow + Private cant As Int = 0 +' Dim ins As InputStream +' Dim bmp As Bitmap +' Dim jpeg() As Byte +' jpeg = p.GetBlob("CAT_GP_IMG") +' ins.InitializeFromBytesArray(jpeg, 0, jpeg.Length) +' bmp.Initialize2(ins) + If hayPedido And cantsMap.ContainsKey(p.GetString("CAT_GP_ID")) Then cant = cantsMap.Get(p.GetString("CAT_GP_ID")) + Dim tempMap As Map = CreateMap("prod":p.GetString("CAT_GP_NOMBRE"), "precio":p.GetString("CAT_GP_PRECIO"), "almacen":p.GetString("CAT_GP_ALMACEN"), "id":p.GetString("CAT_GP_ID"), "cant":cant, "img":Null) + listaProds.Add(tempMap) +' Log($"${p.GetString("CAT_GP_ID")}, ${p.GetString("CAT_GP_NOMBRE")}, ${cant}"$) + Loop + p.Close + +' Log("LISTAPRODS: " & listaProds) + PCLV.Commit + clv_prods_ll.Clear + Private listaProdsConCant, listaProdsConCantIndex As List + listaProdsConCant.Initialize + listaProdsConCantIndex.Initialize + listaHints.Initialize +' Log(listaProds) + For q = 0 To listaProds.Size - 1' Sacamos los productos con cantidad previa. + If listaProds.Get(q).As(Map).Get("cant").As(Int) <> 0 Then +' Log(listaProds.Get(q).As(Map).Get("prod")) + listaProdsConCant.Add(listaProds.Get(q)) + listaProdsConCantIndex.Add(q) + End If + Next +' Log("PRODCONCANT: " & listaProdsConCant) +' Log(listaProdsConCantIndex) + Private cont As Int = 0 + For pr0=0 To listaProdsConCant.Size - 1 'Agregamos los productos con cantidad previa. + Private Pnl As B4XView = xui.CreatePanel("") + Pnl.SetLayoutAnimated(0, 0, 0, clv_prods_ll.AsView.Width, 70dip) + clv_prods_ll.Add(Pnl, listaProdsConCant.Get(pr0)) + listaHints.Add(listaProdsConCant.get(pr0).As(Map).Get("prod")) + cont = cont + 1 + Next +' LogColor(clv_prods_ll.Size, Colors.red) +' Log(listaProds.Size) + For pr = 0 To listaProds.Size - 1 + If listaProdsConCantIndex.IndexOf(pr) = -1 Then + Private Pnl As B4XView = xui.CreatePanel("") + If listaProds.Get(pr).As(Map).Get("almacen") < 1 Then +' Log("EN CERO" & listaProds.Get(pr).As(Map).Get("prod") & "|" & listaProds.Get(pr).As(Map).Get("almacen")) + Else + Pnl.SetLayoutAnimated(0, 0, 0, clv_prods_ll.AsView.Width, 70dip) +' Log(listaProds.Get(pr)) + clv_prods_ll.Add(Pnl, listaProds.Get(pr)) + listaHints.Add(listaProds.get(pr).As(Map).Get("prod")) + cont = cont + 1 + End If + End If + Next +' LogColor(clv_prods_ll.Size, Colors.red) +' PCLV.Commit +' Log("CONT=" & cont) +' Log("CLV_PRODSLL="&clv_prods_ll.Size) + If clv_prods_ll.Size > 0 Then + clv_prods_ll.JumpToItem(0) 'Vamos al primer artículo de la lista. + End If + PCLV.B4XSeekBar1.MaxValue = clv_prods_ll.Size + PCLV.B4XSeekBar1.MinValue = 0 + PCLV.B4XSeekBar1.Interval = clv_prods_ll.Size/20 + PCLV.B4XSeekBar1.Value = clv_prods_ll.Size + PCLV.B4XSeekBar1.Update +' Log($"Min:0, max:${clv_prods_ll.Size}, Interval:${clv_prods_ll.Size/20}"$) + reiniciarlistaProds = False +End Sub + +Private Sub clv_prods_ll_VisibleRangeChanged (FirstIndex As Int, LastIndex As Int) +' Private inicioContador As String = DateTime.Now +' Log($"clv_prods_ll_VisibleRangeChanged : ${FirstIndex}, ${LastIndex} "$) + Dim ExtraSize As Int = 30 'List size + For i = Max(0, FirstIndex - ExtraSize) To Min(LastIndex + ExtraSize, clv_prods_ll.Size - 1) + Dim Pnl As B4XView = clv_prods_ll.GetPanel(i) + If i > FirstIndex - ExtraSize And i < LastIndex + ExtraSize Then +' Log(listaRenglones) +' Log(clv_prods_ll.GetValue(i)) + If Pnl.NumberOfViews = 0 Then 'Add each item/layout to the list/main layout + Pnl.LoadLayout("proditem") +' p_botMasMen.Left = (p_prods.Width * 0.66) - (p_botMasMen.Width / 2) + p_prods.Width = Root.Width * 0.99 +' p_botMasMen.Left = p_prods.Width - (p_botMasMen.Width + 5) +' Log(Root.Width) + p_botMasMen.Left = (p_prods.Width - p_botMasMen.Width - 75) +' Log(p_botMasMen.left) + Private cs As CSBuilder + cs.Initialize + l_prodX.SetTextSizeAnimated(0, 13) + If clv_prods_ll.GetValue(i).As(Map).Get("cant") <> Null And clv_prods_ll.GetValue(i).As(Map).Get("cant") > 0 Then + p_prods.Color=0xFFE2EEFF + et_pCant.TextColor=Colors.Red +' Log("VENDIDO ") + b_prodMenos.Tag = "vendido" + b_prodMas.Tag = "vendido" + End If + Private precio As String=NumberFormat2(clv_prods_ll.GetValue(i).As(Map).Get("precio").As(Double),1,2,2,False) + If clv_prods_ll.GetValue(i).As(Map).Get("cant") <> Null Then et_pCant.Text = clv_prods_ll.GetValue(i).As(Map).Get("cant") + l_prodX.Text = cs.Color(Colors.red).append(clv_prods_ll.GetValue(i).As(Map).Get("prod")).pop.append(CRLF).Color(0xFF017F01).Append($"Precio $${NumberFormat2(precio, 1, 2, 2, True)}"$).Popall + l_prodX.Tag = clv_prods_ll.GetValue(i).As(Map).Get("almacen") + l_pCant.Tag = clv_prods_ll.GetValue(i).As(Map).Get("id") +' Log(clv_prods_ll.GetValue(i).As(Map).Get("id")) +' Private rs_img As ResultSet = Starter.skmt.ExecQuery($"select CAT_GP_IMG from cat_gunaprod where CAT_GP_ID = '${clv_prods_ll.GetValue(i).As(Map).Get("id")}'"$) + i_prod.Bitmap = clv_prods_ll.GetValue(i).As(Map).Get("img") + End If +' Log($"${i}, ${FirstIndex}, ${LastIndex}, ${Pnl.NumberOfViews}. ${clv_prods_ll.Size}"$) + Else 'Not visible + ' If Pnl.NumberOfViews > 0 Then + ' Pnl.RemoveAllViews 'Remove none visable item/layouts from the list/main layout + ' End If + End If + PCLV.B4XSeekBar1.Value = clv_prods_ll.Size - FirstIndex +' Log($"Bar value: ${PCLV.B4XSeekBar1.Value}"$) + Next +End Sub + +Sub et_busca_TextChanged (Old As String, New As String) +' Private inicioContador As String = DateTime.Now + If New.Length = 1 And Not(forzarBusqueda) Then Return + forzarBusqueda = False + If lfila.text = "PROMOCIONES" Then +' If Not(lv_promos.Visible) Then lv_promos.Visible = True +' Private cPromo As Cursor=Starter.skmt.ExecQuery($"select CAT_GP_ID, CAT_GP_NOMBRE, CAT_GP_PRECIO, CAT_GP_ALMACEN, CAT_GP_IMG from ${query} where CAT_GP_NOMBRE like '%${New}%' and CAT_GP_ALMACEN > 0 AND CAT_GP_TIPO = 'PROMOS' AND CAT_GP_SUBTIPO = 'PROMOS' AND CAT_GP_TIPOPROD <> 1 and (length(CAT_GP_CODPROMO) = 1 OR CAT_GP_CODPROMO = CAT_GP_ID)"$) +' Log($"res:${cPromo.RowCount}"$) +' If cPromo.RowCount > 0 Then +' lv_promos.Clear +' For i=0 To cPromo.RowCount -1 +' cPromo.Position=i +' Private tm As Map = Subs.procesaPromocion(cPromo.GetString("CAT_GP_ID"), ticketId) +' If tm.Get("status") = "ok" Then 'Solo muestrala si hay producto. +' lv_promos.AddTwoLines(cPromo.GetString("CAT_GP_NOMBRE"),"# " & cPromo.GetString("CAT_GP_ALMACEN") & " $ " & cPromo.GetString("CAT_GP_PRECIO") & " F:" & tm.Get("mp").As(Map).Get("prodsFijosCant") & " V:" & tm.Get("mp").As(Map).Get("prodsVariablesCant")) +' End If +' Next +' Else +' ToastMessageShow("No hay promociones disponibles.", False) +' End If +' cPromo.Close + Else + If Not(clv_prods_ll.AsView.Visible) Then clv_prods_ll.AsView.Visible = True + clv_prods_ll.Clear + listaProds.Initialize + listaHints.Initialize + Sleep(0) + Dim p As ResultSet = Starter.skmt.ExecQuery($"Select CAT_GP_ID, CAT_GP_NOMBRE, CAT_GP_ALMACEN, CAT_GP_PRECIO, CAT_GP_TIPOPROD, CAT_GP_IMG from cat_gunaprod where CAT_GP_NOMBRE like '%${New}%' and CAT_GP_PRECIO > 0 And CAT_GP_CLASIF <> 'PROMOS' order by CAT_GP_NOMBRE"$) + Log($"Llamamos LlenaProdsLL con ${p.RowCount} registros"$) + LlenaProdsLL(p, Null) + p.Close + End If +End Sub + +Sub llenaCarrito 'ignore + Private totalPedido As String = 0 + Private cantPedido As String = 0 + p_mesas.Visible = False +' Subs.agrupador +' lv_carrito.Clear + clv_carrito.Clear + list_prodsPedido.Initialize + Private c_prods As Cursor=Starter.skmt.ExecQuery("select PE_PRONOMBRE,PE_COSTO_TOT, PE_COSTOU, PE_CANT, PE_FOLIO, PE_CEDIS, PE_PROID FROM PEDIDO WHERE PE_TICKET IN (Select CUENTA from cuentaa) order by PE_CEDIS, PE_PRONOMBRE") +' Log(c_prods.RowCount) + If c_prods.RowCount > 0 Then + c_prods.Position = 0 +' lv_carrito.BringToFront + clv_carrito.AsView.BringToFront + Private cs As CSBuilder + For i = 0 To c_prods.RowCount -1 + cs.Initialize + c_prods.Position = i +' Dim label1 As Label +' lv_carrito.TwoLinesLayout.ItemHeight = 50dip +' label1 = lv_carrito.TwoLinesLayout.Label +' label1.TextSize = 15 +' label1.TextColor = Colors.Black +' label1.color = Colors.White +' label1.Height = 30dip + Private textColor As Int = Colors.black 'ignore +' Log(c_prods.GetString("PE_CEDIS")) + If Not(IsNumber(c_prods.GetString("PE_CEDIS"))) Then textColor = Colors.RGB(210,105,30) 'Si es promo, cambiamos el color del texto. + If c_prods.GetString("PE_CEDIS") = "DUR" Then textColor = Colors.red 'Si es promo, cambiamos el color del texto. +' Dim label2 As Label +' label2 = lv_carrito.TwoLinesLayout.SecondLabel +' label2.TextSize = 10 +' label2.TextColor = Colors.Blue +' label2.Tag = i +' Log(c_prods.GetString("PE_PRONOMBRE")) +' lv_carrito.AddTwoLines(cs.Color(textColor).append(c_prods.GetString("PE_PRONOMBRE")).pop,"Cantidad #"& c_prods.GetString("PE_CANT")& " SubTotal $"& c_prods.GetString("PE_COSTO_TOT")& " Folio "& c_prods.GetString("PE_FOLIO")) + Private tempMap As Map = CreateMap("prod":c_prods.GetString("PE_PRONOMBRE"), "almacen":1000, "id": c_prods.GetString("PE_PROID"), "cant": c_prods.GetString("PE_CANT"), "precio": c_prods.GetString("PE_COSTOU"), "precioT": c_prods.GetString("PE_COSTO_TOT")) + list_prodsPedido.Add(tempMap) +' Private bmp As Bitmap = Subs.traeImgDeDB(c_prods.GetString("PE_PROID")) +' Private elTexto As String = cs.Color(Colors.red).append(c_prods.GetString("PE_PRONOMBRE")).pop.append(CRLF).Color(0xFF017F01).Append($"Precio $${NumberFormat2(c_prods.GetString("PE_COSTO_TOT"), 1, 2, 2, True)}"$).Popall + clv_carrito.Add(CreateListItem(c_prods.GetString("PE_PRONOMBRE"), c_prods.GetString("PE_CANT"), c_prods.GetString("PE_COSTO_TOT"), 1000, clv_carrito.AsView.Width, 150dip, Null, c_prods.GetString("PE_PROID")), tempMap) + folio = 0 + totalPedido = totalPedido + (c_prods.GetString("PE_COSTOU") * c_prods.GetString("PE_CANT")) + cantPedido = cantPedido + c_prods.GetString("PE_CANT") + If c_prods.GetString("PE_FOLIO") <> Null Then folio = c_prods.GetString("PE_FOLIO") + Next + Else + l_carritoVacio.Visible = True + l_carritoVacio.Text = "No hay productos en tu carrito." + End If +' Log(list_prodsPedido) + c_prods.Close +' l_total2.Text = $"$1.2{totalPedido}"$ +' l_cant.Text = cantPedido +' If Subs.revisaImpresa Then b_rechazar.Visible = False Else b_rechazar.Visible = True +' p_vistaPreviaTrans.Width = Root.Width +' p_vistaPreviaTrans.Height = Root.Height +' Subs.centraPanel(p_vistaPrevia, Root.Width) +' p_vistaPrevia.Visible=True +' p_vistaPreviaTrans.Visible=True +End Sub + +'Return the hint that will be displayed when the user fast scrolls the list. It can be a string or CSBuilder. +Sub PCLV_HintRequested(Index As Int) As Object + Dim word As String = listaHints.get(Index) + Return word +End Sub + +'Return the hint that will be displayed when the user fast scrolls the list. It can be a string or CSBuilder. +Sub PCLVM_HintRequested(Index As Int) As Object + Dim word As String = listaHintsM.get(Index) + Return word +End Sub +'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage. + +Private Sub WobbleMenu1_Tab1Click + LlenaMesas(Null, Null) +' LlenaProdsLL(Null, Null) + Subs.panelVisible(p_mesas, 0, 0) + PCLVM.B4XSeekBar1.mBase.Visible = True + PCLV.B4XSeekBar1.mBase.Visible = False + p_productos.Visible = False + p_carrito.Visible = False + p_historial.Visible = False + p_mesa.Visible = False +End Sub + +Private Sub WobbleMenu1_Tab2Click + LlenaProdsLL(Null, Null) + PCLVM.B4XSeekBar1.mBase.Visible = False + PCLV.B4XSeekBar1.mBase.BringToFront + PCLV.B4XSeekBar1.mBase.Visible = True + Subs.panelVisible(p_productos, 0, 0) + p_mesas.Visible = False + p_carrito.Visible = False + p_historial.Visible = False + p_mesa.Visible = False +End Sub + +Private Sub WobbleMenu1_Tab3Click + PCLVM.B4XSeekBar1.mBase.Visible = False + PCLV.B4XSeekBar1.mBase.Visible = False + Subs.panelVisible(p_carrito, 0, 0) + p_carrito.BringToFront +' p_carrito.BringToFront + p_productos.Visible = False + p_mesas.Visible = False + p_historial.Visible = False + l_carritoVacio.Visible = False + l_compraTerminada.Visible = False + p_mesa.Visible = False + llenaCarrito + If clv_carrito.Size > 0 Then p_botonesCarrito.Visible = True Else p_botonesCarrito.Visible = False +End Sub + +Private Sub WobbleMenu1_Tab4Click + Subs.panelVisible(p_historial, 0, 0) + p_productos.Visible = False + p_carrito.Visible = False + p_mesas.Visible = False + p_mesa.Visible = False + llenaHistorial +End Sub + +Private Sub b_continuar_Click + WobbleMenu1.SetCurrentTab(2) +End Sub + +Private Sub p_botonesVenta_Click + +End Sub + +Private Sub lv_promos_ItemClick (Position As Int, Value As Object) + +End Sub + +'Private Sub p_mesas_Click +' 'Para evitar que el clic en pantalla no se siga hacia atras +'End Sub + +Private Sub p_historial_Click + 'Para evitar que el clic en pantalla no se siga hacia atras +End Sub + +Private Sub p_carrito_Click + 'Para evitar que el clic en pantalla no se siga hacia atras +End Sub + +Private Sub b_buscar_Click + forzarBusqueda = True + et_busca_TextChanged("",et_busca.Text) +End Sub + +Private Sub b_terminar_Click + DateTime.DateFormat= $"yyMMdd-HHmmss-${Starter.ticketActual}"$ + Private id As String = DateTime.Date(DateTime.Now) + Starter.skmt.ExecNonQuery($"insert into cat_hist_compras (H_IDCOMPRA, H_FOLIO, H_MESA, H_CEDIS, H_COSTO_TOT, H_COSTOU, H_CANT, H_PRONOMBRE, H_PROID, H_TICKET, H_FECHA) select '${id}', PE_FOLIO, PE_MESA, PE_CEDIS, PE_COSTO_TOT, PE_COSTOU, PE_CANT, PE_PRONOMBRE, PE_PROID, PE_TICKET, PE_FECHA from pedido where PE_TICKET = '${Starter.ticketActual}'"$) + Starter.skmt.ExecNonQuery($"delete from pedido where PE_TICKET = '${Starter.ticketActual}'"$) +' lv_carrito.Clear + clv_carrito.Clear +' et_busca_TextChanged("", et_busca.Text) + LlenaProdsLL(Null, Null) + l_compraTerminada.Text = $"¡Felicidades!${CRLF}${CRLF}Tu compra con número de orden ${id} ha sido registrada.${CRLF}${CRLF}Llegará en tu siguiente día de entrega."$ + l_compraTerminada.Visible = True + l_compraTerminada.BringToFront + l_totalCarrito.Text = "" +End Sub + +Sub llenaHistorial + Dim rs_hist As ResultSet = Starter.skmt.ExecQuery($"Select h_idcompra, sum(h_costo_tot) as total, sum(h_cant) as cantidad, h_fecha from cat_hist_compras group by h_idcompra"$) + If rs_hist.RowCount > 0 Then +' c_prods.Position = 0 +' l_total2.Text = c_prods.GetString("PE_COSTO_TOT") +' lv_historial.BringToFront + Private cs As CSBuilder + Do While rs_hist.NextRow +' Private rs_do As ResultSet = Starter.skmt.ExecQuery($"select * from CAT_HIST_COMPRAS where H_IDCOMPRA = '${rs_hist.GetString("H_IDCOMPRA")}'"$) + cs.Initialize + Dim Label1 As Label +' lv_historial.TwoLinesLayout.ItemHeight = 50dip + Label1 = lv_historial.TwoLinesLayout.Label + Label1.TextSize = 16 + Label1.TextColor = Colors.red + Label1.color = Colors.White + Label1.Height = 30dip +' Private textColor As Int = Colors.black + Dim label2 As Label + label2 = lv_historial.TwoLinesLayout.SecondLabel + label2.TextSize = 14 + label2.TextColor = Colors.RGB(1,127,1) +' Do While rs_do.NextRow +' Log($"${rs_do.GetString("H_IDCOMPRA")}, ${rs_do.GetString("H_PRONOMBRE")}, ${rs_do.GetString("H_CANT")}"$) +' Loop + Private fecha As String = rs_hist.GetString("H_FECHA") + fecha = fecha.SubString2(1,10) + lv_historial.AddTwoLines("Orden: " & rs_hist.GetString("H_IDCOMPRA"), $"Fecha: ${fecha}, Productos: ${rs_hist.GetString("cantidad")}, Total: $${NumberFormat2(rs_hist.GetString("total"), 1, 2, 2, True)}"$) +' totalPedido = totalPedido + (rs_hist.GetString("PE_COSTOU") * rs_hist.GetString("PE_CANT")) +' cantPedido = cantPedido + rs_hist.GetString("PE_CANT") + Loop +' Private c As Cursor = Starter.skmt.ExecQuery("select pc_noart, pc_monto from PEDIDO_TICKET where pc_cliente in (Select CUENTA from cuentaa)") +' c.Position=0 + '' l_cant.Text = c.GetString("PC_NOART") +' c.Close + Else + l_historialVacio.Visible = True + l_historialVacio.Text = "No hay ordenes en tu historial." + End If + rs_hist.Close +End Sub + +Sub CreateListItem(Text As String, cant As Int, precioU As String, inv As Int, Width As Int, Height As Int, img As Bitmap, prodId As String) As Panel 'ignore + Dim p As B4XView = xui.CreatePanel("") + Dim cs As CSBuilder + cs.Initialize + p.SetLayoutAnimated(0, 0, 0, Width, Height) + p.LoadLayout("prodItemCarrito") +' i_prod.Bitmap = img + l_prodX.TextSize = 15 + p_prods.Height = Height + p_prods.Width = Width - 10 +' Log($"${clv_carrito.AsView.Width}, ${Root.Width}, ${p_prods.Width}"$) + p_botMasMen.Left = p_prods.Width - (p_botMasMen.Width - 75) + l_prodX.Height = Height + l_prodX.Text = Text&CRLF&"# " & inv & " $ " & precioU + l_prodX.Text = cs.Color(Colors.red).append(Text).pop.append(CRLF).Color(0xFF017F01).Append($"Precio $${NumberFormat2(precioU, 1, 2, 2, True)}"$).Popall + l_prodX.Tag = $"ID: ${prodId}${CRLF}${Text}${CRLF}Precio: $$1.2{precioU}${CRLF}Inv: ${inv} pzs"$ + l_pCant.Tag = precioU&"|"&inv&"|"&prodId + et_pCant.Tag = precioU&"|"&inv&"|"&prodId + et_pCant.Text = cant + et_pCant.BringToFront + Return p +End Sub + +Private Sub b_borrar_Click + clv = clv_carrito +' Private buttonTag As String = Sender.As(Button).tag + Dim index As Int = clv.GetItemFromView(Sender) + Msgbox2Async("¿Seguro que deseas borrar este producto?", "Borrar Producto", "Si", "", "No", Null, False) + Wait For Msgbox_Result (Result As Int) + If Result = DialogResponse.POSITIVE Then + LogColor("b_borrar_Click", Colors.Magenta) + Private precio As String=clv.GetValue(index).As(Map).Get("precio") +' Private inv As Int = clv.GetValue(index).As(Map).Get("almacen") + Dim pnl0 As B4XView = clv.GetPanel(index) + Dim pnl As B4XView = pnl0.GetView(0) + Dim laCant As B4XView = pnl.GetView(2).GetView(2) + If WobbleMenu1.GetCurrentTab = 3 Then laCant = pnl.GetView(2).GetView(4) + Log(laCant.text) + laCant.Text = "0" + Private id As String=clv.GetValue(index).As(Map).Get("id") + Private almacenX As String = Subs.traeAlmacen + Private nombreX As String = Subs.traeProdNombre(id) + Private precioX As String = precio + Subs.actualizaProducto(almacenX, precioX, laCant.text, nombreX, id, Starter.ticketActual, Subs.traeFecha, Subs.traeUsuarioDeBD, Starter.mesaActual, 0, Starter.tipov) +' Log($"${almacenX}, ${precioX}, ${laCant.text}, ${nombreX}, ${id}, ${Starter.ticketActual}, ${Subs.traeFecha}, ${Subs.traeUsuarioDeBD}, ${rutaUsuario}, 0, ${Starter.tipov}"$) + cuentaProds + llenaCarrito + End If +End Sub + +Private Sub lv_historial_ItemClick (Position As Int, Value As Object) + +End Sub + +Private Sub clv_mesas_VisibleRangeChanged (FirstIndex As Int, LastIndex As Int) +' Log($"clv_mesa_VisibleRangeChanged : ${FirstIndex}, ${LastIndex} "$) + Dim ExtraSize As Int = 30 'List size + Private m As Map + For i = Max(0, FirstIndex - ExtraSize) To Min(LastIndex + ExtraSize, clv_mesas.Size - 1) + Dim Pnl As B4XView = clv_mesas.GetPanel(i) + m = clv_mesas.GetValue(i) + If i > FirstIndex - ExtraSize And i < LastIndex + ExtraSize Then + If Pnl.NumberOfViews = 0 Then 'Add each item/layout to the list/main layout + Pnl.LoadLayout("mesasItem") + p_mesasItem.Width = Root.Width * 0.99 + Private cs As CSBuilder + cs.Initialize + l_mesaX.SetTextSizeAnimated(0, 13) + l_estatus.text = "DISPONIBLE" +' Log(m) + If m.Get("estatus") = "ABIERTA" Then l_estatus.Text = "ABIERTA" + If l_estatus.text = "ABIERTA" Then + l_mesaX.Text = cs.Color(Colors.red).Size(16).Append($"Mesa ${m.Get("id")}"$).pop.append(CRLF).Color(0xFF017F01).Append($"Comensales ${m.Get("comensales")}"$).Append(" - Mesero ").pop.Color(Colors.red).append(m.Get("mesero")).pop.append(CRLF).Color(Colors.black).Append($"Subtotal. $${NumberFormat2(m.Get("subtotal"), 1,2,2,True)} - Articulos: ${m.Get("articulos")}"$).Popall + Else + l_mesaX.Text = cs.Color(Colors.red).Size(16).Append($"Mesa ${m.Get("id")}"$).Popall + End If + l_mesaX.Tag = m + p_mesasItem.Tag = m + End If + Else 'Not visible + ' If Pnl.NumberOfViews > 0 Then + ' Pnl.RemoveAllViews 'Remove none visable item/layouts from the list/main layout + ' End If + End If + Next +End Sub + +Sub LlenaMesas(p As ResultSet, extra As String) 'ignore +' Dim p As ResultSet = Starter.skmt.ExecQuery($"select *, IFNULL(M_ESTATUS, 'DISPONIBLE') as ESTATUS2, IFNULL(M_MESERO, 'NINGUNO') as MESERO, IFNULL(M_COMENSALES, 0) as COMENSALES from cat_mesas"$) + + Dim p As ResultSet = Starter.skmt.ExecQuery($"Select *, IFNULL(M_ESTATUS, 'DISPONIBLE') as ESTATUS2, IFNULL(M_MESERO, 'NINGUNO') as MESERO, IFNULL(M_COMENSALES, 0) as COMENSALES, M_TICKET, IFNULL(PC_MONTO, 0) as SUBTOTAL, IFNULL(PC_NOART, 0) as NO_ARTS from CAT_MESAS left join pedido_ticket on M_TICKET = pc_ticket"$) + +' Log(p.RowCount) + PCLVM.Commit + clv_mesas.Clear + Private m_mesas As Map + m_mesas.Initialize + Do While p.NextRow + Dim tempMap As Map = CreateMap("id":p.GetString("M_ID"), "numero":p.GetString("M_NUMERO"), "nombre":p.GetString("M_NOMBRE"), "zona":p.GetString("M_ZONA"), "ticket":p.GetString("M_TICKET"), "estatus":p.GetString("ESTATUS2"), "mesero":p.GetString("MESERO"), "comensales":p.GetString("COMENSALES"), "subtotal":p.GetString("SUBTOTAL"), "articulos":p.GetString("NO_ARTS")) +' m_mesas.Put(p.GetString("M_ID"), tempMap) + Private Pnl As B4XView = xui.CreatePanel("") + Pnl.SetLayoutAnimated(0, 0, 0, clv_mesas.AsView.Width, 70dip) + clv_mesas.Add(Pnl, tempMap) + listaHintsM.Add($"Mesa ${p.GetString("M_ID")}"$) + Loop + p.Close + PCLVM.B4XSeekBar1.MaxValue = clv_mesas.Size + PCLVM.B4XSeekBar1.MinValue = 0 + PCLVM.B4XSeekBar1.Interval = clv_mesas.Size/20 + PCLVM.B4XSeekBar1.Value = clv_mesas.Size + PCLVM.B4XSeekBar1.Update + reiniciarlistaProds = False +End Sub + +'Entramos a la mesa seleccionada. +Private Sub p_mesasItem_Click + Log(Sender.As(Panel).tag) + Subs.panelVisible(p_mesa, 0, 0) + Private m As Map = Sender.As(Panel).tag + Starter.mesaActual = m.Get("id") + Starter.ticketActual = m.Get("ticket") + l_mesa.Text = $"MESA NO. ${m.Get("id")}"$ + Log(m) + b_mesaCerrar.Tag = m + Starter.skmt.ExecNonQuery("delete from cuentaa") + Starter.skmt.ExecNonQuery($"insert into cuentaa (cuenta) values ('${m.Get("ticket")}')"$) + LlenaProdsLL(Null, Null) + p_mesas.Visible = False + cb_mesero.SelectedIndex = 0 + cb_pago.SelectedIndex = 0 + cb_comensales.SelectedIndex = 0 +' Private mesero As String = Subs.traeMesero(m.Get("id")) + If m.Get("mesero") <> "NINGUNO" Then cb_mesero.SelectedIndex = cb_mesero.IndexOf(m.Get("mesero")) + If m.Get("comensales") <> "0" Then cb_comensales.SelectedIndex = cb_comensales.IndexOf(m.Get("comensales")) +' Log(Subs.traeMesaEstatus(m.Get("id"))) + If Subs.traeMesaEstatus(m.Get("id")) = "CERRADA" Then + p_mesaCampos.Visible = True + b_abrirMesa.Visible = True + p_mesaAbierta.Visible = False + Else + p_mesaCampos.Visible = False + b_abrirMesa.Visible = False + p_mesaAbierta.Visible = True + p_mesaAbierta.BringToFront + l_meseroAbierta2.Text = m.Get("mesero") + l_comensalesAbierta2.Text = m.Get("comensales") + End If +End Sub + +Private Sub b_abrirMesa_Click + If cb_mesero.SelectedIndex <> 0 Then + Starter.skmt.ExecNonQuery($"update CAT_MESAS set M_TICKET = '${Subs.traeConsecutivoTicket("ABIERTA", "PENDIENTE")}', M_ESTATUS = 'ABIERTA', M_MESERO = '${cb_mesero.SelectedItem}', M_COMENSALES = '${cb_comensales.SelectedItem}' where M_ID = '${Starter.mesaActual}'"$) + Log($"update CAT_MESAS set M_TICKET = '${Subs.traeConsecutivoTicket("ABIERTA", "PENDIENTE")}', M_ESTATUS = 'ABIERTA', M_MESERO = '${cb_mesero.SelectedItem}' where M_ID = '${Starter.mesaActual}'"$) + l_comensalesAbierta2.Text = cb_comensales.SelectedItem + l_meseroAbierta2.Text = cb_mesero.SelectedItem + p_mesaCampos.Visible = False + b_abrirMesa.Visible = False + p_mesaAbierta.Visible = True + Else + ToastMessageShow("Es necesario seleccionar un mesero", False) + End If +End Sub + +Private Sub p_mesa_Click + 'Para evitar que el clic en pantalla no se siga hacia atras +End Sub + +Private Sub cb_comensales_SelectedIndexChanged (Index As Int) + Log(Index) +End Sub + +Private Sub cb_mesero_SelectedIndexChanged (Index As Int) + Log(Index) +End Sub + +Private Sub b_mesaCerrar_Click + Log("Cerrar") + Log(Sender.As(Button).tag) + p_pago.BringToFront + p_pago.Visible = True +End Sub + +Private Sub b_mesaEditar_Click + p_mesaCampos.Visible = True + b_abrirMesa.Visible = True + p_mesaAbierta.Visible = False +End Sub + +Private Sub p_mesaAbierta_Click + 'Para evitar que el clic en pantalla no se siga hacia atras +End Sub + +Private Sub lv_categorias_ItemClick (Position As Int, Value As Object) + +End Sub + +Private Sub p_pago_Click + 'Para evitar que el clic en pantalla no se siga hacia atras +End Sub + +Private Sub b_pagoCerrar_Click + p_pago.Visible = False +End Sub + +Private Sub cb_pago_SelectedIndexChanged (Index As Int) + Log(cb_pago.SelectedItem) +End Sub \ No newline at end of file diff --git a/B4A/DBRequestManager.bas b/B4A/DBRequestManager.bas new file mode 100644 index 0000000..cda673d --- /dev/null +++ b/B4A/DBRequestManager.bas @@ -0,0 +1,277 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Class +Version=6.8 +@EndOfDesignText@ +'Necesita la libreria RandomAccessFile + +'Class module +Sub Class_Globals + Private mTarget As Object + Type DBResult (Tag As Object, Columns As Map, Rows As List) + Type DBCommand (Name As String, Parameters() As Object) + Private link As String + Private bc As ByteConverter + Private T_NULL = 0, T_STRING = 1, T_SHORT = 2, T_INT = 3, T_LONG = 4, T_FLOAT = 5 _ + ,T_DOUBLE = 6, T_BOOLEAN = 7, T_BLOB = 8 As Byte + Private VERSION As Float = 0.9 + Private tempArray(1) As Object + Dim jobTagAnterior As String = "" 'Mod por CHV - 211027 + Dim logger As Boolean = False +End Sub + +'Target - The module that handles JobDone (usually Me). +'ConnectorLink - URL of the Java server. +Public Sub Initialize (Target As Object, ConnectorLink As String) + mTarget = Target + link = ConnectorLink +End Sub + +'Sends a query request. +'Command - Query name and parameters. +'Limit - Maximum rows to return or 0 for no limit. +'Tag - An object that will be returned in the result. +Public Sub ExecuteQuery(Command As DBCommand, Limit As Int, Tag As Object) + Dim j As HttpJob + Dim ms As OutputStream + Dim out2 As OutputStream = StartJob(j,ms, Tag) + + WriteObject(Command.Name, out2) + WriteInt(Limit, out2) + WriteList(Command.Parameters, out2) + out2.Close + j.PostBytes(link & "?method=query", ms.ToBytesArray) +End Sub + +'Executes a batch of (non-select) commands. +'ListOfCommands - List of the commands that will be executes. +'Tag - An object that will be returned in the result. +Public Sub ExecuteBatch(ListOfCommands As List, Tag As Object) + Dim j As HttpJob + Dim ms As OutputStream + Dim out2 As OutputStream = StartJob(j,ms, Tag) + WriteInt(ListOfCommands.Size, out2) + For Each Command As DBCommand In ListOfCommands + WriteObject(Command.Name, out2) + WriteList(Command.Parameters, out2) + Next + out2.Close + j.PostBytes(link & "?method=batch", ms.ToBytesArray) +End Sub + +'Similar to ExecuteBatch. Sends a single command. +Public Sub ExecuteCommand(Command As DBCommand, Tag As Object) + ExecuteBatch(Array As DBCommand(Command), Tag) +End Sub + +Private Sub StartJob(j As HttpJob, MemoryStream As OutputStream, Tag As Object) As OutputStream + j.Initialize("DBRequest", mTarget) + j.Tag = Tag + MemoryStream.InitializeToBytesArray(0) + Dim compress As CompressedStreams + Dim out As OutputStream = compress.WrapOutputStream(MemoryStream, "gzip") + WriteObject(VERSION, out) + Return out +End Sub + +Private Sub WriteList(Parameters As List, out As OutputStream) + Dim data() As Byte + If Parameters = Null Or Parameters.IsInitialized = False Then + Dim Parameters As List + Parameters.Initialize + End If + data = bc.IntsToBytes(Array As Int(Parameters.Size)) + out.WriteBytes(data, 0, data.Length) + For Each o As Object In Parameters + WriteObject(o, out) + Next +End Sub + +Private Sub WriteObject(o As Object, out As OutputStream) + Dim data() As Byte + tempArray(0) = o + If tempArray(0) = Null Then + out.WriteBytes(Array As Byte(T_NULL), 0, 1) + Else If tempArray(0) Is Short Then + out.WriteBytes(Array As Byte(T_SHORT), 0, 1) + data = bc.ShortsToBytes(Array As Short(o)) + Else If tempArray(0) Is Int Then + out.WriteBytes(Array As Byte(T_INT), 0, 1) + data = bc.IntsToBytes(Array As Int(o)) + Else If tempArray(0) Is Float Then + out.WriteBytes(Array As Byte(T_FLOAT), 0, 1) + data = bc.FloatsToBytes(Array As Float(o)) + Else If tempArray(0) Is Double Then + out.WriteBytes(Array As Byte(T_DOUBLE), 0, 1) + data = bc.DoublesToBytes(Array As Double(o)) + Else If tempArray(0) Is Long Then + out.WriteBytes(Array As Byte(T_LONG), 0, 1) + data = bc.LongsToBytes(Array As Long(o)) + Else If tempArray(0) Is Boolean Then + out.WriteBytes(Array As Byte(T_BOOLEAN), 0, 1) + Dim b As Boolean = 0 + Dim data(1) As Byte + If b Then data(0) = 1 Else data(0) = 0 + Else If GetType(tempArray(0)) = "[B" Then + data = o + out.WriteBytes(Array As Byte(T_BLOB), 0, 1) + WriteInt(data.Length, out) + Else 'If o Is String Then (treat all other values as string) + out.WriteBytes(Array As Byte(T_STRING), 0, 1) + data = bc.StringToBytes(o, "UTF8") + WriteInt(data.Length, out) + End If + If data.Length > 0 Then out.WriteBytes(data, 0, data.Length) +End Sub + +Private Sub ReadObject(In As InputStream) As Object + Dim data(1) As Byte + In.ReadBytes(data, 0, 1) + Select data(0) + Case T_NULL + Return Null + Case T_SHORT + Dim data(2) As Byte + Return bc.ShortsFromBytes(ReadBytesFully(In, data, data.Length))(0) + Case T_INT + Dim data(4) As Byte + Return bc.IntsFromBytes(ReadBytesFully(In, data, data.Length))(0) + Case T_LONG + Dim data(8) As Byte + Return bc.LongsFromBytes(ReadBytesFully(In, data, data.Length))(0) + Case T_FLOAT + Dim data(4) As Byte + Return bc.FloatsFromBytes(ReadBytesFully(In, data, data.Length))(0) + Case T_DOUBLE + Dim data(8) As Byte + Return bc.DoublesFromBytes(ReadBytesFully(In, data, data.Length))(0) + Case T_BOOLEAN + Dim b As Byte = ReadByte(In) + Return b = 1 + Case T_BLOB + Dim len As Int = ReadInt(In) + Dim data(len) As Byte + Return ReadBytesFully(In, data, data.Length) + Case Else + Dim len As Int = ReadInt(In) + Dim data(len) As Byte + ReadBytesFully(In, data, data.Length) + Return BytesToString(data, 0, data.Length, "UTF8") + End Select +End Sub + +Private Sub ReadBytesFully(In As InputStream, Data() As Byte, Len As Int) As Byte() + Dim count = 0, read As Int + Do While count < Len And read > -1 + read = In.ReadBytes(Data, count, Len - count) + count = count + read + Loop + Return Data +End Sub + +Private Sub WriteInt(i As Int, out As OutputStream) + Dim data() As Byte + data = bc.IntsToBytes(Array As Int(i)) + out.WriteBytes(data, 0, data.Length) +End Sub + +Private Sub ReadInt(In As InputStream) As Int + Dim data(4) As Byte + Return bc.IntsFromBytes(ReadBytesFully(In, data, data.Length))(0) +End Sub + +Private Sub ReadByte(In As InputStream) As Byte + Dim data(1) As Byte + In.ReadBytes(data, 0, 1) + Return data(0) +End Sub + +'Handles the Job result and returns a DBResult. +Public Sub HandleJob(Job As HttpJob) As DBResult +' Dim start As Long = DateTime.Now + Dim In As InputStream = Job.GetInputStream + Dim cs As CompressedStreams + If Starter.Logger Then logger = Starter.Logger + In = cs.WrapInputStream(In, "gzip") + Dim serverVersion As Float = ReadObject(In) 'ignore + Dim method As String = ReadObject(In) + Dim table As DBResult + table.Initialize + table.Columns.Initialize + table.rows.Initialize + table.Tag = Job.Tag + If jobTagAnterior <> Job.Tag Then LogColor("HandleJob: '"&Job.Tag&"'", Colors.Blue) 'Mod por CHV - 211023 + jobTagAnterior = Job.Tag 'Mod por CHV - 211023 + If method = "query" Then + Dim numberOfColumns As Int = ReadInt(In) + For i = 0 To numberOfColumns - 1 + table.Columns.Put(ReadObject(In), i) + Next + Do While ReadByte(In) = 1 + Dim rowObjects(numberOfColumns) As Object + table.rows.Add(rowObjects) + For col = 0 To numberOfColumns - 1 + Dim o As Object = ReadObject(In) + rowObjects(col) = o + Next + Loop + Else If method = "batch" Then + table.Columns.Put("AffectedRows", 0) + Dim rows As Int = ReadInt(In) + For i = 0 To rows - 1 + table.rows.Add(Array As Object(ReadInt(In))) + Next + End If + In.Close +' Log("HandleJob: " & (DateTime.Now - start)) + Return table +End Sub +'Reads a file and returns the file as a bytes array. +Public Sub FileToBytes(Dir As String, FileName As String) As Byte() + Dim out As OutputStream + out.InitializeToBytesArray(0) + Dim In As InputStream = File.OpenInput(Dir, FileName) + File.Copy2(In, out) + out.Close + Return out.ToBytesArray +End Sub + +'Converts an image to a bytes array (for BLOB fields). +Public Sub ImageToBytes(Image As Bitmap) As Byte() + Dim out As OutputStream + out.InitializeToBytesArray(0) + Image.WriteToStream(out, 100, "JPEG") + out.Close + Return out.ToBytesArray +End Sub + +'Converts a bytes array to an image (for BLOB fields). +Public Sub BytesToImage(bytes() As Byte) As Bitmap + Dim In As InputStream + In.InitializeFromBytesArray(bytes, 0, bytes.Length) + Dim bmp As Bitmap + bmp.Initialize2(In) + Return bmp +End Sub + +'Prints the table to the logs. +Public Sub PrintTable(Table As DBResult) + Log("Tag: " & Table.Tag & ", Columns: " & Table.Columns.Size & ", Rows: " & Table.Rows.Size) + Dim sb As StringBuilder + sb.Initialize + For Each col In Table.Columns.Keys + sb.Append(col).Append(TAB) + Next + Log(sb.ToString) + For Each row() As Object In Table.Rows + Dim sb As StringBuilder + sb.Initialize + For Each record As Object In row + sb.Append(record).Append(TAB) + Next + ToastMessageShow(sb.ToString, True) + Next +End Sub + + \ No newline at end of file diff --git a/B4A/Files/candado.png b/B4A/Files/candado.png new file mode 100644 index 0000000000000000000000000000000000000000..81226005c13244c4990cd56976b650a36002e30e GIT binary patch literal 17760 zcmXV%byQo=^Y?=kcPZ|!MT{RMG?>%R!_PrQL>(+f*%*8mtKhhn^%iQ} zmbq~16*tdZ$GEtLdW$%y{M$tpLJLTfWpPi2Gi1~bAH-TuyV)p>cR6{j!x zy5D`@3HG^b&DB0{YzG)v5H!WPEumFsyadM6xStyYrF-JZf!-luK;?s&XSMid)3+qu zR~|)v5F;}e)*x%^{>zy!giPxPaGY=Ku?7|b*yu5lV(j-~zq!!bIr*LFn3ZsS$%8u( z|0JG7WiI>~R`eQ0e5uEd@TG3;U_c{KpKec`HMP}mV%e~^W1W_G~|3}=t z@zkFF7M3k?GKelnI~FrCJLjXTzW?$_hk^HBlQVzMF0Z+nZ4(M9ftRFADqf3ac*)E4 zz)l9gzrEWzde(xY>GV;3-dfMU)l43~hsjv%+D6c)`JZH=f#QFDUPax0`3j?ylBp6q z{tH?X<nW#FKw~VJ|^z}lCIKuQnmEA7#=te0~_Fr38@6j5cviL3SHtSV# zr9$r{I$2CI;*ij?fU<{8E84RH$nHZDe1w(lahgj9VXDYWg%z{9#v7k^-pBZ?pBD_( zTotI?^?4CL4l$s8D%lHVcFRQKI}rOh8@k(ws_{lohELMQ&#TSyw+q0%O_@;7ib2xi zk15+H#I3pj#d{>qe`|c+_*tK^d{^NUs)a2_nx8Jm$BHSIozwbm`S_m&(0!e6eDM3? zGbss|gS494`Lb#4h>MMk$o~zvYM5xDv+MZ0K|>@~_@{ ze|iMK`X9e#`>_*IH|D9SXR}kY8S=_P@L|8nq&@`*%haCH<_dpw08DEGY?40{{P$b< zT^upL+q_@k_4K$k==;RXKFzfH`PP&*IJtlVd6yUetCr6X$yGoRjgR}QiQL>lcZFBz9I0sJy12ieB1%svIkGw~t^6ZGOLOUkB0CTxm4`Ph2or4P z^_<;3=;B(xm|x9KI<+FlQ2?y3xjq)xb(Tpi(>8uP$@(IAi-Qi7V3f>grUgPWf>`Lq zKnxyz!U2h8IR+$=O#Y+RmXN8%ONScP;L=hr#M&(I^MxMR3nd{PknTq- z$Vr0EjWpaHx*aJgDlN+(9GnD*Hr)=&p$iYeS4CzG|3k}7mn)vRG6yIv-Q-gub^AdC z{mo5Jwk7Io?zH^&se1tZH*QAtcWBlo25t>TdRlIx;KPsDS}Iy@W$Xc6SWEyboR~>sr*M>ey@yZL+ z5IK1XuR64DIrNXu4?>;r((B*d3u9T&cf-1{o^M*%pX@L{Q5cXS><9iJJXA9b_!+vh zAYWI7k{)Dft>A#4AmnY6-3>lTE53D-8z(eQX16g~f98WEQa_k?J33P3^WR3u8fCPp zX|EG8h|(_!iY8wncCPD$E$MgFlEt@c+qYu!pzn(PxfeIeWghz<-(l~5kKBvvV*p)j ziQ=nG8M~q(Y&3ICY$Th1Z}_dF|6v~qnF)!gT5_@>C-i>{_|0g6mP*PYfWu%8VX%?S zA4V-l3_K8WaxPxA-Tp7n5s3unKn#sdkb$Dc0pxZ~>uyBEjr2*2Rdes=OMZ=T0w14} zm|6fSKEkPUS>yX(eVG)v-tyC-zExY9PDz`h_QZd*%agVx|89n-u2{pVXQ~sw{>b%!&kGKctt*Zr6 zs<{D0O;DuyurtM!!7Cbn0N|kY78E>y0>_U8cU+GQzX`+)3Zq}=_g+9Xqq^Jp*Bm?X z0pwdH0DcL(J#alEzf2%JBL`D^pA8A)%}B%z6gEOG@viDHQ;yNoFey*~Lj@sSkyt{- zJukj(l=STKcN!vs{`LX}%MT|<9tIM&^H)m*kL2jG8p85xBfOK+eVRzgb|@tuf6gzx zP;5L;{{2hyf@AUk{v{rTCH4!i{%g49$*FypT*8~uSh;y~4?`JhkWdAEg>?+a&eE>qetx5GyP}k`9m+!x8(w4K9POSQ|->?Gu~NimaGhzvhpBK*}Eq6kw~fn zZZ%n>QE_%bGBEav-)lE0fEm?;|H|{d#^dVotLw4CI$u2kAM~x(pIO=CWVIiMn{ib< zaiDtr@9>C1e2`TiI?q4mn3z9(MrDsgEx_4h*To5orItsQl#wOR zfA)3$-jj?L6jrbvnq1R=`1Q$TPWxdRjb1rZRG9*dPZXS7ikoW0wYvYa4$JWxOYVTs zEY@8k{k`GK6v~bjvPz6Bhg)j7g-!*!>0k4=xW7HrZ*qFpkR$YEL5I|(Z-q0tWFAi9 z@4UAu)}{_||At@2KSG`%8mfJ=akJt;LVCMTr-+dLS%wlrwS0g1_eQ{x%GTrkQ_Df# zgxJU@S}VQ%+;*eX^01OJkb(*Cq@ruX6#;6gfqOiqOslJtYubi_7$=eyXox@4&&8Qj zHd97rE`b~w!?seBh)6)JENp51Tly4-|q!Yd1UtGK{v);NE+ zEt3ANI&kpU9C)gNI#)@r6P-4BHCNub>E2PH5+Bt{t8l*H)<8Lz&fy0?j;gc_MU4+O z*Ls&rN_lWe0jRNeZi%e>~I|Q#XpvC!|}-67`fKh09F(9 z9K#ByzYzxd?6;V>zLNvd#nhav`hqEMdQb5i=Iuo`C`sCYDJYf(mnn8bK(ykC7R0e? zJw%cj^}2PR(rcr|x^Gq0fjAb7t&?ZJ?ge!mR^Yu-kd}3(y?_$TZWKA>)Lbt|J;gR_ z@10Q7Tg{ygP1%nguy)`9ry3LtY$TM=Rzd<)FenM8nx!x5dHPB@jzko|ZhC)MFA1Th zo}e3nRlL>*Q!%$QDNzW$ZII$ZXFz{xWo+f)nbn{5Ve{8gfel>dUIq*tIE@sSEB^Et zl#)};AE{geeoF8X1|@&oSWBtvaDc{PG)|qO$f0ny-$Wyo+8v3Y@+O}lJTPK~-{DIL zMxS#GTOvSxWqxbYS@)2^B!9~AN+feFhxv^0zk}}0hw<0{@4A=&B5a(}?L9U8aQQ8g5aXrS6?*fprLzxA-IUl0!E;An6OtHqsYh%X^z4+Xv`kT?5U%QvHe*sL zev3TIWNgRGGbU|>IMZEn**S{!Xd(10gj_jk#Lm@mOBrr1Bqt5*$X2=~ovEvqgA5#| zM#c3`S4G-Y!SpH|k5`6rzrW@;ZS-YbCP{Kztw_07dAW)8ofPcsDdhQg6H)od5u_?g z3(nWV3M8$bxXHkmuc)=vpmkmid(hOjA#__OR#Z9AMV&8pWt^Bu9Yl?|xc9U!MM!*y zHDeUW+pc1N_tO)H0JWLvbL3r3dTDrEVm@`Pe^i;I*K^w ztMCq*zFd1*eo30BNJ|2rND+JsHP@8UEoOgvlWz~&6H1!q%Lu=y5%QO8vDRV-^B;3s z!G=GX-6k7{{N8a(TCauRn=&&K31hD)CkP-iuqyMIR=RJwxoSTgP5Jmd?IY{vqQBBLD3NzTmm*tFGlhjK zzVIlO>pFgYJ=XH?h>pEVGVev#6YR~%W5CUKp4@Mbk>~Wr;Fy{DX)&L3c|gmw#o}W~hr>%z;m>P=;Z@CN8eyrszS@gj9&(Q5v|Jw%zOil^9GYb09jnd91b5HBOiGMvQ+zXgi zy1&v#z7q3p{?$Ki^DJP6l<6FNNKPSX8~QlMYy3c(b%lb9MvbWgr=AHgH#c&8i2@Jw zp=fWS=^P}?Ri{Qtpk5+qb$(`BU{CB^HUFIaF|C>_<;^8&=7m?0F{ZDB*I#0tebOw}; zURO@dq5!*~V`K_bXQj-|Gt$gNPdSa*U~>x-nV)s0Z?hQ(CO2v>_VasYLgB8SU^B03 zq&`G+NIUtVv3zX00cWJo=m%an$uyG98W?-;MRMH)IAD40KX*dNL^gPijnt9<%k%x& zbrLN)M0DNiu6!r!XKxtWCo$67>TR^#X>+=E2bQm>?%o`>cxDM3!1Py3h{X+4vrRdf zLqo=tA!o3I9?j!_)XzQ`wb`ftnrtvhHPb7%B=!d#MMPA47T_5@s32=l_{!O*0o@6I z8$@nt#yg7_noMtGJ?5VhjU^h*z~Ml93y8+;z9)dXGqQR(z$xv1k>=vBh2TFWq~&V; z^UpeY>~;?w9LaTz216k|{$8#-=Z|ED4ilDbUJcZ4DO*-?s$)B9!SIk+Q{66Y-=pR4 zlQ$@`ypEX5E2bYi>Pj|psaa$*d9)+@_iwfQoXQ+Ke`OhLk{Dj@n*Zd?G1d`*rS^`= zuOyC3i#8otKQ^OLLxH}82R1V=k@M~;mUrU?brv5Qwe8woJxSmy6p)I{s%wH3u5Sw$ za6r~-se3iu7kgBaD$h~5T#I3e1@$>U*jJVr+@!o1*`h;m0UTKR<)!be#@wMY%=9fQ z@``}s!q?Ay?_YhrW5`5Tn_EzTDp8qul5lQHvT|&qGI&9=Q=3tM3a6e7ur|$=&eKC0 z_uKG$c-V@2tN=)_qHh$IXX26TIejP@Beq1eHaoU9@$_W-^U+3bXsq@C53wS4a!Cwc z9bDiL(zkSqwMK!qNX&HFXcRw_s7r8|*9<4B+chPIL@M$s;olDS7jwTBZo7t$r|&r?<*Xr?3PCNV{F; za@#KocD>UF=!DaT7B{+vey7@*9e&Ku7CvcXhVQNf_r9Wz&8>86Z5wV`0C%)MRIWLm z2c>JJwjQC4BPFEdbZ#9mJFY`JrX#8<#lMsw0U#FgVQ!SthoPr!YWh26 zU1Ze(#+E#dL*^$s_Zyz(*seh?XyS1qpUEp^0a-NIZ_Vn1(<_IRHNbvz*>5S9eccU~ zR8N)lU(|hORy%8Uo?v9?kj6y^#|2e*a|wOQ4e(y($Ai^+MCMq!n{jgLE zRkF@k#WYKMx*}EKjd!mdNnTgYft7=^NyL;nrNxvJ2fESSQ3@6k-?rj}t#&+b(O8d3 z(hz!5*e)7@n0`?wAa?4X;-wG8d7fr=5{-|CZM_TZaufCrr#h`l@JFaSt4pXr@-%w ziJuM_s^fqS`9y2vWj~nRMz16WfLC20EQM44JtEHy2YJ@@izWOWSAs~O44{m5MCGh>=_fGraaYTR+W!cbW7)w*4nxYx_Xf$t|I7An;vBBm?bT)fSd`{r}L!UqBq(;JHMHppAa!bmt2OrKr~r;_&XQ*WH~gsB)RvB>Jt{7b(Dd=8bqi%XEd4 zr+S8%eO7XVeQgf+D;>^I4#n`Vq6!3#mT0A<$yAxSkT-DpAp;ohYbkM!C7@0q^FV2L(!o4xi0dv|tq(h&oVMAs5BIdj; z;y_pF>8_DB>J>+8qxqi-^;^KvTgjCVg=|hbcQi_x65|?0y}8fOm2t63QSy;qr`%{8 z^>>J8Q~F|UF;;XXrlUYf8*-lmI#{xe7Cd z%gFApaxCX_;j#5Kd>n?2dPA`fW=cN0bFy*ce1L^EG%yE9NG`;JUObi4Q-8^lg`@F5x`vC@!8t#OR8f;ln6tzJX936>$nqN*BbFj0c!Moh8x(okGfgdy#&9#X|Nj-SZ}`CY{yiq)Q-1J<6B-+) z97skSsEx=~g!#o+Z}PfG@;E0dQ2<9`S6oxJVioCs7MBGhmFgq~uuE z{2UMkyd!nWq8!;qGwmcjYC&9Rh%!$&O=#FPEvDV(E=?IWdAl1yk8wz*J8XzS@FppJg5@c%s&eB4{_HWU!}pKfd@{8?teEwyYTpxO1HXG|t$E6^_4dDSl zN8zg+|D2YZijVpPoczVNepOzd)`!J9E;Ygmz^q)^3W@)w#jrY_<(mV$*|WGEiAdKX z37EmfGLa}zV@T%+PT~+sDQ?e|V^bhwGgUuR3PNSq<=`1mit$n-5lTkS>h;Z{k=4<} zQ8idbDNtY9P=r9#8!95Aec4OJhCkIhsWVTgMB&OJr-GUuF?YngvV_mV*xi!jTzyx+ zCi9sTAG`+Lzv=z6+d&*iH@481GYNOI#{MmR^|>g7{3%|Qt|MO~;7-l9TrI=6Vi8$+ z*icVUEHxl0RBud-*J*n#Bj6w>}%MOV6}lan6#eV0kIQso{(uk4~GV z)Da@__OF-;h$KH+#4%Ix6eOH_+DfWQ5y6}y3VgO;g(SPAaFB&NyL#6HpoW1xk41U| z|862b_aw9vOctdrLrr{s0Iflsqd3ZE9q2*FMHks%9jvaY{d{}b!yLJ|4IaWX8*%-W zC%vjhxu`XN+>PtPML9CpK#8)wAje_dLyY=H7OaIo2qE1vvF67x@NI+GeOK+-TA~PN z?j&4{ou(bz@SCY?{IGkW&OZ7z=W)09u!xxL(oc5ZS;b97O#zD{>s@vR{3R3ZHkw^SI}+o!!?JW5vCrQ|L~%`O=8t!QzVCB2IN zFM;Bku@TLQ7WxCb*Umh%9I`}<;xGq`x(u9od4&=F=3=8<_hfPywg(Axls{L(B@Mtb zJ6=v9{&f>ZlC1HflJb?omc#h;1bg4c;sJ|Ylb;*Hgj2+Y+v=h0%K-L3M^%cxh*(?P z281Smk&e>Iru2d1DDa=E5y{17VD^GHewOW*yQ92A>=k-1>n)g~jbc4zlF!9MAG z=M!O%5=NyNeK;bPr6NYdoWX}=@-^u820IgF`uWAiKDH~EBNEdSF_4ny2$MXBK1BdF zEv@VtbwLfgdwZQRyx$SiUlS>Nd zPsdH;6mRlCbTjemncH7G)cki;L@<@L`CTLTXKf!vF`xlti7@O9NP^8ORj<{2CwzDV zWHLWx@%6OMdmM0qH%;i*>7twHl2p=XixQHo!a@d1ed^inCKK_9BIExJN!}sYD7hQt zqfW~y*<(rkh3g$&z-)Z@2@7j(TOLdbQV4}J$Evsbsl3}^>;nrtF2b2j()Yh?-IyP3 zGIWlDD#Ca;3z!)rT*ZK_81)EQOMngbPa~@juMa4H071hjFSOL0u4_uBFWEJ-{CBz6 z>l9Cuiq}ZaNrg_(E}J{6Bl43`c7QZuQ>d^m%G_F?%Y_xBS49}U&OHKbXHwd(x;6aq z`YW^|E_Pn&St3_W&5lbq*Ah?e=iN70RgHx4e<6Y9+a&Vrw93H~KHg_+brpTi@U&8# z;;3w3bo34Z9qdb?XHq|zgW?=`faLvZ8xHYEVOWd_g+hS?TfBlx{DZVC5mqICk|edg z1TdIl4Oy`;wvr|yB`jI)Vt28Y1Kcg4y{Pd?f2qNoL+UFiP<;4ZqU9n@M4>IV{3)vl zMJxBzoRcR2cL$`y1~m7wj7t8bhVBOC4D}dR8h8pUL<%h#j2;9n(m5z|@d1hCNm**|(QY4vb=_=wi6c8}8Mp8-LN5 z_w?-1?8o{}{n3YcAhTGFQ_?$?vb)tKGB6`q^YdSjy7VUF7x|S@MtDTB{pZ2G)MeMA zJs>#l>Dlu;mK+L!{X(-KcRQI*dcGrVJC`lHGh^+ptuLXQ0xk4zJ zy~xe-YcXK!es$T%|P^7 z%9RiT-Y^@XG9Tlf)f^&5pJFE~`@`&t5^4Nnr#|NE9Q$(JSAvz@Jhlojx=hadb;;P^ zZy*V;OItDu{GV;LKR=_FU3ad~jVoU;H1PmRrptuv+Qulofvfd}ni9Y?kQgs~KvYJB z+}_|?kiW2{8Za^>1Qp%7f|omFt9dqAeY@KH~>2}>XIRCPKjYwL%fVQ ziZQE5mxYMgv)zXbI01^bD_f0ff*t`$0yjI|5_#f)DCmOAL2=7d_xzpJ#)*=0x!5u| zCk}c)ybOz$as?ClcY^+PI>4E7zk*gi|3M-H6RErv)~8HwA$y=y$i-^a_o3Ghj`0&C zi6T#{Jp8VJ(@2WH#T&zk&@}=I5d!`9+~PsLa%vr9OVej#tKqGplsJyRKY;Q9rW#MH z$_Yky-gL=ZlVZn=Jec%-{>kbX!)<@YHOAl{9u@k7H@tN9hm( zdev?NnZ9RrDB7)M{HRImHuJW@I{h25#ljofz?s^2M~P))gUM~fLz&4u&{Q}}_Q*aW z+t-J)Fu;mq@q9VRmd4?EZSsjDSafCi40j~BO`-$8ET$a$LD|l%2KGpw3td)Ttk1}n z;-OT@<-|wLRxa@loP#d=Nchd81JM{{6r}dpmr3g8dX)HTFX-{(S+xxC2)L%(U5o#i z{0AZw5g#&pDvxTCEyg1T*?Fc_%M>|1C)T~uKP_Z#XYxb1%_y9gS@BLU$D(9eXlw_s zV?;51sO&FC3B1ucuv$xbWWVuMnWLL!I8CC~nKsq0zqx`xo=W92XU9(69V7{^tdK;h zYC`E7OcUPNejXGP`%-x0E*2P~w8zlLtE1PpWw6G*`ju3{DL%54%#E%lZsnotBbe!J z*je6mUW%>}t;)(TUXe0i7^KJ_&aOGj8@X(4mc1qKL_x1K=cJ6Poc`%Y_>jhZq`6&( z-rJ1Gc8p=#j|FyRytnP;k}XdMMINF_66~Kr-Hy~2=cFe;l;(}xtvbs4*rrJ6rH^Sj zvYPI{MK!Ok>8`$d7a05DS!x<2da!d=aPjhfi5gd@hrwv#xRDYUt{qgR*6TRsg5As^ zYuZy%7PJi?y^lM!_1*Q7Oz3$}mTPI+U2Oo}7cQ6q3~P=}hRrG-59?p2&_-4e7JB9) zHf1v;_O#rRA$?w=#j3)QHK%@I{aY*|JA3%)+!>JWyX>yCW|j{={LZ*i=ph&F19}ocX(1mZr0FPQ zUz6F#%7fWLoX??gkNAU9t5?9E3o{3&$Wnh z^?dAnRg-8b_!c-F&rvhO)N{akv7US7kErS;pIqD7`LBv3bb>$H9fkh$bswHnT&qL2iB%%Y^*HHM z+SY$s-3u~n@qDYMNWityWG#@6MXgG||H zzo_OI2rc4f`Y9%WuMLk--DsnPPc0;XWox|5Cig5&{ETD)%mYVfzl4nLJiN$z#11VC#4CMyuq_i5?~Ni;mYrUzPxZ3h5-5wMg< zGs;$xdSW(CFBqrTj8>VL%o?4S=vDT3*WPjSc3NSwYjU)g98OCzuCV~&!Ky}3g7p?{j~=Kj3h+skY9bMAn6}y2_WKa zP+TTE47n^-7(1LJ4$=9l6P^zy@Y%sBT(doN`b zm1D+}@3#i;um*ZC0UXH17|Gg4O>09(_R&zB&9ZY##QMb<&B&asAxVc0v#se)5~Y?z z=V;1{55-SUi``R%`XtRf5L~6Vq$Cs&Pz4=##!}}Aejsd9nY!rXqYm9`2#F^qvlsLP zpJj!)o31jeJG5zw$Dz4jx>x%QMtQ~M8JVm}-7H1Ew*bDsHJj9VzXD|{ip>SPEW;Hy z#^rD#;AkQ-rJWyLpra7l44M1$k(h0!OKp1~d zdb~O(l=ctIb{~R?Ss`klJ^Th%N5@}3hkp>7rHWtmO~h9tnM&uiCt$l((RiG^h%%H* z2|zUwjEWJ~$4f5?iEpZ)*45ojVoR8EB5~Z3b_NJV)s6BkxtS#>z@wgA zmmfF(=D03aIV75Qn~U>$Vi6w{)S!gLPMHgLDZ4|y-(m-u1`skyes~;0v5bz+9&kY3 zBgbpCdRSs_eRBT|Wc5h7X4vcf<9*#jy>SO?{iNa0ej$S>B0imnJux72EJ}1_6fxpB zwY-!4<-KgCooIj1dRn8NJ0vx;sJ8N__fP-<^yr_!G&_bg6$D(q8KWe>LrLE19!~mG zasS5T%Eq6s0|lt>T$eLL09w7C~Vh*Lb@_JYXF!Q+Dj< zhu4V9fMFc<{)6QlO`^%RjT?IAmk}*dcufO@3;b`MZpyRXX@^k)3n&K>v#9RUho$YSu@cr=*HeIG5 zT}gZ@fv3XcX2jC3pn8fF{6?ivcNE!i$PbdSc=&>K>kcDAjE`6=vGt9FK)K1$e`npG z_JT1eSNXDi7$N%p>Cvs07-Zny(|X2W#Gr^4v;R;53csIc%I1+D9}zMW8RGr~y~m(m z99Yc`+})onAXRpljVbLzJMPKa;D-KpzUH@dX{}PGy#itwlsI>47Ohf_z+OjfUbhdM z%vP|W1lW*Ouq7huI<4wn_nwBrvYr)_`R@>QKwbCv2Q~ay9`m=(1^*5`ls1{uGU!^i z84FehIIM~m%G#jzaYySgVR=@0A>lVMd)Mw2jGXXiXH7x#&0~(eLNGw|XK| z@bf%*9a$G6!tdpD_K2Vt`5!|m8$c9tui(z(@N$O!o$^GwX7e7uV~CGh$=q{x9tVsQ zs&m9lk--FwxA@qZqMkGEU-1mjOIeh~32ESIkErf>cu-}+=P<6|uCR5&{$j&-;nMAk9yPtcGN7sV&KXxrSw#vJ9!xrJMZRUH$VKH zve+aK)wbEvwuMxAqb_#>(u22DCAkEIH3j6(EOi&9bcFDBx$epA&TL8C=-Ew*9MWsn zl0xokab;s_ytISAt?_kO^k;ntUy)=kjuHKt8?qeoJTGeYNcG=v2`nt(I}z1Lg$L`= zZx2xbu?ZxBPx7;PQKxR5={0gXe^{;hg!{a{-u;K{dUW4T2efk`*pq;%X4UYlbHQCT ze(R`O>j}sYoZ2cvn2MK}ndL%miTomu1Nzrn>K!_hjkOm}&UJ!R@RabOpG_dYURjdH zO*!VO#lKC1g;}6Jx<2TbzzAHJ&(--|9ww$s@dq_Vxej{ z1-3_tyWL>z+Kulf%{ZIB!?5HQu_P60slGV&MjK0FBxWnv&2j!wt5i$Ia9~;qLp5VR zi#zaMuEO%A5fxhGv4lht>h!6PN2VxEShKbF7$VbZ^R~e*vVW8B>lcaTPv85s&&X@z zR%EoZT3XB-zhJ0Fmd$-f9GV;vXRwbo75P?UjSP1`VMqj_o^;RJsH1;7Rk9=DZb%Ia zTP@tjcs+!V`<^f3f|54Wl$=K|G}Uqhv%asYr4fOML9Q~fDp`sy#5@zb(W=k=1dOme zvV{KFvu$$akNnx+zhigjg0P;^9&Ml0(+>a^)N4GbJ8l9s2OU=Pz2aB|9Fl0o`er_i z;>V@=Qs1$j=vJl^ojvHFLUV&CaQ^w_LtTrhv}3oh*yH<(EIozf6mA(iMD6UbHcLG7 zMexb}T;jj+_)r)zq&5-J^I(4dFcXITmQgmsU~Z_zV)JfNxD+{=@D3OmO{MMqAT5I^ z<81&`F%D_z*);d?RDR=Zu+!GqUY=^}^(W*KF7c3Ma-xto!l8lTTi~~dc#pIHvxOF#8XD&UEh?Ax z`(l>h0@dbiU<*>GVSW`;@ujuu4DT7^KS=trHp3G+m0(s(RtKTW$&K86%On$3P6{Qt zR#4?y>e4x+U$S0Yb6cRy=g+^8y(52ewG#%Q$_*ocALaR7i$Nt1LMYru@teSJ&E}M2 zKK2*%r=zYDKodYlJo$Li{p0D&p9~ju*35|V!Jl8Txao&BlD|5^t5><&EHkd{Y;sydJnhi9x zxR$ul*vnHb1F5@Q3E-hpZu=PceTJ)CgA(s5i*Kw-N$1aYoO?Vh{T>wBu;^77v(SOt zoxdPzVDkX4zlIq-A-}OsYLy@ z_BRd9KQTcCo5oxuk8-3!d?G^l$sg?(1$v>mYOc}LB~^wN;dl)6Gsr-ulR#16V)cMQ zUQNRL+upOl@;vc|mYdwb&dJB}%C7-G@7lx*g30vj_N4tpW^MvrQupZd_jct5cy=*R z__3hcD?eNG8fE}P>Y_kIEzSmnmXMsUFdVsI5nOpiy@OtLIq1x+9G#guNk6)AGY5e- z*%?@9QD!tJaK~ls>b?$2#;?7DK_B1Om2=EmjsrPGRa=op{}%t&=9Q-7q>9Y(X*PWR z*s&fQf+ti~gsgFJ>RX+pd!uI2xSRO({!ctsEcg;L!8jc$lY^~%pIs?s48=gKH;XOj zLD^&WuKqth)vd>U28(l_UJDa9g#AV373I;{bN3(E;GROCTMED}Z+OM;A4}xp-&J*h zKngT9NWk=WH1bXzAeE`*poTNY;Kl4eG?ilIhCoonG@=sY&_w$=>E@U9M30c5t3Ce< zd22HyZ8%b2vH5Q3TkQ9mIkwBK7WsW1?EcKngt;qzQulYeae)>2QkmH=0~_7BF=B|) zePR*XIc%dVW9Oq!-^b8u80Fci;wVnB{1H*?Y3Oeudch-RQW~qauNDpS@%_E8a;G-y z5x}dZ_sG4=sgwvV(__RvPiKt`Y>-kW#aCLUHsAUWa(w@A!uPmP`|hPSTkG z%N|6?9r?i$Nj0v)`$%g&_LLgSAR4~WuYZl-?rhQ+EE|0&l4_-WodvM#ytpqvpV>tM zei;*qHZXK2&CX~4u+{6(JvIn_6xRs)jm#X+{c>*M!)|uUN6K4 z{RGkfj{X~eO?ON-ISb=p%8@8W@y*~WGEb<0Xbk1AJA#!HGT9pzW(!%4qf&UJMOfe2 zR$Z}U+sMZne2E2Ir*6oXt8QNqQlyV>HyKtQ#4k+WOA?Hm7T1^KOM+WQAf`eKMPlX( z`7172B0v9UhAimVL<2%fivj0<160+hD<=Jxnaa*YSHec zIiXN>CuD0?^=Kg%LC~^*i1--FbT3-<{sQcBct_+N0(RoKJ8M)6$Z6FXDn2Z{ayfR8 z#lvA{sf**M(x}Kk%F7EQ_6cu-P zrf(_%kr5*i7ZfY6tjFU=_28S?USm-puE8*q9%vE4Hynga6Un({r5-R+>?Oh^Q~6e z5bIgaTx#?Y22AeINy&|%oem_mG7VAMZ2*gj7Y(iRd+gvh)bg=87UWQKgmf{13OepU z#-%SuQ#INa+X%|DsfKVyqMo{)UnXp6de?Q zrxGIR%#!oEB{Gs3Z9R7lz#VEWsD3?AKv8gknA}RYcLS#SGGeAeAFgS!b0AGd z?sLX^Ia_^4e=X7;#JlZj_Gr-s5H@yfb6P#6F@CzJ`z;Y6aS9vdswf`U|G+MtwBate zY87E-;dHA@qBDV?cD*1eO6#DGmJvQ%bVBlPwV3k%MPiOr}ZaAQUuu5s&9^ zs@%l5X-F*kD`peMUR9&ExsMDDvJ^2bTsco`Dpu()RdJAG~_DoG^%rnR%KQsj9#cOqDqsIGmcKMiS zthTrNsmsuZ>kq#|fKH3BMFfJ>96P^@nT|TP+Dx@2u;LPnD1uOd{9+JgCL?PNnUun&4rrd4K8B1lyoEC4?SxuU7@-^Xi?e{_RbVZ%!n+2`)WwxcpcXzJ^aa)HJv}gb2 z{t_G6G)x4Pvgfogiz)9+QU;+iH)0@eZT10K;~4@YH;j0ZdDmxGbKQHPPb+G$$#T_;4yiq{3mUHQLgSDutDS83Zoe_xBqLWR5I@RcV?xqW6WM4>X|v z3IRmb{Nfn_*l~#}6Vh9W4Yk7wb|{>XsLkZo2@8ekm%QpytN-w$PL6WWY8Rv;2_Ab2 zW6f1Fc$GS}ZPN-3J}LLnKycsg!nBsb3z1gPZRVgu-Mx!kxJm}9>;w{Td+*XK0yHtj zkm8pJpBj+Y;{OH812z0SK~T56!~56+W67*~U_4h~VFEDn&e4r=j<$kxjB}7tK;)~_ zQLAGBM?kW#LvRr+bqOp*?o#A3%>i^wT5CN5s6fYFhJ*p?s!7QxYuaENum_eD9zsJV`SBOp0&uw*Q{Dy~aH zVNu8|gCGx6gDDnu1b{TSysDPaUCNxKrU*wC6GqEiV^pO&t}r74Ton9d6=_Qn%F9A( znM(#70m*@bB~uK=Meb4-mKzZ;i~^)7aj!`nWt78|fiez~?G#~D9i+(BSqh+xa))tY zbQBmJNm>DL1SAIc+7ghvDj_xC2uK2$;!vDP!dSkYNQ=lRsvf$;JucNv#uaw>^HT&zme4(_x=2R? zH9Nr}`nfKPZrgDpoHD=&NJ1TOm$EH!PM=%PZ7YPc;b&WOO{ zL^w)W!N!RJo~`ipPK0B0WAcn}jesQ70a&txz*GUJsJT53h_auj;vjXFtQ|Eul<3JjfcT}xzC#iC)fHErNW=yTRE&H4k z^Y2kWjsqiuYXl^r^Z`?r&x~?=hGKp(&Mk`mzl;mF+E`p{W^E?i!aaC(Q=KmwAZmYd~ao8ONOjiM(QLtq(&s`Q>WMY6L zAPJ=(m@EdGaiOrD@VS-%j-6O>69q0O;q#2)^76DNf13p*s|5t({zz9e} z{SVD3aH_(U#W+SS!FlOMd`{*tS(~tnf-s;6NJ4<7GCZTsBdv|ERsYr7bDMErs{}(p z5s-uc&8414TASxu(wwB~*SSmhS%BgI>;DTd0QEe}{R0Xx8UO$Q07*qoM6N<$f)jK2 AE&u=k literal 0 HcmV?d00001 diff --git a/B4A/Files/durakelo.png b/B4A/Files/durakelo.png new file mode 100644 index 0000000000000000000000000000000000000000..e1c956c4a8f40776c8f62ee4196a2cc5ac587ead GIT binary patch literal 7098 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.=fr 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≠AGTxvc2C_UUZyg%|V(r|41%_Mj@+ zU`_8nw-;|s)kvtw^^j%zc&*89pOscELWDWxlz1Y#c)4<#tbKlkaD%-QBRKkp{hX4x zFe0oIVKGUPQ3jdsX9iP}*&bgrRxd43TBT>wcM4^$Vz{K>4g9mQh@yGg1h~Y;F%X%SDkx zx8KOa*n9`?ruIOmD_$ai;+;T6R6O)a2_`uXL{=6PS>Y{pnAe6SN-rP*8Ag5pOD1O0Vp19@e^=Le&syb!i{YiN5&k$?geyQ(%VU? zc|sZ(m(`y7U;;Vk3J*>%NRFve>;K_>^sAOD1T^*iuLglaV0aNw^M82zUbS2ypyt0C z0}6rRML^B};q80Xa)p4J|7r{<1cny@JpV_uZ)w`M^eg&5Wqv*Lj`lm9+;lc~`Lfj?KbaxwABk_udeK)aE@=Aks8lb7vYB%+(noQT}!r6HYae zH6CN#co+_1yD1|ea`i0ZEcOv432I165EZcp68)d?v*CRPs+KDRh7N%dJ#(aR?xOns zAG)4b4OR#w2&nm=K%s6F0z-#@n*T%B<*LC7fdm0H{}U+GjY44P5K!}f=(=1rSRs%g zFq%22?a@axeMJ9;amIMdcq@t09{LM(56?~)LDG%q+!SMP#Dg4TruMV*VxrDk>}K1a29uZRk>|DPM6 zpl2~3ms{Z4m2B?xX}yyp)p9|(hCmsKo%$jvP>?iOQWVviRRlji%7Cd5eUg}}4WZvm z>CZe&mouoDvEv~-;M)pnpb4+kd<0s!k{p_qL6TA?I0;UT;A~j~bszK5%)eC3 z=FXhaI|oU(%dBU5f^&~3YGwyzsrP^Pd8h6a0>g%Yn*YPr!|Y;cwF~7X0DIK8$9_CmRpEAb+ih>AK%40Y14XIRTS> z@;SZ(W@WHvqqw&ueD&dl1O5P$zuQXoqDHfrqaVUiEN+Rx>Mm!4gPw$y5U;0KG4tEaQZ_d^slPFrf>=cOnSlWR((t8=D_-{} z2;-s~6!Wjy1m?~xfti}V!j`?T;u7!ANid5sU@HmBG;A_js#&n12i;hN)3~*s$+Gyd z!_Rcfx65>MQNd_4^c<29e$S^%1S*sU2gHg-e%1S^mBk-4xAJm=+ob{#1^f)Mq{;o)}d#a)7321!TthG zENwg&aeyLK5J*5MafnNFs2{9q76dj)No3V35_%W9P(L6g-HElp(%Kl;--eTQSocFv zbcV}!Ub#v%d=J=B-S1~>(J~wi!i)JRZ!{{r{|7xH6kQ>p5ZI*%sQJH3J61JIA+Q4k z)coH8NGgd!V3#7G=Kn73Sk)|rzzz_=^M8;2H7)Z}=4TmQ|C;{h4l=1Ej~{`3nB^-z zHTZuvk#cf7s(I1MXZ}S=;Cf4nyJb!t*iT7Vw0UbkF+u5)m?;#cAIPtGsgq_<5w^|> zh>VxsUXqIwVrXH6KqPP7(g+Pp?07+)L)WQU`$t5gyvHRCe;`!Hss;S$CwhBPYB+5Y zNrN|wt9x*w6?ZLQLGFIQg4{)c1-Tmo3vwYV3vxp<2nwz&5F&LEVo6xYOu_$%%uL{Bt~s zz?$M(h*A-t=&nbg`?kwYop6(kX*zE$*!VY=Lk6Q;SB92C_Tq0{?-jg2wL>L67oyktlb z>6xEh@=9~7z1mt&#!`3x-zRLUs_H5P6atR{0rma=7(i4k6ar5u0(|}(|L}x1Kvi2I zpb$t9m>na3+=f4)_udp{X6NQFTqMiedKHDJ7&;M(%w%bBb`;i`u~)65S{&3ZSYg$` zt$0wp9aZgXuz%5j?5<i46G8w27_XYD1tTnpjhybs0Mz7ickjj?;cPDs$q#hIJgd1fkRwF?jQ!F zg&tmuKBDJf0Xwi?V4)7a;9(e8AZQraoN~>tyEV%m$foKd3)ZZb6I!)Fb+rP&RCira z2oA0*vTP@|y#PQN#D*p*IrtQ$0kHauZauWip;NI#C~n|z!s%S+M$IYxg0YWlUPS&Q z>s78*P*e#A_f;7xjFEy4Riam{QLhyo#(1>g@8ifLqPz~f8F?r2LIHbLO>y~ zs}VS?AJDWh9sg<5q@`;9@9GX$jZ+8+2n?A2nZMWIpZZe>Jede=FDz0K(P>FUBG%0pg7ib@|q^aTkag!#TRd+*G6 zcVlnj2Ohf8ojv#5d(S=RyXTyHcD6T@$(-%UWG=_|4z$bA@|Dn@x5G2<13jQSCw!}3 zS3bvQ%E}FW%YP5YM;c-1xy{i&a3V&oId9(fMhfetQ>%_zZbdnk&&_7aHQTM)*5s+E z=c`#?1(s|uQl2hO9WPFCvtpALWr|fhEUCxBgfg1N4OLjS8sT)KPCe{$#dB*{ff^V) zZOy9VwpwVe<6Ogw<~rW2M@8&%-3o#Q&#!WlU2X&o%eOsF8nTT2D|_5$xyniGA$=lJCvpYbS|>CVw_R>6 z)9+8v8xr(J&>ukiAllUlntET0b{*P>(5^?j0qw>Fy(vL&PS9Ht^wtEu z4YbyCdxEBoYl{@R>ob+(B8?a9+Yo1&6W*oS^te{Xj z8i%>M>0InSfbP7igi4(~Q(l;}L)DMqnDt!C=?_BRuB)Jb!4Bv8eO2vuY*+Q$f#+Bu zdY;=a3(A9gZyy>O+Oxm^p;6DBSAJ+$y@x6MSqR_sCGO5c?*H;@m#-OIUu^vGyRW{q zdFz{%El<7u_|tFvxVCk}+vn9+uidok(Cd@099#Qj{U5n?r~iKNnU`j-E)Bo@*B8EX zrQm%jD<^Mf1q_nkQRb$89xJAXI4{`vm==(cV7M>hTB*|mS(+5gLM z>aE7@Z@u~4LhaXwHXYsimtAlE=|@lh^Ti)}-+%o-r~a_}SL>eJGWO^! zvyJdVb8KM54o_Qk-KDP$=yglRs6)+m)asrYvQ_fT7;x|{=3$b`r2&$Z)I8Gfgmqfc zG>r>muhwv!>58wEOINksiqoj7k{voS^AT&_BEr<(#cE<+w|vL~Au$|Uvkd=`Dx{uY%Mu)u+40JdIO^D3B=2&=fi~pJ-~DlAFIsLLk!3nB2enACZtSd7Es#PP9ws-&Xa@#5hUzegs=3tTgupO|LFHFmgDG)nCw(YUk~1Vrx;~jDsgLsXtGS5YL=`VzKv2?7)!y+P7$Q# zZyqTaLN09kUB~@YBN`d$SCk9G#W{ z-zybpuhgR=nwHBbE7BZGQI?=Wunx`XLbPx3oqsK|GU&}RI@U6`WUF{E4+ud|6@q9B z!QxcxVP)Dh3~FsgZ|xR7&@wreq+-c75V3*VHG2n$o6!0e@z{wbl0Gb)^RI2cnH);v zr{@+th=>%hP1|>&Yg7^CUImANljD}g5`lt~KZ3Si@E~jk4`Zn@NAQqZJWG)=FgL*< znf~*|#YF+;ZfGrg{}+VOMkI+nSiYLTU|RtOV&$WO86HkJML&j&Djk5KM+q>T90Nm` z(!g-y^1yJ70J9f_0CSB7=4Eh5*H-^zMw!%xoy9$oCe z?Xefq>qW>Up1J$*NI1^N&~0^`4lcu_Cw@VsI`{$=`lYyCL z1>IkOka+ty2r-Yz*%;g=1IO|95N1jS{y2y@18>*t9UvY?%c6BGh+1-PyL9&n2xvW} zec-maA!(bWJF3+o-BDor5DtRV8zs6{_{$i)SoqV4jwdC+^9B{*&w~))m%I8-V&Wwy zIysL;Na|Fe>hs`vT4=c$JoxFk;AMylU`eH$ybRNVF5y;83lg>3`AY>OEA|&UeENFi z?~wy&aoI$HX@64SYZOYW2UIcB5(2wHEP8)SRxDd1743AU@y$#F>surz8< z=A|rZEnAsL(`C_X;2c1UuQ>{g@xKzigJ{jN=nzPg!H3aFycf{F|E_?&BODsVqd=mF z$MRYJEzFWE&zDUSue=3TbitJ{F^bo%pak!2AmR(IPqWv7xC|}ld8oFoY=$%*s55ZY;oXu>fPr zqdUPd+FTHrPCt(4A)z(D41wExJ=vONxT(CJWDOntI0msFtzp0xhH-c0oiRlUZmSShONv& zFXwig93y(R2S=yqoy?_%BVEY^1KcHA)rg%F9`WeU(>(Qtiq z?IBbuE)1BW#Kpb`LgMWy5EARWs!jB#(>z8pJty&qJmOQJ#3McpBKC+r&E}nb8Cvc$ zc<^G0>!T~sYyLU;1W2==XkhT8T*2>eAS9o2avHXc;7Gm~bAEuH(fJy5db46(+WH<0 z$aIr!7@o2>38RgX1ZFcAD^Oip|0I@lw4Sh={g$(ylULDtLMP~~*m^8z`Bk!FFL)Y@ zJL2$J45o3QA4(J%F90L*0#1%`U=0`rPudqa-JD=YU!d*c3-^H#G+08*Nic64os1+f zn;4Wpb?FPA!;+2|d>(^lzYe}oM42j)z{zP0($+Kg7@a#>zY*fZdWNr9PuOMeeh@|* OBMHo8Rnn%L$@~v9gGP@4 literal 0 HcmV?d00001 diff --git a/B4A/Files/logo.png b/B4A/Files/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8e6dfc1010380338fdcec59d686581c18999d5a2 GIT binary patch literal 6777 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 literal 0 HcmV?d00001 diff --git a/B4A/Files/mainpage.bal b/B4A/Files/mainpage.bal new file mode 100644 index 0000000000000000000000000000000000000000..acba0d3aca30950dbaa9481775c1060ad7765659 GIT binary patch literal 1584 zcmbtUOHUL*5S|ql9RcwHicj!`JeHM*kHm|N>>AN!h|7wJ2c?3nx<{h*iR!)V;>E} zlAYf#gG0+B&p*|z{?uN4`0}}Pqiv-z zyEeQvwD#`n`_@;ln|d>eCb?oP%{PD4+TXtEdQ5(=(?CR4kXtPBQ-o48ED%;Q#RDSmj@tQ@l^L={HZGk;{zc}K zF9NCplFi~Gi4*XrfC>?%EsH=&@cul2m8xJx$cr8cqwa}^>-&8uA8yht;m4~=|bA-UR>Z{Z- z<7MjM(~PZ>3Kv76=_s+X<0jnPu>IrLHqBZ+g3@s-NQ-Oe#dr)9C|{_jvLX^4PYRSN za5yv_A)x%V5{SpzNY))C5wl6)nJCa60u)(k&`BzRlOdp4tH=AUI}L%Qeujh!y@S9` zMxCMhECGD==Sb-1NnD^2kEy&a62y~M0be3O`A-{YNxg?e6hRb|N*p&u3G`w!5?55f zVIPeq#Rq6h(1>gON+wC_mq|n<4L~zUVu*$!DI#PTrYj__0$d{z@lYW$V(fnzCD)bz KH99id$r!UX| literal 0 HcmV?d00001 diff --git a/B4A/Files/mesasitem.bal b/B4A/Files/mesasitem.bal new file mode 100644 index 0000000000000000000000000000000000000000..0dfa9a61a286697f08148bb02c5cc20cb85774ef GIT binary patch literal 2460 zcmbtWOLH4V5ME))AmWe!352J^D>#WFY=>ufBq~cO1d0?C5mOv+#=B!{VYRE;9mzPS zRB@pKRHZ6a6xZCja^S#;3$c9yP80|D2XNyizOOgC@#%Erxi zrrs{B)i#bFy*O1bt`(+!4+|%5?yJ`~s=2qqnb|96KKX9!+Mm{^-~9aj;kAQT_cX7c z{Au?3jbFY#@c9=L$7+QMbG3B2v-ex;&{tm``2hY;WAI!%YOQwlqu|PmDst^&Sx4@& zufyUwZB&94BQ~%b1>n8VDc|iV;|6}Y7s|}wolvc)MNc0Y;koi-PgXUtB&4WTo!z(=Xn?GP-}kzE7!NZo}*i?@x<~&)mO}x+4$Ja{JScI zFECOKqn3G);STx}MnYtL`flVRA0FCQp{sl|O;?^?GAyMDy4<|tI;Kt6ZS5|%4L7!x zZ?}U`e8embPkrP%5qo3$A&^n!B?>m}Vh}nylyrv6 zd4@~0Y}wFMj@yd_WKZ{{mJD0_tfaH8^{MG9$8r7T-BOUtv*TLD{yn!FxtFCJ^+vry zZ=T#MxnfI!Z%QjV3gR+zNo$s+UGmVQ9TblE*D7aQJOLf3Q5COh2Yy7e2yuD3=K7j& zM`qQNlGhu}bETTJwEoyI6oXk{VQJatOUl*^r(8K(dbif1vwnIeYu##`XXR$NJAFNP z6Xq)QR;9V{W}{hszfo_MYWs%5i!=8TyQK91I3eQGy{~_GwJqU_FD8%Si5gVbV|}xE~-91bAeci9kW)XE7!O4`!d@ zk!G5v6XPL?)8!BtEMj2Dh@RDyvtNTGjVAR(yY0YCK_AyrV>Bsdd~IaAfJcWz@CfBBM$S4(tLH&d zEMK66$G(U$&PGkqeTk}OQ$IKUj^{Uey$;Z5W0s~~YB{tvu) z*|s*~D7;zv?RZ~`@qQhue~&jE{wKTu+s7fIa{K literal 0 HcmV?d00001 diff --git a/B4A/Files/principal.bal b/B4A/Files/principal.bal new file mode 100644 index 0000000000000000000000000000000000000000..914a290f6b2a0792d19db417efaa49e171685e4d GIT binary patch literal 28832 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 literal 0 HcmV?d00001 diff --git a/B4A/Files/proditem.bal b/B4A/Files/proditem.bal new file mode 100644 index 0000000000000000000000000000000000000000..7ec8f9db7318348846ee3bb6a4165c0ff1b65af2 GIT binary patch literal 5149 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 ez&&c`-}tTPAiZg)Y5xI3ZTRT` literal 0 HcmV?d00001 diff --git a/B4A/Files/usuario.png b/B4A/Files/usuario.png new file mode 100644 index 0000000000000000000000000000000000000000..2935f41a7b156661e9224766883c83c25d88dc25 GIT binary patch literal 17227 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 DS$Fry literal 0 HcmV?d00001 diff --git a/B4A/Files/vecteezy_white-diagonal-stripes-with-red-line-isolated-on-white_12833309-[convertido].png b/B4A/Files/vecteezy_white-diagonal-stripes-with-red-line-isolated-on-white_12833309-[convertido].png new file mode 100644 index 0000000000000000000000000000000000000000..a304e7d9454ef91b70c9d997ccd7f8b6117577d4 GIT binary patch literal 14983 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 S{Pw?ZGyy|%gX;5_WBxxZ#>e&m literal 0 HcmV?d00001 diff --git a/B4A/MarketPlace.b4a b/B4A/MarketPlace.b4a new file mode 100644 index 0000000..9097958 --- /dev/null +++ b/B4A/MarketPlace.b4a @@ -0,0 +1,123 @@ +Build1=Default,mp.keymon.lat,HU2_PUBLIC +File1=candado.png +File10=mesasItem.bal +File11=principal.bal +File12=proditem.bal +File13=proditemCarrito.bal +File14=usuario.png +File15=vecteezy_white-diagonal-stripes-with-red-line-isolated-on-white_12833309-[Convertido].png +File2=durakelo.png +File3=engrane.png +File4=engranes.png +File5=fondoblanco.png +File6=kmt.db +File7=login.bal +File8=logo.png +File9=MainPage.bal +FileGroup1=Default Group +FileGroup10=Default Group +FileGroup11=Default Group +FileGroup12=Default Group +FileGroup13=Default Group +FileGroup14=Default Group +FileGroup15=Default Group +FileGroup2=Default Group +FileGroup3=Default Group +FileGroup4=Default Group +FileGroup5=Default Group +FileGroup6=Default Group +FileGroup7=Default Group +FileGroup8=Default Group +FileGroup9=Default Group +Group=Default Group +Library1=appupdating +Library10=wobblemenu +Library11=preoptimizedclv +Library2=b4xpages +Library3=byteconverter +Library4=compressstrings +Library5=core +Library6=json +Library7=okhttputils2 +Library8=randomaccessfile +Library9=sql +ManifestCode='This code will be applied to the manifest file during compilation.~\n~'You do not need to modify it in most cases.~\n~'See this link for for more information: https://www.b4x.com/forum/showthread.php?p=78136~\n~AddManifestText(~\n~~\n~)~\n~SetApplicationAttribute(android:icon, "@drawable/icon")~\n~SetApplicationAttribute(android:label, "$LABEL$")~\n~CreateResourceFromFile(Macro, Themes.LightTheme)~\n~'End of default text.~\n~~\n~SetApplicationAttribute(android:usesCleartextTraffic, "true") +Module1=B4XMainPage +Module2=C_Principal +Module3=DBRequestManager +Module4=errorManager +Module5=Starter +Module6=Subs +NumberOfFiles=15 +NumberOfLibraries=11 +NumberOfModules=6 +Version=12.5 +@EndOfDesignText@ +#Region Project Attributes + #ApplicationLabel: MarketPlace + #VersionCode: 1 + #VersionName: 3.07.20 + 'SupportedOrientations possible values: unspecified, landscape or portrait. + #SupportedOrientations: portrait + #CanInstallToExternalStorage: False +#End Region + +#Region Activity Attributes + #FullScreen: false + #IncludeTitle: false +#End Region + +'#BridgeLogger: True + +Sub Process_Globals + Public ActionBarHomeClicked As Boolean +End Sub + +Sub Globals + +End Sub + +Sub Activity_Create(FirstTime As Boolean) + Dim pm As B4XPagesManager + pm.Initialize(Activity) +End Sub + +'Template version: B4A-1.01 +#Region Delegates + +Sub Activity_ActionBarHomeClick + ActionBarHomeClicked = True + B4XPages.Delegate.Activity_ActionBarHomeClick + ActionBarHomeClicked = False +End Sub + +Sub Activity_KeyPress (KeyCode As Int) As Boolean + Return B4XPages.Delegate.Activity_KeyPress(KeyCode) +End Sub + +Sub Activity_Resume + B4XPages.Delegate.Activity_Resume +End Sub + +Sub Activity_Pause (UserClosed As Boolean) + B4XPages.Delegate.Activity_Pause +End Sub + +Sub Activity_PermissionResult (Permission As String, Result As Boolean) + B4XPages.Delegate.Activity_PermissionResult(Permission, Result) +End Sub + +Sub Create_Menu (Menu As Object) + B4XPages.Delegate.Create_Menu(Menu) +End Sub + +#if Java +public boolean _onCreateOptionsMenu(android.view.Menu menu) { + processBA.raiseEvent(null, "create_menu", menu); + return true; + +} +#End If +#End Region + +'Program code should go into B4XMainPage and other pages. \ No newline at end of file diff --git a/B4A/MarketPlace.b4a.meta b/B4A/MarketPlace.b4a.meta new file mode 100644 index 0000000..542f99c --- /dev/null +++ b/B4A/MarketPlace.b4a.meta @@ -0,0 +1,24 @@ +ModuleBookmarks0= +ModuleBookmarks1= +ModuleBookmarks2= +ModuleBookmarks3= +ModuleBookmarks4= +ModuleBookmarks5= +ModuleBookmarks6= +ModuleBreakpoints0= +ModuleBreakpoints1= +ModuleBreakpoints2= +ModuleBreakpoints3= +ModuleBreakpoints4= +ModuleBreakpoints5= +ModuleBreakpoints6= +ModuleClosedNodes0= +ModuleClosedNodes1= +ModuleClosedNodes2= +ModuleClosedNodes3=14 +ModuleClosedNodes4= +ModuleClosedNodes5=6 +ModuleClosedNodes6=68 +NavigationStack=C_Principal,b_prodMas_Click,287,0,C_Principal,Class_Globals,64,0,C_Principal,p_pago_Click,950,0,Visual Designer,principal.bal,-100,6,C_Principal,B4XPage_Created,111,4,C_Principal,cb_mesero_SelectedIndexChanged,927,0,C_Principal,cb_pago_SelectedIndexChanged,959,3,C_Principal,b_pagoCerrar_Click,956,1,C_Principal,lv_categorias_ItemClick,948,0,C_Principal,p_mesaAbierta_Click,944,0,C_Principal,b_mesaEditar_Click,940,0 +SelectedBuild=0 +VisibleModules=1,5,6,2 diff --git a/B4A/Starter.bas b/B4A/Starter.bas new file mode 100644 index 0000000..9ade8f3 --- /dev/null +++ b/B4A/Starter.bas @@ -0,0 +1,120 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Service +Version=9.85 +@EndOfDesignText@ +#Region Service Attributes + #StartAtBoot: False + #ExcludeFromLibrary: True +#End Region + +Sub Process_Globals + 'These global variables will be declared once when the application starts. + 'These variables can be accessed from all modules. + Public rp As RuntimePermissions + Dim reqManager As DBRequestManager + Dim skmt, errorLog As SQL + Dim server, ruta As String + 'Para los Logs + Dim logs As StringBuilder + Private logcat As LogCat + Dim Logger As Boolean + Dim rutav As String = "" + Dim tipov As String = "VENTA" + Dim mesaActual As String + Dim ticketActual As String +End Sub + +Sub Service_Create + 'This is the program entry point. + 'This is a good place to load resources that are not specific to a single activity. + If Logger Then LogColor("'/////////////////////////////////////////////////////////////////////////////////////////////", Colors.Green) + If Logger Then LogColor("'///////////////////////////////////// Iniciamos Starter /////////////////////////////////", Colors.Green) + If Logger Then LogColor("'/////////////////////////////////////////////////////////////////////////////////////////////", Colors.Green) + ruta = File.DirInternal + If File.Exists(ruta, "kmt.db") = False Then + File.Copy(File.DirAssets, "kmt.db", ruta, "kmt.db") + End If + skmt.Initialize(ruta,"kmt.db", True) + 'Para los Logs + #if RELEASE + logcat.LogCatStart(Array As String("-v","raw","*:F","B4A:v"), "logcat") + #end if + logs.Initialize + server = "http://keymon.lat:1782" + If Logger Then Log($"Starter reqManager server: ${server}"$) + Logger = False +End Sub + +Sub Service_Start (StartingIntent As Intent) + Service.StopAutomaticForeground 'Starter service can start in the foreground state in some edge cases. + reqManager.Initialize(Me, server) + Subs.revisaBD + #if DEBUG + Logger = True + #else + Logger = False + #End If +End Sub + +Sub Service_TaskRemoved + 'This event will be raised when the user removes the app from the recent apps list. +End Sub + +'Return true to allow the OS default exceptions handler to handle the uncaught exception. 'Para los Logs +Sub Application_Error (Error As Exception, StackTrace As String) As Boolean + 'wait for 500ms to allow the logs to be updated. + Dim jo As JavaObject + Dim l As Long = 500: jo.InitializeStatic("java.lang.Thread").RunMethod("sleep", Array(l)) 'Sleep 500ms + logcat.LogCatStop + logs.Initialize + logs.Append("Ver " & Application.VersionName & CRLF) + logs.Append("R:" & rutav & CRLF) + logs.Append(StackTrace) + Subs.revisaBD + Subs.errorLog.ExecNonQuery2("INSERT INTO errores(fecha, error) VALUES (?,?)", Array As Object (Subs.fechaKMT(DateTime.now), logs)) + StartActivity(errorManager) + Return True +End Sub + +Sub Service_Destroy +' Timer1.Enabled=False + If Logger Then LogColor("starter destroyed", Colors.red) +End Sub + +Sub reinicializaReqManager + reqManager.Initialize(Me, server) + If Logger Then Log(server) +End Sub + +Sub JobDone(Job As HttpJob) + LogColor("Starter - JobDone", Colors.Magenta) + If Job.Success = False Then +' ToastMessageShow("Error: " & Job.ErrorMessage, True) + Else + If Logger Then LogColor("JobDone: '" & reqManager.HandleJob(Job).tag & "' - Registros: " & reqManager.HandleJob(Job).Rows.Size, Colors.Green) 'Mod por CHV - 211110 + If Job.JobName = "DBRequest" Then + Dim result As DBResult = reqManager.HandleJob(Job) + If result.Tag = "updateKell_UTR" Then 'query tag + If Logger Then Subs.logJobDoneResultados(result) + End If + End If + End If + Job.Release +End Sub + +'Para los Logs +Private Sub logcat_LogCatData (Buffer() As Byte, Length As Int) + logs.Append(BytesToString(Buffer, 0, Length, "utf8")) + If logs.Length > 4000 Then + logs.Remove(0, logs.Length - 2000) 'Obtenemos log de 2000 ~ 4000 chars + End If +End Sub + +'Revisa que la conexion a la base de datos este bien. +Sub revisaBD 'ignore + If Logger Then Log("revisaBD") + If Not(File.Exists(ruta, "kmt.db")) Then File.Copy(File.DirAssets, "kmt.db", ruta, "kmt.db") + If Not(skmt.IsInitialized) Then skmt.Initialize(ruta, "kmt.db", True) +End Sub diff --git a/B4A/Subs.bas b/B4A/Subs.bas new file mode 100644 index 0000000..d54bfe4 --- /dev/null +++ b/B4A/Subs.bas @@ -0,0 +1,1408 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=StaticCode +Version=11 +@EndOfDesignText@ +'Code module +'Subs in this code module will be accessible from all modules. +Sub Process_Globals + 'These global variables will be declared once when the application starts. + 'These variables can be accessed from all modules. + Public GZip As GZipStrings 'Usa la libreria CompressStrings + Private su As StringUtils 'Usa la libreria StringUtils + Dim phn As Phone + Dim devModel As String + Dim kmt, errorLog As SQL 'Requiere la libreria "SQL" +' Dim wifi As MLwifi + Dim ssid As String 'ignore + Dim rutaMaxPoints As Int = 3000 + Dim rutaHrsAtras As Int = 48 +' Dim rutaInicioHoy As String = "" + Private subsLogs As Boolean = False +End Sub + +'Pone el valor de phn.Model en la variable global "devModel" +Sub getPhnId As String 'ignore + 'Requiere la libreria "Phone" + devModel = phn.Model + If devModel.Length <= 3 Then 'Si phn.Model esta en blanco ... + Dim t As String = phn.GetSettings("android_id") 'Intentamos con "android_id" + devModel = t + End If + If devModel.Length >= 3 Then 'Si tenemos valor para phn.Model + File.WriteString(File.DirInternal, "phnId.txt", devModel) 'Sobreescribimos archivo phnId.txt with deviceId +' Log("Tenemos phnId: "&devModel&" "&File.DirInternal&"/phn.txt sobreescrito") + Else If devModel.Length < 3 Then ' Si no tenemos valor, lo leemos de phnId.txt + Dim s As String = File.ReadString(File.DirInternal, "phnId.txt") + devModel = s +' Log("Leemos id de "&File.DirInternal&"/phnId.txt") +' Log(devModel) + End If + Return devModel +End Sub + +'Comprime y regresa un texto (str) en base64 +Sub compress(str As String) As String 'ignore + 'Requiere la libreria "CompressStrings" + Dim compressed() As Byte = GZip.compress(str) +' Log($"UncompressedBytesLength: ${str.Length}"$) +' Log($"CompressedBytesLength: ${compressed.Length}"$) + Dim base64 As String = su.EncodeBase64(compressed) + Log($"Comprimido: ${base64.Length}"$) +' Log($"CompressedBytes converted to base64: ${base64}"$) + Return base64 +End Sub + +'Descomprime y regresa un texto en base64 +Sub decompress(base64 As String) As String 'ignore + Dim decompressedbytes() As Byte = su.DecodeBase64(base64) +' Log($"decompressedbytesLength: ${decompressedbytes.Length}"$) + Dim bc As ByteConverter + Dim uncompressed As String = bc.StringFromBytes(decompressedbytes,"UTF8") + Log($"Descomprimido: ${uncompressed.Length}"$) +' Log($"Decompressed String = ${uncompressed}"$) + Return uncompressed +End Sub + +'Convierte una fecha al formato yyMMddHHmmss +Sub fechaKMT(fecha As String) As String 'ignore +' Log(fecha) + Dim OrigFormat As String = DateTime.DateFormat 'save orig date format + DateTime.DateFormat="yyMMddHHmmss" + Dim nuevaFecha As String=DateTime.Date(fecha) + DateTime.DateFormat=OrigFormat 'return to orig date format +' Log(nuevaFecha) + Return nuevaFecha +End Sub + +'Genera una notificacion con importancia alta +Sub notiHigh(title As String, body As String, activity As Object) 'ignore + Private notif As Notification + notif.Initialize2(notif.IMPORTANCE_HIGH) + notif.Icon = "icon" + notif.Vibrate = False + notif.Sound = False + notif.AutoCancel = True + Log("notiHigh: "&title) + notif.SetInfo(title, body, activity) +' Log("notiHigh SetInfo") + notif.Notify(777) +End Sub + +'Regresa el objeto de una notificacion con importancia baja +Sub notiLowReturn(title As String, Body As String, id As Int) As Notification 'ignore + Private notification As Notification + notification.Initialize2(notification.IMPORTANCE_LOW) + Log("notiLowReturn: "&title) + notification.Icon = "icon" + notification.Sound = False + notification.Vibrate = False + notification.SetInfo(title, Body, Main) + notification.Notify(id) +' Log("notiLowReturn SetInfo") + Return notification +End Sub + +'Escribimos las coordenadas y fecha a un archivo de texto +Sub guardaInfoEnArchivo(coords As String) 'ignore + ' Cambiamos el formato de la hora + Dim OrigFormat As String=DateTime.DateFormat 'save orig date format + DateTime.DateFormat="MMM-dd HH:mm:ss" + Dim lastUpdate As String=DateTime.Date(DateTime.Now) + DateTime.DateFormat=OrigFormat 'return to orig date format + + Dim ubic As String = coords&","&lastUpdate + Dim out As OutputStream = File.OpenOutput(File.DirRootExternal, "gps.txt", True) + Dim s As String = ubic & CRLF + Dim t() As Byte = s.GetBytes("UTF-8") + out.WriteBytes(t, 0, t.Length) + out.Close +End Sub + +'Escribimos las coordenadas (latitud, longitud, fecha) y fecha a una BD +Sub guardaInfoEnBD(coords As String) 'ignore + Log("Guardamos ubicacion en BD - "&coords) + Try + Dim latlon() As String = Regex.Split("\|", coords) + If latlon.Length < 2 Then latlon = Regex.Split(",", coords) 'Si son menos de 2, entonces estan separadas por comas y no por "|" + If subsLogs Then Log("LatLon="&latlon) + kmt.ExecNonQuery2("INSERT INTO RUTA_GPS(FECHA, LAT, LON) VALUES (?,?,?)", Array As Object (latlon(2),latlon(0),latlon(1))) + Catch + LogColor(LastException, Colors.red) + End Try +End Sub + +'Regresa la ruta solicitada comprimida y en base64 +Sub dameRuta(inicioRuta As String, origenRuta As String) As String 'ignore +' 'Requiere la libreria "SQL" +' Dim fechaInicio As String +' Try 'incioRuta es numero +' inicioRuta = inicioRuta * 1 +'' Log("fechaInicio numerica="&fechaInicio) +' fechaInicio = fechaKMT(DateTime.Now - (DateTime.TicksPerHour * inicioRuta)) +' Catch 'inicioRuta es string +' fechaInicio = fechaInicioHoy +'' Log("fechaInicio string="&fechaInicio) +' End Try +' If subsLogs Then Log("fechaInicio: "&fechaInicio&" | rutaHrsAtras="&rutaHrsAtras) 'fechaKMT(DateTime.Now) +' Dim c As Cursor +' If kmt.IsInitialized = False Then kmt.Initialize(Starter.ruta, "kmt.db", True) +' If subsLogs Then Log("select FECHA, LAT, LON from "& origenRuta &" where FECHA > " & fechaInicio & " order by FECHA desc limit " & rutaMaxPoints) +' c = kmt.ExecQuery("select FECHA, LAT, LON from "& origenRuta &" where FECHA > " & fechaInicio & " order by FECHA desc limit " & rutaMaxPoints) +' c.Position = 0 +' Dim ruta2 As String = "" +' If c.RowCount>0 Then +' For i=0 To c.RowCount -1 +' c.Position=i +' ruta2=ruta2&CRLF&c.GetString("LAT")&","&c.GetString("LON")&","&c.GetString("FECHA") +' B4XPages.MainPage.fechaRuta = c.GetString("FECHA") +' Next +' End If +' c.Close +' Return compress(ruta2) +End Sub + +'Limpiamos la tabla RUTA_GPS de la BD +Sub deleteGPS_DB 'ignore + kmt.ExecNonQuery("delete from RUTA_GPS") + kmt.ExecNonQuery("vacuum;") + ToastMessageShow("Borramos BD Coords GPS", False) +End Sub + +'Limpiamos la tabla errorLog de la BD +Sub deleteErrorLog_DB 'ignore + errorLog.ExecNonQuery("delete from errores") + errorLog.ExecNonQuery("vacuum;") + ToastMessageShow("BD Errores Borrada", False) +End Sub + +'Borramos el archio "gps.txt" +Sub borramosArchivoGPS 'ignore + Dim out As OutputStream = File.OpenOutput(File.DirRootExternal, "gps.txt", False) + Dim s As String = "" + Dim t() As Byte = s.GetBytes("UTF-8") + out.WriteBytes(t, 0, t.Length) + out.Close +End Sub + +'Revisa que exista la BD y si es necesario crea algunans tablas dentro de ella +Sub revisaBD 'ignore +' Main.ruta = File.DirInternal +' Log(Starter.ruta) +' Log(File.Exists(Starter.ruta, "kmt.db")) + If Not(File.Exists(Starter.ruta, "kmt.db")) Then + File.Copy(File.DirAssets, "kmt.db", Starter.ruta, "kmt.db") + LogColor("copiamos kmt.db de "&File.DirAssets & " a " & Starter.ruta,Colors.Green) + End If + If Not(kmt.IsInitialized) Then kmt.Initialize(Starter.ruta, "kmt.db", True) + kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS RUTA_GPS(FECHA INTEGER, LAT TEXT, LON TEXT)") +' kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS UUC(fecha INTEGER, lat TEXT, lon TEXT)") 'LastKnownLocation + kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS bitacora(fecha INTEGER, texto TEXT)") 'Bitacora + kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS HIST_AVANCE(HA_MARCA TEXT, HA_AVANCE TEXT, HA_OBJETIVO TEXT, HA_PORCENTAJE TEXT)") 'Historico avance mes actual + kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS ABONOSP(NOTA TEXT, CLIENTE TEXT, SALDO_PENDIENTE TEXT)") + kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS CLIENTE_NUEVO(CN_ID_CLIENTE TEXT, CN_NOMBRE TEXT, CN_enviado text)") + kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS RUTA_SUPLENCIA(RS_RUTA TEXT)") + kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS CAT_MESAS(M_ID TEXT, M_NUMERO TEXT, M_NOMBRE TEXT, M_ZONA TEXT, M_ESTATUS TEXT, M_TICKET TEXT DEFAULT 'PENDIENTE' NOT NULL, M_MESERO TEXT, M_PAGO TEXT, M_COMENSALES INTEGER)") + kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS CAT_MESEROS(MS_ID TEXT, MS_NOMBRE TEXT, MS_MESAS_ASIGNADAS TEXT)") + kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS bitacora(fecha INTEGER, texto TEXT)") 'Bitacora +' kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS MESAA(MESA STRING)") +' kmt.ExecNonQuery("drop table PEDIDO_INICIO_FINAL") 'Bitacora + kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS PEDIDO_INICIO_FINAL(PIF_CLIENTE TEXT, PIF_HORA_INICIO LONG, PIF_HORA_FINAL LONG)") 'Bitacora + kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS PEDIDO3 (PE_PRECIO2 TEXT,PE_TIPO TEXT,PE_FOLIO NUMERIC,PE_DESC NUMERIC,PE_COSTO_SIN TEXT,PE_MESA TEXT,PE_CEDIS TEXT,PE_COSTO_TOT NUMERIC,PE_COSTOU NUMERIC,PE_CANT NUMERIC,PE_PRONOMBRE TEXT,PE_PROID TEXT,PE_TICKET TEXT,PE_FECHA TEXT,PE_MESERO TEXT)") + kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS PEDIDO (PE_PRECIO2 TEXT,PE_TIPO TEXT,PE_FOLIO NUMERIC,PE_DESC NUMERIC,PE_COSTO_SIN TEXT,PE_MESA TEXT,PE_CEDIS TEXT,PE_COSTO_TOT NUMERIC,PE_COSTOU NUMERIC,PE_CANT NUMERIC,PE_PRONOMBRE TEXT,PE_PROID TEXT,PE_TICKET TEXT,PE_FECHA TEXT,PE_MESERO TEXT)") + kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS PEDIDO_TICKET (PC_FACT TEXT, PC_COSTO_SIN TEXT, PC_MESA TEXT, PC_ALMACEN TEXT, PC_LON TEXT, PC_LAT TEXT, PC_TICKET TEXT, PC_FECHA TEXT, PC_USER TEXT, PC_NOART NUMERIC, PC_MONTO NUMERIC, PC_ENVIO_OK INTEGER, PC_TIEMPO_TIENDA FLOAT, PC_FACTURA INTEGER)") + kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS CAT_HIST_COMPRAS (H_IDCOMPRA TEXT, H_FOLIO NUMERIC, H_MESA TEXT, H_CEDIS TEXT, H_COSTO_TOT NUMERIC, H_COSTOU NUMERIC, H_CANT NUMERIC, H_PRONOMBRE TEXT, H_PROID TEXT, H_TICKET TEXT, H_FECHA TEXT)") + + 'Tabla para la bitacora de errores + If Not(errorLog.IsInitialized) Then errorLog.Initialize(Starter.ruta, "errorLog.db", True) + errorLog.ExecNonQuery("CREATE TABLE IF NOT EXISTS errores(fecha INTEGER, error TEXT)") + +End Sub + +'Obtiene el ssid al que esta conectado el telefono +Sub getSSID 'ignore +' 'Requiere la libreria "MLWifi400" +' If wifi.isWifiConnected Then +' ssid = wifi.WifiSSID +' End If +End Sub + +'Convierte un texto en formato JSON a un objeto "Map" +Sub JSON2Map(theJson As String) As Map 'ignore + 'Requiere la libreria "JSON" + Try + Private json As JSONParser + json.Initialize(theJson) + Return json.NextObject + Catch + Log(LastException) + log2DB("JSON2Map: "&LastException) + Private m As Map = CreateMap("title":"Error generating JSON", "t":"Error", "Message":LastException, "text" : LastException) + Return m + End Try +End Sub + +'Convierte un mapa a formato JSON +Sub map2JSON(m As Map) As String 'ignore + 'Requiere la libreria "JSON" + 'Convierte un objecto "Map" a JSON + Dim jg As JSONGenerator + jg.Initialize(m) + Dim t As String = jg.ToString + Return t +End Sub + +'Mandamos "coords" en un mensaje a "Sprvsr" +'Sub mandamosLoc(coords As String) 'ignore +'' Log("Iniciamos mandamosLoc "&coords) +'' Log("locRequest="&Tracker.locRequest) +' guardaInfoEnBD(coords)'Escribimos coordenadas y fecha a una bd +' Dim t As String +' If Tracker.locRequest="Activa" Then +' If PushService.au = 1 Then +' t = "au" ' es una actualizacion +' Else +' t = "u" ' es una peticion +' End If +' Dim params As Map = CreateMap("topic":"Sprvsr", "coords":coords, "t":t, "b":PushService.battery, "mt":Main.montoActual) +' CallSub2(PushService, "mandaMensaje",params) +' Tracker.locRequest="Enviada" +' CallSubDelayed(Tracker,"CreateLocationRequest") +' End If +'End Sub + +'Regresa la fecha y hora de hoy a las 00:00 en el formato "yyMMddHHMMSS" +Sub fechaInicioHoy As String 'ignore + Dim OrigFormat As String = DateTime.DateFormat 'save orig date format + DateTime.DateFormat="yyMMdd" + Private h As String = DateTime.Date(DateTime.Now)&"000000" + DateTime.DateFormat=OrigFormat 'return to orig date format + Log("Hoy="&h) + Return h +End Sub + +'Guardamos "texto" a la bitacora +Sub log2DB(texto As String) 'ignore + LogColor(fechaKMT(DateTime.Now)&" - log2BD: '"&texto&"'", Colors.LightGray) + kmt.ExecNonQuery2("INSERT INTO bitacora(fecha, texto) VALUES (?,?)", Array As Object (fechaKMT(DateTime.now), texto)) +End Sub + +'Regresa verdadero si ya pasaron XX minutos de la fecha dada +Sub masDeXXMins(hora As Int, mins As Int) As Boolean 'ignore + If (hora + mins * DateTime.TicksPerMinute) < DateTime.Now Then + Return True + Else + Return False + End If +End Sub + +'Regresa verdadero si ya pasaron XX minutos de la fechaKMT dada +Sub masDeXXMinsKMT(hora As String, mins As Int) As Boolean 'ignore + Try + ' LogColor($"Hora=${fechaKMT(fechaKMT2Ticks(hora) + mins * DateTime.TicksPerMinute)}, Mins=${mins}, Actual=${fechaKMT(DateTime.Now)}"$,Colors.red) + If fechaKMT2Ticks(hora) + mins * DateTime.TicksPerMinute < DateTime.Now Then + ' Log("+++ +++ "&fechaKMT(fechaKMT2Ticks(hora) + mins * DateTime.TicksPerMinute) & " < " & fechaKMT(DateTime.Now)) + Return True + Else + ' Log("+++ +++ "&fechaKMT(fechaKMT2Ticks(hora) + mins * DateTime.TicksPerMinute) & " > " & fechaKMT(DateTime.Now)) + Return False + End If + Catch + Log(LastException) + End Try +End Sub + +'Limpiamos la tabla "bitacora" de la BD +Sub borraLogDB 'ignore + LogColor("Borramos BD de log", Colors.Magenta) + kmt.ExecNonQuery("delete from bitacora") + kmt.ExecNonQuery("vacuum;") +End Sub + +'Monitoreamos los servicios para ver si estan activos (No pausados), y si no, los reniciamos +'Sub Monitor 'ignore +' Private monitorStatus As Boolean = True +' LogColor("Corriendo Subs.Monitor", Colors.RGB(161,150,0)) +' If IsPaused(Tracker) Then +' log2DB("Reiniciando 'Tracker Pausado' desde Subs.Monitor") +' StartService(Tracker) +' monitorStatus = False +' Else +' CallSubDelayed(Tracker, "revisaFLP") +' End If +' If IsPaused(PushService) Then +' log2DB("Reiniciando 'PushService Pausado' desde Subs.Monitor") +' StartService(PushService) +' monitorStatus = False +' Else +' revisaPushService +' End If +' If monitorStatus Then LogColor(" +++ +++ Servicios Activos", Colors.Green) +'End Sub + +'Compara la UUG (Ultima Ubicacion Guardada) con FLP.LastKnowLocation y si +'cumple con los requisitos de distancia y precision la guardamos en la BD. +Sub revisaUUG 'ignore +' Try +'' revisaFLP +' If Tracker.FLP.GetLastKnownLocation.IsInitialized Then +' Dim daa As Int = Tracker.UUGCoords.DistanceTo(Tracker.FLP.GetLastKnownLocation) 'Distancia de la UUG a la actual de Tracker.FLP.GetLastKnownLocation +' If Starter.Logger Then LogColor($"**** UUC "${fechaKMT(Tracker.FLP.GetLastKnownLocation.Time)}|$0.2{Tracker.FLP.GetLastKnownLocation.Accuracy}|$0.8{Tracker.FLP.GetLastKnownLocation.Latitude}|$0.8{Tracker.FLP.GetLastKnownLocation.Longitude}|$0.2{Tracker.FLP.GetLastKnownLocation.Speed}|"$, Colors.RGB(255,112,35)) +' If daa > 40 And Tracker.FLP.GetLastKnownLocation.Accuracy < 35 Then 'Si la distancia de la ubicacion anterior es mayor de XX y la precision es menor de XX, la guardamos ... +' kmt.ExecNonQuery2("INSERT INTO RUTA_GPS(fecha, lat, lon) VALUES (?,?,?)", Array As Object (fechaKMT(Tracker.FLP.GetLastKnownLocation.Time),Tracker.FLP.GetLastKnownLocation.Latitude,Tracker.FLP.GetLastKnownLocation.Longitude)) +' If Starter.Logger Then Log("++++ Distancia a anterior="&daa&"|"&"Precision="&Tracker.FLP.GetLastKnownLocation.Accuracy) +' End If +' Tracker.UUGCoords = Tracker.FLP.GetLastKnownLocation +' End If +' Catch +' LogColor("If Tracker.FLP.GetLastKnownLocation.IsInitialized --> "&LastException, Colors.Red) +' End Try +End Sub + +'Revisamos que el FLP (FusedLocationProvider) este inicializado y activo +Sub revisaFLP 'ignore +' LogColor("**** **** Revisamos FLP **** ****", Colors.RGB(78,0,227)) +' Private todoBienFLP As Boolean = True +' Try +' If Not(Tracker.FLP.IsInitialized) Then +' log2DB("revisaFLP: No esta inicializado ... 'Reinicializando FLP'") +' Tracker.FLP.Initialize("flp") +' todoBienFLP = False +' End If +' Catch +' LogColor("If Not(Tracker.FLP.IsInitialized) --- "&LastException, Colors.Red) +' End Try +' Try +' If Tracker.FLP.IsInitialized Then +' Try +' If Not(Tracker.FLP.IsConnected) Then +' log2DB("revisaFLP: No esta conectado ... 'Reconectando FLP'") +' ' Tracker.FLP.Connect +' CallSubDelayed(Tracker,"StartFLP") +' todoBienFLP = False +' End If +' Catch +' LogColor("If Not(Tracker.FLP.IsConnected) --> "&LastException, Colors.Red) +' End Try +' Try +' If Tracker.FLP.IsConnected And _ +' Tracker.FLP.GetLastKnownLocation.IsInitialized And _ +' Tracker.FLP.GetLastKnownLocation.DistanceTo(Tracker.UUGCoords) > 500 Then +' log2DB("revisaFLP: 'No se esta actualizando, lo reiniciamos ...'") +' StartService(Tracker) +' todoBienFLP = False +' End If +' Catch +' LogColor("If FLP.IsConnectctd and FLP.getLKL.IsInitialized --> "&LastException, Colors.Red) +' End Try +' End If +' If todoBienFLP Then LogColor(" +++ +++ Sin errores en FLP", Colors.Green) +' Catch +' LogColor("If Tracker.FLP.IsInitialized --> "&LastException, Colors.Red) +' End Try +' ' revisar hora de lastKnownlocation y si es mayor de 10 minutos llamar StartFLP +End Sub + +'Revisamos que el servicio "PushService" este inicializado y activo +'Sub revisaPushService 'ignore +' Private todoBienPS As Boolean = True +' LogColor("**** **** Revisamos PushService **** ****", Colors.RGB(78,0,227)) +' If Not(PushService.wsh.IsInitialized) Then 'Si no esta inicializado ... +' log2DB("revisaPushService: No esta inicializado ... 'Reinicializando PushService'") +' CallSubDelayed(PushService, "Connect") +' todoBienPS = False +' End If +' If Not(PushService.wsh.ws.Connected) Then 'Si no esta conectado ... +' log2DB("revisaPushService: No esta conectado ... 'Reconectando PushService'") +' CallSubDelayed(PushService, "Connect") +' todoBienPS = False +' End If +' If masDeXXMinsKMT(Starter.pushServiceActividad, 5) Then 'Si mas de xx minutos de la ultima actividad entonces ... +' PushService.wsh.Close +' CallSubDelayed(PushService, "Connect") +'' StartService(PushService) +' log2DB("revisaPushService: 'Reconectamos 'PushService' por inactividad") +' Starter.pushServiceActividad = fechaKMT(DateTime.Now) +' todoBienPS = False +' End If +' If todoBienPS Then LogColor(" +++ +++ Sin errores en PushService", Colors.Green) +'End Sub + +'Borramos renglones extra de la tabla de errores +Sub borraArribaDe100Errores 'ignore + revisaBD + LogColor("Borramos BD de log", Colors.Magenta) + errorLog.ExecNonQuery("DELETE FROM errores WHERE fecha NOT in (SELECT fecha FROM errores ORDER BY fecha desc LIMIT 99 )") + errorLog.ExecNonQuery("vacuum;") + Log("Borramos mas de 100 de errorLog") +End Sub + +'Borramos renglones extra de la tabla de bitacora +Sub borraArribaDe600RenglonesBitacora 'ignore + revisaBD + LogColor("Borramos BD de log", Colors.Magenta) + kmt.ExecNonQuery("DELETE FROM bitacora WHERE fecha NOT in (SELECT fecha FROM bitacora ORDER BY fecha desc LIMIT 599 )") + kmt.ExecNonQuery("vacuum;") + Log("Borramos mas de 600 de bitacora") +End Sub + +'Inserta 50 renglones de prueba a la tabla "errores" +Sub insertaRenglonesPruebaEnErrorLog 'ignore + revisaBD + Log("insertamos 50 renglones a errorLog") + For x = 1 To 50 + errorLog.ExecNonQuery2("INSERT INTO errores(fecha, error) VALUES (?,?)", Array As Object (fechaKMT(DateTime.now), "abc")) + Log(x) + Next +End Sub + +'Regresa la tabla "errores" en una lista de mapas convertida a JSON +Sub dameErroresJSON(SQL As SQL, maxErrores As Int, comprimido As Boolean) As String 'ignore + Log("dameErroresJSON") + Private j As JSONGenerator + Private lim As String + Private cur As ResultSet + Private l As List + Private i As Int = 0 + l.Initialize + Dim m, m2 As Map + m2.Initialize + If maxErrores = 0 Then lim = "" Else lim = "limit "&maxErrores + cur = SQL.ExecQuery("select * from errores order by fecha desc "&lim) + Do While cur.NextRow + m.Initialize + m.Put("fecha", cur.GetString("fecha")) + m.Put("error", cur.GetString("error")) + m2.Put(i,m) + i = i + 1 + Loop + cur.Close + j.Initialize(m2) + Log(j.ToString) + If comprimido Then + Return compress(j.ToString) + Else + Return j.ToString + End If +End Sub + +'Convierte una fecha en formato YYMMDDHHMMSS a Ticks +Sub fechaKMT2Ticks(fKMT As String) As Long 'ignore + Try + If fKMT.Length = 12 Then + Private parteFecha As String = fKMT.SubString2(0,6) + Private parteHora As String = fKMT.SubString(6) + Private OrigFormat As String = DateTime.DateFormat 'save original date format + DateTime.DateFormat="yymmdd" + DateTime.TimeFormat="HHmmss" + Private ticks As Long = DateTime.DateTimeParse(parteFecha,parteHora) + DateTime.DateFormat=OrigFormat 'return to original date format + Return ticks + Else + Log("Formato de fecha incorrecto, debe de ser 'YYMMDDHHMMSS', no '"&fKMT&"' largo="&fKMT.Length) + Return 0 + End If + Catch + Log(LastException) + LogColor($"Fecha dada: ${fKMT}, Parte Fecha: ${parteFecha}, Parte Hora: ${parteHora}"$, Colors.Red) + Return 0 + End Try +End Sub + +Sub InstallAPK(dir As String, apk As String) 'ignore + If File.Exists(dir, apk) Then + Dim i As Intent + i.Initialize(i.ACTION_VIEW, "file://" & File.Combine(dir, apk)) + i.SetType("application/vnd.android.package-archive") + StartActivity(i) + End If +End Sub + +'Copia la base de datos del almacenamiento interno al externo en el directorio kmts +Sub copiaDB(result As Boolean) 'ignore + ToastMessageShow("copiaDB", False) + If result Then + Dim p As String + If File.ExternalWritable Then + p = File.DirRootExternal +' Log("Externo") + Else + p = File.DirInternal +' Log("Interno") + End If + Dim theDir As String + Try + File.MakeDir(File.DirRootExternal,"kmts") + theDir = "/kmts" + Catch + theDir = "" + End Try + Try + File.Copy(File.DirInternal,"kmt.db",File.DirRootExternal&theDir,"cedex_kmt.db") + File.Copy(File.DirInternal,"errorLog.db",File.DirRootExternal&theDir,"cedex_errorLog.db") + ToastMessageShow("BD copiada!", False) + Catch + ToastMessageShow("No se pudo hacer la copia: "&LastException, True) + End Try + Log("rootExternal="&p) + Log("File.DirInternal="&File.DirInternal) + Log("File.DirRootExternal="&File.DirRootExternal) + Else + ToastMessageShow("Sin permisos", False) + End If +End Sub + +'HAcel elpanel dado del ancho y alto especificados. +Sub panelWH(panel As Panel, w As Int, h As Int) + panel.Width = w + panel.Height = h +End Sub + +'Hace visible y trae al frente el panel con los parametros "Top" y "Left" dados +Sub panelVisible(panel As Panel, top As Int, left As Int) 'ignore +' panel.BringToFront + panel.Visible = True + panel.Top = top + panel.Left = left +End Sub + +'Centra una etiqueta dentro de un elemento superior +Sub centraEtiqueta(elemento As Label, anchoElementoSuperior As Int) 'ignore + elemento.Left = Round(anchoElementoSuperior/2)-(elemento.Width/2) +End Sub + +'Centra un panel horizontalmente dentro de un elemento superior +Sub centraPanel(elemento As Panel, anchoElementoSuperior As Int) 'ignore + elemento.Left = Round(anchoElementoSuperior/2)-(elemento.Width/2) +End Sub + +'Centra un panel verticalmente dentro de un elemento superior +Sub centraPanelV(elemento As Panel, altoElementoSuperior As Int) 'ignore + elemento.Top = Round(altoElementoSuperior/2)-(elemento.Height/2) +End Sub + +'Centra una barra de progreso dentro de un elemento superior +Sub centraProgressBar(elemento As ProgressBar, anchoElementoSuperior As Int) 'ignore + elemento.Left = Round(anchoElementoSuperior/2)-(elemento.Width/2) +End Sub + +'Centra un oton dentro de un elemento superior +Sub centraBoton(elemento As Button, anchoElementoSuperior As Int) 'ignore + elemento.Left = Round(anchoElementoSuperior/2)-(elemento.Width/2) +End Sub + +'Regresa el usuario de la tabla USUARIOA si es que existe, si no existe, regresa "SinUsuario". +Sub buscaDBUsuario As String 'ignore + Private c As Cursor + Private usuario As String = "SinUsuario" + c=kmt.ExecQuery("select USUARIO from usuarioa") + c.Position=0 + If c.RowCount > 0 Then usuario = c.GetString("USUARIO") + Return usuario +End Sub + +'Saca el usuario de la tabla USUARIOA +Sub dameUsuarioDeDB As String 'ignore + Private c As Cursor + Private u As String = "SinUsuario" + If Not(kmt.IsInitialized) Then revisaBD + c=kmt.ExecQuery("select USUARIO from usuarioa") + c.Position=0 + If c.RowCount > 0 Then u = c.GetString("USUARIO") + c.Close + Return u +End Sub + +''Inserta un producto en la tabla "PEDIDO" +'Sub guardaProductoX(cedis As String, costoTot As String, costoU As String, cant As String, nombre As String, prodId As String, ticketId As String, fecha As String, usuario As String, tipoV As String, precio2 As String, query As String) 'ignore +'' LogColor("guardaProducto", Colors.Magenta) +'' Log($"Guardamos producto ${prodId}"$) +'' B4XPages.MainPage.skmt.ExecNonQuery2("INSERT INTO PEDIDO (PE_CEDIS, PE_COSTO_TOT, PE_COSTOU, PE_CANT, PE_PRONOMBRE, PE_PROID, PE_TICKET, PE_FECHA, PE_USUARIO, PE_TIPO, PE_PRECIO2, PE_RUTA) VALUES(?,?,?,?,?,?,?,?,?,?,?,?) ", Array As Object (cedis, costoTot, costoU, cant, nombre, prodId, ticketId, fecha, usuario, tipoV, precio2, Starter.rutaV)) +'' B4XPages.MainPage.skmt.ExecNonQuery2("update " & query & " set cat_gp_almacen = cat_gp_almacen - ? where cat_gp_id = ? ", Array As Object(cant, prodId)) +'' ToastMessageShow("guardaProd", False) +'End Sub + +'Sub guardaProductoSin(cedis As String, costoTot As String, costoU As String, cant As String, nombre As String, prodId As String, ticketId As String, fecha As String, usuario As String, rutaV As String, precioSin As String, tipoV As String, precio2 As String, query As String) 'ignore +'' LogColor("guardaProductoSin", Colors.Magenta) +'' B4XPages.MainPage.skmt.ExecNonQuery2("INSERT INTO PEDIDO (PE_CEDIS, PE_COSTO_TOT, PE_COSTOU, PE_CANT, PE_PRONOMBRE, PE_PROID, PE_TICKET, PE_FECHA, PE_USUARIO, PE_RUTA, PE_COSTO_SIN, PE_TIPO, PE_PRECIO2) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?) ", Array As Object (cedis, costoTot,costoU, cant, nombre, prodId, ticketId, fecha, usuario, rutaV, precioSin, tipoV, precio2)) +'' B4XPages.MainPage.skmt.ExecNonQuery2("update " & query & " set cat_gp_almacen = cat_gp_almacen - ? where cat_gp_id = ? ", Array As Object(cant, prodId)) +'' DateTime.DateFormat = "MM/dd/yyyy" +'' Private sDate As String =DateTime.Date(DateTime.Now) +'' Private sTime As String =DateTime.Time(DateTime.Now) +'' Private c As Cursor = B4XPages.MainPage.skmt.ExecQuery("select sum(pe_costo_tot) as TOTAL_CLIE, SUM(PE_CANT) AS CANT_CLIE, SUM(PE_COSTO_SIN) AS TOTAL_CLIE_SIN FROM PEDIDO WHERE PE_TICKET IN (Select CUENTA from cuentaa)") +'' c.Position=0 +'' B4XPages.MainPage.skmt.ExecNonQuery("delete from PEDIDO_TICKET where PC_CLIENTE In (select cuenta from cuentaa)") +'' B4XPages.MainPage.skmt.ExecNonQuery2("insert into PEDIDO_TICKET(PC_CLIENTE, PC_FECHA, PC_USER, PC_NOART, PC_MONTO,PC_LON, PC_LAT,PC_ALMACEN,PC_RUTA,PC_COSTO_SIN) VALUES (?,?,?,?,?,?,?,?,?,?)", Array As Object(ticketId, sDate & sTime, usuario, c.GetString("CANT_CLIE"),c.GetString("TOTAL_CLIE"), B4XPages.MainPage.lon_gps, B4XPages.MainPage.lat_gps, cedis, rutaV, c.GetString("TOTAL_CLIE_SIN"))) +'' B4XPages.MainPage.skmt.ExecNonQuery("UPDATE kmt_info set gestion = 2 where CAT_CL_CODIGO In (select cuenta from cuentaa)") +'' c.Close +' ToastMessageShow("guardaProdSin", False) +'End Sub + +'Regresa el almacen actual de la base de datos. +Sub traeAlmacen As String 'ignore + Private c As Cursor + Private a As String + c=Starter.skmt.ExecQuery("select ID_ALMACEN from CAT_ALMACEN") + c.Position = 0 + a = C.GetString("ID_ALMACEN") + c.Close + Return a +End Sub + +'Regresa el nombre del producto desde CAT_GUNAPROD +Sub traeProdNombre(id As String) As String + Private h As Cursor + Private n As String + h=Starter.skmt.ExecQuery2("select CAT_GP_NOMBRE from CAT_GUNAPROD where CAT_GP_ID = ? ", Array As String(id.Trim)) + If h.RowCount > 0 Then + h.Position = 0 + n = h.GetString("CAT_GP_NOMBRE") +' Log(h.RowCount&"|"&id&"|"&n&"|") + End If + h.Close + If n = Null Or n="" Then n = "N/A" +' Log(h.RowCount&"|"&id&"|"&n&"|") + Return n +End Sub + +'Regresa la mesa actual de la base de datos. +Sub traeMesa As String 'ignore + Private c As Cursor + Private m As String + c=Starter.skmt.ExecQuery("select MESA from MESAA") + m = "0" + If c.RowCount > 0 Then + c.Position=0 + m = c.GetString("MESA") + End If + c.Close + Return m +End Sub + +Sub traeTicket(mesaId As String) As String 'ignore + Private c As Cursor + Private cl As String = "PENDIENTE" + c=Starter.skmt.ExecQuery("Select M_TICKET from CAT_MESAS where M_ID = '${mesaId}'") + If c.RowCount > 0 Then + c.Position=0 + cl = c.GetString("M_TICKET") + End If + c.Close + Return cl +End Sub + +Sub traeFecha As String 'ignore + DateTime.DateFormat = "MM/dd/yyyy" + Private sDate As String =DateTime.Date(DateTime.Now) + Private sTime As String =DateTime.Time(DateTime.Now) + Return sDate & sTime +End Sub + +'Regresa el usuario de la tabla USUARIOA +Sub traeUsuarioDeBD As String 'ignore + Private c As Cursor + Private u As String = "SinUsuario" + If Not(kmt.IsInitialized) Then revisaBD + c=kmt.ExecQuery("select USUARIO from usuarioa") + c.Position=0 + If c.RowCount > 0 Then u = c.GetString("USUARIO") + c.Close + Return u +End Sub + +'Regresa un mapa con la información de la promo. +'Regresa: {id, maxXcliente, maxRecurrente, maxPromos, historico, +' productos={idProducto={idProducto, preciosimptos, precio, almacen, tipo, piezas, usuario, fecha, regalo, clasif}} 'Mapa con los productos de la promo y los datos de cada uno. +' tipos={idProducto=tipo} 'Mapa con id y tipo del producto, 0 si es fijo y 1 si es variable. +' prodsFijos={idProducto,idProducto} 'Lista con los ids de los productos fijos. +' prodsVariables={idProducto,idProducto} 'Lista con los ids de los productos variables. +' resultado="OK" 'Ok si existe la promocion. +' prodsVariablesRequeridos=5} 'Cantidad de productos variables requeridos para la promoción. +Sub traePromo(promo As String, cliente As String) As Map + Private inicioContador As String = DateTime.Now + Private c As Cursor = Starter.skmt.ExecQuery("Select * from promos_comp where cat_pa_id = '"& promo&"'") 'Obtenemos las el maximo de promocioones a otorgar. + Private siHistorico As String = 0 + Private promoMap As Map + Private prodsFijos, prodsFijosPrecios, prodsFijosPiezas, prodsVariables, prodsVariables2 As List + promoMap.Initialize + prodsFijos.Initialize + prodsFijosPrecios.Initialize + prodsFijosPiezas.Initialize + prodsVariables.Initialize + prodsVariables2.Initialize + c.Position = 0 + If c.RowCount > 0 Then promoMap = CreateMap("id":promo, "maxXcliente":c.GetString("CAT_PA_MAXPROMCLIE"), "maxRecurrente":c.GetString("CAT_PA_MAXPROMREC"), "maxPromos":c.GetString("CAT_PA_MAXPROM")) + c = Starter.skmt.ExecQuery("Select count(*) as hist from HIST_PROMOS where HP_CLIENTE = '"& cliente & "' and HP_CODIGO_PROMOCION = '" & promo & "'") 'Revisamos si hay historico de la promoción. + c.Position = 0 + If c.GetString("hist") > 0 Then siHistorico = 1 + promoMap.Put("historico", siHistorico) + c = Starter.skmt.ExecQuery("Select * from CAT_DETALLES_PAQ where CAT_DP_ID = '"& promo & "'") 'Obtenemos los detalles de la promoción. + c.Position = 0 + If c.RowCount > 0 Then + Private prods, tipos As Map + prods.Initialize + tipos.Initialize + For i=0 To c.RowCount -1 + c.Position=i + prods.Put(c.GetString("CAT_DP_IDPROD"), CreateMap("idProducto":c.GetString("CAT_DP_IDPROD"), "precioSimptos":c.GetString("CAT_DP_PRECIO_SIMPTOS"), "precio":c.GetString("CAT_DP_PRECIO"), "almacen":c.GetString("CAT_DP_ALMACEN"), "tipo":c.GetString("CAT_DP_TIPO"), "piezas":c.GetString("CAT_DP_PZAS"), "usuario":c.GetString("CAT_DP_USUARIO"), "regalo":c.GetString("CAT_DP_REGALO"), "clasif":c.GetString("CAT_DP_CLASIF"))) + tipos.Put(c.GetString("CAT_DP_IDPROD"), c.GetString("CAT_DP_TIPO")) + If c.GetString("CAT_DP_TIPO") = "0" Then + prodsFijos.Add(c.GetString("CAT_DP_IDPROD")) + prodsFijosPrecios.Add(c.GetString("CAT_DP_PRECIO")) + prodsFijosPiezas.Add(c.GetString("CAT_DP_PZAS")) + End If + If c.GetString("CAT_DP_TIPO") = "1" Then prodsVariables.Add(c.GetString("CAT_DP_IDPROD")) + If c.GetString("CAT_DP_TIPO") = "2" Then +' LogColor(c.GetString("CAT_DP_IDPROD") & "|" & c.GetString("CAT_DP_TIPO"), Colors.Blue) + prodsVariables2.Add(c.GetString("CAT_DP_IDPROD")) + End If +' Log($"id:${c.GetString("CAT_DP_IDPROD")}, tipo:${c.GetString("CAT_DP_TIPO")}"$) +' If prodsVariables2.Size > 0 Then LogColor(c.GetString("CAT_DP_ID") & "|" & prodsVariables2, Colors.red) + Next + promoMap.Put("productos", prods) 'Mapa con los productos de la promocion (id, precio, almacen, tipo, piezas, etc.) + promoMap.Put("tipos", tipos) 'Mapa con los productos de la promoción y su tipo (fijo o variable). + promoMap.Put("prodsFijos", prodsFijos) 'Lista de los productos fijos de la promoción. + promoMap.Put("prodsVariables", prodsVariables) 'Lista de los productos variables de la promoción. + promoMap.Put("prodsVariables2", prodsVariables2) + promoMap.Put("prodsFijosCant", prodsFijos.Size) + promoMap.Put("prodsFijosPrecios", prodsFijosPrecios) + promoMap.Put("prodsFijosPiezas", prodsFijosPiezas) + promoMap.Put("prodsVariablesCant", prodsVariables.Size) + promoMap.Put("prodsVariables2Cant", prodsVariables2.Size) + promoMap.Put("resultado", "ok") + Else + promoMap.Put("resultado", "No hay datos de la promoción.") + End If + c = Starter.skmt.ExecQuery("Select CAT_GP_STS, CAT_GP_IMP1, CAT_GP_NOMBRE from CAT_GUNAPROD where CAT_GP_ID = '"& promo & "'") 'Obtenemos las piezas requeridas de productos variables para la promoción. + c.Position = 0 + Private pvr As String = 0 + Private pvr2 As String = 0 + If c.RowCount > 0 Then + c.Position = 0 + pvr = c.GetString("CAT_GP_STS") + pvr2 = c.GetString("CAT_GP_IMP1") + promoMap.Put("prodsVariablesRequeridos", pvr) 'Cantidad de productos variables requeridos para la promoción. + promoMap.Put("prodsVariables2Requeridos", pvr2) + promoMap.put("descripcion", c.GetString("CAT_GP_NOMBRE")) + End If + c.Close +' Log($"Inv variables: ${cuantosVariablesTengoBD(promo)}"$) +' Log($"Inv dispo: ${traemosInventarioDisponibleParaPromo(promo)}"$) +' LogColor($"Promo ${promo}: ${promoMap}"$, Colors.Green) +' LogColor("TIEMPO para traePromo -=" & promo & "=- : " & ((DateTime.Now-inicioContador)/1000), Colors.Red) + Return promoMap +End Sub + +'Regresa un mapa con el inventario disponible por producto para la promoción (desde la base de datos). +Sub traemosInventarioDisponibleParaPromo(promo As String) As Map 'ignore + Private c As Cursor + c = Starter.skmt.ExecQuery2("SELECT CAT_GP_ID, CAT_GP_ALMACEN FROM CAT_GUNAPROD WHERE CAT_GP_ID IN (select CAT_DP_IDPROD FROM CAT_DETALLES_PAQ WHERE CAT_DP_ID = ?)", Array As String(promo)) +' Private prodInv As Map +' prodInv.Initialize + Private prods As Map + prods.Initialize + If c.RowCount > 0 Then + For i=0 To c.RowCount -1 + c.Position=i + prods.Put(c.GetString("CAT_GP_ID"), c.GetString("CAT_GP_ALMACEN")) +' Log($"prod:${c.GetString("CAT_GP_ID")}, inventario:${c.GetString("CAT_GP_ALMACEN")}"$) + Next +' prodInv.Put("inventarios", prods) + End If + Return prods +End Sub + +'Resta los productos fijos del inventario de la promoción (mapa) y regresa un mapa con el nuevo inventario. +'Hay que darle como parametro un mapa (traePromo(promo)) con toda la informacion de la promocion. +'Regresa en el mapa la llave "resultado" que nos da "ok" o "No hay suficiente producto para la promocion". +Sub restaFijosPromo(promoMap As Map) As Map 'ignore + Private thisLog As Boolean = False 'Si es verdadero, muestra los logs de este sub. + Private inventariosDisponiblesParaEstaPromo As Map = traemosInventarioDisponibleParaPromo(promoMap.Get("id")) 'Obtenemos un mapa con el inventario disponible para cada producto de la promocion desde la base de datos. + If thisLog Then LogColor(inventariosDisponiblesParaEstaPromo, Colors.red) + If thisLog Then LogColor("Inventario inicial antes de FIJOS: "&inventariosDisponiblesParaEstaPromo, Colors.Gray) 'Inventario inicial. + Private i As Int + Private prodsmap As Map = promoMap.Get("productos") 'Obtenemos un mapa con todos los productos de la promoción. + Private prodsFijos As List = promoMap.get("prodsFijos") 'Obtenemos una lista con los productos fijos de la promoción. + For p = 0 To prodsFijos.Size - 1 + Private t As String = prodsFijos.Get(p) 'Obtenemos el Id de este producto desde la lista de productos fijos. + Private p2 As Map = prodsmap.Get(t) 'Obtenemos un mapa con los datos de este producto (id, precio, almacen, tipo, piezas, etc.) + If thisLog Then Log($"T: ${t}, prod ${p2.Get("idProducto")}, piezas: ${p2.Get("piezas")}"$) 'Producto y piezas requeridas + If thisLog Then Log("inventariosDisponiblesParaEstaPromo="&inventariosDisponiblesParaEstaPromo) + If inventariosDisponiblesParaEstaPromo.ContainsKey(t) Then 'Si el mapa del inventario contiene el id del producto entonces ... + i = inventariosDisponiblesParaEstaPromo.get(t) 'Obtenemos del mapa el inventario de este producto. + If thisLog Then Log($"Nuevo inventario de ${t}: ${i}-${promoMap.Get("prodsFijosPiezas").As(List).get(p)} = $1.0{i - promoMap.Get("prodsFijosPiezas").As(List).get(p)}"$) 'El nuevo inventario. + inventariosDisponiblesParaEstaPromo.Put(t, $"${i - promoMap.Get("prodsFijosPiezas").As(List).get(p)}"$) 'Restamos del inventario las piezas requeridas para la promoción y guardamos el nuevo inventario en el mapa. + inventariosDisponiblesParaEstaPromo.Put("resultado", "ok") + Else 'Si en el mapa no esta el id del producto, entonces no tenemos inventario. + inventariosDisponiblesParaEstaPromo.Put("resultado", "No hay suficiente producto para la promocion.") + LogColor("Sin suficiente inventario fijo: " & t, Colors.Blue) + Exit + End If + If i - p2.Get("piezas") < 0 Then + inventariosDisponiblesParaEstaPromo.Put("resultado", "No hay suficiente producto para la promocion.") 'Si el inventario de este producto sale negativo, quiere decir que no tenemos suficiente inventario para la promoción. + Exit + End If + Next + If prodsFijos.Size = 0 Then inventariosDisponiblesParaEstaPromo.Put("resultado", "ok") 'No hay productos fijos. + If thisLog Then LogColor("Inventario final depues de FIJOS: "&inventariosDisponiblesParaEstaPromo, Colors.blue) 'Inventario final. + Return inventariosDisponiblesParaEstaPromo +End Sub + +'Revisa si tenemos los productos variables requeridos para la promoción (mapa). +'Hay que darle como parametro un mapa (traePromo(promo)) con toda la informacion de la promocion. +Sub alcanzanLosVariablesParaPromo(promoMap As Map, inventarioSinFijos As Map) As Boolean 'ignore + Private thisLog As Boolean = False 'Si es verdadero, muestra los logs de este sub. + If thisLog Then LogColor("Inventario inicial: "&inventarioSinFijos, Colors.Gray) 'Inventario inicial. + Private totalProdsVariables As Int = 0 + Private totalProdsVariables2 As Int = 0 +' Private prodsmap As Map = promoMap.Get("productos") 'Obtenemos un mapa con todos los productos de la promoción. + Private prodsVariables As List = promoMap.get("prodsVariables") 'Obtenemos un a lista con los productos variables de la promoción. + Private prodsVariables2 As List = promoMap.get("prodsVariables2") + For p = 0 To prodsVariables.Size - 1 + Private t As String = prodsVariables.Get(p) 'Obtenemos el Id de este producto desde la lista de productos fijos. + If inventarioSinFijos.ContainsKey(t) Then 'Si existe el producto en la lista del inventario, entonces ... + Private p2 As String = inventarioSinFijos.Get(t) 'Obtenemos el inventario disponible este producto. + totalProdsVariables = totalProdsVariables + p2 + If thisLog Then Log($"prod ${t}, hay: ${p2}"$) 'Producto y piezas requeridas + End If + Next + For p = 0 To prodsVariables2.Size - 1 + Private t As String = prodsVariables2.Get(p) 'Obtenemos el Id de este producto desde la lista de productos fijos. + If inventarioSinFijos.ContainsKey(t) Then 'Si existe el producto en la lista del inventario, entonces ... + Private p2 As String = inventarioSinFijos.Get(t) 'Obtenemos el inventario disponible este producto. + totalProdsVariables2 = totalProdsVariables2 + p2 + If thisLog Then Log($"prod ${t}, hay: ${p2}"$) 'Producto y piezas requeridas + End If + Next + If thisLog Then Log("Total prods variables=" & totalProdsVariables & ", requeridos=" & promoMap.Get("prodsVariablesRequeridos")) + If thisLog Then Log("Total prods variables2=" & totalProdsVariables2 & ", requeridos2=" & promoMap.Get("prodsVariables2Requeridos")) + Private res As Boolean = False + If totalProdsVariables >= promoMap.Get("prodsVariablesRequeridos") Then res = True 'Si el total de inventario de productos variables (totalProdsVariables) es mayor o igual a los productos requeridos entonces regresamos TRUE + If totalProdsVariables2 >= promoMap.Get("prodsVariables2Requeridos") Then res = True 'Si el total de inventario de productos variables (totalProdsVariables) es mayor o igual a los productos requeridos entonces regresamos TRUE + Return res +End Sub + +'Regresa el numero máximo de promociones permitidas, tomando en cuenta recurrentes, clientes y maxPromos. +Sub traeMaxPromos(pm As Map) As Int +' Private thisLog As Boolean = False 'Si es verdadero, muestra los logs de este sub. +' Private maxPromos As List +' Private vendidas As Int = 0 +' maxPromos.Initialize +'' If Starter.promosLog Then Log("==== HISTORICO:"&pm.Get("historico")) +' If thisLog Then Log(pm) +' If pm.Get("historico") = "1" Then maxPromos.Add(pm.Get("maxRecurrente")) 'Si hay historico, agregamos maxRecurrente +' maxPromos.Add(pm.Get("maxPromos")) 'Agregamos maxPromos +' maxPromos.Add(pm.Get("maxXcliente")) 'Agregamos maxXcliente +' maxPromos.Sort(True) +' +'' Log($"|${pm.Get("id").As(String).trim}|${traeTicket.Trim}|"$) +' Private c As Cursor = Starter.skmt.ExecQuery2("select sum(PE_CANT) as vendidas from PEDIDO where PE_PROID = ? and PE_TICKET = ? ", Array As String(pm.Get("id").As(String).trim, traeTicket(Starter.mesaActual).Trim)) +' If c.RowCount > 0 Then +' c.Position = 0 +' vendidas = c.GetInt("vendidas") +'' Log(vendidas) +' End If + +' If Starter.promosLog Then Log(maxPromos) +' If Starter.promosLog Then Log("Max Promos="&maxPromos.Get(0)) +' LogColor($"maxPromos=${maxPromos.Get(0)} - vendidas=${vendidas}"$, Colors.red) +' Return maxPromos.Get(0) - vendidas 'Regresamos el numero mas pequeño de las opciones. +End Sub + +'Regresa la cantidad de promos que se le han vendido al cliente. +Sub traePromosVendidas(promo As String, cliente As String) As Int + Private c As Cursor + Private pv As Int = 0 + c=Starter.skmt.ExecQuery($"select PE_CANT from PEDIDO where PE_PROID = '${promo}' and PE_TICKET = '${cliente}'"$) + If c.RowCount > 0 Then + c.Position = 0 + pv = c.GetInt("PE_CANT") + End If + Return pv +End Sub + +Sub procesaPromocion(idPromo As String, cliente As String) As Map 'ignore + Private thisLog As Boolean = False 'Si es verdadero, muestra los logs de este sub. + Private inicioContador As String = DateTime.Now + If thisLog Then LogColor($"********* Iniciamos revision de Promo ${idPromo} *********"$, Colors.Magenta) + 'Obtenemos el mapa con toda la info de la promoción. + Private pm As Map = traePromo(idPromo, cliente) + If thisLog Then LogColor(pm, Colors.Blue) + If pm.Get("resultado") = "ok" Then 'Si encontramos la promoción, entonces ... + 'Buscamos el máximo de promociones permitidas. + If thisLog Then LogColor($"Promociones permitidas=${traeMaxPromos(pm)}"$, Colors.Blue) + If thisLog Then Log("Promos vendidas: " & traePromosVendidas(idPromo, cliente)) + If traePromosVendidas(idPromo, cliente) >= traeMaxPromos(pm) Then + If thisLog Then LogColor("Ya se vendieron las promos PERMITIDAS para el cliente", Colors.red) + Return CreateMap("status":"ko", "mp":pm) + End If + 'Restamos del inventario (mapa) las piezas necesarias para los productos fijos. + Private inventarioSinFijos As Map = restaFijosPromo(pm) + If thisLog Then LogColor("inventariosfijos="&inventarioSinFijos, Colors.Green) + + If inventarioSinFijos.Get("resultado") = "ok" Then + 'Revisamos que los productos variables requeridos sean menos que el inventario total (mapa). + Private pv As Boolean = alcanzanLosVariablesParaPromo(pm, inventarioSinFijos) + If thisLog Then Log("Alcanzan los variables? --> " & pv) + If pv Then Return CreateMap("status":"ok", "mp":pm) Else Return CreateMap("status":"ko", "mp":pm) + Else + If thisLog Then LogColor("NO HAY INVENTARIO SUFICIENTE " & idPromo, Colors.red) + Return CreateMap("status":"ko", "mp":pm) + End If + End If + ' Si tenemos suficiente inventario para los variables mostramos la promocion, si no ... + ' break 'NO HAY INVENTARIO SUFICIENTE PARA LA PROMOCION. + + LogColor("TIEMPO DE PROCESO ESTA PROMO: " & ((DateTime.Now-inicioContador)/1000), Colors.Red) +End Sub + +'Regresa cuantas promos alcanzan con los productos FIJOS que hay en inventario. +Sub revisaMaxPromosProdsFijosPorInventario2(pm As Map) As Int + Private thisLog As Boolean = False + If thisLog Then Log($"pm=${pm}"$) +' Private prodsFijos As List = pm.get("prodsFijos") + Private invDispParaPromo As Map = traemosInventarioDisponibleParaPromo(pm.Get("id")) + If thisLog Then Log($"invDispParaPromo=${invDispParaPromo}"$) + Private maxPromos As String = traeMaxPromos(pm) + Private maxPromosFijosXinv As Int = 1 + Private fpf2, pdp2 As Int + Private salir As Boolean = False + Private pf As List = pm.Get("prodsFijos") + Private pfp As List = pm.Get("prodsFijosPiezas") + If thisLog Then Log($"maxPromos=${maxPromos}, prodsFijos=${pf}, piezas=${pfp}"$) + If thisLog Then LogColor($"InvFijo disponible=${invDispParaPromo}"$, Colors.Blue) + Private invFijoXpromo As Map + invFijoXpromo.Initialize + For p = 0 To pf.Size -1 'Generamos mapa con los productos fijo y piezas requeridos por promo. + invFijoXpromo.Put(pf.Get(p), pfp.Get(p)) + Next + If thisLog Then LogColor("Inv req. de prods fijos x promo" & invFijoXpromo, Colors.Green) + For i = 1 To maxPromos 'Revisamos cuantas promociones alcanzan, hasta llegar al máximo de promos permitadas. + If thisLog Then LogColor("Prods para promo " & (i+1), Colors.Magenta) + For q = 0 To pf.Size - 1 + Private q2 As String = pf.Get(q) + If thisLog Then Log("q="&q2) +' fpf2 = invFijoXpromo.Get(q2) * i 'Multiplicamos las piezas requeridas por la cantidad de promos. + fpf2 = pfp.Get(q) * i 'Multiplicamos las piezas requeridas por la cantidad de promos. + pdp2 = invDispParaPromo.Get(q2) + If thisLog Then Log($"pf=${q2}, Actual=${(i)}, max promos: ${pdp2}-${fpf2}=${pdp2 - fpf2}"$) + If pdp2 - fpf2 < 0 Then 'Si el inventario es negativo, entonces ya no alcanza para este producto. + salir=True + Exit + End If + Next + If salir Then Exit + maxPromosFijosXinv = i + Next + If thisLog Then LogColor("InvFijo requerido x promo="&invFijoXpromo, Colors.blue) + LogColor("Maximo de promociones de prodsFijos POR inventario = " & maxPromosFijosXinv, Colors.Red) + Return maxPromosFijosXinv +End Sub + +'Regresa cuantas promos alcanzan con los productos FIJOS que hay en inventario. +Sub revisaMaxPromosProdsFijosPorInventario(pm As Map) As Int + Private thisLog As Boolean = False + Private invFijoXpromo As Map + Private t As List + t.Initialize + t.Add(traeMaxPromos(pm)) ' Agregamos a la lista las promos maximas permitidas (recurrente, cliente y promo). + invFijoXpromo.Initialize + If thisLog Then LogColor($"pm=${pm}"$, Colors.Blue) + Private invDispParaPromo As Map = traemosInventarioDisponibleParaPromo(pm.Get("id")) + If thisLog Then Log($"invDispParaPromo=${invDispParaPromo}"$) + Private prodsFijosPiezas As List = pm.Get("prodsFijosPiezas") + Private idProdsFijos As List = pm.Get("prodsFijos") + For p = 0 To idProdsFijos.Size -1 'Generamos una lista con las promos disponibles por producto (dividimos el inventario total entre las piezas requeridas). + If thisLog Then Log($"id=${idProdsFijos.Get(p)}, inv=${invDispParaPromo.Get(idProdsFijos.Get(p))}, pzas=${prodsFijosPiezas.Get(p)}"$) + If thisLog Then Log($"${(invDispParaPromo.Get(idProdsFijos.Get(p)) / prodsFijosPiezas.Get(p))}"$) + Private x() As String = Regex.Split("\.", $"${(invDispParaPromo.Get(idProdsFijos.Get(p)) / prodsFijosPiezas.Get(p))}"$) 'Separamos el resultado de la division por el punto decimal. + If thisLog Then Log(x(0)) + t.Add(x(0).As(Int)) 'Solo guardamos la parte del entero de la division. + Next + t.Sort(True) 'Ordenamos la lista para que en el lugar 0 este el resultao mas pequeño. + If thisLog Then LogColor($"prodsFijos=${idProdsFijos}"$, Colors.Blue) + If thisLog Then LogColor($"prodsFijosPiezasReq=${prodsFijosPiezas}"$, Colors.Blue) + If thisLog Then LogColor($"invFijoXpromo=${invFijoXpromo}"$, Colors.Blue) +' LogColor("Max promos de prodsFijos POR inventario = " & t.Get(0), Colors.red) + Return t.Get(0) 'Regresamos el resultado mas pequeño. +End Sub + +'Regresa cuantas promos alcanzan con los productos VARIABLES que hay en inventario. +'La cantidad de promos disponibles se calcula DESPUES de descontar los productos fijos, y si las +'promos por productos fijos llega al maximo, aunque se puedan mas de producos variables, solo se +'regresa el maximo por productos fijos. Ej. si las promos por variables es 10, pero el maximo por +'fijos es 5, entonces regresamos 5. +Sub revisaMaxPromosProdsVariablesPorInventario(pm As Map) As Int 'ignore + Private thisLog As Boolean = False + If thisLog Then Log("======================================================") + If thisLog Then Log("======================================================") + Private invFijoXpromo As Map + invFijoXpromo.Initialize + Private totalProdsVariablesDisponibles As Int = 0 + Private totalProdsVariables2Disponibles As Int = 0 + If thisLog Then LogColor($"pm=${pm}"$, Colors.Blue) + Private invDispParaPromo As Map = traemosInventarioDisponibleParaPromo(pm.Get("id")) + If thisLog Then Log($"invDispParaPromo=${invDispParaPromo}"$) + Private maxPromos As String = traeMaxPromos(pm) + Private maxPromosXFijos As Int = revisaMaxPromosProdsFijosPorInventario(pm) + Private idProdsVariables As List = pm.Get("prodsVariables") + Private idProdsVariables2 As List = pm.Get("prodsVariables2") + Private prodsVariablesRequeridos As Int = pm.Get("prodsVariablesRequeridos") + Private prodsVariables2Requeridos As Int = pm.Get("prodsVariables2Requeridos") + Private prodsFijosPiezas As List = pm.Get("prodsFijosPiezas") + Private idProdsFijos As List = pm.Get("prodsFijos") + For p = 0 To idProdsFijos.Size -1 'Generamos mapa con los productos fijos y piezas requeridas por promo. + invFijoXpromo.Put(idProdsFijos.Get(p), prodsFijosPiezas.Get(p)) + Private idEsteProd As String = idProdsFijos.Get(p) + Private invEsteProd As Int = invDispParaPromo.Get(idEsteProd) + Private pzasReqEsteProd As Int = prodsFijosPiezas.Get(p) + If thisLog Then Log($"id=${idEsteProd}, inv=${invEsteProd}, pzas=${pzasReqEsteProd}"$) +' invDispParaPromo.Put( idEsteProd, (invEsteProd - (1)) ) + Next + If thisLog Then LogColor($"MaxPromos=${maxPromos}, promosXFijos=${maxPromosXFijos}"$, Colors.Blue) + If thisLog Then LogColor($"prodsFijos=${idProdsFijos}"$, Colors.Blue) + If thisLog Then LogColor($"prodsFijosPiezasReq=${prodsFijosPiezas}"$, Colors.Blue) + If thisLog Then LogColor($"prodsVariables=${idProdsVariables}${CRLF}Variables Req=${prodsVariablesRequeridos} "$, Colors.Blue) + If thisLog Then LogColor($"prodsVariables2=${idProdsVariables2}${CRLF}Variables2 Req=${prodsVariables2Requeridos} "$, Colors.Blue) + If thisLog Then LogColor($"invFijoXpromo=${invFijoXpromo}"$, Colors.Blue) + If thisLog Then Log($"Prods variables disponibles = ${totalProdsVariablesDisponibles}"$) + If thisLog Then Log($"Prods variables2 disponibles = ${totalProdsVariables2Disponibles}"$) + Private maxPromosXVariables As Int = 0 + Private maxPromosXVariables2 As Int = 0 + For x = 1 To maxPromosXFijos + If thisLog Then Log("=====================================================") + If thisLog Then Log("=====================================================") + For i = 0 To idProdsFijos.Size - 1 + If thisLog Then Log($"FIJO - ${idProdsFijos.Get(i)}, ${invDispParaPromo.Get(idProdsFijos.Get(i))} - ${prodsFijosPiezas.Get(i).As(Int)*(i+1)}"$) + invDispParaPromo.Put(idProdsFijos.Get(i), invDispParaPromo.Get(idProdsFijos.Get(i)).As(Int) - prodsFijosPiezas.Get(i).As(Int)*(i+1)) 'Restamos las piezas de los productos fijos del inventario disponible. + Next + If thisLog Then LogColor("Inv disponible despues de restar fijos = " & invDispParaPromo, Colors.Blue) + + totalProdsVariablesDisponibles = 0 + totalProdsVariables2Disponibles = 0 + For i = 0 To idProdsVariables.Size - 1 'Obtenemos total de productos variables disponibes. + If invDispParaPromo.ContainsKey(idProdsVariables.Get(i)) Then + totalProdsVariablesDisponibles = totalProdsVariablesDisponibles + invDispParaPromo.Get(idProdsVariables.Get(i)) + End If + Next + For i = 0 To idProdsVariables2.Size - 1 'Obtenemos total de productos variables disponibes. + If invDispParaPromo.ContainsKey(idProdsVariables2.Get(i)) Then + totalProdsVariables2Disponibles = totalProdsVariables2Disponibles + invDispParaPromo.Get(idProdsVariables2.Get(i)) + End If + Next + 'Revisamos variables. + If thisLog Then Log($"Var disponibles - var requeridos : ${totalProdsVariablesDisponibles} - ${prodsVariablesRequeridos*x}"$) + totalProdsVariablesDisponibles = totalProdsVariablesDisponibles - (prodsVariablesRequeridos*x) + totalProdsVariables2Disponibles = totalProdsVariables2Disponibles - (prodsVariables2Requeridos*x) + If thisLog Then Log("prodsVariables disponibles despues de promo = " & totalProdsVariablesDisponibles) + If thisLog Then Log("prodsVariables2 disponibles despues de promo = " & totalProdsVariables2Disponibles) + If totalProdsVariablesDisponibles < 0 Then Exit 'Ya no hay inventario disponible. + If totalProdsVariables2Disponibles < 0 Then Exit 'Ya no hay inventario disponible. + maxPromosXVariables = x + Next + 'Restamos fijos. + If thisLog Then LogColor("Max promos de prodsVariables POR inventario = " & maxPromosXVariables, Colors.red) + Return maxPromosXVariables +End Sub + +'Regresa la suma del inventario de los productos variables de la promoción dada desde la base de datos. +Sub cuantosVariablesTengoBD(promo As String) As String 'ignore +' Private x As String = "0" +' If promo <> "" Then +' Private c As Cursor +' c = Starter.skmt.ExecQuery2("Select SUM(CAT_GP_ALMACEN) as variables FROM CAT_GUNAPROD2 WHERE CAT_GP_ID IN (Select CAT_DP_IDPROD FROM CAT_DETALLES_PAQ WHERE CAT_DP_ID = ? and cat_dp_tipo = 1 GROUP BY CAT_DP_IDPROD)", Array As String (promo)) +' If c.RowCount > -1 Then +' c.Position = 0 +' If c.GetString("variables") <> Null Then x = c.GetString("variables") +' End If +' End If +' Return x +End Sub + +'Regresa un mapa con los datos del producto desde la base de datos. +'el mapa incluye: Id, nombre, tipo y subtipo del producto. +Sub traeProdIdDeBD As Map 'ignore + Private c As Cursor + Private m As Map + c=Starter.skmt.ExecQuery("select CAT_GP_ID,CAT_GP_NOMBRE,CAT_GP_TIPO,CAT_GP_SUBTIPO from CAT_GUNAPROD where CAT_GP_NOMBRE In (Select PDESC from PROID)") + If c.RowCount > 0 Then + c.Position = 0 + m = CreateMap("id":c.GetString("CAT_GP_ID"), "nombre":c.GetString("CAT_GP_NOMBRE"), "tipo":c.GetString("CAT_GP_TIPO"), "subtipo":c.GetString("CAT_GP_SUBTIPO")) + Else + m = CreateMap("id":"N/A", "nombre":"N/A", "tipo":"N/A", "subtipo":"N/A") + End If + c.Close + Return m +End Sub + +'Regresa el total de productos y monto del pedido del ticket actual. +Sub traeTotalesTicketActual As Map + Private m As Map + m.Initialize + Private c_prodsX As Cursor = Starter.skmt.ExecQuery("select ifnull(sum(PE_CANT), 0) as cantProds, ifnull(sum(PE_COSTO_TOT), 0) as costoTotal FROM PEDIDO WHERE PE_TICKET IN (Select CUENTA from cuentaa) order by PE_PRONOMBRE asc") + c_prodsX.Position=0 +' LogColor($"Productos de la orden: ${c_prodsX.GetString("cantProds")}, Total: ${c_prodsX.GetString("costoTotal")}"$, Colors.red) + m = CreateMap("productos": c_prodsX.GetString("cantProds"), "monto" : c_prodsX.GetString("costoTotal")) + Return m +End Sub + +'Borra el pedido del cliente actual. +'Borra los registros de la tabla "pedido" y "PEDIDO_TICKET" +'Actualiza las tablas "cat_gunaprod" y "kmt_info". +Sub borraPedidoClienteActual As String +' Private thisC As Cursor +' thisC=B4XPages.MainPage.skmt.ExecQuery("select PE_PROID,PE_CANT FROM PEDIDO where PE_TICKET in (Select CUENTA from cuentaa) ") +' If thisC.RowCount>0 Then +' For i=0 To thisC.RowCount -1 +' thisC.Position=i +' B4XPages.MainPage.skmt.ExecNonQuery2("update cat_gunaprod set cat_gp_almacen = cat_gp_almacen + ? where cat_gp_id = ?", Array As Object(thisC.GetString("PE_CANT"),thisC.GetString("PE_PROID"))) +' B4XPages.MainPage.skmt.ExecNonQuery2("INSERT INTO INVENT_X_ENVIAR (ALMACEN , PROID , CANTIDAD ) VALUES(?,?,?) ", Array As Object (traeAlmacen, thisC.GetString("PE_PROID"),thisC.GetString("PE_CANT")* -1)) +' Next +' End If +' B4XPages.MainPage.skmt.ExecNonQuery("delete from PEDIDO_TICKET where pc_cliente in (Select CUENTA from cuentaa)") +' B4XPages.MainPage.skmt.ExecNonQuery("delete from pedido where PE_TICKET in (Select CUENTA from cuentaa)") +' B4XPages.MainPage.skmt.ExecNonQuery("UPDATE kmt_info set gestion = 0 where CAT_CL_CODIGO In (select cuenta from cuentaa)") + Return 1 +End Sub + +'Regresa verdadero si la columna gestion en la tabla "kmt_info" tene valor 2. +'si no, entonces regresa falso. +Sub pedidoGuardado As Boolean +' Private guardado As Boolean = False +' Private g As Cursor = B4XPages.MainPage.skmt.ExecQuery("select gestion from kmt_info where CAT_CL_CODIGO in (Select CUENTA from cuentaa)") +' If g.RowCount > 0 Then +' g.Position=0 +' If g.GetString("gestion") = "2" Then guardado = True +' End If +' Log($"Guardado=${guardado}"$) +' Return guardado +End Sub + +'Regresa verdadero si hay pedido en la tabla "PEDIDO" del cliente actual. +Sub hayPedido As Boolean +' Log($"TraeTicket: ${traeTicket}"$) + Private thisC As Cursor=Starter.skmt.ExecQuery($"select count(PE_TICKET) as hayPedido from PEDIDO where PE_TICKET = '${Starter.ticketActual}'"$) +' Log($"select count(PE_TICKET) as hayPedido from PEDIDO where PE_TICKET = '${Starter.ticketActual}'"$) + thisC.Position = 0 + Private hay As Boolean = False + If thisC.GetInt("hayPedido") > 0 Then hay = True + ' Log($"Cliente actual=${traeTicket}, hayPedido=${hay}"$) + Return hay +End Sub + +'Muestra en el Log los campos y valores que regresan en el JobDone. +Sub logJobDoneResultados(resultado As DBResult) + For Each records() As Object In resultado.Rows + LogColor($"====== ${resultado.Tag} - REGISTROS = ${resultado.Rows.Size}"$, Colors.RGB(215,37,0)) + For Each k As String In resultado.Columns.Keys + LogColor(k & " = " & records(resultado.Columns.Get(k)), Colors.RGB(215,37,0)) + Next + Next +End Sub + +'Agrega una columna a la tabla especificada. +'Hay que indicar el "tipo" de la columna (TEXT, INTEGER, ETC) +'Ej. agregaColumna("TABLA", "COLUMNA", "TIPO") +Sub agregaColumna(tabla As String, columna As String, tipo As String) + Try 'Intentamos usar "pragma_table_info" para revisar si existe la columna en la tabla + Private c As Cursor = Starter.skmt.ExecQuery($"SELECT COUNT(*) AS fCol FROM pragma_table_info('${tabla}') WHERE name='${columna}'"$) + c.Position = 0 + If c.GetString("fCol") = 0 Then 'Si no esta la columna la agregamos + Starter.skmt.ExecNonQuery($"ALTER TABLE ${tabla} ADD COLUMN ${columna} ${tipo}"$) + Log($"Columna "${columna} ${tipo}", agregada a "${tabla}"."$) + End If + Catch 'Si no funciona "pragma_table_info" lo hacemos con try/catch + Try + Starter.skmt.ExecNonQuery($"ALTER TABLE ${tabla} ADD COLUMN ${columna} ${tipo}"$) + Log($"Columna "${columna} ${tipo}", agregada a "${tabla}".."$) + Catch + Log(LastException) + End Try + End Try +End Sub + +'Regresa el total del pedido en la tabla "PEDIDO" del cliente actual. +Sub totalPedido As String + Private cT As Cursor = Starter.skmt.ExecQuery($"select sum(PE_COSTO_TOT) as total from PEDIDO where PE_TICKET = '${traeTicket(Starter.mesaActual)}'"$) + Private pTotal As String = "0" + If cT.RowCount > 0 Then + cT.Position = 0 +' Log("|"&cT.GetLong("total")&"|"&pTotal) + Private tempT As String = cT.GetLong("total") + If tempT <> "null" And tempT <> Null Then +' Log("|"&cT.GetLong("total")&"|") + pTotal = tempT + End If +' Log($"Cliente actual=${traeTicket}, hayPedido=${hay}"$) + End If + cT.Close + Return pTotal +End Sub + +Sub actualizaProducto(cedis As String, costoU As String, cant As String, nombre As String, prodId As String, ticketId As String, fecha As String, usuario As String, mesa As String, precioSin As String, tipoVenta As String) + If nombre.Length < 6 Then ToastMessageShow("(actualizaProducto) El nombre del producto no es valido " & nombre, True) + LogColor($"actualizaProducto, p=${prodId}, nombre=${nombre}, cant=${cant}, cedis=${cedis}, tipo=${tipoVenta}, mesa=${mesa}, ticket=${ticketId}"$, Colors.Magenta) +' Private tablaProds As String = "cat_gunaprod2" +' If tipoVenta = "ABORDO" Then tablaProds = "cat_gunaprod" + Private c As Cursor=Starter.skmt.ExecQuery($"select * from pedido where pe_cedis = '${cedis}' and pe_proid = '${prodId}' and PE_TICKET = '${ticketId}'"$) + If c.RowCount > 0 Then + LogColor("ACTUALIZAMOS PROD", Colors.Blue) + c.Position=0 + Private antCant As Int = 0 + If IsNumber(c.GetInt("PE_CANT")) Then antCant=c.GetInt("PE_CANT") + Private difCant As Int = cant - antCant + Starter.skmt.ExecNonQuery($"update pedido set pe_cant = ${cant}, pe_costo_tot = ${(cant*c.GetString("PE_COSTOU"))} where pe_cedis = '${cedis}' and pe_proid = '${prodId}' and PE_TICKET = '${ticketId}' "$) + Starter.skmt.ExecNonQuery($"update cat_gunaprod set cat_gp_almacen = cat_gp_almacen - (${difCant}) where cat_gp_id = '${prodId}' "$) + c=Starter.skmt.ExecQuery($"select sum(pe_costo_tot) as TOTAL_CLIE, SUM(PE_CANT) AS CANT_CLIE, SUM(PE_COSTO_SIN) AS TOTAL_CLIE_SIN FROM PEDIDO WHERE PE_TICKET = '${ticketId}'"$) + Log($"select sum(pe_costo_tot) as TOTAL_CLIE, SUM(PE_CANT) AS CANT_CLIE, SUM(PE_COSTO_SIN) AS TOTAL_CLIE_SIN FROM PEDIDO WHERE PE_TICKET = '${ticketId}'"$) + c.Position=0 + Starter.skmt.ExecNonQuery($"delete from PEDIDO_TICKET where PC_TICKET = '${ticketId}'"$) + Starter.skmt.ExecNonQuery2("insert into PEDIDO_TICKET(PC_TICKET, PC_FECHA, PC_USER, PC_NOART, PC_MONTO, PC_ALMACEN, PC_MESA, PC_COSTO_SIN) VALUES (?,?,?,?,?,?,?,?)", Array As Object(ticketId, fecha, usuario, c.GetString("CANT_CLIE"), c.GetString("TOTAL_CLIE"), cedis, mesa, c.GetString("TOTAL_CLIE_SIN"))) + If cant = 0 Then + LogColor($"BORRAMOS PRODUCTO - ${prodId}"$, Colors.Red) + Starter.skmt.ExecNonQuery($"delete from pedido where pe_cedis = '${cedis}' and pe_proid = '${prodId}' and PE_TICKET = '${ticketId}' "$) + Log($"Borramos pe_cedis='${cedis}' and pe_proid='${prodId}' and PE_TICKET='${ticketId}'"$) + Private pe As Cursor = Starter.skmt.ExecQuery("select count(PE_TICKET) as cuantosPedidos from pedido where PE_TICKET = '${ticketId}'") + pe.Position=0 + If pe.GetString("cuantosPedidos") = 0 Then Starter.skmt.ExecNonQuery($"delete from PEDIDO_TICKET where PC_TICKET = '${ticketId}'"$) + End If + Else + 'INSERTAMOS + LogColor("INSERTAMOS PROD", Colors.red) + If cant > 0 Then guardaProductoSinGestion(cedis, costoU, cant, nombre, prodId, ticketId, fecha, usuario, mesa, precioSin, tipoVenta) + End If + c.Close +End Sub + +'Inserta un producto en la tabla "pedido" y "PEDIDO_TICKET" y actualiza "cat_gunaprod". +'NO ACTUALIZA LA BANDERA DE GESTION EN LA TABLA "kmt_info". +'Si "gestion=2" entonces el sistema considera que el pedido ya se guardó y ya no se debe modificar. +Sub guardaProductoSinGestion(cedis As String, costoU As String, cant As String, nombre As String, prodId As String, ticketId As String, fecha As String, usuario As String, mesa As String, precioSin As String, tipoVenta As String) + If nombre.Length < 6 Then ToastMessageShow("(guardaProductoSinGestion) El nombre del producto no es valido " & nombre, True) + LogColor("guardaProductoSinGestion: "&prodId&", cant="&cant&", tipo="&tipoVenta&" , ticket="&ticketId&", mesa="&mesa, Colors.Magenta) + Private c As Cursor +' Private tablaProds As String = "cat_gunaprod2" +' If tipoVenta = "ABORDO" Then tablaProds = "cat_gunaprod" + Starter.skmt.ExecNonQuery2("INSERT INTO PEDIDO (PE_CEDIS, PE_COSTO_TOT, PE_COSTOU, PE_CANT, PE_PRONOMBRE, PE_PROID, PE_TICKET, PE_FECHA, PE_MESERO, PE_MESA, PE_COSTO_SIN, PE_TIPO) VALUES(?,?,?,?,?,?,?,?,?,?,?,?) ", Array As Object (cedis, (cant * costoU), costoU, cant, nombre, prodId, ticketId, fecha, usuario, mesa, precioSin, tipoVenta)) + 'Actualizamos el inventario en cat_gunaprod solo si no es RMI + Starter.skmt.ExecNonQuery2($"update cat_gunaprod set cat_gp_almacen = cat_gp_almacen - ? where cat_gp_id = ? "$, Array As Object(cant, prodId)) + c=Starter.skmt.ExecQuery($"select sum(pe_costo_tot) as TOTAL_CLIE, SUM(PE_CANT) AS CANT_CLIE, SUM(PE_COSTO_SIN) AS TOTAL_CLIE_SIN FROM PEDIDO WHERE PE_TICKET = '${ticketId}'"$) + Log($"select sum(pe_costo_tot) as TOTAL_CLIE, SUM(PE_CANT) AS CANT_CLIE, SUM(PE_COSTO_SIN) AS TOTAL_CLIE_SIN FROM PEDIDO WHERE PE_TICKET = '${ticketId}'"$) + c.Position=0 + Starter.skmt.ExecNonQuery($"delete from PEDIDO_TICKET where PC_TICKET = '${ticketId}'"$) + Starter.skmt.ExecNonQuery2("insert into PEDIDO_TICKET(PC_TICKET, PC_FECHA, PC_USER, PC_NOART, PC_MONTO, PC_ALMACEN, PC_MESA, PC_COSTO_SIN) VALUES (?,?,?,?,?,?,?,?)", Array As Object(ticketId, fecha, usuario, c.GetString("CANT_CLIE"), c.GetString("TOTAL_CLIE"), cedis, mesa, c.GetString("TOTAL_CLIE_SIN"))) +End Sub + +Sub agrupador() +' Private c As Cursor +' Private YA_IMPRIMIO As String +' If traeTicket <> "0" Then +' c=Starter.skmt.ExecQuery("SELECT SUM(PE_FOLIO) AS FOLIO FROM PEDIDO WHERE PE_TICKET IN (Select CUENTA from cuentaa)") +' c.Position = 0 +' If c.GetString("FOLIO") <> Null And c.GetString("FOLIO") > 0 Then +' YA_IMPRIMIO = 1 +' Else +' YA_IMPRIMIO = 0 +' End If +' c.Close +' End If +'' Log($"Ya imprimio=${YA_IMPRIMIO}"$) +' Starter.skmt.ExecNonQuery("delete from pedido3") +' Starter.skmt.ExecNonQuery("UPDATE PEDIDO SET PE_FOLIO = 0 where PE_FOLIO IS NULL") +' Starter.skmt.ExecNonQuery("INSERT INTO PEDIDO3 (PE_PRECIO2, PE_TIPO, PE_DESC, PE_COSTO_SIN, PE_RUTA, PE_CEDIS, PE_COSTO_TOT, PE_COSTOU, PE_CANT, PE_PRONOMBRE, PE_PROID, PE_TICKET, PE_USUARIO ) SELECT PE_PRECIO2, PE_TIPO, PE_DESC, PE_COSTO_SIN, PE_RUTA, PE_CEDIS, SUM(PE_COSTO_TOT) AS PE_COSTO_TOT, PE_COSTOU, SUM(PE_CANT) As PE_CANT, PE_PRONOMBRE, PE_PROID, PE_TICKET, PE_USUARIO FROM PEDIDO WHERE PE_TICKET IN (Select CUENTA from cuentaa) GROUP BY PE_PRECIO2, PE_TIPO, PE_DESC, PE_COSTO_SIN, PE_RUTA, PE_CEDIS, PE_COSTOU, PE_PRONOMBRE, PE_PROID, PE_TICKET ") +'' Log("update pedido3") +' Starter.skmt.ExecNonQuery2("UPDATE PEDIDO3 SET PE_FOLIO = ? WHERE PE_TICKET IN (Select CUENTA from cuentaa)", Array As Object(YA_IMPRIMIO)) +' Starter.skmt.ExecNonQuery("delete from pedido WHERE PE_TICKET IN (Select CUENTA from cuentaa)") +' Starter.skmt.ExecNonQuery("INSERT INTO PEDIDO SELECT * FROM PEDIDO3") +' Starter.skmt.ExecNonQuery2("UPDATE PEDIDO SET PE_FECHA = ? where PE_TICKET IN (Select CUENTA from cuentaa) and PE_FECHA IS NULL", Array As Object(traeFecha)) +End Sub + +'Trae el blob de la imagen desde la base de datos, con el ID del producto dado. +Sub traeImgDeDB(prodId As String) As Bitmap + Private ins As InputStream + Private bmp As Bitmap + Private jpeg() As Byte +' Starter.skmt.ExecQuery($"select cat_gp_img from cat_gunaprod where cat_gp_id = '${prodId}'"$) + Private laImg As ResultSet = Starter.skmt.ExecQuery($"select CAT_GP_IMG from cat_gunaprod where cat_gp_id = '${prodId}'"$) + Do While laImg.NextRow + jpeg = laImg.GetBlob("CAT_GP_IMG") + ins.InitializeFromBytesArray(jpeg, 0, jpeg.Length) + bmp.Initialize2(ins) + Loop + laImg.Close + Return bmp +End Sub + +'Regresa una lista con los meseros desde la base de datos. +Sub traeMeserosLista As List 'ignore + Private cc As Cursor = Starter.skmt.ExecQuery($"select * from cat_meseros order by ms_nombre"$) + Private items As List + items.Initialize + items.Add("SELECCIONA UN MESERO") + If cc.RowCount > 0 Then + For i = 0 To cc.RowCount - 1 + cc.Position = i +' lv_giro.AddSingleLine(cc.GetString("descripcion")) + items.Add(cc.GetString("MS_NOMBRE")) + Next + End If + cc.Close + Return items +End Sub + +'Regresa una lista con el id de los meseros desde la base de datos. +Sub traeMeserosIdLista As List 'ignore + Private cc As Cursor = Starter.skmt.ExecQuery($"select * from cat_meseros order by ms_nombre"$) + Private items As List + items.Initialize + items.Add("SELECCIONA UN MESERO") + If cc.RowCount > 0 Then + For i = 0 To cc.RowCount - 1 + cc.Position = i +' lv_giro.AddSingleLine(cc.GetString("descripcion")) + items.Add(cc.GetString("MS_ID")) + Next + End If + cc.Close + Return items +End Sub + +'Regresa el mesero de la mesa dada. +Sub traeMesero(mesaId As String) As String + Private m As String = "NINGUNO" + Private c As Cursor = Starter.skmt.ExecQuery($"select IFNULL(M_MESERO, "NINGUNO") as MESERO from CAT_MESAS where M_ID = '${mesaId}'"$) + Log($"select IFNULL(M_MESERO, "NINGUNO") as MESERO from CAT_MESAS where M_ID = '${mesaId}'"$) + If c.RowCount > 0 Then + c.Position = 0 + m = c.GetString("MESERO") + End If + Return m +End Sub + +'Regresa el siguente consecutivo para el ticket. +Sub traeConsecutivoTicket(estatus As String, pago As String) As String + Private m As String = "00001" + Private sqlPago As String = $"M_PAGO = '${pago}'"$ + If pago = "PENDIENTE" Then sqlPago = $"M_PAGO is NULL"$ + Private c As Cursor = Starter.skmt.ExecQuery($"select max(M_TICKET) as ultimo from CAT_MESAS where M_ESTATUS = '${estatus}' and ${sqlPago}"$) + Log($"select max(M_TICKET) as ultimo from CAT_MESAS where M_ESTATUS = '${estatus}' and M_PAGO = '${pago}'"$) + If c.RowCount > 0 Then + c.Position = 0 + Log(c.GetString("ultimo")) + If c.GetString("ultimo") <> Null And c.GetString("ultimo") <> "null" Then m = NumberFormat2(c.GetString("ultimo"), 5, 0,0, False) + End If + Log(m + 1) + Return NumberFormat2(m+1, 5, 0, 0, False) +End Sub + +'Regresa el estaus de la mesa con el Id dado. +Sub traeMesaEstatus(id As String) As String + Private e As String = "CERRADA" + Private c As Cursor = Starter.skmt.ExecQuery($"select IFNULL(M_ESTATUS, "CERRADA") as estatus from CAT_MESAS where M_ID = '${id}'"$) + If c.RowCount > 0 Then + c.Position = 0 + e = c.GetString("estatus") + End If + Return e +End Sub \ No newline at end of file diff --git a/B4A/errorManager.bas b/B4A/errorManager.bas new file mode 100644 index 0000000..15d27d5 --- /dev/null +++ b/B4A/errorManager.bas @@ -0,0 +1,167 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Activity +Version=10.2 +@EndOfDesignText@ +#Region Activity Attributes + #FullScreen: False + #IncludeTitle: True +#End Region +'****************************************************************************** +'Este modulo intercepta los errores de la aplicación mediante "Starter.Application_Error" y muestra una pantalla +'con el log del error y lo manda al servidor con un query de DBRequestManager, se necesita que exista el query +'en el "config.properties" llamado "guardaErrores" y que tenga el siguiente texto: +' +'sql.guardaErrores=INSERT INTO KELLOGGS.PUSH_INFO (ID, RUTA, FECHA, DATOS) VALUES((?),(?),(?),(?)) +' +'Agregar estas lineas a "Starter.Process_Globals" +' 'Para los Logs +' Dim logs As StringBuilder +' Private logcat As LogCat +' +'Agregar estas lineas a "Starter.Service_Create" +' 'Para los Logs +' #if RELEASE +' logcat.LogCatStart(Array As String("-v","raw","*:F","B4A:v"), "logcat") +' #end if +' logs.Initialize +' +'Agregar este Sub a "Starter" +' +'Return true to allow the OS default exceptions handler to handle the uncaught exception. 'Para los Logs +'Sub Application_Error (Error As Exception, StackTrace As String) As Boolean +' 'wait for 500ms to allow the logs to be updated. +' Dim jo As JavaObject +' Dim l As Long = 500: jo.InitializeStatic("java.lang.Thread").RunMethod("sleep", Array(l)) 'Sleep 500ms +' logcat.LogCatStop +' logs.Append(StackTrace) +' Subs.revisaBD +' Subs.errorLog.ExecNonQuery2("INSERT INTO errores(fecha, error) VALUES (?,?)", Array As Object (Subs.fechaKMT(DateTime.now), logs)) +' StartActivity(errorManager) +' Return True +'End Sub +'****************************************************************************** + +Sub Process_Globals + 'These global variables will be declared once when the application starts. + 'These variables can be accessed from all modules. + +End Sub + +Sub Globals + 'These global variables will be redeclared each time the activity is created. + 'These variables can only be accessed from this module. +' Dim errorLog As SQL + Dim c As Cursor + Private p_principal As Panel + Private l_titulo As Label + Private svScroll As ScrollView + Private etText As EditText + Private c_continuar As Button + Private p_botones As Panel + Private b_salir As Button +End Sub + +Sub Activity_Create(FirstTime As Boolean) + 'Do not forget to load the layout file created with the visual designer. For example: + Activity.LoadLayout("errorManager") +End Sub + +Sub Activity_Resume + Dim elError As String = "" + Dim laFecha As String = "" +' svScroll.Initialize(500dip) +' Activity.AddView(svScroll, 0, 300, 100%x, 80%y) + p_principal.Height = Activity.Height + p_principal.Width = Activity.Width + svScroll.Width = Round(p_principal.Width * 0.9) + svScroll.Left = Round(p_principal.Width/2)-Round(svScroll.Width/2) + p_botones.Left = Round(p_principal.Width/2)-Round(p_botones.Width/2) + p_botones.Top = Activity.Height - (p_botones.Height + 80) + etText.Initialize("") + svScroll.Panel.AddView(etText, 0, 0, 90%x, 80%y) + etText.InputType = etText.INPUT_TYPE_NONE + etText.Gravity = Gravity.TOP + etText.SingleLine = False + etText.Wrap = False +' Dim lblText, edtText As StringBuilder + Dim lbl As Label + lbl.Initialize("") + Activity.AddView(lbl, 0, 300, 100%x, 100%y) 'ignore + etText.Text = "" + Subs.revisaBD + c = Subs.errorLog.ExecQuery("select * from errores order by fecha desc limit 1") + If c.RowCount > 0 Then + c.Position = 0 + elError = c.GetString("error") + laFecha = c.GetString("fecha") + etText.Text = elError + End If + c.Close + Dim usuario As String = "" + c = Starter.skmt.ExecQuery("select usuario from usuarioa") + If c.RowCount > 0 Then + c.Position = 0 + usuario = c.GetString("USUARIO") + End If + +' Log("++++++" & Starter.logsStr) +' etText.Text = etText.Text & Starter.logsStr +' lbl.TextSize = etText.TextSize +' lbl.Text = etText.Text +' Dim su As StringUtils +' Dim edheight As Int = su.MeasureMultilineTextHeight(lbl, lbl.Text) +' lbl.RemoveView +' etText.Height = edheight +' svScroll.Panel.Height = edheight + svScroll.Height = Round(Activity.Height * 0.9) +' Log(edheight) + + Dim cmd As DBCommand + cmd.Initialize + cmd.Name = "guardaErrores" + cmd.Parameters = Array As Object(laFecha, usuario&"|"&Starter.rutaV, laFecha, elError) + Log($"Mandamos: ${Subs.fechaKMT(DateTime.Now)}, |${usuario}|, ${Subs.fechaKMT(DateTime.Now)}"$) + Starter.reqManager.ExecuteCommand(cmd,"guardaErrores") +End Sub + +Sub Activity_Pause (UserClosed As Boolean) + +End Sub + +Sub JobDone(Job As HttpJob) + Log("errorManager - JobDone") + If Job.Success = False Then + ToastMessageShow("Error: " & Job.ErrorMessage, True) + Else + LogColor("JobDone: '" & Starter.reqManager.HandleJob(Job).tag & "' - Registros: " & Starter.reqManager.HandleJob(Job).Rows.Size, Colors.Green) 'Mod por CHV - 211110 + If Job.JobName = "DBRequest" Then + Dim result As DBResult = Starter.reqManager.HandleJob(Job) + If result.Tag = "guardaErrores" Then 'query tag + For Each records() As Object In result.Rows + For Each k As String In result.Columns.Keys + Log("GuardaErrores: " & k & ": " & records(result.Columns.Get(k))) + Next + Next + End If + End If + End If + Job.Release +End Sub + +Private Sub c_continuar_Click +' Subs.iniciaActividad("Principal") +' B4XPages.ShowPage("Principal") +End Sub + +Private Sub b_salir_Click + cierraActividades +End Sub + +Sub cierraActividades + Log("closing activities") + Dim jo As JavaObject + jo.InitializeContext + jo.RunMethod("finishAffinity", Null) +End Sub \ No newline at end of file diff --git a/gitpull.bat b/gitpull.bat new file mode 100644 index 0000000..d0aed61 --- /dev/null +++ b/gitpull.bat @@ -0,0 +1 @@ +git pull