B4A=true
Group=Default Group
ModulesStructureVersion=1
Type=Class
Version=11.5
@EndOfDesignText@
Sub Descripcion
'	*** FLUJO DE LAS PROMOCIONES ***
'	Aquí está el desglose del flujo actual de decisión para mostrar una promoción, calculando los máximos y aplicando las restricciones de Segmentación, Inventario y Trade Spending (Bonificaciones).
'	
'	### Flujo Maestro: ¿Se muestra la promo y cuántas alcanzan?
'	
'	El proceso se ejecuta secuencialmente. Si en algún punto el resultado es 0, la promoción no se muestra o se marca como agotada.
'	
'	#### 1. Cálculo de Límites Administrativos (La Base)
'
'	Lo primero que hace el sistema es determinar el "Techo Teórico" de cuántas promociones se pueden vender Sin mirar inventario ni dinero aún.
'	* **Paso A: Datos Generales:** Se obtienen los límites configurados en `PROMOS_COMP`: Máximo por Cliente, Máximo Recurrente y Máximo Global.
'	* **Paso B: Lógica de Promociones Segmentadas:** Aquí entra el filtro crítico.
'	* El sistema consulta `HIST_CLIENTE_CANT_PROMOS`.
'	* **Si la promo es segmentada:**
'		* Si el cliente **NO** está en la lista: Se establecen todos los máximos a 0. La promo se oculta.
'		* Si el cliente **SÍ** está en la lista: Se ignoran los límites generales y se usan los específicos asignados al cliente.
'	* **Fórmula:** `MaxDisponible = Asignado - Vendido`.
'	* **Paso C: Cálculo del Mínimo:** Se comparan todos los límites (Global, Recurrente, Cliente/Segmentado) y se toma el **valor más pequeño** como el `MaxPromos` inicial.
'
'	#### 2. Restricción por Inventario de Productos FIJOS
'
'	Una vez que sabemos cuántas *podríamos* vender administrativamente, revisamos si tenemos los productos obligatorios (Fijos).
'	* El sistema itera sobre cada producto fijo de la promoción.
'	* **Cálculo:** `InventarioDisponible / PiezasRequeridasPorPromo`.
'	* **Resultado:** El `MaxPromos` se actualiza al **mínimo** entre el valor del Paso 1 y lo que permite el inventario de cada producto fijo.
'	* *Nota Crítica:* Si este valor es 0, la promo se marca como "KO" (No disponible).
'
'	#### 3. El Cruce de Inventarios (La Resta)
'
'	Este es el punto que mencionaste y es vital en el flujo actual. Antes de evaluar si alcanzan los productos variables, el código **simula la venta de los productos fijos**.
'	* Se toma el mapa de inventario actual.
'	* Se ejecuta `restaFijosDePromo`.
'	* **Acción:** Para cada producto fijo, se resta: `(MaxPromosCalculado * PiezasRequeridas)`.
'	* **Resultado:** Se genera un *Nuevo Mapa de Inventario Virtual* que contiene solo lo que sobró después de apartar lo necesario para la parte fija. Este mapa es el que se pasa a la siguiente etapa.
'
'	#### 4. Cálculo de Variables y Restricción de Trade Spending (TS)
'
'	Aquí es donde la lógica se vuelve compleja y utiliza los bucles iterativos para validar tanto existencia física como presupuesto financiero (Bonificaciones).
'	Se ejecuta `revisaMaxPromosProdsVariablesPorInventario`, que usa el *Inventario Virtual* del paso anterior.
'	**El Bucle de Validación (Paso a Paso):**
'	El código prueba vender 1 promo, luego 2, hasta llegar al `MaxPromos` calculado en el paso 2.
'	1. **Iteración `x` (Número de promos a probar):**
'	2. **Consumo de Fijos en Variables:** Si un producto variable *también* es fijo, el código descuenta (otra vez) el inventario necesario para la parte fija dentro de este bucle para asegurar integridad.
'	3. **Suma de Inventario Variable:** Se suman las existencias de todos los productos que califican como variables para esta promo.
'	4. **Validación de Trade Spending (El Presupuesto):**
'	* Dentro del bucle, para cada producto variable disponible, se llama a `ts.traeBonificacionesMaximas`.
'	* **La Lógica de ts:** El sistema verifica si el producto actual califica como bonificación (precio especial/cero).
'	* **Si califica:** Verifica si hay saldo en el presupuesto de "BONIFICACIONES". Si no hay saldo, este producto variable **no se cuenta** como disponible para armar la promo en esta iteración.
'	* **Si NO califica:** (Es un producto de precio normal dentro de la promo), no consume presupuesto y se cuenta libremente según su inventario físico.
'	5. **Prueba de Fuego:**
'	* Se compara: `InventarioVariableValidado (Físico + Financiero)` vs `(PiezasVariablesRequeridas * x)`.
'	* Si alcanza, el ciclo continúa para probar `x + 1`.
'	* Si no alcanza, el ciclo se rompe y se define el máximo posible.
'
'	### Resumen del Factor TS en el Flujo
'
'	El presupuesto de ts no bloquea la promo "per se", sino que **filtra qué productos variables están disponibles**.
'	* Si la promo pide 3 variables.
'	* Tienes 5 opciones en inventario físico.
'	* 2 opciones son "Bonificación" (consumen presupuesto) y 3 son venta normal.
'	* **Escenario Sin Presupuesto:** Al iterar, `ts.traeBonificacionesMaximas` devolverá 0 para los 2 productos de bonificación. El sistema solo verá 3 productos disponibles (los normales).
'	* **Resultado:** Como la promo pide 3 y el sistema "ve" 3 disponibles, la promo **SÍ SE MUESTRA**.
'	* **Bloqueo:** Solo se bloquearía si la promo pidiera 4 variables, ya que Sin presupuesto ts solo "vemos" 3 productos disponibles, insuficientes para armar el paquete.
'
'	### Este flujo garantiza que la promo se muestre siempre que sea *físicamente* posible armarla, restringiendo la parte financiera solo a los ítems que realmente cuestan dinero al presupuesto de bonificaciones.
End Sub

