Compare commits

...
4 Commits
6 changed files with 76 additions and 7 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ android {
applicationId = "pl.firmatpp.kierowca"
minSdk = 26
targetSdk = 35
versionCode = 47
versionCode = 50
versionName = "1.0.44"
setProperty("archivesBaseName", "pl.firmatpp.kierowca")
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@@ -18,7 +18,7 @@ interface RouteActionDao {
"""
SELECT * FROM route_actions
WHERE routeId = :routeId
AND status IN ('PENDING', 'WAITING_FOR_PHOTOS', 'SYNCING', 'FAILED_RETRYABLE', 'FAILED_CONFLICT', 'FAILED_PERMANENT')
AND status IN ('PENDING', 'WAITING_FOR_PHOTOS', 'SYNCING', 'CONFIRMED', 'FAILED_RETRYABLE', 'FAILED_CONFLICT', 'FAILED_PERMANENT')
ORDER BY createdAtEpochMillis DESC
""",
)
@@ -28,6 +28,14 @@ interface RouteActionDao {
"""
SELECT * FROM route_actions
WHERE status IN ('PENDING', 'WAITING_FOR_PHOTOS', 'SYNCING', 'FAILED_RETRYABLE', 'FAILED_CONFLICT', 'FAILED_PERMANENT')
OR clientActionId IN (
SELECT confirmed.clientActionId
FROM route_actions AS confirmed
WHERE confirmed.status = 'CONFIRMED'
AND confirmed.routeId = route_actions.routeId
ORDER BY confirmed.createdAtEpochMillis DESC
LIMIT 2
)
ORDER BY createdAtEpochMillis DESC
""",
)
@@ -1,6 +1,7 @@
package pl.firmatpp.kierowca.ui
import pl.firmatpp.kierowca.data.model.DriverRouteDto
import pl.firmatpp.kierowca.data.model.RoutePhotoDto
import pl.firmatpp.kierowca.data.upload.RouteActionEntity
import pl.firmatpp.kierowca.data.upload.RouteActionStatus
import pl.firmatpp.kierowca.data.upload.RouteActionType
@@ -21,14 +22,18 @@ internal val routeActionVisibleStatuses = setOf(
RouteActionStatus.FailedPermanent,
)
private val routeActionProjectionStatuses = routeActionVisibleStatuses + RouteActionStatus.Confirmed
fun projectDriverRoute(route: DriverRouteDto, actions: List<RouteActionEntity>): ProjectedDriverRoute {
val visible = actions
.filter { it.routeId == route.id && it.status in routeActionVisibleStatuses }
val projectable = actions
.filter { it.routeId == route.id && it.status in routeActionProjectionStatuses }
var projectedRoute = route
var loadingWeightPending = false
var unloadingWeightPending = false
visible
projectable
.sortedWith(compareBy<RouteActionEntity> { it.createdAtEpochMillis }.thenBy { it.clientActionId })
.forEach { action ->
when (action.action) {
@@ -37,8 +42,9 @@ fun projectDriverRoute(route: DriverRouteDto, actions: List<RouteActionEntity>):
status = "W TRAKCIE",
loadingWeight = action.weight,
trackingStatus = "active",
photos = projectedRoute.safePhotos(),
)
loadingWeightPending = true
loadingWeightPending = action.status != RouteActionStatus.Confirmed
}
RouteActionType.Finish -> {
projectedRoute = projectedRoute.copy(
@@ -46,8 +52,9 @@ fun projectDriverRoute(route: DriverRouteDto, actions: List<RouteActionEntity>):
unloadingWeight = action.weight,
trackingStatus = "finished",
completedAt = action.occurredAt,
photos = projectedRoute.safePhotos(),
)
unloadingWeightPending = true
unloadingWeightPending = action.status != RouteActionStatus.Confirmed
}
}
}
@@ -67,3 +74,5 @@ fun projectDriverRoutes(routes: List<DriverRouteDto>, actions: List<RouteActionE
fun routeActionNeedsAttention(status: String): Boolean =
status == RouteActionStatus.FailedConflict || status == RouteActionStatus.FailedPermanent
internal fun DriverRouteDto.safePhotos(): List<RoutePhotoDto> = photos.orEmpty()
@@ -151,9 +151,9 @@ fun routeFlowSteps(route: DriverRouteDto, actions: List<RouteActionEntity>): Lis
)
}
fun routePhotosForStage(photos: List<RoutePhotoDto>, stage: String): List<RoutePhotoDto> {
fun routePhotosForStage(photos: List<RoutePhotoDto>?, stage: String): List<RoutePhotoDto> {
val normalized = normalizedRoutePhotoStage(stage)
return photos.filter { normalizedRoutePhotoStage(it.stage) == normalized }
return photos.orEmpty().filter { normalizedRoutePhotoStage(it.stage) == normalized }
}
fun normalizedRoutePhotoStage(stage: String?): String =
@@ -617,6 +617,7 @@ class DriverViewModel(application: Application) : AndroidViewModel(application)
status = "W TRAKCIE",
loadingWeight = weight,
trackingStatus = "active",
photos = route.safePhotos(),
)
}
"unloading" -> {
@@ -626,6 +627,7 @@ class DriverViewModel(application: Application) : AndroidViewModel(application)
unloadingWeight = weight,
trackingStatus = "finished",
completedAt = Instant.now().toString(),
photos = route.safePhotos(),
)
}
else -> route
@@ -1,11 +1,13 @@
package pl.firmatpp.kierowca.ui
import com.google.gson.Gson
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test
import pl.firmatpp.kierowca.data.model.DriverRouteDto
import pl.firmatpp.kierowca.data.model.RoutePhotoDto
import pl.firmatpp.kierowca.data.upload.RouteActionEntity
import pl.firmatpp.kierowca.data.upload.RouteActionStatus
import pl.firmatpp.kierowca.data.upload.RouteActionType
@@ -57,6 +59,54 @@ class DriverRouteProjectionTest {
assertEquals("finished", projection.route.trackingStatus)
}
@Test
fun confirmedFinishStillProjectsPlannedRouteAsFinishedWithoutSyncCallout() {
val projection = projectDriverRoute(
route = route(status = "ZAPLANOWANA"),
actions = listOf(
action(RouteActionType.Finish, RouteActionStatus.Confirmed, weight = 11.8, createdAt = 2000),
),
)
assertEquals("ZAKOŃCZONA", projection.route.status)
assertEquals(11.8, projection.route.unloadingWeight)
assertEquals("finished", projection.route.trackingStatus)
assertFalse(projection.unloadingWeightPending)
assertEquals(emptyList<RouteActionEntity>(), projection.visibleActions)
}
@Test
fun routeProjectionNormalizesNullPhotosFromCachedJsonBeforeCopy() {
val route = Gson().fromJson(
"""
{
"id": "1",
"startsAt": "",
"originName": "Baza",
"destinationName": "Instalacja",
"contractorName": "TPP",
"contractName": "Kontrakt",
"contractCode": "TPP-1",
"relationLabel": "Baza -> Instalacja",
"status": "ZAPLANOWANA",
"distanceKm": 1.0,
"notes": null,
"truck": null,
"photos": null
}
""".trimIndent(),
DriverRouteDto::class.java,
)
val projection = projectDriverRoute(
route = route,
actions = listOf(action(RouteActionType.Start, RouteActionStatus.Confirmed, weight = 12.5)),
)
assertEquals("W TRAKCIE", projection.route.status)
assertEquals(emptyList<RoutePhotoDto>(), projection.route.photos)
}
@Test
fun conflictKeepsLocalRouteValuesAndMarksStageAsAttention() {
val projection = projectDriverRoute(