diff --git a/app/src/main/java/com/fieldbook/tracker/brapi/model/Observation.java b/app/src/main/java/com/fieldbook/tracker/brapi/model/Observation.java index f1a3975b4..c36f7c7c8 100644 --- a/app/src/main/java/com/fieldbook/tracker/brapi/model/Observation.java +++ b/app/src/main/java/com/fieldbook/tracker/brapi/model/Observation.java @@ -7,6 +7,7 @@ public class Observation extends BrapiObservation { private String collector; private String season; private String studyId; + private String internalVariableDbId; private String value; private String rep; @@ -49,6 +50,14 @@ public void setStudyId(String studyId) { this.studyId = studyId; } + public String getInternalVariableDbId() { + return internalVariableDbId; + } + + public void setInternalVariableDbId(String internalVariableDbId) { + this.internalVariableDbId = internalVariableDbId; + } + public String getValue() { return value; } diff --git a/app/src/main/java/com/fieldbook/tracker/brapi/service/BrAPIServiceV2.java b/app/src/main/java/com/fieldbook/tracker/brapi/service/BrAPIServiceV2.java index c19c7838e..e814533bb 100644 --- a/app/src/main/java/com/fieldbook/tracker/brapi/service/BrAPIServiceV2.java +++ b/app/src/main/java/com/fieldbook/tracker/brapi/service/BrAPIServiceV2.java @@ -86,6 +86,7 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import org.threeten.bp.OffsetDateTime; import java.lang.reflect.Type; import java.util.ArrayList; @@ -308,31 +309,31 @@ public void getPrograms(final BrapiPaginationManager paginationManager, final Function failFunction) { Integer initPage = paginationManager.getPage(); try { - BrapiV2ApiCallBack callback = new BrapiV2ApiCallBack() { - @Override - public void onSuccess(BrAPIProgramListResponse programsResponse, int i, Map> map) { - // Cancel processing if the page that was processed is not the page - // that we are currently on. For Example: User taps "Next Page" before brapi call returns data - if (initPage.equals(paginationManager.getPage())) { - updatePageInfo(paginationManager, programsResponse.getMetadata()); - List programList = programsResponse.getResult().getData(); - function.apply(mapPrograms(programList)); - } - } - - @Override - public void onFailure(ApiException error, int i, Map> map) { - failFunction.apply(error.getCode()); - Log.e("BrAPIServiceV2", "API Exception", error); - } - }; - ProgramQueryParams queryParams = new ProgramQueryParams(); - queryParams.page(paginationManager.getPage()).pageSize(paginationManager.getPageSize()); - programsApi.programsGetAsync(queryParams, callback); - } catch (ApiException error) { - failFunction.apply(error.getCode()); - Log.e("BrAPIServiceV2", "API Exception", error); - } + BrapiV2ApiCallBack callback = new BrapiV2ApiCallBack() { + @Override + public void onSuccess(BrAPIProgramListResponse programsResponse, int i, Map> map) { + // Cancel processing if the page that was processed is not the page + // that we are currently on. For Example: User taps "Next Page" before brapi call returns data + if (initPage.equals(paginationManager.getPage())) { + updatePageInfo(paginationManager, programsResponse.getMetadata()); + List programList = programsResponse.getResult().getData(); + function.apply(mapPrograms(programList)); + } + } + + @Override + public void onFailure(ApiException error, int i, Map> map) { + failFunction.apply(error.getCode()); + Log.e("BrAPIServiceV2", "API Exception", error); + } + }; + ProgramQueryParams queryParams = new ProgramQueryParams(); + queryParams.page(paginationManager.getPage()).pageSize(paginationManager.getPageSize()); + programsApi.programsGetAsync(queryParams, callback); + } catch (ApiException error) { + failFunction.apply(error.getCode()); + Log.e("BrAPIServiceV2", "API Exception", error); + } } private List mapPrograms(List programList) { @@ -972,6 +973,13 @@ private Observation mapToObservation(BrAPIObservation obs){ newObservation.setDbId(obs.getObservationDbId()); newObservation.setUnitDbId(obs.getObservationUnitDbId()); newObservation.setVariableDbId(obs.getObservationVariableDbId()); + newObservation.setTimestamp(obs.getObservationTimeStamp().toString()); + + newObservation.setTimestamp( + OffsetDateTime.parse( + obs.getObservationTimeStamp().toString() + ) + ); //search imported obs references for first field book id List references = obs.getExternalReferences(); @@ -1012,6 +1020,11 @@ private List mapObservations(List brapiObservatio String internalVarId = extVariableDbIdMap.get(brapiObservation.getObservationVariableDbId()); newObservation.setVariableDbId(internalVarId); newObservation.setValue(brapiObservation.getValue()); + newObservation.setTimestamp( + OffsetDateTime.parse( + brapiObservation.getObservationTimeStamp().toString() + ) + ); //Make sure we are on the right experiment level. // This will cause bugs if there have been plot and plant level traits found as the observations retrieves all of them @@ -1024,8 +1037,8 @@ private List mapObservations(List brapiObservatio } public void createObservations(List observations, - final Function, Void> function, - final Function failFunction) { + final Function, Void> function, + final Function failFunction) { try { BrapiV2ApiCallBack callback = new BrapiV2ApiCallBack() { @Override @@ -1071,8 +1084,8 @@ public void onFailure(ApiException error, int statusCode, Map observations, - final Function, Void> function, - final Function failFunction) { + final Function, Void> function, + final Function failFunction) { try { BrapiV2ApiCallBack callback = new BrapiV2ApiCallBack() { diff --git a/app/src/main/java/com/fieldbook/tracker/database/dao/ObservationDao.kt b/app/src/main/java/com/fieldbook/tracker/database/dao/ObservationDao.kt index b1bd7cb2f..fe6f3efe4 100644 --- a/app/src/main/java/com/fieldbook/tracker/database/dao/ObservationDao.kt +++ b/app/src/main/java/com/fieldbook/tracker/database/dao/ObservationDao.kt @@ -172,6 +172,7 @@ class ObservationDao { obs.value AS value, obs.observation_time_stamp, obs.observation_unit_id, + obs.observation_variable_db_id, obs.observation_db_id, obs.last_synced_time, obs.collector, @@ -197,6 +198,7 @@ class ObservationDao { rep = getStringVal(row, "rep") unitDbId = getStringVal(row, "uniqueName") variableDbId = getStringVal(row, "external_db_id") + internalVariableDbId = getStringVal(row, "observation_variable_db_id") value = CategoryJsonUtil.processValue(row) variableName = getStringVal(row, "observation_variable_name") fieldBookDbId = getStringVal(row, "id") @@ -378,14 +380,14 @@ class ObservationDao { fun insertObservation(studyId: Int, model: BrapiObservation, traitIdToTypeMap:Map): Int = withDatabase { db -> - if (getObservation("$studyId", model.unitDbId, model.variableDbId, "1")?.dbId != null) { + if (getObservation("$studyId", model.unitDbId, model.variableDbId, model.rep ?: "1")?.dbId != null) { println( "DbId: ${ getObservation( "$studyId", model.unitDbId, model.variableDbId, - "1" + model.rep ?: "1" )?.dbId }" ) @@ -398,7 +400,7 @@ class ObservationDao { "observation_variable_name" to model.variableName, "observation_variable_field_book_format" to variableFormat, "value" to model.value, - "observation_time_stamp" to model.timestamp, + "observation_time_stamp" to model.timestamp.toString(), "collector" to model.collector, // "geoCoordinates" to model.geo_coordinates, "geoCoordinates" to null, @@ -406,7 +408,7 @@ class ObservationDao { // "additional_info" to model.additional_info, "additional_info" to null, "observation_db_id" to model.dbId, - "rep" to "1", + "rep" to model.rep, Study.FK to studyId, ObservationUnit.FK to model.unitDbId, ObservationVariable.FK to model.variableDbId diff --git a/app/src/main/java/com/fieldbook/tracker/dialogs/BrapiSyncObsDialog.kt b/app/src/main/java/com/fieldbook/tracker/dialogs/BrapiSyncObsDialog.kt index e265dcab9..a932561ba 100644 --- a/app/src/main/java/com/fieldbook/tracker/dialogs/BrapiSyncObsDialog.kt +++ b/app/src/main/java/com/fieldbook/tracker/dialogs/BrapiSyncObsDialog.kt @@ -161,9 +161,9 @@ class BrapiSyncObsDialog(context: Context, private val syncController: FieldSync null }) { - println("Stopped:") - null - } + println("Stopped:") + null + } null }) { null } @@ -256,30 +256,37 @@ internal class ImportRunnableTask( } try { - //Sorting here to only save the most recently taken observation if it is not already in the DB - val observationList = - studyObservations.observationList.sortedByDescending { it.timestamp } + // Calculate rep numbers for new observations based on existing observations + val hostURL = BrAPIService.getHostUrl(context) + val existingObservations = dataHelper.getObservations(hostURL) + + // Track the count of existing observations for each unit-variable pair + val observationRepBaseMap = mutableMapOf, Int>() + for (obs in existingObservations) { + val key = Pair(obs.unitDbId, obs.internalVariableDbId) + observationRepBaseMap[key] = observationRepBaseMap.getOrDefault(key, 0) + 1 + } + + // Sort new observations by timestamp so rep # will ascend in order with time + val observationList = studyObservations.observationList.sortedBy { it.timestamp } - //Then sync the observations for (obs in observationList) { - //Leaving this here for debugging purposes -// println("****************************") -// println("Saving: varName: " + obs.variableName) -// println("Saving: value: " + obs.value) -// println("Saving: studyId: " + obs.studyId) -// println("Saving: unitDBId: " + obs.unitDbId) -// println("Saving: varDbId: " + obs.variableDbId) + val key = Pair(obs.unitDbId, obs.variableDbId) + val baseRep = observationRepBaseMap.getOrDefault(key, 0) + val nextRep = baseRep + 1 + obs.rep = nextRep.toString() + + // Save observation to the database and update highest rep # for the pair dataHelper.setTraitObservations(studyObservations.fieldBookStudyDbId, obs, traitIdToType) + observationRepBaseMap[key] = nextRep } return 0 - } - catch (exc: Exception) { + } catch (exc: Exception) { fail = true failMessage = exc.message ?: "ERROR" - println(exc) + Log.e("ImportRunnableTask", "Exception occurred: ${exc.message}", exc) return null } - }