Sub Class_Globals
	Private Root As B4XView 'ignore
	Private xui As XUI
	Private l_promoDesc As Label
	Private lv_prodsFijos As ListView
	Private clv_prodsVariabes As CustomListView
	Private l_prodsFijos As Label
	Private l_prodsVariables As Label
	Private i_prod As ImageView
	Private l_prodX As Label
	Private p_prods As Panel
	Private b_prodMenos As Button
	Private et_pCant As EditText
	Private b_prodMas As Button
	Private l_pCant As Label
	Dim totalProds As Int = 0
	Dim prodsVarReq As Int = 0
	Dim prodsVarReq2 As Int = 0
	Dim totalCompra As Float = 0
	Dim prodsFijosTot As Float = 0
	Dim tpf As Int = 0
	Dim tpf2 As Int = 0
	Dim maxCantPromos As Int = 1
	Private l_totProds As Label
	Private l_total As Label
	Private b_terminar1 As Button
	Private p_promociones As Panel
	Dim prodsIds, prodsCants, prodsPrecios, prodsIds2, prodsCants2, prodsPrecios2 As List
	Dim estaPromo, esteCliente As String
	Private b_promoMas As Button
	Private b_promoMenos As Button
	Dim et_promoCant As EditText
	Private l_promosCant As Label
	Private b_continuar As Button
	Private p_prodsVariables As Panel
	Dim laPromo = "", elCliente = "" As String
	Dim prodsPedidoActual As String
	Dim montoPedidoActual As String
	Dim promosMap As Map
	Dim ts As C_TrendSpending
	Dim TS_RMI() As String
	Dim TS_DESCUENTOS() As String
	Dim TS_BONIFICACIONES() As String
End Sub

'You can add more parameters here.
Public Sub Initialize As Object
'	promosC.Initialize(Me, "promosC", Starter.skmt)
	ts.Initialize("ts", "ts", Starter.skmt)
	Log(TS_RMI)
	Log(TS_DESCUENTOS)
	Log(TS_BONIFICACIONES)
	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("promociones")
	promosMap.Initialize
	p_promociones.Top=0
	p_promociones.Left=0
	p_promociones.Height=Root.Height
	p_promociones.Width=Root.Width
	b_terminar1.Left = Root.Width - (b_terminar1.Width + 10)
	b_continuar.Left = Root.Width - b_terminar1.Width - (b_continuar.Width + 20)
End Sub

Sub B4XPage_Appear
	B4XPages.MainPage.productos.entro = 3
'	LogColor(B4XPages.MainPage.productos.prodsMap, Colors.blue)
	prodsIds.Initialize
	prodsCants.Initialize
	prodsPrecios.Initialize
	prodsIds2.Initialize
	prodsCants2.Initialize
	prodsPrecios2.Initialize
	Dim m As Map = Subs.traeTotalesClienteActual
	prodsPedidoActual = m.Get("productos")
	montoPedidoActual = m.Get("monto")
	Log($"laPromo=${laPromo}, el cliente=${elCliente}"$)
	If laPromo <> "" Then muestraPromo(laPromo, elCliente)
End Sub
'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage.

Sub muestraPromo(promo As String, cliente As String)
	LogColor($"****************************************************************"$, Colors.red)
	LogColor($"************       muestraPromo: ${promo}       *************"$, Colors.red)
'	Log("muestraPromo: "&promo)
	Private thisLog As Boolean = False
'	If thisLog Then Log(promo)
	estaPromo = promo
	esteCliente = cliente
	Private mp As Map = Subs.traePromo(promo, cliente)
	If thisLog Then LogColor(mp, Colors.blue)
	Private prodsPromo As Map = mp.Get("productos") 'Los productos de la promoción.
