Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
30c23dc
Reapply "feat(responses): get responses by list of ids"
alexisszmundy Jun 2, 2026
edfc29c
test: KO tests
alexisszmundy Jun 3, 2026
3dff31f
refactor: converter tests
alexisszmundy Jun 4, 2026
5d7ba86
test: null raw process IT
alexisszmundy Jun 4, 2026
7d19d3c
test: add get latest null IT
alexisszmundy Jun 4, 2026
3529cb9
feat(rawresponses): keep null values if variable present in last surv…
alexisszmundy Jun 5, 2026
d550698
refactor: moved absent variable management to abstract
alexisszmundy Jun 5, 2026
256b1e0
refactor: moved common raw process logic into abstract class
alexisszmundy Jun 8, 2026
7b3c7a0
fix: fixed legacy process test
alexisszmundy Jun 8, 2026
eb254da
feat(lunaticjsondata): keep null values
alexisszmundy Jun 8, 2026
01e6432
fix: fixed tests
alexisszmundy Jun 9, 2026
ed1f4dd
add bpm import
Hajarel-moukh Jun 9, 2026
d5a7f35
make RestClient calls null-saf
Hajarel-moukh Jun 9, 2026
ef844f8
fix: query index
alexisszmundy Jun 12, 2026
4fef1c4
fix: null data.COLLECTED case
alexisszmundy Jun 12, 2026
f9a092b
Merge branch 'main' into devNullVariables
alexisszmundy Jun 12, 2026
29a0ee1
fix: rawRecordDate
alexisszmundy Jun 12, 2026
84f33f4
fix: add null iterations
alexisszmundy Jun 15, 2026
1db3506
fix: fixed tests
alexisszmundy Jun 15, 2026
ba959a6
test: add iteration to lunatic raw IT
alexisszmundy Jun 15, 2026
0697dd6
Merge branch 'devNullVariables' of https://github.com/InseeFr/Genesis…
Hajarel-moukh Jun 18, 2026
8957bee
merge main in branch
Hajarel-moukh Jun 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import fr.insee.genesis.exceptions.ReviewDisabledException;
import fr.insee.genesis.infrastructure.utils.FileUtils;
import fr.insee.modelefiliere.RawResponseDto;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
Expand Down Expand Up @@ -286,7 +287,7 @@ public ResponseEntity<Object> findResponsesByInterrogationAndCollectionInstrumen
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<List<SurveyUnitModel>> getLatestByInterrogationAndCollectionInstrument(@RequestParam("interrogationId") String interrogationId,
@RequestParam("collectionInstrumentId") String collectionInstrumentId) {
List<SurveyUnitModel> responses = surveyUnitService.findLatestByIdAndByCollectionInstrumentId(interrogationId, collectionInstrumentId);
List<SurveyUnitModel> responses = surveyUnitService.findLatestByInterrogationIdAndCollectionInstrumentId(interrogationId, collectionInstrumentId);
return ResponseEntity.ok(responses);
}

