diff --git a/README.md b/README.md index 9286bcd..0859092 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Android application developed in Kotlin using Jetpack Compose that scans barcode ## 馃殌 Features - **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. - **Connection Status**: Real-time indicator on the home screen. - **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 ); --- Table for Assignments +-- Table for SAI - Person Assignments CREATE TABLE Asignado ( id_asignacion INT AUTO_INCREMENT PRIMARY KEY, id_sai INT, id_persona INT, fecha_asignado DATE, fecha_devolucion DATE, + observaciones VARCHAR(255), FOREIGN KEY (id_sai) REFERENCES SAIs(id_sai), FOREIGN KEY (id_persona) REFERENCES Persona(id_persona) ); diff --git a/app/src/main/java/com/example/saipp/data/AssignmentRepository.kt b/app/src/main/java/com/example/saipp/data/AssignmentRepository.kt index 6979e51..ed8a66c 100644 --- a/app/src/main/java/com/example/saipp/data/AssignmentRepository.kt +++ b/app/src/main/java/com/example/saipp/data/AssignmentRepository.kt @@ -11,7 +11,7 @@ class AssignmentRepository { val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error")) try { 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 FROM Asignado a LEFT JOIN SAIs s ON a.id_sai = s.id_sai @@ -27,6 +27,7 @@ class AssignmentRepository { idPersona = resultSet.getInt("id_persona"), assignedDate = resultSet.getString("fecha_asignado"), returnDate = resultSet.getString("fecha_devolucion"), + observations = resultSet.getString("observaciones"), saiNs = resultSet.getString("sai_ns"), personName = resultSet.getString("person_name") )) @@ -42,7 +43,7 @@ class AssignmentRepository { suspend fun getById(id: Int): Result = withContext(Dispatchers.IO) { val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error")) 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) statement.setInt(1, id) val resultSet = statement.executeQuery() @@ -52,7 +53,8 @@ class AssignmentRepository { idSai = resultSet.getInt("id_sai"), idPersona = resultSet.getInt("id_persona"), assignedDate = resultSet.getString("fecha_asignado"), - returnDate = resultSet.getString("fecha_devolucion") + returnDate = resultSet.getString("fecha_devolucion"), + observations = resultSet.getString("observaciones") )) } else { Result.failure(Exception("not_found")) @@ -67,12 +69,13 @@ class AssignmentRepository { suspend fun insert(item: Assignment): Result = withContext(Dispatchers.IO) { val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error")) 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) statement.setInt(1, item.idSai) statement.setInt(2, item.idPersona) statement.setString(3, item.assignedDate) statement.setString(4, item.returnDate) + statement.setString(5, item.observations) if (statement.executeUpdate() > 0) Result.success(Unit) else Result.failure(Exception("no_rows_inserted")) @@ -86,13 +89,14 @@ class AssignmentRepository { suspend fun update(item: Assignment): Result = withContext(Dispatchers.IO) { val connection = MariaDbConnection.getConnection() ?: return@withContext Result.failure(Exception("db_connection_error")) 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) statement.setInt(1, item.idSai) statement.setInt(2, item.idPersona) statement.setString(3, item.assignedDate) 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) else Result.failure(Exception("update_failed")) diff --git a/app/src/main/java/com/example/saipp/data/model/Assignment.kt b/app/src/main/java/com/example/saipp/data/model/Assignment.kt index 53955a4..4795b9c 100644 --- a/app/src/main/java/com/example/saipp/data/model/Assignment.kt +++ b/app/src/main/java/com/example/saipp/data/model/Assignment.kt @@ -6,6 +6,7 @@ data class Assignment( val idPersona: Int, val assignedDate: String? = null, val returnDate: String? = null, + val observations: String? = null, // Optional display fields for joining data val saiNs: String? = null, val personName: String? = null diff --git a/app/src/main/java/com/example/saipp/ui/management/AddAssignmentScreen.kt b/app/src/main/java/com/example/saipp/ui/management/AddAssignmentScreen.kt index 19b45da..6e92385 100644 --- a/app/src/main/java/com/example/saipp/ui/management/AddAssignmentScreen.kt +++ b/app/src/main/java/com/example/saipp/ui/management/AddAssignmentScreen.kt @@ -43,6 +43,7 @@ fun AddAssignmentScreen( var assignedDateDb by remember { mutableStateOf("") } var returnDateDisplay by remember { mutableStateOf("") } var returnDateDb by remember { mutableStateOf("") } + var observations by remember { mutableStateOf("") } var sais by remember { mutableStateOf>(emptyList()) } var people by remember { mutableStateOf>(emptyList()) } @@ -118,7 +119,7 @@ fun AddAssignmentScreen( Scaffold( topBar = { TopAppBar( - title = { Text("A帽adir Asignaci贸n") }, + title = { Text("A帽adir SAI - Persona") }, navigationIcon = { IconButton(onClick = onNavigateBack) { Icon(Icons.Default.ArrowBack, contentDescription = "Atr谩s") @@ -233,6 +234,16 @@ fun AddAssignmentScreen( 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)) Button( @@ -245,10 +256,11 @@ fun AddAssignmentScreen( idSai = selectedSaiId!!, idPersona = selectedPersonId!!, assignedDate = assignedDateDb.takeIf { it.isNotBlank() }, - returnDate = returnDateDb.takeIf { it.isNotBlank() } + returnDate = returnDateDb.takeIf { it.isNotBlank() }, + observations = observations.takeIf { it.isNotBlank() } ) ).onSuccess { - Toast.makeText(context, "Asignaci贸n guardada", Toast.LENGTH_SHORT).show() + Toast.makeText(context, "Asignaci贸n SAI - Persona guardada", Toast.LENGTH_SHORT).show() onNavigateBack() }.onFailure { Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show() diff --git a/app/src/main/java/com/example/saipp/ui/management/AssignmentListScreen.kt b/app/src/main/java/com/example/saipp/ui/management/AssignmentListScreen.kt index c93dc93..c5387b9 100644 --- a/app/src/main/java/com/example/saipp/ui/management/AssignmentListScreen.kt +++ b/app/src/main/java/com/example/saipp/ui/management/AssignmentListScreen.kt @@ -55,7 +55,8 @@ fun AssignmentListScreen( val filteredItems = remember(items, searchQuery) { items.filter { 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( topBar = { TopAppBar( - title = { Text("Listado de Asignaciones") }, + title = { Text("Listado SAI - Persona") }, navigationIcon = { IconButton(onClick = onNavigateBack) { Icon(Icons.Default.ArrowBack, contentDescription = "Atr谩s") @@ -84,7 +85,7 @@ fun AssignmentListScreen( }, floatingActionButton = { FloatingActionButton(onClick = onNavigateToAdd) { - Icon(Icons.Default.Add, contentDescription = "A帽adir Asignaci贸n") + Icon(Icons.Default.Add, contentDescription = "A帽adir SAI - Persona") } } ) { padding -> @@ -122,6 +123,9 @@ fun AssignmentListScreen( if (item.returnDate != null) { Text("Devoluci贸n: ${formatDate(item.returnDate)}") } + if (!item.observations.isNullOrBlank()) { + Text("Obs: ${item.observations}", style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.secondary) + } } }, trailingContent = { diff --git a/app/src/main/java/com/example/saipp/ui/management/EditAssignmentScreen.kt b/app/src/main/java/com/example/saipp/ui/management/EditAssignmentScreen.kt index 4b6c700..94d2762 100644 --- a/app/src/main/java/com/example/saipp/ui/management/EditAssignmentScreen.kt +++ b/app/src/main/java/com/example/saipp/ui/management/EditAssignmentScreen.kt @@ -44,6 +44,7 @@ fun EditAssignmentScreen( var assignedDateDb by remember { mutableStateOf("") } var returnDateDisplay by remember { mutableStateOf("") } var returnDateDb by remember { mutableStateOf("") } + var observations by remember { mutableStateOf("") } var sais by remember { mutableStateOf>(emptyList()) } var people by remember { mutableStateOf>(emptyList()) } @@ -68,6 +69,7 @@ fun EditAssignmentScreen( val item = assignmentResult.getOrNull()!! selectedSaiId = item.idSai selectedPersonId = item.idPersona + observations = item.observations ?: "" val dbFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) val displayFormat = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()) @@ -159,7 +161,7 @@ fun EditAssignmentScreen( Scaffold( topBar = { TopAppBar( - title = { Text("Editar Asignaci贸n") }, + title = { Text("Editar SAI - Persona") }, navigationIcon = { IconButton(onClick = onNavigateBack) { Icon(Icons.Default.ArrowBack, contentDescription = "Atr谩s") @@ -279,6 +281,16 @@ fun EditAssignmentScreen( 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)) Button( @@ -292,10 +304,11 @@ fun EditAssignmentScreen( idSai = selectedSaiId!!, idPersona = selectedPersonId!!, assignedDate = assignedDateDb.takeIf { it.isNotBlank() }, - returnDate = returnDateDb.takeIf { it.isNotBlank() } + returnDate = returnDateDb.takeIf { it.isNotBlank() }, + observations = observations.takeIf { it.isNotBlank() } ) ).onSuccess { - Toast.makeText(context, "Asignaci贸n actualizada", Toast.LENGTH_SHORT).show() + Toast.makeText(context, "Asignaci贸n SAI - Persona actualizada", Toast.LENGTH_SHORT).show() onNavigateBack() }.onFailure { Toast.makeText(context, "Error: ${it.message}", Toast.LENGTH_SHORT).show() diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7ee2cc2..04efb2e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -26,10 +26,11 @@ Gesti贸n de SAIs Gesti贸n de Bater铆as Gesti贸n de Personas - Gesti贸n de Asignaciones + Gestion SAI - Persona Persona Fecha Asignaci贸n (DD-MM-AAAA) Fecha Devoluci贸n (DD-MM-AAAA) + Observaciones Seleccionar Persona \ No newline at end of file