sin-titulo

Pasted Nov 5, 2026, 8:59 PM1 file832 lines

Scan to open on your phone

Point a camera at the QR code - it opens this exact paste, no app needed.

https://codepastes.com/zzgsbvc1x4sqs1cx
sin-titulo
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
import com.negocio.desinfectantes.data.VentaEntity
import com.negocio.desinfectantes.data.DetalleVentaEntity
import com.negocio.desinfectantes.data.PagoVentaEntity
import com.negocio.desinfectantes.data.MovimientoInventarioEntity
import com.negocio.desinfectantes.data.ProductoDao
import androidx.compose.runtime.rememberCoroutineScope

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
}

private fun generarId(): String {
    return java.util.UUID.randomUUID().toString()
}
@Composable
fun VentaScreen(
    modifier: Modifier = Modifier,
    clientes: List<ClienteEntity>,
    productos: List<ProductoEntity>,
    aromas: List<AromaEntity>,
    presentaciones: List<PresentacionEntity>,
    productoDao: ProductoDao,
    onVolver: () -> Unit
) {
    val scope = rememberCoroutineScope()
    var guardando by remember { mutableStateOf(false) }
    var mensajeError by remember { mutableStateOf<String?>(null) }
    var ventaRegistrada by remember { mutableStateOf(false) }
    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)
    }

    var otroMetodoPago by remember {
        mutableStateOf("")
    }

    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))

                    if (tipoVenta != "CONTADO") {
                        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
                                    }
                                )
                            }
                        }

                    }
                    if (metodoPago == "Otro") {
                        Spacer(modifier = Modifier.height(8.dp))

                        OutlinedTextField(
                            value = otroMetodoPago,
                            onValueChange = { otroMetodoPago = it },
                            label = { Text("Especifica el método de pago") },
                            modifier = Modifier.fillMaxWidth(),
                            singleLine = true
                        )
                    }

                    Spacer(modifier = Modifier.height(18.dp))

                    val totalVenta = detallesVenta.sumOf { it.subtotal }

                    val pagoInicial = if (tipoVenta == "CONTADO") {
                        totalVenta
                    } else {
                        montoPagoTexto
                            .replace(",", ".")
                            .toDoubleOrNull() ?: 0.0
                    }

                    val saldoPendiente = (totalVenta - pagoInicial).coerceAtLeast(0.0)
                    val pagoExcedeTotal = tipoVenta != "CONTADO" &&
                            pagoInicial > totalVenta

                    val creditoPagadoCompleto = tipoVenta == "CREDITO" &&
                            totalVenta > 0 &&
                            pagoInicial >= totalVenta

                    if (pagoExcedeTotal || creditoPagadoCompleto) {
                        Text(
                            text = if (pagoExcedeTotal) {
                                "El pago inicial no puede superar el total de la venta."
                            } else {
                                "Una venta a crédito debe tener un saldo pendiente. Si paga todo, selecciona Contado."
                            },
                            color = Color(0xFFFF6B6B),
                            fontWeight = FontWeight.Bold
                        )
                    }

                    HorizontalDivider(
                        color = SoftBlue.copy(alpha = 0.3f)
                    )

                    Spacer(modifier = Modifier.height(12.dp))

                    Text(
                        "Resumen de pago",
                        color = Color.White,
                        fontWeight = FontWeight.Bold,
                        style = MaterialTheme.typography.titleMedium
                    )

                    Spacer(modifier = Modifier.height(10.dp))

                    Text(
                        "Modalidad: ${
                            when (tipoVenta) {
                                "CONTADO" -> "Contado"
                                "CREDITO" -> "Crédito"
                                "PEDIDO_ANTICIPADO" -> "Pedido anticipado"
                                else -> tipoVenta
                            }
                        }",
                        color = SoftBlue
                    )

                    Text(
                        "Método de pago: ${
                            if (metodoPago == "Otro") {
                                otroMetodoPago.ifBlank { "Sin especificar" }
                            } else {
                                metodoPago
                            }
                        }",
                        color = SoftBlue
                    )

                    Spacer(modifier = Modifier.height(8.dp))

                    HorizontalDivider(
                        color = SoftBlue.copy(alpha = 0.3f)
                    )

                    Spacer(modifier = Modifier.height(8.dp))

                    Text(
                        "Total de la venta: \$${totalVenta}",
                        color = SoftBlue
                    )

                    Text(
                        "Pago inicial: \$${pagoInicial}",
                        color = SoftBlue
                    )

                    Text(
                        "Saldo pendiente: \$${saldoPendiente}",
                        color = if (saldoPendiente > 0) {
                            Color(0xFFFFB74D)
                        } else {
                            Color(0xFF81C784)
                        },
                        fontWeight = FontWeight.Bold
                    )

                    Spacer(modifier = Modifier.height(12.dp))

                    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))
    }
}



30,617 chars · codepastes.com