'	Private invDispPromo As Map = Subs.traemosInventarioDisponibleParaPromo(promo)
	Private invDispPromo As Map = Subs.restaFijosPromo(mp)
	If thisLog Then Log($"invDispPromo=${invDispPromo}"$)
	If thisLog Then Log("Max promos por inv de prods FIJOS: " & Subs.revisaMaxPromosProdsFijosPorInventario(mp))
	If thisLog Then Log("Max promos por inv de prods VARIABLES: " & Subs.revisaMaxPromosProdsVariablesPorInventario(mp))
	maxCantPromos = Subs.revisaMaxPromosProdsVariablesPorInventario(mp)
	et_promoCant.Text = 1
	l_promosCant.text = "Max promos: " & maxCantPromos
	Private cs As CSBuilder
	cs.Initialize
	If thisLog Then Log(mp)
	If thisLog Then Log(prodsPromo)
	'Ponemos la promo y descripción.
'	Dim desc As String = $"Promoción: ${promo}${CRLF}${mp.Get("descripcion")}"$
'	Dim desc As String = cs.append("Promocion: ").Color(Colors.RGB(100,149,237)).Append(promo).pop.append(CRLF).Append(mp.Get("descripcion")).Popall
	l_promoDesc.Text = cs.Color(Colors.RGB(100,149,237)).append("Promocion: ").pop.append(CRLF).Append(promo).append(CRLF).Append(mp.Get("descripcion")).Popall
	prodsFijosTot = 0
	'Ponemos el texto en las etiquetas de la cantidad de productos.
'	Dim pf As List = mp.Get("prodsFijos")
	Dim pv As List = mp.Get("prodsVariables")
	Dim listaPreciosPV As List = mp.Get("prodsVariablesPrecios")
'	Logcolor(listaPreciosPV, Colors.red)
	If thisLog Then Log(mp)
	tpf = 0
	For Each pfp As Int In mp.Get("prodsFijosPiezas").As(List)
		tpf = tpf + pfp
	Next
	tpf2 = tpf
'	tpf = tpf * maxCantPromos
	l_prodsFijos.Text = $"Productos fijos (${tpf})"$
	prodsVarReq = mp.Get("prodsVariablesRequeridos")
	prodsVarReq2 = prodsVarReq
	l_prodsVariables.Text = $"Productos variables requeridos: ${prodsVarReq}"$
	If prodsVarReq = 0 Then
		p_prodsVariables.Visible = False
	Else
		p_prodsVariables.Visible = True
	End If
	'Llenamos el listview con los productos fijos.
	Dim label1 As Label
	label1 = lv_prodsFijos.SingleLineLayout.Label
	label1.TextSize = 13
	label1.TextColor = Colors.black
	lv_prodsFijos.SingleLineLayout.ItemHeight = 30dip
	lv_prodsFijos.Clear
'	If pf.Size < 1 Then pf.Add("Sin productos fijos.")
	lv_prodsFijos.Clear
	agregaFijosALista(mp, True)
	If thisLog Then Log("Total prods fijos = " & prodsFijosTot)
'	If thisLog Then Log("======="&prodsMap)
	l_totProds.text = $"Productos: ${tpf}"$
	l_total.Text = $"Total: $$1.2{prodsFijosTot}"$
'	Dim ins As InputStream
'	Dim bmp As Bitmap
'	Dim jpeg() As Byte

	'Llenamos el listview con los productos variables.
	If thisLog Then Log("Prods variables: " & pv)
'	If thisLog Then Log("invDisp=" & invDispPromo)
	clv_prodsVariabes.Clear
	For Each p As String In pv
		If invDispPromo.ContainsKey(p) Then 'Si no esta en la lista de productos con inventario no lo mostramos.
			If thisLog Then Log("Prod Variable: " & invDispPromo.get(p))
			Private existenciaProdVariable As String = invDispPromo.get(p)
'			c2.Position=i
'			jpeg = c2.GetBlob("CAT_GP_IMG")
'			ins.InitializeFromBytesArray(jpeg, 0, jpeg.Length)
'			bmp.Initialize2(ins)
			Private indicePV = pv.IndexOf(p)
			Private estePrecio = listaPreciosPV.Get(indicePV)
			Private thisProd As Map = prodsPromo.Get(p)
			If thisLog Then Log(thisProd)
			If existenciaProdVariable > 0 Then
				If thisLog Then Log($">>>>>  AGREGAMOS PROD VARIABLE ${p}"$)
				clv_prodsVariabes.Add(CreateListItem(Subs.traeProdNombre(p)&CRLF&"Hay " & invDispPromo.Get(p) & " $" & estePrecio, estePrecio, invDispPromo.Get(p), clv_prodsVariabes.AsView.Width, 50dip, Null, p), p)
			End If
		End If
	Next
	b_terminar1.Visible = False
	b_continuar.Visible = False
	cuentaProds
End Sub

