Scan to open on your phone
Point a camera at the QR code - it opens this exact paste, no app needed.
https://codepastes.com/zzgsbxxcyz7gbp2psin-tituloPlain Text
package com.negocio.desinfectantes.ui.ventas
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.negocio.desinfectantes.data.ClienteEntity
import com.negocio.desinfectantes.data.ProductoEntity
import com.negocio.desinfectantes.data.AromaEntity
import com.negocio.desinfectantes.data.PresentacionEntity
private val Navy = Color(0xFF101D35)
private val CardBlue = Color(0xFF1B2D4A)
private val AccentBlue = Color(0xFF2585F5)
private val SoftBlue = Color(0xFFA9BEDB)
private data class DetalleTemporalVenta(
val presentacionId: String,
val producto: String,
val aroma: String,
val presentacion: String,
val cantidad: Int,
val precioUnitario: Double
) {
val subtotal: Double
get() = cantidad * precioUnitario
}
@Composable
fun VentaScreen(
modifier: Modifier = Modifier,
clientes: List<ClienteEntity>,
productos: List<ProductoEntity>,
aromas: List<AromaEntity>,
presentaciones: List<PresentacionEntity>,
onVolver: () -> Unit
) {
var clienteSeleccionado by remember { mutableStateOf<ClienteEntity?>(null) }
var sedeSeleccionada by remember { mutableStateOf("Barrancas") }
var mostrarClientes by remember { mutableStateOf(false) }
var productoSeleccionado by remember {
mutableStateOf<ProductoEntity?>(null)
}
var aromaSeleccionado by remember {
mutableStateOf<AromaEntity?>(null)
}
var presentacionSeleccionada by remember {
mutableStateOf<PresentacionEntity?>(null)
}
var mostrarProductos by remember { mutableStateOf(false) }
var mostrarAromas by remember { mutableStateOf(false) }
var mostrarPresentaciones by remember { mutableStateOf(false) }
var cantidadTexto by remember { mutableStateOf("1") }
var precioTexto by remember { mutableStateOf("") }
var detallesVenta by remember {
mutableStateOf(listOf<DetalleTemporalVenta>())
}
var tipoVenta by remember {
mutableStateOf("CONTADO")
}
var estadoEntrega by remember {
mutableStateOf("ENTREGADA")
}
var montoPagoTexto by remember {
mutableStateOf("")
}
var metodoPago by remember {
mutableStateOf("Efectivo")
}
var mostrarMetodosPago by remember {
mutableStateOf(false)
}
Column(
modifier = modifier
.fillMaxSize()
.background(Navy)
.verticalScroll(rememberScrollState())
.padding(20.dp)
) {
TextButton(onClick = onVolver) {
Text("← Volver", color = SoftBlue)
}
Text(
"Nueva venta",
color = Color.White,
style = MaterialTheme.typography.headlineMedium,
fontWeight = FontWeight.Bold
)
Spacer(modifier = Modifier.height(8.dp))
Text(
"Registra los productos y pagos de tus clientes.",
color = SoftBlue
)
Spacer(modifier = Modifier.height(24.dp))
// CLIENTE
Card(
colors = CardDefaults.cardColors(
containerColor = CardBlue
),
shape = RoundedCornerShape(16.dp)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text(
"1. Información del cliente",
color = Color.White,
fontWeight = FontWeight.Bold,
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(12.dp))
Box {
OutlinedButton(
onClick = { mostrarClientes = true },
modifier = Modifier.fillMaxWidth()
) {
Text(
clienteSeleccionado?.nombre
?: "Seleccionar cliente",
color = Color.White
)
}
DropdownMenu(
expanded = mostrarClientes,
onDismissRequest = { mostrarClientes = false }
) {
clientes.forEach { cliente ->
DropdownMenuItem(
text = { Text(cliente.nombre) },
onClick = {
clienteSeleccionado = cliente
mostrarClientes = false
}
)
}
}
}
if (clientes.isEmpty()) {
Spacer(modifier = Modifier.height(8.dp))
Text(
"Todavía no hay clientes registrados.",
color = SoftBlue
)
}
}
}
Spacer(modifier = Modifier.height(18.dp))
// SEDE
Card(
colors = CardDefaults.cardColors(
containerColor = CardBlue
),
shape = RoundedCornerShape(16.dp)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text(
"2. Sede de la venta",
color = Color.White,
fontWeight = FontWeight.Bold,
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(14.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(10.dp)
) {
FilterChip(
selected = sedeSeleccionada == "Barrancas",
onClick = { sedeSeleccionada = "Barrancas" },
label = { Text("Barrancas") }
)
FilterChip(
selected = sedeSeleccionada == "Valledupar",
onClick = { sedeSeleccionada = "Valledupar" },
label = { Text("Valledupar") }
)
}
}
}
Spacer(modifier = Modifier.height(18.dp))
// PRODUCTOS
Card(
colors = CardDefaults.cardColors(
containerColor = CardBlue
),
shape = RoundedCornerShape(16.dp)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text(
"3. Productos",
color = Color.White,
fontWeight = FontWeight.Bold,
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(14.dp))
// SELECCIONAR PRODUCTO
Text("Producto", color = SoftBlue)
Box {
OutlinedButton(
onClick = { mostrarProductos = true },
modifier = Modifier.fillMaxWidth()
) {
Text(
productoSeleccionado?.nombre ?: "Seleccionar producto",
color = Color.White
)
}
DropdownMenu(
expanded = mostrarProductos,
onDismissRequest = { mostrarProductos = false }
) {
productos.filter { it.activo }.forEach { producto ->
DropdownMenuItem(
text = { Text(producto.nombre) },
onClick = {
productoSeleccionado = producto
aromaSeleccionado = null
presentacionSeleccionada = null
mostrarProductos = false
}
)
}
}
}
Spacer(modifier = Modifier.height(14.dp))
// SELECCIONAR AROMA
Text("Aroma", color = SoftBlue)
Box {
OutlinedButton(
onClick = {
if (productoSeleccionado != null) {
mostrarAromas = true
}
},
enabled = productoSeleccionado != null,
modifier = Modifier.fillMaxWidth()
) {
Text(
aromaSeleccionado?.nombre ?: "Seleccionar aroma",
color = Color.White
)
}
DropdownMenu(
expanded = mostrarAromas,
onDismissRequest = { mostrarAromas = false }
) {
aromas.filter {
it.productoId == productoSeleccionado?.id && it.activo
}.forEach { aroma ->
DropdownMenuItem(
text = { Text(aroma.nombre) },
onClick = {
aromaSeleccionado = aroma
presentacionSeleccionada = null
mostrarAromas = false
}
)
}
}
}
Spacer(modifier = Modifier.height(14.dp))
// SELECCIONAR PRESENTACION
Text("Presentación", color = SoftBlue)
Box {
OutlinedButton(
onClick = {
if (aromaSeleccionado != null) {
mostrarPresentaciones = true
}
},
enabled = aromaSeleccionado != null,
modifier = Modifier.fillMaxWidth()
) {
Text(
presentacionSeleccionada?.nombre
?: "Seleccionar presentación",
color = Color.White
)
}
DropdownMenu(
expanded = mostrarPresentaciones,
onDismissRequest = { mostrarPresentaciones = false }
) {
presentaciones.filter {
it.aromaId == aromaSeleccionado?.id && it.activo
}.forEach { presentacion ->
DropdownMenuItem(
text = { Text(presentacion.nombre) },
onClick = {
presentacionSeleccionada = presentacion
precioTexto = presentacion.precio.toString()
cantidadTexto = "1"
mostrarPresentaciones = false
}
)
}
}
}
if (productoSeleccionado != null &&
aromaSeleccionado != null &&
presentacionSeleccionada != null
) {
Spacer(modifier = Modifier.height(12.dp))
Text(
"Precio del catálogo: \$${presentacionSeleccionada!!.precio}",
color = SoftBlue
)
Spacer(modifier = Modifier.height(12.dp))
OutlinedTextField(
value = cantidadTexto,
onValueChange = { cantidadTexto = it },
label = { Text("Cantidad") },
singleLine = true,
modifier = Modifier.fillMaxWidth(),
colors = OutlinedTextFieldDefaults.colors(
focusedTextColor = Color.White,
unfocusedTextColor = Color.White,
focusedLabelColor = SoftBlue,
unfocusedLabelColor = SoftBlue
)
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
value = precioTexto,
onValueChange = { precioTexto = it },
label = { Text("Precio acordado por unidad") },
singleLine = true,
modifier = Modifier.fillMaxWidth(),
colors = OutlinedTextFieldDefaults.colors(
focusedTextColor = Color.White,
unfocusedTextColor = Color.White,
focusedLabelColor = SoftBlue,
unfocusedLabelColor = SoftBlue
)
)
Spacer(modifier = Modifier.height(14.dp))
Button(
onClick = {
val presentacion = presentacionSeleccionada
val cantidad = cantidadTexto.toIntOrNull()
val precio = precioTexto.replace(",", ".").toDoubleOrNull()
if (
presentacion != null &&
cantidad != null &&
cantidad > 0 &&
precio != null &&
precio >= 0
) {
val nuevoDetalle = DetalleTemporalVenta(
presentacionId = presentacion.id,
producto = productoSeleccionado!!.nombre,
aroma = aromaSeleccionado!!.nombre,
presentacion = presentacion.nombre,
cantidad = cantidad,
precioUnitario = precio
)
detallesVenta = detallesVenta + nuevoDetalle
presentacionSeleccionada = null
aromaSeleccionado = null
productoSeleccionado = null
cantidadTexto = "1"
precioTexto = ""
}
},
modifier = Modifier.fillMaxWidth(),
colors = ButtonDefaults.buttonColors(
containerColor = AccentBlue
)
) {
Text("+ Agregar a la venta", color = Color.White)
}
}
}
}
// RESUMEN DE PRODUCTOS AGREGADOS
if (detallesVenta.isNotEmpty()) {
Spacer(modifier = Modifier.height(14.dp))
Card(
colors = CardDefaults.cardColors(
containerColor = CardBlue
),
shape = RoundedCornerShape(16.dp)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text(
"Artículos de la venta",
color = Color.White,
fontWeight = FontWeight.Bold,
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(12.dp))
detallesVenta.forEachIndexed { index, detalle ->
Text(
detalle.producto,
color = Color.White,
fontWeight = FontWeight.Bold
)
Text(
"${detalle.aroma} · ${detalle.presentacion}",
color = SoftBlue
)
Text(
"${detalle.cantidad} × \$${detalle.precioUnitario}",
color = SoftBlue
)
Text(
"Subtotal: \$${detalle.subtotal}",
color = Color.White,
fontWeight = FontWeight.Bold
)
TextButton(
onClick = {
detallesVenta = detallesVenta.toMutableList().also {
it.removeAt(index)
}
}
) {
Text(
"Eliminar artículo",
color = Color(0xFFFF6B6B)
)
}
if (index < detallesVenta.lastIndex) {
HorizontalDivider(
modifier = Modifier.padding(vertical = 10.dp),
color = SoftBlue.copy(alpha = 0.3f)
)
}
}
HorizontalDivider(
modifier = Modifier.padding(vertical = 12.dp),
color = SoftBlue
)
Text(
"TOTAL: \$${detallesVenta.sumOf { it.subtotal }}",
color = Color.White,
fontWeight = FontWeight.Bold,
style = MaterialTheme.typography.titleLarge
)
}
}
}
// PAGOS
Card(
colors = CardDefaults.cardColors(
containerColor = CardBlue
),
shape = RoundedCornerShape(16.dp)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp)
) {
Text(
"4. Pago y entrega",
color = Color.White,
fontWeight = FontWeight.Bold,
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(8.dp))
Text(
"Modalidad de venta",
color = SoftBlue,
fontWeight = FontWeight.Bold
)
Spacer(modifier = Modifier.height(8.dp))
Column {
listOf(
"CONTADO" to "Contado",
"CREDITO" to "Crédito",
"PEDIDO_ANTICIPADO" to "Pedido anticipado"
).forEach { (valor, etiqueta) ->
Row(
verticalAlignment = androidx.compose.ui.Alignment.CenterVertically
) {
RadioButton(
selected = tipoVenta == valor,
onClick = { tipoVenta = valor },
colors = RadioButtonDefaults.colors(
selectedColor = AccentBlue,
unselectedColor = SoftBlue
)
)
Text(
etiqueta,
color = Color.White
)
}
}
Spacer(modifier = Modifier.height(18.dp))
Spacer(modifier = Modifier.height(18.dp))
Text(
"Pago inicial",
color = SoftBlue,
fontWeight = FontWeight.Bold
)
Spacer(modifier = Modifier.height(8.dp))
OutlinedTextField(
value = montoPagoTexto,
onValueChange = { montoPagoTexto = it },
label = { Text("¿Cuánto dinero entrega el cliente?") },
placeholder = { Text("Ejemplo: 40000") },
singleLine = true,
modifier = Modifier.fillMaxWidth(),
colors = OutlinedTextFieldDefaults.colors(
focusedTextColor = Color.White,
unfocusedTextColor = Color.White,
focusedLabelColor = SoftBlue,
unfocusedLabelColor = SoftBlue,
focusedPlaceholderColor = SoftBlue,
unfocusedPlaceholderColor = SoftBlue
)
)
Spacer(modifier = Modifier.height(14.dp))
Text(
"Método de pago",
color = SoftBlue,
fontWeight = FontWeight.Bold
)
Spacer(modifier = Modifier.height(8.dp))
Box {
OutlinedButton(
onClick = { mostrarMetodosPago = true },
modifier = Modifier.fillMaxWidth()
) {
Text(metodoPago, color = Color.White)
}
DropdownMenu(
expanded = mostrarMetodosPago,
onDismissRequest = { mostrarMetodosPago = false }
) {
listOf(
"Efectivo",
"Transferencia bancaria",
"Nequi",
"Daviplata",
"Otro"
).forEach { metodo ->
DropdownMenuItem(
text = { Text(metodo) },
onClick = {
metodoPago = metodo
mostrarMetodosPago = false
}
)
}
}
}
Text(
"Estado de entrega",
color = SoftBlue,
fontWeight = FontWeight.Bold
)
Spacer(modifier = Modifier.height(8.dp))
Column {
listOf(
"ENTREGADA" to "Producto entregado",
"PENDIENTE_FABRICACION" to "Pendiente de fabricación",
"PENDIENTE_ENTREGA" to "Pendiente de entrega"
).forEach { (valor, etiqueta) ->
Row(
verticalAlignment = androidx.compose.ui.Alignment.CenterVertically
) {
RadioButton(
selected = estadoEntrega == valor,
onClick = { estadoEntrega = valor },
colors = RadioButtonDefaults.colors(
selectedColor = AccentBlue,
unselectedColor = SoftBlue
)
)
Text(
etiqueta,
color = Color.White
)
}
}
}
}
}
}
Spacer(modifier = Modifier.height(24.dp))
}
}
25,416 chars · codepastes.com