F6 · Modelo definitivo de Inventarios + APK Android (#29)

Jerarquía física definitiva, compatibilidades N↔N de clasificaciones, Hallazgos y campos técnicos por familia, navegación WEB/Android y APK F6 0.14.0-debug.
This commit is contained in:
2026-09-09 11:19:12 -03:00
committed by GitHub
parent 0f4bb13fc7
commit d938db7913
28 changed files with 1355 additions and 702 deletions
+3 -3
View File
@@ -12,8 +12,8 @@ android {
applicationId = "com.korexlabs.dhinspeccion"
minSdk = 26
targetSdk = 36
versionCode = 20
versionName = "0.13.0"
versionCode = 21
versionName = "0.14.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
@@ -77,4 +77,4 @@ dependencies {
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")
}
}
@@ -49,6 +49,8 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
var inventory: List<FieldInventoryItem> by mutableStateOf(emptyList())
private set
var inventoryParentId: String? by mutableStateOf(null)
private set
var fieldTypes: List<FieldType> by mutableStateOf(emptyList())
private set
var selectedFieldAsset: FieldAssetDetail? by mutableStateOf(null)
@@ -96,6 +98,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
visits = emptyList()
visit = null
inventory = emptyList()
inventoryParentId = null
fieldTypes = emptyList()
selectedFieldAsset = null
clearActState()
@@ -112,6 +115,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
fun openVisit(id: String) = launchBusy {
visit = repository.visit(id)
inventory = emptyList()
inventoryParentId = visit?.operationalArea?.id
fieldTypes = emptyList()
selectedFieldAsset = null
clearFindingState()
@@ -121,6 +125,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
fun closeVisitView() {
visit = null
inventory = emptyList()
inventoryParentId = null
fieldTypes = emptyList()
selectedFieldAsset = null
clearActState()
@@ -132,6 +137,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
val id = visit?.id ?: return
launchBusy {
visit = repository.startVisit(id)
inventoryParentId = visit?.operationalArea?.id
notice = "Inspección iniciada."
loadActsInternal(id, selectDraft = true)
loadVisitsInternal()
@@ -189,25 +195,34 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
}
fun searchInventory(search: String, parentId: String? = null) {
val id = visit?.id ?: return
val currentVisit = visit ?: return
launchBusy {
inventory = repository.fieldInventory(id, search, parentId).data
val effectiveParentId = parentId ?: inventoryParentId ?: currentVisit.operationalArea?.id
inventory = repository.fieldInventory(currentVisit.id, search, effectiveParentId).data
}
}
fun loadFieldTypes(parentId: String? = null) {
val id = visit?.id ?: return
val currentVisit = visit ?: return
launchBusy {
fieldTypes = repository.fieldTypes(id, parentId).data
val effectiveParentId = parentId ?: currentVisit.operationalArea?.id
inventoryParentId = effectiveParentId
fieldTypes = repository.fieldTypes(currentVisit.id, parentId).data
inventory = repository.fieldInventory(currentVisit.id, null, effectiveParentId).data
}
}
private suspend fun reloadCurrentInventory(visitId: String) {
val effectiveParentId = inventoryParentId ?: visit?.operationalArea?.id
inventory = repository.fieldInventory(visitId, null, effectiveParentId).data
}
fun selectExisting(item: FieldInventoryItem) {
val visitId = visit?.id ?: return
launchBusy {
selectedFieldAsset = repository.selectFieldAsset(visitId, item.id)
notice = "Inventario agregado a la Inspección."
inventory = repository.fieldInventory(visitId, null, null).data
reloadCurrentInventory(visitId)
val draft = selectedDraftAct()
if (selectedFieldAsset?.capture?.readyForFinding == true && draft != null) {
selectedAct = actsRepository.ensureAsset(draft.id, item.id)
@@ -236,7 +251,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
return
}
if (type.familyRequired && familyId == null) {
error = "Elegí una familia técnica o la opción Otro / no catalogado."
error = "Elegí una clasificación técnica o la opción Otro / no catalogado."
return
}
launchBusy {
@@ -254,7 +269,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
)
selectedFieldAsset = repository.createFieldAsset(visitId, request)
notice = "Inventario creado con GPS. Falta la fotografía obligatoria. Si ya existía, podés fusionarlo antes de continuar."
inventory = repository.fieldInventory(visitId, null, null).data
reloadCurrentInventory(visitId)
}
}
@@ -278,7 +293,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
)
selectedFieldAsset = repository.selectFieldAsset(visitId, result.canonical.id)
notice = "Fusión registrada. Se conserva ${result.canonical.code} y la historia de ${result.source.code} permanece trazable."
inventory = repository.fieldInventory(visitId, null, null).data
reloadCurrentInventory(visitId)
val draft = selectedDraftAct()
if (selectedFieldAsset?.capture?.readyForFinding == true && draft != null) {
selectedAct = actsRepository.ensureAsset(draft.id, result.canonical.id)
@@ -311,7 +326,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
} else {
"Fotografía registrada."
}
inventory = repository.fieldInventory(visitId, null, null).data
reloadCurrentInventory(visitId)
val draft = selectedDraftAct()
if (response.capture.readyForFinding && draft != null) {
selectedAct = actsRepository.ensureAsset(draft.id, asset.id)