'Agregamos los productos fijos a una lista para despues meterlos en el pedido.
Sub agregaFijosALista(mp As Map, addListItem As Boolean)
	Private thisLog As Boolean = False
	Private cont As Int = 0
	prodsFijosTot = 0
	Dim pf As List = mp.Get("prodsFijos")
	If pf.Size < 1 Then pf.Add("Sin productos fijos.")
'	Private m As Map
'	prodsMap.Put(estaPromo, CreateMap("cant":1, "precio":0))
'	prodsIds.Add(estaPromo)
	prodsIds.clear
	prodsCants.clear
	prodsPrecios.clear
	prodsIds.Add(estaPromo)
	prodsCants.Add(et_promoCant.text.As(Int))
	prodsPrecios.Add(0)
	For Each p As String In pf
'		Log($"cont=${cont}, mp=${mp}"$)
		If mp.Get("prodsFijosPiezas").As(List).Size > 0 Then
			Private tpi As String = mp.Get("prodsFijosPiezas").As(List).Get(cont)
		Else
			Private tpi As String = 0
		End If
		If mp.Get("prodsFijosPrecios").As(List).Size > 0 Then
			Private tpr As String = mp.Get("prodsFijosPrecios").As(List).Get(cont)
		Else
			Private tpr As String = 0
		End If
		prodsFijosTot = prodsFijosTot + (tpi * tpr)
		If thisLog Then Log("|"&tpi&"|"&p)
		Private ntpi As Int = tpi * et_promoCant.text
		If addListItem And tpi > 0 Then lv_prodsFijos.AddSingleLine(ntpi & " " & Subs.traeProdNombre(p) & " - $" & tpr)
		cont = cont+1
'		m=CreateMap("cant":tpi, "precio":tpr)
'		prodsMap.Put(p, m)
		prodsIds.Add(p)
		prodsCants.Add(tpi.As(Int)*et_promoCant.text.As(Int))
		prodsPrecios.Add(tpr) '*et_promoCant.text.As(Int)
	Next
End Sub

