sin-titulo

Pasted Nov 8, 2026, 6:26 AM1 file1,560 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/zzgsa1mb543hfbqz
sin-titulo
package com.negocio.desinfectantes.data

import android.content.Context
import androidx.room.Room
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase

object DatabaseProvider {

    private val MIGRATION_2_3 = object : Migration(2, 3) {

        override fun migrate(database: SupportSQLiteDatabase) {

            database.execSQL("""
                CREATE TABLE IF NOT EXISTS producciones (
                    id TEXT NOT NULL,
                    presentacionId TEXT NOT NULL,
                    cantidadProducida INTEGER NOT NULL,
                    fechaCreacion INTEGER NOT NULL,
                    PRIMARY KEY(id)
                )
            """)

            database.execSQL("""
                CREATE TABLE IF NOT EXISTS distribuciones_produccion (
                    id TEXT NOT NULL,
                    produccionId TEXT NOT NULL,
                    sede TEXT NOT NULL,
                    cantidad INTEGER NOT NULL,
                    fechaCreacion INTEGER NOT NULL,
                    PRIMARY KEY(id)
                )
            """)

            database.execSQL("""
                CREATE TABLE IF NOT EXISTS movimientos_inventario (
                    id TEXT NOT NULL,
                    presentacionId TEXT NOT NULL,
                    sede TEXT NOT NULL,
                    tipoMovimiento TEXT NOT NULL,
                    cantidad INTEGER NOT NULL,
                    referenciaId TEXT,
                    observacion TEXT,
                    fechaCreacion INTEGER NOT NULL,
                    PRIMARY KEY(id)
                )
            """)
        }
    }

    private val MIGRATION_3_4 = object : Migration(3, 4) {

        override fun migrate(database: SupportSQLiteDatabase) {

            database.execSQL("""
                CREATE TABLE IF NOT EXISTS clientes (
                    id TEXT NOT NULL,
                    nombre TEXT NOT NULL,
                    telefono TEXT,
                    direccion TEXT,
                    observaciones TEXT,
                    activo INTEGER NOT NULL,
                    fechaCreacion INTEGER NOT NULL,
                    PRIMARY KEY(id)
                )
            """)
        }
    }

    private val MIGRATION_4_5 = object : Migration(4, 5) {
        override fun migrate(database: SupportSQLiteDatabase) {

            database.execSQL("""
            CREATE TABLE IF NOT EXISTS ventas (
                id TEXT NOT NULL,
                clienteId TEXT NOT NULL,
                sede TEXT NOT NULL,
                tipoVenta TEXT NOT NULL,
                estadoEntrega TEXT NOT NULL,
                total REAL NOT NULL,
                fechaCreacion INTEGER NOT NULL,
                PRIMARY KEY(id)
            )
        """)

            database.execSQL("""
            CREATE TABLE IF NOT EXISTS detalles_venta (
                id TEXT NOT NULL,
                ventaId TEXT NOT NULL,
                presentacionId TEXT NOT NULL,
                cantidad INTEGER NOT NULL,
                precioUnitario REAL NOT NULL,
                subtotal REAL NOT NULL,
                PRIMARY KEY(id)
            )
        """)

            database.execSQL("""
            CREATE TABLE IF NOT EXISTS pagos_venta (
                id TEXT NOT NULL,
                ventaId TEXT NOT NULL,
                monto REAL NOT NULL,
                metodoPago TEXT NOT NULL,
                observacion TEXT,
                fechaCreacion INTEGER NOT NULL,
                PRIMARY KEY(id)
            )
        """)
        }
    }

    @Volatile
    private var INSTANCE: PrestigeDatabase? = null

    fun obtenerBaseDatos(context: Context): PrestigeDatabase {

        return INSTANCE ?: synchronized(this) {

            val instancia = Room.databaseBuilder(
                context.applicationContext,
                PrestigeDatabase::class.java,
                "prestige_clean_database"
            )
                .addMigrations(
                    MIGRATION_2_3,
                    MIGRATION_3_4,
                    MIGRATION_4_5
                )
                .build()

            INSTANCE = instancia

            instancia
        }
    }
}

