Renombrar la gestion de asignaciones por Listado SAI - Persona

This commit is contained in:
2026-08-03 09:15:49 +02:00
parent eb8cc806c1
commit 37b6cb1695
7 changed files with 54 additions and 18 deletions
+3 -2
View File
@@ -5,7 +5,7 @@ Android application developed in Kotlin using Jetpack Compose that scans barcode
## 🚀 Features ## 🚀 Features
- **Instant Scan**: The camera opens when adding a new SAI. - **Instant Scan**: The camera opens when adding a new SAI.
- **Multi-Entity Management**: Dedicated sections for SAIs, Batteries, and People. - **Multi-Entity Management**: Dedicated sections for SAIs, Batteries, People, and SAI-Person Assignments.
- **CRUD Operations**: Add, View, and Delete records for all managed entities. - **CRUD Operations**: Add, View, and Delete records for all managed entities.
- **Connection Status**: Real-time indicator on the home screen. - **Connection Status**: Real-time indicator on the home screen.
- **Visual Overlay**: Centered scanning guide with a red line to help align barcodes. - **Visual Overlay**: Centered scanning guide with a red line to help align barcodes.
@@ -58,13 +58,14 @@ CREATE TABLE Persona (
nombre VARCHAR(255) NOT NULL nombre VARCHAR(255) NOT NULL
); );
-- Table for Assignments -- Table for SAI - Person Assignments
CREATE TABLE Asignado ( CREATE TABLE Asignado (
id_asignacion INT AUTO_INCREMENT PRIMARY KEY, id_asignacion INT AUTO_INCREMENT PRIMARY KEY,
id_sai INT, id_sai INT,
id_persona INT, id_persona INT,
fecha_asignado DATE, fecha_asignado DATE,
fecha_devolucion DATE, fecha_devolucion DATE,
observaciones VARCHAR(255),
FOREIGN KEY (id_sai) REFERENCES SAIs(id_sai), FOREIGN KEY (id_sai) REFERENCES SAIs(id_sai),
FOREIGN KEY (id_persona) REFERENCES Persona(id_persona) FOREIGN KEY (id_persona) REFERENCES Persona(id_persona)
); );
@@ -11,7 +11,7 @@ class AssignmentRepository {
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error")) val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
try { try {
val sql = """ val sql = """
SELECT a.id_asignacion, a.id_sai, a.id_persona, a.fecha_asignado, a.fecha_devolucion, SELECT a.id_asignacion, a.id_sai, a.id_persona, a.fecha_asignado, a.fecha_devolucion, a.observaciones,
s.ns as sai_ns, p.nombre as person_name s.ns as sai_ns, p.nombre as person_name
FROM Asignado a FROM Asignado a
LEFT JOIN SAIs s ON a.id_sai = s.id_sai LEFT JOIN SAIs s ON a.id_sai = s.id_sai
@@ -27,6 +27,7 @@ class AssignmentRepository {
idPersona = resultSet.getInt("id_persona"), idPersona = resultSet.getInt("id_persona"),
assignedDate = resultSet.getString("fecha_asignado"), assignedDate = resultSet.getString("fecha_asignado"),
returnDate = resultSet.getString("fecha_devolucion"), returnDate = resultSet.getString("fecha_devolucion"),
observations = resultSet.getString("observaciones"),
saiNs = resultSet.getString("sai_ns"), saiNs = resultSet.getString("sai_ns"),
personName = resultSet.getString("person_name") personName = resultSet.getString("person_name")
)) ))
@@ -42,7 +43,7 @@ class AssignmentRepository {
suspend fun getById(id: Int): Result<Assignment> = withContext(Dispatchers.IO) { suspend fun getById(id: Int): Result<Assignment> = withContext(Dispatchers.IO) {
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error")) val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
try { try {
val sql = "SELECT id_asignacion, id_sai, id_persona, fecha_asignado, fecha_devolucion FROM Asignado WHERE id_asignacion = ?" val sql = "SELECT id_asignacion, id_sai, id_persona, fecha_asignado, fecha_devolucion, observaciones FROM Asignado WHERE id_asignacion = ?"
val statement = connection.prepareStatement(sql) val statement = connection.prepareStatement(sql)
statement.setInt(1, id) statement.setInt(1, id)
val resultSet = statement.executeQuery() val resultSet = statement.executeQuery()
@@ -52,7 +53,8 @@ class AssignmentRepository {
idSai = resultSet.getInt("id_sai"), idSai = resultSet.getInt("id_sai"),
idPersona = resultSet.getInt("id_persona"), idPersona = resultSet.getInt("id_persona"),
assignedDate = resultSet.getString("fecha_asignado"), assignedDate = resultSet.getString("fecha_asignado"),
returnDate = resultSet.getString("fecha_devolucion") returnDate = resultSet.getString("fecha_devolucion"),
observations = resultSet.getString("observaciones")
)) ))
} else { } else {
Result.failure(Exception("not_found")) Result.failure(Exception("not_found"))
@@ -67,12 +69,13 @@ class AssignmentRepository {
suspend fun insert(item: Assignment): Result<Unit> = withContext(Dispatchers.IO) { suspend fun insert(item: Assignment): Result<Unit> = withContext(Dispatchers.IO) {
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error")) val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
try { try {
val sql = "INSERT INTO Asignado (id_sai, id_persona, fecha_asignado, fecha_devolucion) VALUES (?, ?, ?, ?)" val sql = "INSERT INTO Asignado (id_sai, id_persona, fecha_asignado, fecha_devolucion, observaciones) VALUES (?, ?, ?, ?, ?)"
val statement = connection.prepareStatement(sql) val statement = connection.prepareStatement(sql)
statement.setInt(1, item.idSai) statement.setInt(1, item.idSai)
statement.setInt(2, item.idPersona) statement.setInt(2, item.idPersona)
statement.setString(3, item.assignedDate) statement.setString(3, item.assignedDate)
statement.setString(4, item.returnDate) statement.setString(4, item.returnDate)
statement.setString(5, item.observations)
if (statement.executeUpdate() > 0) Result.success(Unit) if (statement.executeUpdate() > 0) Result.success(Unit)
else Result.failure(Exception("no_rows_inserted")) else Result.failure(Exception("no_rows_inserted"))
@@ -86,13 +89,14 @@ class AssignmentRepository {
suspend fun update(item: Assignment): Result<Unit> = withContext(Dispatchers.IO) { suspend fun update(item: Assignment): Result<Unit> = withContext(Dispatchers.IO) {
val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error")) val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error"))
try { try {
val sql = "UPDATE Asignado SET id_sai = ?, id_persona = ?, fecha_asignado = ?, fecha_devolucion = ? WHERE id_asignacion = ?" val sql = "UPDATE Asignado SET id_sai = ?, id_persona = ?, fecha_asignado = ?, fecha_devolucion = ?, observaciones = ? WHERE id_asignacion = ?"
val statement = connection.prepareStatement(sql) val statement = connection.prepareStatement(sql)
statement.setInt(1, item.idSai) statement.setInt(1, item.idSai)
statement.setInt(2, item.idPersona) statement.setInt(2, item.idPersona)
statement.setString(3, item.assignedDate) statement.setString(3, item.assignedDate)
statement.setString(4, item.returnDate) statement.setString(4, item.returnDate)
statement.setInt(5, item.id) statement.setString(5, item.observations)
statement.setInt(6, item.id)
if (statement.executeUpdate() > 0) Result.success(Unit) if (statement.executeUpdate() > 0) Result.success(Unit)
else Result.failure(Exception("update_failed")) else Result.failure(Exception("update_failed"))
@@ -6,6 +6,7 @@ data class Assignment(
val idPersona: Int, val idPersona: Int,
val assignedDate: String? = null, val assignedDate: String? = null,
val returnDate: String? = null, val returnDate: String? = null,
val observations: String? = null,
// Optional display fields for joining data // Optional display fields for joining data
val saiNs: String? = null, val saiNs: String? = null,
val personName: String? = null val personName: String? = null
@@ -43,6 +43,7 @@ fun AddAssignmentScreen(
var assignedDateDb by remember { mutableStateOf("") } var assignedDateDb by remember { mutableStateOf("") }
var returnDateDisplay by remember { mutableStateOf("") } var returnDateDisplay by remember { mutableStateOf("") }
var returnDateDb by remember { mutableStateOf("") } var returnDateDb by remember { mutableStateOf("") }
var observations by remember { mutableStateOf("") }
var sais by remember { mutableStateOf<List<Sai>>(emptyList()) } var sais by remember { mutableStateOf<List<Sai>>(emptyList()) }
var people by remember { mutableStateOf<List<Person>>(emptyList()) } var people by remember { mutableStateOf<List<Person>>(emptyList()) }
@@ -118,7 +119,7 @@ fun AddAssignmentScreen(
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( TopAppBar(
title = { Text("Añadir Asignación") }, title = { Text("Añadir SAI - Persona") },
navigationIcon = { navigationIcon = {
IconButton(onClick = onNavigateBack) { IconButton(onClick = onNavigateBack) {
Icon(Icons.Default.ArrowBack, contentDescription = "Atrás") Icon(Icons.Default.ArrowBack, contentDescription = "Atrás")
@@ -233,6 +234,16 @@ fun AddAssignmentScreen(
modifier = Modifier.fillMaxWidth().clickable { showReturnDatePicker = true } modifier = Modifier.fillMaxWidth().clickable { showReturnDatePicker = true }
) )
Spacer(modifier = Modifier.height(16.dp))
OutlinedTextField(
value = observations,
onValueChange = { observations = it },
label = { Text(stringResource(R.string.label_observations)) },
modifier = Modifier.fillMaxWidth(),
minLines = 3
)
Spacer(modifier = Modifier.height(32.dp)) Spacer(modifier = Modifier.height(32.dp))
Button( Button(
@@ -245,10 +256,11 @@ fun AddAssignmentScreen(
idSai = selectedSaiId!!, idSai = selectedSaiId!!,
idPersona = selectedPersonId!!, idPersona = selectedPersonId!!,
assignedDate = assignedDateDb.takeIf { it.isNotBlank() }, assignedDate = assignedDateDb.takeIf { it.isNotBlank() },
returnDate = returnDateDb.takeIf { it.isNotBlank() } returnDate = returnDateDb.takeIf { it.isNotBlank() },
observations = observations.takeIf { it.isNotBlank() }
) )
).onSuccess { ).onSuccess {
Toast.makeText(context, "Asignación guardada", Toast.LENGTH_SHORT).show() Toast.makeText(context, "Asignación SAI - Persona guardada", Toast.LENGTH_SHORT).show()
onNavigateBack() onNavigateBack()
}.onFailure { }.onFailure {
Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show() Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show()
@@ -55,7 +55,8 @@ fun AssignmentListScreen(
val filteredItems = remember(items, searchQuery) { val filteredItems = remember(items, searchQuery) {
items.filter { items.filter {
it.personName?.contains(searchQuery, ignoreCase = true) ?: false || it.personName?.contains(searchQuery, ignoreCase = true) ?: false ||
it.saiNs?.contains(searchQuery, ignoreCase = true) ?: false it.saiNs?.contains(searchQuery, ignoreCase = true) ?: false ||
it.observations?.contains(searchQuery, ignoreCase = true) ?: false
} }
} }
@@ -74,7 +75,7 @@ fun AssignmentListScreen(
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( TopAppBar(
title = { Text("Listado de Asignaciones") }, title = { Text("Listado SAI - Persona") },
navigationIcon = { navigationIcon = {
IconButton(onClick = onNavigateBack) { IconButton(onClick = onNavigateBack) {
Icon(Icons.Default.ArrowBack, contentDescription = "Atrás") Icon(Icons.Default.ArrowBack, contentDescription = "Atrás")
@@ -84,7 +85,7 @@ fun AssignmentListScreen(
}, },
floatingActionButton = { floatingActionButton = {
FloatingActionButton(onClick = onNavigateToAdd) { FloatingActionButton(onClick = onNavigateToAdd) {
Icon(Icons.Default.Add, contentDescription = "Añadir Asignación") Icon(Icons.Default.Add, contentDescription = "Añadir SAI - Persona")
} }
} }
) { padding -> ) { padding ->
@@ -122,6 +123,9 @@ fun AssignmentListScreen(
if (item.returnDate != null) { if (item.returnDate != null) {
Text("Devolución: ${formatDate(item.returnDate)}") Text("Devolución: ${formatDate(item.returnDate)}")
} }
if (!item.observations.isNullOrBlank()) {
Text("Obs: ${item.observations}", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.secondary)
}
} }
}, },
trailingContent = { trailingContent = {
@@ -44,6 +44,7 @@ fun EditAssignmentScreen(
var assignedDateDb by remember { mutableStateOf("") } var assignedDateDb by remember { mutableStateOf("") }
var returnDateDisplay by remember { mutableStateOf("") } var returnDateDisplay by remember { mutableStateOf("") }
var returnDateDb by remember { mutableStateOf("") } var returnDateDb by remember { mutableStateOf("") }
var observations by remember { mutableStateOf("") }
var sais by remember { mutableStateOf<List<Sai>>(emptyList()) } var sais by remember { mutableStateOf<List<Sai>>(emptyList()) }
var people by remember { mutableStateOf<List<Person>>(emptyList()) } var people by remember { mutableStateOf<List<Person>>(emptyList()) }
@@ -68,6 +69,7 @@ fun EditAssignmentScreen(
val item = assignmentResult.getOrNull()!! val item = assignmentResult.getOrNull()!!
selectedSaiId = item.idSai selectedSaiId = item.idSai
selectedPersonId = item.idPersona selectedPersonId = item.idPersona
observations = item.observations ?: ""
val dbFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) val dbFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
val displayFormat = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()) val displayFormat = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault())
@@ -159,7 +161,7 @@ fun EditAssignmentScreen(
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( TopAppBar(
title = { Text("Editar Asignación") }, title = { Text("Editar SAI - Persona") },
navigationIcon = { navigationIcon = {
IconButton(onClick = onNavigateBack) { IconButton(onClick = onNavigateBack) {
Icon(Icons.Default.ArrowBack, contentDescription = "Atrás") Icon(Icons.Default.ArrowBack, contentDescription = "Atrás")
@@ -279,6 +281,16 @@ fun EditAssignmentScreen(
modifier = Modifier.fillMaxWidth().clickable { showReturnDatePicker = true } modifier = Modifier.fillMaxWidth().clickable { showReturnDatePicker = true }
) )
Spacer(modifier = Modifier.height(16.dp))
OutlinedTextField(
value = observations,
onValueChange = { observations = it },
label = { Text(stringResource(R.string.label_observations)) },
modifier = Modifier.fillMaxWidth(),
minLines = 3
)
Spacer(modifier = Modifier.height(32.dp)) Spacer(modifier = Modifier.height(32.dp))
Button( Button(
@@ -292,10 +304,11 @@ fun EditAssignmentScreen(
idSai = selectedSaiId!!, idSai = selectedSaiId!!,
idPersona = selectedPersonId!!, idPersona = selectedPersonId!!,
assignedDate = assignedDateDb.takeIf { it.isNotBlank() }, assignedDate = assignedDateDb.takeIf { it.isNotBlank() },
returnDate = returnDateDb.takeIf { it.isNotBlank() } returnDate = returnDateDb.takeIf { it.isNotBlank() },
observations = observations.takeIf { it.isNotBlank() }
) )
).onSuccess { ).onSuccess {
Toast.makeText(context, "Asignación actualizada", Toast.LENGTH_SHORT).show() Toast.makeText(context, "Asignación SAI - Persona actualizada", Toast.LENGTH_SHORT).show()
onNavigateBack() onNavigateBack()
}.onFailure { }.onFailure {
Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show() Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show()
+2 -1
View File
@@ -26,10 +26,11 @@
<string name="menu_sais">Gestión de SAIs</string> <string name="menu_sais">Gestión de SAIs</string>
<string name="menu_batteries">Gestión de Baterías</string> <string name="menu_batteries">Gestión de Baterías</string>
<string name="menu_people">Gestión de Personas</string> <string name="menu_people">Gestión de Personas</string>
<string name="menu_assignments">Gestión de Asignaciones</string> <string name="menu_assignments">Gestion SAI - Persona</string>
<string name="label_person">Persona</string> <string name="label_person">Persona</string>
<string name="label_assigned_date">Fecha Asignación (DD-MM-AAAA)</string> <string name="label_assigned_date">Fecha Asignación (DD-MM-AAAA)</string>
<string name="label_return_date">Fecha Devolución (DD-MM-AAAA)</string> <string name="label_return_date">Fecha Devolución (DD-MM-AAAA)</string>
<string name="label_observations">Observaciones</string>
<string name="select_person">Seleccionar Persona</string> <string name="select_person">Seleccionar Persona</string>
</resources> </resources>