Sub CreateListItem(Text As String, 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("")
	p.SetLayoutAnimated(0, 0, 0, Width, Height)
	p.LoadLayout("prodItem")
	l_prodX.Text = Text
	l_prodX.Tag = inv
	l_prodX.TextSize = 13
	p_prods.Height = Height
	l_prodX.Height = Height
'	l_pCant.Text = 0
	l_pCant.Tag = precioU&"|"&inv&"|"&prodId
	et_pCant.Tag = precioU&"|"&inv&"|"&prodId
	et_pCant.BringToFront
'	i_prod.Bitmap = img
	p.Tag = prodId
	Return p
End Sub

Sub b_prodMenos_Click
	Dim index As Int = clv_prodsVariabes.GetItemFromView(Sender)
	Dim pnl0 As B4XView = clv_prodsVariabes.GetPanel(index)
	Dim pnl As B4XView = pnl0.GetView(0)
'	Dim laCant  As B4XView = pnl.GetView(5)
	Dim laCant As B4XView = pnl.GetView(2).GetView(4)
'	Log($"precio|stock:${laCant.tag}"$)
	laCant.Text = $"$1.0{laCant.Text-1}"$
	If laCant.Text < 0 Then laCant.Text = 0
	
'	Log(Regex.Split("\|", laCant.tag)(0))
	Private precio As String = Regex.Split("\|", laCant.tag)(0)
'	Private inv As String = Regex.Split("\|", laCant.tag)(1)
	Private prodId As String = Regex.Split("\|", laCant.tag)(2)
	Private tmpMap As Map = CreateMap("precio":precio, "cant":laCant.Text, "almacen":estaPromo)
	Log(tmpMap)
	promosMap.Put(prodId, tmpMap)
	If laCant.Text = 0 Then promosMap.Remove(prodId)
	LogColor(promosMap, Colors.Magenta)
	cuentaProds
'	l_total.Text = $"Total Compra: $$1.2{totalCompra}"$
'	l_totProds.text = $"Total Productos: ${totalProds}"$
End Sub

Sub b_prodMas_Click
'	LogColor($"prodmas clic "$,Colors.Magenta)
	If totalProds < prodsVarReq + tpf Then
		Dim index As Int = clv_prodsVariabes.GetItemFromView(Sender)
		Dim pnl0 As B4XView = clv_prodsVariabes.GetPanel(index)
		Dim pnl As B4XView = pnl0.GetView(0)
'		Dim laCant  As B4XView = pnl.GetView(5)
		Dim laCant As B4XView = pnl.GetView(2).GetView(4)
'		Log($"precio|stock:${laCant.tag}"$)
'		Log($"Indice: ${index}, cant:${laCant.Text+1}, precioU: ${laCant.tag}"$)
		Dim esteTag As List = Regex.Split("\|", laCant.Tag)
'		Log(">>>>>     " & esteTag)
		If laCant.Text + 1 <= esteTag.get(1) Then
			laCant.Text = $"$1.0{laCant.Text+1}"$
			cuentaProds
		End If
'		Log(Regex.Split("\|", laCant.tag)(0))
		Private precio As String = Regex.Split("\|", laCant.tag)(0)
'		Private inv As String = Regex.Split("\|", laCant.tag)(1)
		Private prodId As String = Regex.Split("\|", laCant.tag)(2)
		Private tmpMap As Map = CreateMap("precio":precio, "cant":laCant.Text, "almacen":estaPromo)
		promosMap.Put(prodId, tmpMap)
		Log("PRODMAS PROMOSMAP - " & promosMap)
'		LogColor(promosMap, Colors.Magenta)
	End If
'	Log($"Total Prods: ${totalProds}, Total Compra: $$1.2{totalCompra}"$)
'	l_total.Text = $"Total Compra: $$1.2{totalCompra}"$
'	l_totProds.text = $"Total Productos: ${totalProds}"$
End Sub

Private Sub et_pCant_TextChanged (Old As String, New As String)
'	If New = "" Then
'		et_pCant.Text = 0
'		l_pCant.Text = 0
'	End If
'	LogColor($"txt changed - ${Starter.cp_running}"$,Colors.Magenta)
	If New <> "" Then cuentaProds
'	Starter.cp_running = False
End Sub

Sub cuentaProds
'	Log("=====================================================")
'	Log($"Inicia cuentaProds - ${Starter.cp_running}"$)
'	Starter.cp_running = True
	Private thisLog As Boolean = False
	If thisLog Then LogColor($"ProdsFijos=${tpf}, totalProds=${totalProds}, totalCompra=${totalCompra}"$, Colors.Red)
	prodsIds2.Clear
	prodsCants2.Clear
	prodsPrecios2.Clear
	lv_prodsFijos.Clear
	agregaFijosALista(Subs.traePromo(estaPromo, esteCliente), True)
'	Log(prodsIds)
	Private tcpf As Float = 0 'Total de compra de productos fijos.
	For pf = 0 To prodsIds.Size - 1
		If thisLog Then Log($"${tcpf} + ${prodsCants.Get(pf)} * ${prodsPrecios.Get(pf)} = ${(prodsPrecios.Get(pf) * prodsCants.Get(pf))}"$)
		tcpf = tcpf + (prodsPrecios.Get(pf) * prodsCants.Get(pf))
	Next
'	Log("Total compra prodsFijos = " & tcpf)
	totalCompra = tcpf
	totalProds = tpf 'Cantidad total de productos fijos.
	For i = 0 To clv_prodsVariabes.GetSize - 1
		Private p0 As B4XView = clv_prodsVariabes.GetPanel(i)
		Private p As B4XView = p0.GetView(0)
		Private cant1 As B4XView = p.GetView(2).GetView(4)
		If cant1.Text = "" Then cant1.Text = 0
		totalProds = totalProds + cant1.Text
		Private esteTag As List = Regex.Split("\|", cant1.Tag)
		If cant1.Text > esteTag.Get(1) Then cant1.Text = esteTag.Get(1)
'		Log("******  " & esteTag.Get(1) & "|" & cant1.Text)
		If cant1.Text > 0 Then
'			Log(esteTag.Get(2) & "|" & cant1.Text)
			totalCompra = totalCompra + (esteTag.get(0) * cant1.text)
			If thisLog Then Log($"Cant: ${cant1.Text}, Suma: ${totalCompra}"$)
			prodsIds2.Add(esteTag.Get(2))
			prodsCants2.Add(cant1.Text)
			prodsPrecios2.Add(esteTag.get(0))
		End If
		l_total.Text = $"Total: $$1.2{totalCompra}"$
		l_totProds.text = $"Productos: ${totalProds}"$
'		Log(esteTag.Get(2) & "|" & estaPromo)
	Next
	If thisLog Then Log($"Total Prods: ${totalProds}, Total: $$1.2{totalCompra}"$)
	l_total.Text = $"Total: $$1.2{totalCompra}"$
	l_totProds.text = $"Productos: ${totalProds}"$
	If totalProds < prodsVarReq + tpf Or totalProds > prodsVarReq + tpf Then
'		Log("INCOMPLETA")
		b_terminar1.Visible = False
		b_continuar.Visible = False
	Else
'		Log("COMPLETA")
		b_terminar1.Visible = True
		b_continuar.Visible = True
	End If
	If thisLog Then LogColor($"${prodsIds}${CRLF}${prodsCants}${CRLF}${prodsPrecios}"$, Colors.blue)
	If thisLog Then LogColor($"${prodsIds2}${CRLF}${prodsCants2}${CRLF}${prodsPrecios2}"$, Colors.Magenta)
'	LogColor($"Total Prods: ${totalProds}, Total: $$1.2{totalCompra}"$, Colors.Blue)
'	Log($"Termina cuentaProds - ${Starter.cp_running}"$)

	'Si la cantidad es mayor que los productos requeridos, entonces ponemos todos en CERO.
'	If totalProds > prodsVarReq + tpf Then
'		For i = 0 To clv_prodsVariabes.GetSize - 1
'			Private p0 As B4XView = clv_prodsVariabes.GetPanel(i)
'			Private p As B4XView = p0.GetView(0)
'			Private cant1 As B4XView = p.GetView(2).GetView(4)
'			cant1.Text = 0
'		Next
'	End If
	
End Sub

Private Sub et_pCant_FocusChanged (HasFocus As Boolean)
'	LogColor("Focus changed", Colors.Magenta)
	cuentaProds
'	Starter.cp_running = False
End Sub

Private Sub b_promoMenos_Click
	If et_promoCant.Text > 1 Then
		et_promoCant.Text = et_promoCant.Text.As(Int) - 1
	End If
	l_prodsFijos.Text = $"Productos fijos (${tpf2 * et_promoCant.Text.As(Int)})"$
	l_prodsVariables.Text = $"Productos variables requeridos: ${prodsVarReq2 * et_promoCant.Text.As(Int)}"$
	tpf = tpf2 * et_promoCant.Text.As(Int)
	prodsVarReq = prodsVarReq2 * et_promoCant.Text.As(Int)
	Log($"Max promos=${et_promoCant.Text.As(Int)}, Prods fijos=${tpf},  "$)
	
	Private invVariableMod As Map = revisaInvProdsVariables 'Si se modifica el inventario de los prods variables, recargamos el CLV de prods variables.
	If invVariableMod.Size > 0 Then
		Private listProds As List
		listProds.Initialize
		For i = 0 To clv_prodsVariabes.Size - 1 'Generamos una lista con los productos del CLV.
			Private pa1 As B4XView = clv_prodsVariabes.GetPanel(i).GetView(0).GetView(2).GetView(4)
			Private elTag() As String = Regex.Split("\|", pa1.Tag)
			Private elInv As Int = elTag(1)
			If invVariableMod.ContainsKey(elTag(2)) Then elInv = invVariableMod.Get(elTag(2))
			listProds.Add(CreateListItem(Subs.traeProdNombre(elTag(2))&CRLF&"Hay " & elInv & " $" & elTag(0), elTag(0), elInv, clv_prodsVariabes.AsView.Width, 50dip, Null, elTag(2)))
		Next
		clv_prodsVariabes.Clear
		For i = 0 To listProds.Size - 1 'Usamos la lista para poblar el CLV con los datos modificados.
			clv_prodsVariabes.Add(listProds.Get(i), listProds.Get(i).As(Panel).tag)
		Next
	End If
	
	cuentaProds
End Sub

Private Sub b_promoMas_Click
	If et_promoCant.Text < maxCantPromos Then
		et_promoCant.Text = et_promoCant.Text.As(Int) + 1
		l_prodsFijos.Text = $"Productos fijos (${tpf2 * et_promoCant.Text.As(Int)})"$
		l_prodsVariables.Text = $"Productos variables requeridos: ${prodsVarReq2 * et_promoCant.Text.As(Int)}"$
		tpf = tpf2 * et_promoCant.Text.As(Int)
		prodsVarReq = prodsVarReq2 * et_promoCant.Text.As(Int)
		Log($"Max promos=${et_promoCant.Text.As(Int)}, Prods fijos=${tpf},  "$)
	End If
	If et_promoCant.text > maxCantPromos Then et_promoCant.Text = maxCantPromos

	Private invVariableMod As Map = revisaInvProdsVariables 'Si se modifica el inventario de los prods variables, necesitamos recargar el CLV de prods variables.
	If invVariableMod.Size > 0 Then
		Private listProds As List
		listProds.Initialize
		For i = 0 To clv_prodsVariabes.Size - 1 'Generamos una lista con los productos del CLV.
			Private pa1 As B4XView = clv_prodsVariabes.GetPanel(i).GetView(0).GetView(2).GetView(4)
			Private elTag() As String = Regex.Split("\|", pa1.Tag)
			Private elInv As Int = elTag(1)
			If invVariableMod.ContainsKey(elTag(2)) Then elInv = invVariableMod.Get(elTag(2))
			listProds.Add(CreateListItem(Subs.traeProdNombre(elTag(2))&CRLF&"Hay " & elInv & " $" & elTag(0), elTag(0), elInv, clv_prodsVariabes.AsView.Width, 50dip, Null, elTag(2)))
		Next
		clv_prodsVariabes.Clear
		For i = 0 To listProds.Size - 1 'Usamos la lista para poblar el CLV con los datos modificados.
			clv_prodsVariabes.Add(listProds.Get(i), listProds.Get(i).As(Panel).tag)
		Next
	End If

	cuentaProds
End Sub

' Revisa si el inventario de un producto variable cambia cuando se modifica la cantidad de promociones que se van a ordenar. 
' Esto pasa cuando el producto fijo de una promocion tambien es parte de los productos variables de la misma, asi que
' si la promo usa 3 productos fijos y quedan 10 para los variables, cuando pedimos 2 promociones, en lugar de usar
' 3 para los fijos, ahora vamos a necesitar 6, y en lugar de quedar 10 para los variables, ahora solo quedan 7.
' Regresa un mapa con el nuevo inventario de los productos variables afectados.
Sub revisaInvProdsVariables As Map
	Private invVariablesModificados As Map = CreateMap()
'	Private prodsFijosOriginales As Int = (tpf / et_promoCant.Text)
'	 LogColor($"Prods fijos originales = ${prodsFijosOriginales}"$, Colors.Red)
	Private nuevoInvDisponible As Int
	For f = 0 To prodsIds.Size - 1
'		Log(prodsIds.Get(f))
'		LogColor($"${prodsIds.Get(f)} -> ${prodsCants.Get(f)}"$, Colors.Red)
		For i = 0 To clv_prodsVariabes.GetSize - 1
			Private pa0 As B4XView = clv_prodsVariabes.GetPanel(i).GetView(0).GetView(1)
			Private pa1 As B4XView = clv_prodsVariabes.GetPanel(i).GetView(0).GetView(2).GetView(4)
			Private pp As String = pa1.Tag
'			Log($"EL TAG -> ${pp}"$)
			Private elTag() As String = Regex.Split("\|", pp)
			If elTag.Length > 1 Then
				If elTag(2) = prodsIds.Get(f) Then
					Private invDeBD As Int = Subs.traeInvDeBD(elTag(2))
'					Log($"XXX -> ${pa0.text} -> ${invDeBD}"$)
					nuevoInvDisponible = invDeBD - tpf
					LogColor($"Nuevo inv desponible = ${invDeBD} - ${tpf} = ${nuevoInvDisponible}"$, Colors.Red)
					invVariablesModificados.Put(prodsIds.Get(f), nuevoInvDisponible)
				End If
			End If
		Next
	Next
	Log($"INV MODIFICADOS: ${invVariablesModificados}"$)
	Return invVariablesModificados
End Sub

Private Sub b_terminar1_Click
	cuentaProds
	Private elMontoTSDeLaVenta As String = 0
'	Log("====================================================================")
	Log($"${prodsIds}${CRLF}${prodsCants}${CRLF}${prodsPrecios}"$)
	For t = 0 To prodsIds.Size - 1 'Guardamos los productos fijos de la promocion en pedido.
		Private pn As String = Subs.traeProdNombre(prodsIds.Get(t))

		Private idProdFijo As String = prodsIds.Get(t)
		Private cantProdFijo As Int = prodsCants.Get(t)
		Private prodsPrecio As String = prodsPrecios.Get(t)

		Log($"#### idProdFijo: ${idProdFijo}, ${cantProdFijo}, ${prodsPrecio}"$)

'		' Asumimos que el índice 0 es el encabezado de la promoción (estaPromo) y no tiene bonificación de producto.
		If t > 0 Then
			Private bonificacion_monto As String = ts.traeMontoBonificacion(idProdFijo, prodsPrecio, estaPromo)
			Log(bonificacion_monto)
			Log("elMontoTSDeLaVenta=" & elMontoTSDeLaVenta)
			Log($"${elMontoTSDeLaVenta} + (${bonificacion_monto} * ${cantProdFijo})"$)
			elMontoTSDeLaVenta = elMontoTSDeLaVenta + (bonificacion_monto * cantProdFijo)
			Log($"TS Fijo Acumulado: ${elMontoTSDeLaVenta}, Prod: ${idProdFijo}"$)
		End If

		If prodsCants.Get(t) > 0 Then Subs.guardaProductoSinGestion(estaPromo, prodsPrecios.Get(t), prodsCants.Get(t), pn, prodsIds.Get(t), Subs.traeCliente, Subs.traeFecha, Subs.traeUsuarioDeBD, Subs.traeRuta, 0, Starter.tipov)
	Next
	For t = 0 To prodsIds2.Size - 1 'Guardamos los productos variables de la promocion en pedido.
		Private pn As String = Subs.traeProdNombre(prodsIds2.Get(t))
		Subs.guardaProductoSinGestion(estaPromo, prodsPrecios2.Get(t), prodsCants2.Get(t), pn, prodsIds2.Get(t), Subs.traeCliente, Subs.traeFecha, Subs.traeUsuarioDeBD, Subs.traeRuta, 0, Starter.tipov)
		' Traemos el monto de las bonificacionos a guardar. -- Trade Spending
		Log("Monto Bonificacion -->> " & ts.traeMontoBonificacion(prodsIds2.Get(t), prodsPrecios2.Get(t), estaPromo))
		elMontoTSDeLaVenta = elMontoTSDeLaVenta + (ts.traeMontoBonificacion(prodsIds2.Get(t), prodsPrecios2.Get(t), estaPromo) * prodsCants2.Get(t))
		Log("Acumulado: " & elMontoTSDeLaVenta)
	Next
	ts.modTrendSpending("RESTA", "BONIFICACIONES", elMontoTSDeLaVenta)
	Log($"###   modTrendSpending("RESTA", "BONIFICACIONES", ${elMontoTSDeLaVenta})"$)
	lv_prodsFijos.Clear
	B4XPages.MainPage.bTerminarClicked = True
	B4XPages.ShowPage("productos")
	B4XPages.MainPage.productos.b_terminar1_Click
End Sub

Private Sub b_continuar_Click
	cuentaProds
	Private elMontoTSDeLaVenta As String = 0
'	Log("====================================================================")
	Log($"${prodsIds}${CRLF}${prodsCants}${CRLF}${prodsPrecios}"$)
	For t = 0 To prodsIds.Size - 1 'Guardamos los productos fijos de la promocion en pedido.
		Private pn As String = Subs.traeProdNombre(prodsIds.Get(t))

		Private idProdFijo As String = prodsIds.Get(t)
		Private cantProdFijo As Int = prodsCants.Get(t)
		Private prodsPrecio As String = prodsPrecios.Get(t)

		Log($"#### idProdFijo: ${idProdFijo}, ${cantProdFijo}, ${prodsPrecio}"$)

'		' Asumimos que el índice 0 es el encabezado de la promoción (estaPromo) y no tiene bonificación de producto.
		If t > 0 Then
			Private bonificacion_monto As String = ts.traeMontoBonificacion(idProdFijo, prodsPrecio, estaPromo)
			Log(bonificacion_monto)
			Log("elMontoTSDeLaVenta=" & elMontoTSDeLaVenta)
			Log($"${elMontoTSDeLaVenta} + (${bonificacion_monto} * ${cantProdFijo})"$)
			elMontoTSDeLaVenta = elMontoTSDeLaVenta + (bonificacion_monto * cantProdFijo)
			Log($"TS Fijo Acumulado: ${elMontoTSDeLaVenta}, Prod: ${idProdFijo}"$)
		End If

		If prodsCants.Get(t) > 0 Then Subs.guardaProductoSinGestion(estaPromo, prodsPrecios.Get(t), prodsCants.Get(t), pn, prodsIds.Get(t), Subs.traeCliente, Subs.traeFecha, Subs.traeUsuarioDeBD, Subs.traeRuta, 0, Starter.tipov)
	Next
	For t = 0 To prodsIds2.Size - 1 'Guardamos los productos variables de la promocion en pedido.
		Private pn As String = Subs.traeProdNombre(prodsIds2.Get(t))
		Subs.guardaProductoSinGestion(estaPromo, prodsPrecios2.Get(t), prodsCants2.Get(t), pn, prodsIds2.Get(t), Subs.traeCliente, Subs.traeFecha, Subs.traeUsuarioDeBD, Subs.traeRuta, 0, Starter.tipov)
		' Traemos el monto de las bonificacionos a guardar. -- Trade Spending
		Log("Monto Bonificacion -->> " & ts.traeMontoBonificacion(prodsIds2.Get(t), prodsPrecios2.Get(t), estaPromo))
		elMontoTSDeLaVenta = elMontoTSDeLaVenta + (ts.traeMontoBonificacion(prodsIds2.Get(t), prodsPrecios2.Get(t), estaPromo) * prodsCants2.Get(t))
		Log("Acumulado: " & elMontoTSDeLaVenta)
	Next
	ts.modTrendSpending("RESTA", "BONIFICACIONES", elMontoTSDeLaVenta)
	Log($"###   modTrendSpending("RESTA", "BONIFICACIONES", ${elMontoTSDeLaVenta})"$)
	lv_prodsFijos.Clear
'	Activity_KeyPress(KeyCodes.KEYCODE_BACK)
'	CallSubDelayed2(productos, "Activity_KeyPress", KeyCodes.KEYCODE_BACK)
	Private prodspage As C_Productos
	If prodspage.IsInitialized Then
		prodspage.lv_catalogos.Visible = True
		prodspage.lv_promos.Visible = False
		prodspage.clv_productos.AsView.Visible = False
	End If
	B4XPages.MainPage.bTerminarClicked = True
	B4XPages.ShowPage("productos")
End Sub

'Sub Activity_KeyPress (key As Int) As Boolean 'ignore
'	' BACK key pressed
'	Log("Keypress")
'	If key=KeyCodes.KEYCODE_BACK Then
'		Log("BACK")
'		Return False
'	End If
'	Return False
'	' Returning False signals the system to handle the key
'End Sub

Private Sub et_promoCant_TextChanged (Old As String, New As String)
	If IsNumber(New) And New > maxCantPromos Then et_promoCant.Text = maxCantPromos
	If IsNumber(New) Then cuentaProds
End Sub