Scan to open on your phone
Point a camera at the QR code - it opens this exact paste, no app needed.
https://codepastes.com/zzgs99k8413f0panuntitledPlain Text
package com.negocio.desinfectantes.ui.produccion
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.Composable
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.*
import java.text.NumberFormat
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
private val LoteNavy = Color(0xFF101D35)
private val LoteCardBlue = Color(0xFF1B2D4A)
private val LoteAccentBlue = Color(0xFF2585F5)
private val LoteSoftBlue = Color(0xFFA9BEDB)
private val LoteWhite = Color(0xFFFFFFFF)
@Composable
fun HistorialLotesScreen(
modifier: Modifier = Modifier,
lotes: List<LoteProduccionEntity>,
detalles: List<LoteDetalleEntity>,
gastos: List<LoteGastoEntity>,
inventariosLote: List<LoteInventarioEntity>,
ingresosPorLoteYSede: List<IngresoLoteSedeResultado> = emptyList(),
productos: List<ProductoEntity>,
aromas: List<AromaEntity>,
presentaciones: List<PresentacionEntity>,
onVolver: () -> Unit
) {
val formatoFecha = SimpleDateFormat(
"dd/MM/yyyy • hh:mm a",
Locale("es", "CO")
)
val formatoPesos = NumberFormat.getCurrencyInstance(
Locale("es", "CO")
).apply {
maximumFractionDigits = 0
minimumFractionDigits = 0
}
Column(
modifier = modifier
.fillMaxSize()
.background(LoteNavy)
.verticalScroll(rememberScrollState())
.padding(20.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
TextButton(onClick = onVolver) {
Text("← Volver", color = LoteSoftBlue)
}
Text(
"Historial de lotes",
color = LoteWhite,
style = MaterialTheme.typography.headlineMedium,
fontWeight = FontWeight.Bold
)
Text(
"Consulta las producciones y sus gastos registrados.",
color = LoteSoftBlue
)
if (lotes.isEmpty()) {
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(
containerColor = LoteCardBlue
),
shape = RoundedCornerShape(16.dp)
) {
Column(
modifier = Modifier.padding(20.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
"Todavía no hay lotes registrados",
color = LoteWhite,
fontWeight = FontWeight.Bold
)
Text(
"Cuando registres una producción, aparecerá aquí.",
color = LoteSoftBlue
)
}
}
}
lotes.forEach { lote ->
val producto = productos.firstOrNull {
it.id == lote.productoId
}
val aroma = aromas.firstOrNull {
it.id == lote.aromaId
}
val detallesLote = detalles.filter {
it.loteId == lote.id
}
val gastosLote = gastos.filter {
it.loteId == lote.id
}
val inventarios = inventariosLote.filter {
it.loteId == lote.id
}
val totalUnidades = detallesLote.sumOf {
it.cantidadFabricada
}
val totalGastos = gastosLote.sumOf {
it.monto
}
val ingresosLote = ingresosPorLoteYSede.filter {
it.loteId == lote.id
}
val ingresosBarrancas = ingresosLote
.filter { it.sede.equals("Barrancas", ignoreCase = true) }
.sumOf { it.ingresos }
val ingresosValledupar = ingresosLote
.filter { it.sede.equals("Valledupar", ignoreCase = true) }
.sumOf { it.ingresos }
val ingresosTotales = ingresosBarrancas + ingresosValledupar
val gananciaLote = ingresosTotales - totalGastos
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(
containerColor = LoteCardBlue
),
shape = RoundedCornerShape(18.dp)
) {
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Text(
lote.numeroLote,
color = LoteAccentBlue,
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold
)
Text(
producto?.nombre ?: "Producto no encontrado",
color = LoteWhite,
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold
)
Text(
"Aroma: ${aroma?.nombre ?: "No encontrado"}",
color = LoteSoftBlue
)
Text(
"Fecha: ${formatoFecha.format(Date(lote.fechaCreacion))}",
color = LoteSoftBlue
)
HorizontalDivider(color = Color(0xFF40536F))
Text(
"Producción",
color = LoteAccentBlue,
fontWeight = FontWeight.Bold
)
detallesLote.forEach { detalle ->
val presentacion = presentaciones.firstOrNull {
it.id == detalle.presentacionId
}
val distribuciones = inventarios.filter {
it.presentacionId == detalle.presentacionId
}
Column(
verticalArrangement = Arrangement.spacedBy(5.dp)
) {
Text(
presentacion?.nombre
?: "Presentación no encontrada",
color = LoteWhite,
fontWeight = FontWeight.SemiBold
)
Text(
"${detalle.cantidadFabricada} unidades fabricadas",
color = LoteSoftBlue
)
distribuciones.forEach { distribucion ->
Text(
"• ${distribucion.sede}: ${distribucion.cantidadDisponible} unidades disponibles",
color = LoteSoftBlue
)
if (distribucion.cantidadReservada > 0) {
Text(
" ${distribucion.cantidadReservada} unidades reservadas",
color = LoteAccentBlue
)
}
}
}
}
HorizontalDivider(color = Color(0xFF40536F))
Text(
"Gastos de producción",
color = LoteAccentBlue,
fontWeight = FontWeight.Bold
)
if (gastosLote.isEmpty()) {
Text(
"No se registraron gastos.",
color = LoteSoftBlue
)
} else {
gastosLote.forEach { gasto ->
Column(
verticalArrangement = Arrangement.spacedBy(3.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
gasto.concepto,
color = LoteWhite,
modifier = Modifier.weight(1f)
)
Text(
formatoPesos.format(gasto.monto),
color = LoteWhite,
fontWeight = FontWeight.SemiBold
)
}
if (!gasto.observacion.isNullOrBlank()) {
Text(
gasto.observacion,
color = LoteSoftBlue,
style = MaterialTheme.typography.bodySmall
)
}
}
}
}
HorizontalDivider(color = Color(0xFF40536F))
Text(
"Rentabilidad del lote",
color = LoteAccentBlue,
fontWeight = FontWeight.Bold
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text("Ingresos Barrancas", color = LoteSoftBlue)
Text(
formatoPesos.format(ingresosBarrancas),
color = LoteWhite
)
}
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text("Ingresos Valledupar", color = LoteSoftBlue)
Text(
formatoPesos.format(ingresosValledupar),
color = LoteWhite
)
}
HorizontalDivider(color = Color(0xFF40536F))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
"Ingresos totales",
color = LoteWhite,
fontWeight = FontWeight.Bold
)
Text(
formatoPesos.format(ingresosTotales),
color = LoteWhite,
fontWeight = FontWeight.Bold
)
}
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
if (gananciaLote >= 0) "Ganancia del lote" else "Pérdida del lote",
color = LoteWhite,
fontWeight = FontWeight.Bold
)
Text(
formatoPesos.format(gananciaLote),
color = if (gananciaLote >= 0) Color(0xFF4ADE80)
else Color(0xFFFF6B6B),
fontWeight = FontWeight.Bold
)
}
HorizontalDivider(color = Color(0xFF40536F))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
"Unidades fabricadas",
color = LoteSoftBlue
)
Text(
totalUnidades.toString(),
color = LoteWhite,
fontWeight = FontWeight.Bold
)
}
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
"Total de gastos",
color = LoteSoftBlue
)
Text(
formatoPesos.format(totalGastos),
color = LoteWhite,
fontWeight = FontWeight.Bold
)
}
}
}
}
Spacer(modifier = Modifier.height(20.dp))
}
}
13,785 chars · codepastes.com