package com.negocio.desinfectantes.data

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "detalles_venta")
data class DetalleVentaEntity(
    @PrimaryKey
    val id: String,
    val ventaId: String,
    val presentacionId: String,
    val cantidad: Int,
    val precioUnitario: Double,
    val subtotal: Double
)



package com.negocio.desinfectantes.ui.produccion

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.background
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.Alignment
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
import com.negocio.desinfectantes.data.*

private val Navy = Color(0xFF101D35)
private val CardBlue = Color(0xFF1B2D4A)
private val AccentBlue = Color(0xFF2585F5)
private val SoftBlue = Color(0xFFA9BEDB)

@Composable
fun ProduccionScreen(
    modifier: Modifier = Modifier,
    productos: List<ProductoEntity>,
    aromas: List<AromaEntity>,
    presentaciones: List<PresentacionEntity>,
    onVolver: () -> Unit,
    onGuardar: (PresentacionEntity, Int, Int, Int) -> Unit
) {
    var productoSeleccionado by remember {
        mutableStateOf<ProductoEntity?>(null)
    }

    var aromaSeleccionado by remember {
        mutableStateOf<AromaEntity?>(null)
    }

    var presentacionSeleccionada by remember {
        mutableStateOf<PresentacionEntity?>(null)
    }

    var cantidadProducida by remember { mutableStateOf("") }
    var cantidadBarrancas by remember { mutableStateOf("") }
    var cantidadValledupar by remember { mutableStateOf("") }

    var menuProducto by remember { mutableStateOf(false) }
    var menuAroma by remember { mutableStateOf(false) }
    var menuPresentacion by remember { mutableStateOf(false) }

    val aromasDisponibles = aromas.filter {
        it.productoId == productoSeleccionado?.id && it.activo
    }

    val presentacionesDisponibles = presentaciones.filter {
        it.aromaId == aromaSeleccionado?.id && it.activo
    }

    val producidas = cantidadProducida.toIntOrNull()
    val barrancas = cantidadBarrancas.toIntOrNull()
    val valledupar = cantidadValledupar.toIntOrNull()

    val totalDistribuido =
        (barrancas ?: 0) + (valledupar ?: 0)

    val datosCompletos =
        presentacionSeleccionada != null &&
                producidas != null && producidas > 0 &&
                barrancas != null && valledupar != null &&
                barrancas >= 0 && valledupar >= 0

    val distribucionCorrecta =
        datosCompletos && totalDistribuido == producidas

    val mensajeValidacion = when {
        cantidadProducida.isNotEmpty() && (producidas == null || producidas <= 0) ->
            "Escribe una cantidad fabricada válida."

        cantidadBarrancas.isNotEmpty() && barrancas == null ->
            "La cantidad de Barrancas no es válida."

        cantidadValledupar.isNotEmpty() && valledupar == null ->
            "La cantidad de Valledupar no es válida."

        datosCompletos && totalDistribuido > producidas!! ->
            "Has distribuido ${totalDistribuido - producidas} unidades de más."

        datosCompletos && totalDistribuido < producidas!! ->
            "Faltan ${producidas - totalDistribuido} unidades por distribuir."

        distribucionCorrecta ->
            null

        else ->
            null
    }

    Column(
        modifier = modifier
            .fillMaxSize()
            .background(Navy)
            .verticalScroll(rememberScrollState())
            .padding(20.dp)
    ) {

        Row(
            verticalAlignment = Alignment.CenterVertically
        ) {
            TextButton(onClick = onVolver) {
                Text("← Volver", color = SoftBlue)
            }
        }

        Text(
            "Nueva producción",
            color = Color.White,
            style = MaterialTheme.typography.headlineMedium,
            fontWeight = FontWeight.Bold
        )

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

        Text(
            "Registra lo que fabricaste y distribuye las unidades entre tus sedes.",
            color = SoftBlue,
            style = MaterialTheme.typography.bodyMedium
        )

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

        // PRODUCTO

        Text("1. Seleccionar producto", color = Color.White)

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

        Box {
            OutlinedButton(
                onClick = { menuProducto = true },
                modifier = Modifier.fillMaxWidth(),
                shape = RoundedCornerShape(12.dp)
            ) {
                Text(
                    productoSeleccionado?.nombre ?: "Elegir producto",
                    modifier = Modifier.weight(1f)
                )
                Text("▼")
            }

            DropdownMenu(
                expanded = menuProducto,
                onDismissRequest = { menuProducto = false }
            ) {
                productos.filter { it.activo }.forEach { producto ->
                    DropdownMenuItem(
                        text = { Text(producto.nombre) },
                        onClick = {
                            productoSeleccionado = producto
                            aromaSeleccionado = null
                            presentacionSeleccionada = null
                            menuProducto = false
                        }
                    )
                }
            }
        }

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

        // AROMA

        Text("2. Seleccionar aroma", color = Color.White)

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

        Box {
            OutlinedButton(
                onClick = { menuAroma = true },
                enabled = productoSeleccionado != null,
                modifier = Modifier.fillMaxWidth(),
                shape = RoundedCornerShape(12.dp)
            ) {
                Text(
                    aromaSeleccionado?.nombre ?: "Elegir aroma",
                    modifier = Modifier.weight(1f)
                )
                Text("▼")
            }

            DropdownMenu(
                expanded = menuAroma,
                onDismissRequest = { menuAroma = false }
            ) {
                aromasDisponibles.forEach { aroma ->
                    DropdownMenuItem(
                        text = { Text(aroma.nombre) },
                        onClick = {
                            aromaSeleccionado = aroma
                            presentacionSeleccionada = null
                            menuAroma = false
                        }
                    )
                }
            }
        }

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

        // PRESENTACION

        Text("3. Seleccionar presentación", color = Color.White)

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

        Box {
            OutlinedButton(
                onClick = { menuPresentacion = true },
                enabled = aromaSeleccionado != null,
                modifier = Modifier.fillMaxWidth(),
                shape = RoundedCornerShape(12.dp)
            ) {
                Text(
                    presentacionSeleccionada?.nombre
                        ?: "Elegir presentación",
                    modifier = Modifier.weight(1f)
                )
                Text("▼")
            }

            DropdownMenu(
                expanded = menuPresentacion,
                onDismissRequest = { menuPresentacion = false }
            ) {
                presentacionesDisponibles.forEach { presentacion ->
                    DropdownMenuItem(
                        text = {
                            Text(
                                "${presentacion.nombre} • ${presentacion.contenidoMl} ml"
                            )
                        },
                        onClick = {
                            presentacionSeleccionada = presentacion
                            menuPresentacion = false
                        }
                    )
                }
            }
        }

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

        // CANTIDAD FABRICADA

        Text(
            "4. Cantidad fabricada",
            color = Color.White,
            fontWeight = FontWeight.Bold
        )

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

        OutlinedTextField(
            value = cantidadProducida,
            onValueChange = {
                cantidadProducida = it.filter { c -> c.isDigit() }
            },
            modifier = Modifier.fillMaxWidth(),
            placeholder = { Text("Ejemplo: 100") },
            label = { Text("Unidades fabricadas") },
            keyboardOptions = KeyboardOptions(
                keyboardType = KeyboardType.Number
            ),
            singleLine = true
        )

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

        // DISTRIBUCION

        Text(
            "5. Distribución por sede",
            color = Color.White,
            fontWeight = FontWeight.Bold
        )

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

        Card(
            colors = CardDefaults.cardColors(
                containerColor = CardBlue
            ),
            shape = RoundedCornerShape(16.dp)
        ) {
            Column(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(16.dp)
            ) {

                Text(
                    "Barrancas",
                    color = Color.White,
                    fontWeight = FontWeight.Medium
                )

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

                OutlinedTextField(
                    value = cantidadBarrancas,
                    onValueChange = {
                        cantidadBarrancas = it.filter { c -> c.isDigit() }
                    },
                    modifier = Modifier.fillMaxWidth(),
                    placeholder = { Text("Unidades para Barrancas") },
                    keyboardOptions = KeyboardOptions(
                        keyboardType = KeyboardType.Number
                    ),
                    singleLine = true
                )

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

                Text(
                    "Valledupar",
                    color = Color.White,
                    fontWeight = FontWeight.Medium
                )

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

                OutlinedTextField(
                    value = cantidadValledupar,
                    onValueChange = {
                        cantidadValledupar = it.filter { c -> c.isDigit() }
                    },
                    modifier = Modifier.fillMaxWidth(),
                    placeholder = { Text("Unidades para Valledupar") },
                    keyboardOptions = KeyboardOptions(
                        keyboardType = KeyboardType.Number
                    ),
                    singleLine = true
                )
            }
        }

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

        // RESUMEN DE DISTRIBUCION

        Text(
            "Total distribuido: $totalDistribuido unidades",
            color = SoftBlue,
            fontWeight = FontWeight.Medium
        )

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

        if (mensajeValidacion != null) {
            Text(
                "⚠ $mensajeValidacion",
                color = Color(0xFFFF7777),
                style = MaterialTheme.typography.bodyMedium,
                fontWeight = FontWeight.Medium
            )
        }

        if (distribucionCorrecta) {
            Text(
                "✓ Distribución correcta. Todas las unidades están asignadas.",
                color = Color(0xFF65D69A),
                style = MaterialTheme.typography.bodyMedium,
                fontWeight = FontWeight.Medium
            )
        }

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

        // GUARDAR PRODUCCION

        Button(
            onClick = {
                if (distribucionCorrecta) {
                    onGuardar(
                        presentacionSeleccionada!!,
                        producidas!!,
                        barrancas!!,
                        valledupar!!
                    )
                }
            },
            enabled = distribucionCorrecta,
            modifier = Modifier
                .fillMaxWidth()
                .height(54.dp),
            shape = RoundedCornerShape(14.dp),
            colors = ButtonDefaults.buttonColors(
                containerColor = AccentBlue,
                disabledContainerColor = Color(0xFF34445D)
            )
        ) {
            Text(
                "Guardar producción",
                fontWeight = FontWeight.Bold
            )
        }

        Spacer(modifier = Modifier.height(30.dp))
    }
}


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
import kotlinx.coroutines.launch

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

                                    estadoEntrega = if (valor == "PEDIDO_ANTICIPADO") {
                                        "PENDIENTE_FABRICACION"
                                    } else {
                                        "ENTREGADA"
                                    }
                                },
                                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))

                    if (tipoVenta == "PEDIDO_ANTICIPADO") {
                        Text(
                            "Este pedido quedará pendiente de fabricación. " +
                                    "Cuando fabriques los productos, podrás reservarlos desde el historial.",
                            color = Color(0xFFFFB74D)
                        )
                    } else {
                        Text(
                            "El producto se registrará como entregado.",
                            color = SoftBlue
                        )
                    }
                }
            }
        }
        if (mensajeError != null) {
            Text(
                text = mensajeError!!,
                color = Color(0xFFFF6B6B),
                fontWeight = FontWeight.Bold
            )
            Spacer(modifier = Modifier.height(8.dp))
        }

        if (ventaRegistrada) {
            Text(
                text = "¡Venta registrada correctamente!",
                color = Color(0xFF81C784),
                fontWeight = FontWeight.Bold
            )
            Spacer(modifier = Modifier.height(8.dp))
        }

        Button(
            onClick = {
                val cliente = clienteSeleccionado
                val total = detallesVenta.sumOf { it.subtotal }

                val pagoCalculado = if (tipoVenta == "CONTADO") {
                    total
                } else if (montoPagoTexto.isBlank()) {
                    0.0
                } else {
                    montoPagoTexto.replace(",", ".").toDoubleOrNull() ?: -1.0
                }

                val metodoFinal = if (metodoPago == "Otro") {
                    otroMetodoPago.trim()
                } else {
                    metodoPago
                }

                when {
                    cliente == null -> {
                        mensajeError = "Selecciona un cliente para continuar."
                    }

                    detallesVenta.isEmpty() -> {
                        mensajeError = "Agrega al menos un producto a la venta."
                    }

                    total <= 0 -> {
                        mensajeError = "El total de la venta debe ser mayor que cero."
                    }

                    (tipoVenta == "CREDITO" || tipoVenta == "PEDIDO_ANTICIPADO") &&
                            montoPagoTexto.isBlank() -> {
                        mensajeError = "Ingresa el pago inicial. Si no paga nada, escribe 0."
                    }
                    pagoCalculado < 0 || pagoCalculado > total -> {
                        mensajeError = "El valor del pago inicial no es válido."
                    }

                    tipoVenta == "CREDITO" && pagoCalculado >= total -> {
                        mensajeError = "Una venta a crédito debe tener saldo pendiente."
                    }

                    pagoCalculado > 0 && metodoFinal.isBlank() -> {
                        mensajeError = "Especifica el método de pago."
                    }

                    else -> {
                        mensajeError = null
                        guardando = true

                        scope.launch {
                            try {
                                val fecha = System.currentTimeMillis()
                                val ventaId = generarId()

                                val nuevaVenta = VentaEntity(
                                    id = ventaId,
                                    clienteId = cliente.id,
                                    sede = sedeSeleccionada,
                                    tipoVenta = tipoVenta,
                                    estadoEntrega = estadoEntrega,
                                    total = total,
                                    fechaCreacion = fecha
                                )

                                val detalles = detallesVenta.map { detalle ->
                                    DetalleVentaEntity(
                                        id = generarId(),
                                        ventaId = ventaId,
                                        presentacionId = detalle.presentacionId,
                                        cantidad = detalle.cantidad,
                                        precioUnitario = detalle.precioUnitario,
                                        subtotal = detalle.subtotal
                                    )
                                }

                                val pagos = if (pagoCalculado > 0) {
                                    listOf(
                                        PagoVentaEntity(
                                            id = generarId(),
                                            ventaId = ventaId,
                                            monto = pagoCalculado,
                                            metodoPago = metodoFinal,
                                            fechaCreacion = fecha
                                        )
                                    )
                                } else {
                                    emptyList()
                                }

                                val descontarInventario =
                                    estadoEntrega == "ENTREGADA"

                                val movimientos = if (descontarInventario) {
                                    detallesVenta.map { detalle ->
                                        MovimientoInventarioEntity(
                                            id = generarId(),
                                            presentacionId = detalle.presentacionId,
                                            sede = sedeSeleccionada,
                                            tipoMovimiento = "VENTA",
                                            cantidad = detalle.cantidad,
                                            referenciaId = ventaId,
                                            observacion = "Venta registrada",
                                            fechaCreacion = fecha
                                        )
                                    }
                                } else {
                                    emptyList()
                                }

                                productoDao.registrarVentaCompleta(
                                    venta = nuevaVenta,
                                    detalles = detalles,
                                    pagos = pagos,
                                    movimientos = movimientos,
                                    descontarInventario = descontarInventario
                                )

                                ventaRegistrada = true

                            } catch (e: Exception) {
                                mensajeError = e.message
                                    ?: "No fue posible registrar la venta."
                            } finally {
                                guardando = false
                            }
                        }
                    }
                }
            },
            enabled = !guardando && !ventaRegistrada,
            modifier = Modifier.fillMaxWidth(),
            colors = ButtonDefaults.buttonColors(
                containerColor = AccentBlue
            )
        ) {
            Text(
                text = if (guardando) {
                    "Registrando venta..."
                } else {
                    "Registrar venta"
                },
                color = Color.White,
                fontWeight = FontWeight.Bold
            )
        }

        Spacer(modifier = Modifier.height(24.dp))
    }
}


54,833 chars · codepastes.com