Expand All @@ -300,7 +301,7 @@ public ResponseEntity<List<SurveyUnitModel>> getLatestByInterrogationAndCollecti
public ResponseEntity<SurveyUnitSimplifiedDto> getLatestByInterrogationOneObject(@RequestParam("interrogationId") String interrogationId,
@RequestParam("collectionInstrumentId") String collectionInstrumentId,
@RequestParam("mode") Mode mode) {
List<SurveyUnitModel> responses = surveyUnitService.findLatestByIdAndByCollectionInstrumentId(interrogationId, collectionInstrumentId);
List<SurveyUnitModel> responses = surveyUnitService.findLatestByInterrogationIdAndCollectionInstrumentId(interrogationId, collectionInstrumentId);
List<VariableModel> outputVariables = new ArrayList<>();
List<VariableModel> outputExternalVariables = new ArrayList<>();
RawResponseDto.QuestionnaireStateEnum questionnaireState = null;
Expand Down Expand Up @@ -333,7 +334,7 @@ public ResponseEntity<SurveyUnitSimplifiedDto> getLatestByInterrogationOneObject
@Operation(summary = "Returns the response with the latest variables for a collectionInstrument, mode and " +
"interrogation")
@GetMapping(path = "/{collectionInstrumentId}/{mode}/{interrogationId}")
@PreAuthorize("hasRole('USER_KRAFTWERK')")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<SurveyUnitSimplifiedDto> getResponseByCollectionInstrumentAndInterrogation(
@PathVariable("collectionInstrumentId") String collectionInstrumentId,
@PathVariable("interrogationId") String interrogationId,
Expand Down Expand Up @@ -365,7 +366,7 @@ public ResponseEntity<List<SurveyUnitSimplifiedDto>> getLatestForInterrogationLi
List<SurveyUnitSimplifiedDto> results = new ArrayList<>();
List<Mode> modes = surveyUnitService.findModesByCollectionInstrumentId(collectionInstrumentId);
interrogationIds.forEach(interrogationId -> {
List<SurveyUnitModel> responses = surveyUnitService.findLatestByIdAndByCollectionInstrumentId(
List<SurveyUnitModel> responses = surveyUnitService.findLatestByInterrogationIdAndCollectionInstrumentId(
interrogationId.getInterrogationId(), collectionInstrumentId
);
modes.forEach(mode -> {
Expand Down Expand Up @@ -407,6 +408,7 @@ public ResponseEntity<List<SurveyUnitSimplifiedDto>> getLatestForInterrogationLi
return ResponseEntity.ok(results);
}

//Kraftwerk uses this
@Operation(summary = "Retrieve responses for a collection instrument and a list of interrogations",
description = "Return the latest state for each variable for the given interrogationIds and a given collection instrument (formerly questionnaire).<br>" +
"For a given id, the endpoint returns a document by collection mode (if there is more than one)<br>" +
Expand Down Expand Up @@ -696,6 +698,7 @@ private static String getSuccessMessage(boolean isAnyDataSaved) {
*/
//TODO Unused for now, reuse code for optimizations, also move it to service
@Deprecated
@Hidden
@Operation(summary = "Retrieve all responses for a questionnaire and a list of UE",
description = "Return the latest state for each variable for the given ids and a given questionnaire.<br>" +
"For a given id, the endpoint returns a document by collection mode (if there is more than one).")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,51 +1,71 @@
package fr.insee.genesis.domain.converter.rawdata;

import fr.insee.bpm.metadata.model.Variable;
import fr.insee.bpm.metadata.model.VariablesMap;
import fr.insee.genesis.Constants;
import fr.insee.genesis.domain.model.surveyunit.DataState;
import fr.insee.genesis.domain.model.surveyunit.SurveyUnitModel;
import fr.insee.genesis.domain.model.surveyunit.VariableModel;
import fr.insee.genesis.domain.model.surveyunit.rawdata.LunaticJsonRawDataModel;
import fr.insee.genesis.domain.model.surveyunit.rawdata.RawDataModelType;
import fr.insee.genesis.domain.parser.rawdata.LunaticJsonRawDataPayloadParser;
import fr.insee.genesis.domain.utils.GroupUtils;
import fr.insee.genesis.domain.utils.JsonUtils;
import lombok.RequiredArgsConstructor;
import fr.insee.genesis.domain.ports.api.SurveyUnitApiPort;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Component
@Slf4j
@RequiredArgsConstructor
public class LunaticJsonRawDataConverter {
public class LunaticJsonRawDataConverter extends RawDataConverter {

private final LunaticJsonRawDataPayloadParser payloadParser;

public LunaticJsonRawDataConverter(SurveyUnitApiPort surveyUnitApiPort,
LunaticJsonRawDataPayloadParser lunaticJsonRawDataPayloadParser) {
super(surveyUnitApiPort);
this.payloadParser = lunaticJsonRawDataPayloadParser;
}

public List<SurveyUnitModel> convertRawData(
String questionnaireId,
List<LunaticJsonRawDataModel> rawDataList,
VariablesMap variablesMap
) {
return convertRawDataAndCollectEmptyModels(rawDataList, variablesMap, new ArrayList<>());
return convertRawDataAndCollectEmptyModels(
questionnaireId,
rawDataList,
variablesMap,
new ArrayList<>()
);
}

public List<SurveyUnitModel> convertRawDataAndCollectEmptyModels(

Check failure on line 44 in src/main/java/fr/insee/genesis/domain/converter/rawdata/LunaticJsonRawDataConverter.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this method to reduce its Cognitive Complexity from 17 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=InseeFr_genesis-api&issues=AZ6rT9-MwFyNLchbYkwl&open=AZ6rT9-MwFyNLchbYkwl&pullRequest=492
String questionnaireId,
List<LunaticJsonRawDataModel> rawDataList,
VariablesMap variablesMap,
List<SurveyUnitModel> emptySurveyUnitModels
) {
List<SurveyUnitModel> surveyUnitModels = new ArrayList<>();

Map<String, Map<DataState, SurveyUnitModel>> lastSurveyUnitModelsByInterrogationIdAndState =
getLastSurveyUnitModels(
questionnaireId,
rawDataList.stream().map(LunaticJsonRawDataModel::interrogationId).collect(Collectors.toList())

Check warning on line 55 in src/main/java/fr/insee/genesis/domain/converter/rawdata/LunaticJsonRawDataConverter.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this usage of 'Stream.collect(Collectors.toList())' with 'Stream.toList()' and ensure that the list is unmodified.

See more on https://sonarcloud.io/project/issues?id=InseeFr_genesis-api&issues=AZ6rT9-MwFyNLchbYkwm&open=AZ6rT9-MwFyNLchbYkwm&pullRequest=492
);

for (DataState dataState : List.of(DataState.COLLECTED, DataState.EDITED)) {
for (LunaticJsonRawDataModel rawData : rawDataList) {
RawDataModelType rawDataModelType = getRawDataModelType(rawData);
SurveyUnitModel lastSurveyUnitModelForDataState = null;
if(lastSurveyUnitModelsByInterrogationIdAndState.containsKey(rawData.interrogationId())){
lastSurveyUnitModelForDataState = lastSurveyUnitModelsByInterrogationIdAndState
.get(rawData.interrogationId())
.get(dataState);
}

SurveyUnitModel surveyUnitModel = SurveyUnitModel.builder()
SurveyUnitModel newSurveyUnitModel = SurveyUnitModel.builder()
.collectionInstrumentId(rawData.questionnaireId())
.mode(rawData.mode())
.interrogationId(rawData.interrogationId())
Expand All @@ -59,25 +79,39 @@
.externalVariables(new ArrayList<>())
.build();

convertRawDataCollectedVariables(rawData, surveyUnitModel, dataState, rawDataModelType, variablesMap);
convertCollectedVariables(
rawData.data(),
rawData.interrogationId(),
lastSurveyUnitModelForDataState,
newSurveyUnitModel,
dataState,
rawDataModelType,
variablesMap
);

if (dataState == DataState.COLLECTED) {
convertRawDataExternalVariables(rawData, surveyUnitModel, rawDataModelType, variablesMap);
convertExternalVariables(
rawData.data(),
lastSurveyUnitModelForDataState,
newSurveyUnitModel,
rawDataModelType,
variablesMap
);
}

boolean hasNoVariable = surveyUnitModel.getCollectedVariables().isEmpty()
&& surveyUnitModel.getExternalVariables().isEmpty();
boolean hasNoVariable = newSurveyUnitModel.getCollectedVariables().isEmpty()
&& newSurveyUnitModel.getExternalVariables().isEmpty();

if (hasNoVariable) {
if (surveyUnitModel.getState() == DataState.COLLECTED) {
if (newSurveyUnitModel.getState() == DataState.COLLECTED) {
log.warn("No collected or external variable for interrogation {}, raw data is ignored.",
rawData.interrogationId());
}
emptySurveyUnitModels.add(surveyUnitModel);
emptySurveyUnitModels.add(newSurveyUnitModel);
continue;
}

surveyUnitModels.add(surveyUnitModel);
surveyUnitModels.add(newSurveyUnitModel);
}
}

Expand All @@ -89,127 +123,4 @@
? RawDataModelType.FILIERE
: RawDataModelType.LEGACY;
}

private void convertRawDataCollectedVariables(
LunaticJsonRawDataModel srcRawData,
SurveyUnitModel dstSurveyUnitModel,
DataState dataState,
RawDataModelType rawDataModelType,
VariablesMap variablesMap
) {
Map<String, Object> dataMap = srcRawData.data();
if (rawDataModelType == RawDataModelType.FILIERE) {
dataMap = JsonUtils.asMap(dataMap.get("data"));
}

Map<String, Object> collectedMap = JsonUtils.asMap(dataMap.get("COLLECTED"));

if (collectedMap == null || collectedMap.isEmpty()) {
if (dataState == DataState.COLLECTED) {
log.warn("No collected data for interrogation {}", srcRawData.interrogationId());
}
return;
}

String stateKey = dataState.toString();
List<VariableModel> destination = dstSurveyUnitModel.getCollectedVariables();

for (Map.Entry<String, Object> collectedVariable : collectedMap.entrySet()) {
RawResponseConverter.processCollectedVariable(
collectedVariable,
stateKey,
variablesMap,
dstSurveyUnitModel,
destination
);
}
}


private static void convertRawDataExternalVariables(
LunaticJsonRawDataModel srcRawData,
SurveyUnitModel dstSurveyUnitModel,
RawDataModelType rawDataModelType,
VariablesMap variablesMap
) {
Map<String, Object> dataMap = srcRawData.data();
if (rawDataModelType == RawDataModelType.FILIERE) {
dataMap = JsonUtils.asMap(dataMap.get("data"));
}

Map<String, Object> externalMap = JsonUtils.asMap(dataMap.get("EXTERNAL"));
if (externalMap != null && !externalMap.isEmpty()) {
convertToExternalVar(dstSurveyUnitModel, variablesMap, externalMap);
}
}

private static void convertToExternalVar(
SurveyUnitModel dstSurveyUnitModel,
VariablesMap variablesMap,
Map<String, Object> externalMap
) {
for (Map.Entry<String, Object> externalVariableEntry : externalMap.entrySet()) {
Object valueObject = externalVariableEntry.getValue();

if (valueObject instanceof List<?>) {
convertListVar(valueObject, externalVariableEntry, variablesMap, dstSurveyUnitModel.getExternalVariables());
continue;
}

if (valueObject != null) {
convertOneVar(
externalVariableEntry,
valueObject.toString(),
variablesMap,
1,
dstSurveyUnitModel.getExternalVariables()
);
}
}
}

private static void convertListVar(
Object valuesForState,
Map.Entry<String, Object> collectedVariable,
VariablesMap variablesMap,
List<VariableModel> destination
) {
List<String> values = JsonUtils.asStringList(valuesForState);
if (!values.isEmpty()) {
int iteration = 1;
for (String value : values) {
if (value != null && !value.isEmpty()) {
convertOneVar(collectedVariable, value, variablesMap, iteration, destination);
}
iteration++;
}
}
}

private static void convertOneVar(
Map.Entry<String, Object> variableEntry,
String value,
VariablesMap variablesMap,
int iteration,
List<VariableModel> destination
) {
VariableModel variableModel = VariableModel.builder()
.varId(variableEntry.getKey())
.value(value)
.scope(getIdLoop(variablesMap, variableEntry.getKey()))
.iteration(iteration)
.parentId(GroupUtils.getParentGroupName(variableEntry.getKey(), variablesMap))
.build();

destination.add(variableModel);
}

private static String getIdLoop(VariablesMap variablesMap, String variableName) {
Variable variable = variablesMap.getVariable(variableName);
if (variable == null) {
log.warn("Variable {} not present in metadata, assigning to {}", variableName, Constants.ROOT_GROUP_NAME);
return Constants.ROOT_GROUP_NAME;
}
return variable.getGroupName();
}
}
Loading
Loading