diff --git a/build.gradle.kts b/build.gradle.kts index 434e0d124..c90a3c77d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,7 +16,7 @@ java { allprojects { group = "fr.insee.eno" - version = "3.28.0" + version = "3.29.0" } subprojects { diff --git a/eno-core/src/main/java/fr/insee/eno/core/model/question/DynamicTableQuestion.java b/eno-core/src/main/java/fr/insee/eno/core/model/question/DynamicTableQuestion.java index 54650ba0c..6688a126b 100644 --- a/eno-core/src/main/java/fr/insee/eno/core/model/question/DynamicTableQuestion.java +++ b/eno-core/src/main/java/fr/insee/eno/core/model/question/DynamicTableQuestion.java @@ -1,9 +1,13 @@ package fr.insee.eno.core.model.question; import fr.insee.ddi.lifecycle33.datacollection.QuestionGridType; +import fr.insee.ddi.lifecycle33.reusable.CommandCodeType; +import fr.insee.ddi.lifecycle33.reusable.CommandType; import fr.insee.eno.core.annotations.Contexts.Context; import fr.insee.eno.core.annotations.DDI; import fr.insee.eno.core.annotations.Lunatic; +import fr.insee.eno.core.exceptions.business.IllegalDDIElementException; +import fr.insee.eno.core.model.calculated.CalculatedExpression; import fr.insee.eno.core.model.code.CodeList; import fr.insee.eno.core.model.navigation.Binding; import fr.insee.eno.core.model.question.table.CellLabel; @@ -21,8 +25,8 @@ /** * Eno model class to represent dynamic table questions. * A dynamic table question is a table question where lines can be dynamically added/removed during data collection. - * In DDI, it corresponds to a QuestionGrid similar to table questions (to be verified). - * In Lunatic, it corresponds to the RosterForLoop component (to be verified). + * In DDI, it corresponds to a QuestionGrid similar to table questions. + * In Lunatic, it corresponds to the RosterForLoop component. */ @Getter @Setter @@ -50,14 +54,25 @@ public class DynamicTableQuestion extends MultipleResponseQuestion implements En @Lunatic("setMandatory(#param)") boolean mandatory; + /** Maximum number of lines of the dynamic table. + * Note: In DDI, for some reason, if this information is missing in the xml file, the default value is 1. + * In Lunatic, this property is set in a processing class. + * @see fr.insee.eno.core.processing.out.steps.lunatic.table.DynamicTableQuestionProcessing */ @DDI("getGridDimensionList().?[#this.getRank().intValue() == 1].get(0)" + ".getRoster().getMinimumRequired()") BigInteger minLines; + /** Minimum number of lines of the dynamic table. + * In Lunatic, this property is set in a processing class. + * @see fr.insee.eno.core.processing.out.steps.lunatic.table.DynamicTableQuestionProcessing */ @DDI("getGridDimensionList().?[#this.getRank().intValue() == 1].get(0)" + ".getRoster().getMaximumAllowed()") BigInteger maxLines; + /** VTL expression that defines the size the dynamic table. */ + @DDI("T(fr.insee.eno.core.model.question.DynamicTableQuestion).mapDDISizeExpression(#this)") + CalculatedExpression sizeExpression; + @DDI("getOutParameterList().![#this.getParameterNameArray(0).getStringArray(0).getStringValue()]") List variableNames = new ArrayList<>(); @@ -76,4 +91,23 @@ public class DynamicTableQuestion extends MultipleResponseQuestion implements En @DDI("getCellLabelList()") List cellLabels = new ArrayList<>(); + public static CommandType mapDDISizeExpression(QuestionGridType ddiDynamicTableQuestion) { + checkRank1Dimension(ddiDynamicTableQuestion); + CommandCodeType conditionForContinuation = ddiDynamicTableQuestion.getGridDimensionArray(0).getRoster() + .getConditionForContinuation(); + if (conditionForContinuation == null) + return null; + return conditionForContinuation.getCommandArray(0); + } + + private static void checkRank1Dimension(QuestionGridType ddiDynamicTableQuestion) { + boolean hasRank1Dimension = ddiDynamicTableQuestion.getGridDimensionList().stream() + .filter(gridDimensionType -> gridDimensionType.getRank() != null) + .anyMatch(gridDimensionType -> 1 == gridDimensionType.getRank().intValue()); + if (! hasRank1Dimension) + throw new IllegalDDIElementException( + "DDI dynamic table question '" + ddiDynamicTableQuestion.getIDArray(0).getStringValue() + + "' has no rank 1 dimension."); + } + } diff --git a/eno-core/src/main/java/fr/insee/eno/core/processing/in/steps/ddi/DDIResolveVariableReferencesInExpressions.java b/eno-core/src/main/java/fr/insee/eno/core/processing/in/steps/ddi/DDIResolveVariableReferencesInExpressions.java index dff187907..307f16bcf 100644 --- a/eno-core/src/main/java/fr/insee/eno/core/processing/in/steps/ddi/DDIResolveVariableReferencesInExpressions.java +++ b/eno-core/src/main/java/fr/insee/eno/core/processing/in/steps/ddi/DDIResolveVariableReferencesInExpressions.java @@ -5,14 +5,12 @@ import fr.insee.eno.core.model.calculated.BindingReference; import fr.insee.eno.core.model.calculated.CalculatedExpression; import fr.insee.eno.core.model.navigation.StandaloneLoop; +import fr.insee.eno.core.model.question.DynamicTableQuestion; import fr.insee.eno.core.model.variable.CalculatedVariable; import fr.insee.eno.core.model.variable.Variable; import fr.insee.eno.core.processing.ProcessingStep; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Set; +import java.util.*; public class DDIResolveVariableReferencesInExpressions implements ProcessingStep { @@ -35,6 +33,12 @@ public void apply(EnoQuestionnaire enoQuestionnaire) { .filter(StandaloneLoop.class::isInstance) .map(StandaloneLoop.class::cast) .forEach(this::resolveExpression); + // Dynamic tables with size expression + enoQuestionnaire.getMultipleResponseQuestions().stream() + .filter(DynamicTableQuestion.class::isInstance).map(DynamicTableQuestion.class::cast) + .map(DynamicTableQuestion::getSizeExpression) + .filter(Objects::nonNull) + .forEach(this::resolveExpression); } /** @@ -50,7 +54,7 @@ private void resolveExpression(StandaloneLoop standaloneLoop) { resolveExpression(standaloneLoop.getMaxIteration()); } - private static void resolveExpression(CalculatedExpression expression) { + private void resolveExpression(CalculatedExpression expression) { String value = expression.getValue(); List orderedBindingReferences = orderById(expression.getBindingReferences()); // Iterate on the reverse order, so that if some references overlap, the longer one is replaced first diff --git a/eno-core/src/main/java/fr/insee/eno/core/processing/out/steps/lunatic/table/DynamicTableQuestionProcessing.java b/eno-core/src/main/java/fr/insee/eno/core/processing/out/steps/lunatic/table/DynamicTableQuestionProcessing.java index ac6311012..a81f36fcd 100644 --- a/eno-core/src/main/java/fr/insee/eno/core/processing/out/steps/lunatic/table/DynamicTableQuestionProcessing.java +++ b/eno-core/src/main/java/fr/insee/eno/core/processing/out/steps/lunatic/table/DynamicTableQuestionProcessing.java @@ -23,17 +23,7 @@ public static void process(RosterForLoop lunaticRoster, DynamicTableQuestion eno // Header lunaticRoster.getHeader().addAll(HeaderCellsProcessing.from(enoTable, 0)); - LinesRoster lines = new LinesRoster(); - LabelType minLabel = new LabelType(); - minLabel.setType(LabelTypeEnum.VTL); - minLabel.setValue(Integer.toString(enoTable.getMinLines().intValue())); - lines.setMin(minLabel); - - LabelType maxLabel = new LabelType(); - maxLabel.setType(LabelTypeEnum.VTL); - maxLabel.setValue(Integer.toString(enoTable.getMaxLines().intValue())); - lines.setMax(maxLabel); - lunaticRoster.setLines(lines); + setRosterSize(lunaticRoster, enoTable); List enoTableCells = new ArrayList<>(); enoTableCells.addAll(enoTable.getResponseCells()); @@ -46,4 +36,41 @@ public static void process(RosterForLoop lunaticRoster, DynamicTableQuestion eno lunaticRoster.getComponents().add(lunaticCell); } } + + private static void setRosterSize(RosterForLoop lunaticRoster, DynamicTableQuestion enoTable) { + LinesRoster lines = new LinesRoster(); + if (enoTable.getMinLines() != null && enoTable.getMaxLines() != null) + setMinMaxProperties(enoTable, lines); + else if (enoTable.getSizeExpression() != null) + setSizeExpression(enoTable, lines); + else + throw new IllegalStateException( + "Table question '" + enoTable.getId() + "' has neither a min/max nor an expression size."); + lunaticRoster.setLines(lines); + } + + private static void setMinMaxProperties(DynamicTableQuestion enoTable, LinesRoster lines) { + LabelType minLabel = new LabelType(); + minLabel.setType(LabelTypeEnum.VTL); + minLabel.setValue(Integer.toString(enoTable.getMinLines().intValue())); + lines.setMin(minLabel); + + LabelType maxLabel = new LabelType(); + maxLabel.setType(LabelTypeEnum.VTL); + maxLabel.setValue(Integer.toString(enoTable.getMaxLines().intValue())); + lines.setMax(maxLabel); + } + + /** Business rule: if the size of the roster for loop (dynamic table) is defined by an expression, the expression + * cannot be different between min and max. + * Note: in this case, we could have chosen to create an 'iterations' property in the Lunatic model to have the + * same property as in loop objects, but the min=max solution does the job. */ + private static void setSizeExpression(DynamicTableQuestion enoTable, LinesRoster lines) { + LabelType sizeLabel = new LabelType(); + sizeLabel.setType(LabelTypeEnum.VTL); + sizeLabel.setValue(enoTable.getSizeExpression().getValue()); + lines.setMin(sizeLabel); + lines.setMax(sizeLabel); + } + } diff --git a/eno-core/src/test/java/fr/insee/eno/core/mapping/in/ddi/DynamicTableQuestionTest.java b/eno-core/src/test/java/fr/insee/eno/core/mapping/in/ddi/DynamicTableQuestionTest.java new file mode 100644 index 000000000..d073b936e --- /dev/null +++ b/eno-core/src/test/java/fr/insee/eno/core/mapping/in/ddi/DynamicTableQuestionTest.java @@ -0,0 +1,42 @@ +package fr.insee.eno.core.mapping.in.ddi; + +import fr.insee.eno.core.exceptions.business.DDIParsingException; +import fr.insee.eno.core.mappers.DDIMapper; +import fr.insee.eno.core.model.EnoQuestionnaire; +import fr.insee.eno.core.model.question.DynamicTableQuestion; +import fr.insee.eno.core.serialize.DDIDeserializer; +import org.junit.jupiter.api.Test; + +import java.math.BigInteger; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class DynamicTableQuestionTest { + + @Test + void integrationTest_tableSize() throws DDIParsingException { + // Given + When + EnoQuestionnaire enoQuestionnaire = new EnoQuestionnaire(); + new DDIMapper().mapDDI( + DDIDeserializer.deserialize(this.getClass().getClassLoader().getResourceAsStream( + "integration/ddi/ddi-dynamic-table-size.xml")), + enoQuestionnaire); + + // Then + List dynamicTableQuestions = enoQuestionnaire.getMultipleResponseQuestions().stream() + .filter(DynamicTableQuestion.class::isInstance).map(DynamicTableQuestion.class::cast).toList(); + assertEquals(2, dynamicTableQuestions.size()); + DynamicTableQuestion dynamicTableQuestion1 = dynamicTableQuestions.get(0); + DynamicTableQuestion dynamicTableQuestion2 = dynamicTableQuestions.get(1); + // + assertEquals(BigInteger.valueOf(1), dynamicTableQuestion1.getMinLines()); + assertEquals(BigInteger.valueOf(5), dynamicTableQuestion1.getMaxLines()); + assertNull(dynamicTableQuestion1.getSizeExpression()); + // + assertEquals(BigInteger.valueOf(1), dynamicTableQuestion2.getMinLines()); + assertNull(dynamicTableQuestion2.getMaxLines()); + assertNotNull(dynamicTableQuestion2.getSizeExpression()); + } + +} diff --git a/eno-core/src/test/java/fr/insee/eno/core/processing/out/steps/lunatic/table/DynamicTableQuestionProcessingTest.java b/eno-core/src/test/java/fr/insee/eno/core/processing/out/steps/lunatic/table/DynamicTableQuestionProcessingTest.java index 96ea41095..a9fad7461 100644 --- a/eno-core/src/test/java/fr/insee/eno/core/processing/out/steps/lunatic/table/DynamicTableQuestionProcessingTest.java +++ b/eno-core/src/test/java/fr/insee/eno/core/processing/out/steps/lunatic/table/DynamicTableQuestionProcessingTest.java @@ -8,22 +8,18 @@ import fr.insee.lunatic.model.flat.ComponentTypeEnum; import fr.insee.lunatic.model.flat.LabelTypeEnum; import fr.insee.lunatic.model.flat.RosterForLoop; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; +import java.util.List; import java.util.Optional; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -@TestInstance(TestInstance.Lifecycle.PER_CLASS) class DynamicTableQuestionProcessingTest { - private RosterForLoop lunaticDynamicTable; - - @BeforeAll - void complexMCQ_integrationTestFromDDI() throws DDIParsingException { + @Test + void integrationTestFromDDI() throws DDIParsingException { // Given EnoQuestionnaire enoQuestionnaire = DDIToEno.transform( DynamicTableQuestionProcessingTest.class.getClassLoader().getResourceAsStream( @@ -37,32 +33,49 @@ void complexMCQ_integrationTestFromDDI() throws DDIParsingException { assertTrue(enoDynamicTable.isPresent()); // When - lunaticDynamicTable = new RosterForLoop(); + RosterForLoop lunaticDynamicTable = new RosterForLoop(); DynamicTableQuestionProcessing.process(lunaticDynamicTable, enoDynamicTable.get()); // Then - // -> tests - } - - @Test - void minAndMaxIterations() { + // Min and max assertEquals("1", lunaticDynamicTable.getLines().getMin().getValue()); assertEquals("5", lunaticDynamicTable.getLines().getMax().getValue()); assertEquals(LabelTypeEnum.VTL, lunaticDynamicTable.getLines().getMin().getType()); assertEquals(LabelTypeEnum.VTL, lunaticDynamicTable.getLines().getMax().getType()); - } - - @Test - void dynamicTableHeader() { + // Header assertEquals(3, lunaticDynamicTable.getHeader().size()); - } - - @Test - void dynamicTableCells() { + // Cells assertEquals(3, lunaticDynamicTable.getComponents().size()); assertEquals(ComponentTypeEnum.INPUT, lunaticDynamicTable.getComponents().get(0).getComponentType()); assertEquals(ComponentTypeEnum.INPUT_NUMBER, lunaticDynamicTable.getComponents().get(1).getComponentType()); assertEquals(ComponentTypeEnum.RADIO, lunaticDynamicTable.getComponents().get(2).getComponentType()); } + @Test + void integrationTestFromDDI_sizeExpression() throws DDIParsingException { + // Given + EnoQuestionnaire enoQuestionnaire = DDIToEno.transform( + DynamicTableQuestionProcessingTest.class.getClassLoader().getResourceAsStream( + "integration/ddi/ddi-dynamic-table-size.xml"), + EnoParameters.of(EnoParameters.Context.DEFAULT, EnoParameters.ModeParameter.CAWI)); + // + List enoDynamicTable = enoQuestionnaire.getMultipleResponseQuestions().stream() + .filter(DynamicTableQuestion.class::isInstance) + .map(DynamicTableQuestion.class::cast) + .toList(); + assertEquals(2, enoDynamicTable.size()); + + // When + RosterForLoop lunaticDynamicTable1 = new RosterForLoop(); + RosterForLoop lunaticDynamicTable2 = new RosterForLoop(); + DynamicTableQuestionProcessing.process(lunaticDynamicTable1, enoDynamicTable.get(0)); + DynamicTableQuestionProcessing.process(lunaticDynamicTable2, enoDynamicTable.get(1)); + + // Then + assertEquals("1", lunaticDynamicTable1.getLines().getMin().getValue()); + assertEquals("5", lunaticDynamicTable1.getLines().getMax().getValue()); + assertEquals("cast(HOW_MANY, integer)", lunaticDynamicTable2.getLines().getMin().getValue()); + assertEquals("cast(HOW_MANY, integer)", lunaticDynamicTable2.getLines().getMax().getValue()); + } + } diff --git a/eno-core/src/test/resources/integration/ddi/ddi-dynamic-table-size.xml b/eno-core/src/test/resources/integration/ddi/ddi-dynamic-table-size.xml new file mode 100644 index 000000000..ec6464d35 --- /dev/null +++ b/eno-core/src/test/resources/integration/ddi/ddi-dynamic-table-size.xml @@ -0,0 +1,741 @@ + + + fr.insee + INSEE-m332q6bo + 1 + + + Eno - Dynamic table with size expression + + + + fr.insee + RessourcePackage-m332q6bo + 1 + + fr.insee + InterviewerInstructionScheme-m332q6bo + 1 + + A définir + + + + fr.insee + ControlConstructScheme-m332q6bo + 1 + + fr.insee + Sequence-m332q6bo + 1 + + Eno - Dynamic table with size expression + + template + + fr.insee + m332sbit + 1 + Sequence + + + fr.insee + m332os3s + 1 + Sequence + + + + fr.insee + m332sbit + 1 + + S1 + + + "Sequence 1" + + module + + fr.insee + m332raks-QC + 1 + QuestionConstruct + + + + fr.insee + m332os3s + 1 + + S2 + + + "Sequence 2" + + module + + fr.insee + m333cu10-QC + 1 + QuestionConstruct + + + fr.insee + m333nmhe-QC + 1 + QuestionConstruct + + + + fr.insee + m332raks-QC + 1 + + DYNAMIC_TABLE_MIN_MAX + + + fr.insee + m332raks + 1 + QuestionGrid + + + + fr.insee + m333cu10-QC + 1 + + HOW_MANY + + + fr.insee + m333cu10 + 1 + QuestionItem + + + + fr.insee + m333nmhe-QC + 1 + + DYNAMIC_TABLE_VTL_SIZE + + + fr.insee + m333nmhe + 1 + QuestionGrid + + + + + fr.insee + QuestionScheme-m332q6bo + 1 + + A définir + + + fr.insee + m333cu10 + 1 + + HOW_MANY + + + fr.insee + m333cu10-QOP-m333g4uu + 1 + + HOW_MANY + + + + + fr.insee + m333cu10-RDOP-m333g4uu + 1 + OutParameter + + + fr.insee + m333cu10-QOP-m333g4uu + 1 + OutParameter + + + + + "How many lines in the next table?" + + + + + 1 + 10 + + Decimal + + fr.insee + m333cu10-RDOP-m333g4uu + 1 + + + + + fr.insee + m332raks + 1 + + DYNAMIC_TABLE_MIN_MAX + + + fr.insee + m332raks-QOP-m333hpwf + 1 + + DYNAMIC_TABLE_MIN_MAX1 + + + + + fr.insee + m332raks-RDOP-m333hpwf + 1 + OutParameter + + + fr.insee + m332raks-QOP-m333hpwf + 1 + OutParameter + + + + + "Regular dynamic table" + + + + + + + + + fr.insee + m332raks-secondDimension-fakeCL-1 + 1 + CodeList + + + + + + + + fr.insee + m332raks-RDOP-m333hpwf + 1 + + + + + + + + + + + + + + fr.insee + m333nmhe + 1 + + DYNAMIC_TABLE_VTL_SIZE + + + fr.insee + m333nmhe-QOP-m333qxeo + 1 + + DYNAMIC_TABLE_VTL_SIZE1 + + + + + fr.insee + m333nmhe-RDOP-m333qxeo + 1 + OutParameter + + + fr.insee + m333nmhe-QOP-m333qxeo + 1 + OutParameter + + + + + "Dynamic table with size defined by a VTL expression" + + + + + + + vtl + + fr.insee + m333nmhe-DIM1-ITE-IP-1 + 1 + + HOW_MANY + + + + + fr.insee + m333cu10-QOP-m333g4uu + 1 + OutParameter + + + fr.insee + m333nmhe-DIM1-ITE-IP-1 + 1 + InParameter + + + cast(m333nmhe-DIM1-ITE-IP-1, integer) + + + + + + + + fr.insee + m333nmhe-secondDimension-fakeCL-1 + 1 + CodeList + + + + + + + + fr.insee + m333nmhe-RDOP-m333qxeo + 1 + + + + + + + + + + + + + + + fr.insee + CategoryScheme-m332raks-secondDimension-fakeCL-1 + 1 + + FAKE-CODELIST-m332raks-secondDimension-fakeCL-1 + + + fr.insee + CA-m332raks-secondDimension-fakeCL-1-1 + 1 + + "Foo" + + + + + fr.insee + CategoryScheme-m333nmhe-secondDimension-fakeCL-1 + 1 + + FAKE-CODELIST-m333nmhe-secondDimension-fakeCL-1 + + + fr.insee + CA-m333nmhe-secondDimension-fakeCL-1-1 + 1 + + "Bar" + + + + + fr.insee + CategoryScheme-m332q6bo + 1 + + A définir + + + fr.insee + INSEE-COMMUN-CA-Booleen-1 + 1 + + + + + + + fr.insee + ENO_DYNAMIC_TABLE_SIZE-CLS + 1 + + ENO_DYNAMIC_TABLE_SIZE + + + fr.insee + m332raks-secondDimension-fakeCL-1 + 1 + + FAKE-CODELIST-m332raks-secondDimension-fakeCL-1 + + Regular + + Ordinal + + + fr.insee + m332raks-secondDimension-fakeCL-1-1 + 1 + + fr.insee + CA-m332raks-secondDimension-fakeCL-1-1 + 1 + Category + + 1 + + + + fr.insee + m333nmhe-secondDimension-fakeCL-1 + 1 + + FAKE-CODELIST-m333nmhe-secondDimension-fakeCL-1 + + Regular + + Ordinal + + + fr.insee + m333nmhe-secondDimension-fakeCL-1-1 + 1 + + fr.insee + CA-m333nmhe-secondDimension-fakeCL-1-1 + 1 + Category + + 1 + + + + fr.insee + INSEE-COMMUN-CL-Booleen + 1 + + Booleen + + Regular + + Ordinal + + + fr.insee + INSEE-COMMUN-CL-Booleen-1 + 1 + + fr.insee + INSEE-COMMUN-CA-Booleen-1 + 1 + Category + + 1 + + + + + fr.insee + VariableScheme-m332q6bo + 1 + + Variable Scheme for the survey + + + fr.insee + m332noyi + 1 + + DYNAMIC_TABLE_MIN_MAX1 + + + Foo + + + fr.insee + m332raks-QOP-m333hpwf + 1 + OutParameter + + + fr.insee + m332raks + 1 + QuestionGrid + + + + + + + fr.insee + m333r0sf + 1 + + HOW_MANY + + + HOW_MANY label + + + fr.insee + m333cu10-QOP-m333g4uu + 1 + OutParameter + + + fr.insee + m333cu10 + 1 + QuestionItem + + + + + 1 + 10 + + Decimal + + + + + fr.insee + m333bep2 + 1 + + DYNAMIC_TABLE_VTL_SIZE1 + + + Bar + + + fr.insee + m333nmhe-QOP-m333qxeo + 1 + OutParameter + + + fr.insee + m333nmhe + 1 + QuestionGrid + + + + + + + fr.insee + m332raks-vg + 1 + + + fr.insee + m332raks + 1 + QuestionGrid + + + Loop + + DYNAMIC_TABLE_MIN_MAX + + + fr.insee + m332noyi + 1 + Variable + + + + fr.insee + m333nmhe-vg + 1 + + + fr.insee + m333nmhe + 1 + QuestionGrid + + + Loop + + DYNAMIC_TABLE_VTL_SIZE + + + fr.insee + m333bep2 + 1 + Variable + + + + fr.insee + INSEE-Instrument-m332q6bo-vg + 1 + + + fr.insee + Instrument-m332q6bo + 1 + Instrument + + + Questionnaire + + ENO_DYNAMIC_TABLE_SIZE + + + fr.insee + m333r0sf + 1 + Variable + + + fr.insee + m332raks-vg + 1 + VariableGroup + + + fr.insee + m333nmhe-vg + 1 + VariableGroup + + + + + fr.insee + INSEE-SIMPSONS-PIS-1 + 1 + + SIMPSONS + + + Processing instructions of the Simpsons questionnaire + + + + fr.insee + INSEE-SIMPSONS-MRS + 1 + + Liste de formats numériques et dates de + l'enquête + Numeric and DateTime list for the survey + + + + + fr.insee + StudyUnit-m332q6bo + 1 + + + fr.insee + DataCollection-m332q6bo + 1 + + fr.insee + QuestionScheme-m332q6bo + 1 + QuestionScheme + + + fr.insee + ControlConstructScheme-m332q6bo + 1 + ControlConstructScheme + + + fr.insee + InterviewerInstructionScheme-m332q6bo + 1 + InterviewerInstructionScheme + + + fr.insee + InstrumentScheme-m332q6bo + 1 + + fr.insee + Instrument-m332q6bo + 1 + + ENO_DYNAMIC_TABLE_SIZE + + + Eno - Dynamic table with size expression questionnaire + + A définir + + fr.insee + Sequence-m332q6bo + 1 + Sequence + + + + + + diff --git a/eno-core/src/test/resources/integration/pogues/pogues-dynamic-table-size.json b/eno-core/src/test/resources/integration/pogues/pogues-dynamic-table-size.json new file mode 100644 index 000000000..a5a709819 --- /dev/null +++ b/eno-core/src/test/resources/integration/pogues/pogues-dynamic-table-size.json @@ -0,0 +1,295 @@ +{ + "id": "m332q6bo", + "Name": "ENO_DYNAMIC_TABLE_SIZE", + "Child": [ + { + "id": "m332sbit", + "Name": "S1", + "type": "SequenceType", + "Child": [ + { + "id": "m332raks", + "Name": "DYNAMIC_TABLE_MIN_MAX", + "type": "QuestionType", + "Label": [ + "\"Regular dynamic table\"" + ], + "depth": 2, + "Control": [], + "Response": [ + { + "id": "m333hpwf", + "Datatype": { + "type": "TextDatatypeType", + "Pattern": "", + "typeName": "TEXT", + "MaxLength": 249 + }, + "CollectedVariableReference": "m332noyi" + } + ], + "TargetMode": [ + "CAPI", + "CATI", + "CAWI", + "PAPI" + ], + "Declaration": [], + "FlowControl": [], + "questionType": "TABLE", + "ResponseStructure": { + "Mapping": [ + { + "MappingSource": "m333hpwf", + "MappingTarget": "1 1" + } + ], + "Attribute": [], + "Dimension": [ + { + "dynamic": "DYNAMIC_LENGTH", + "MaxLines": 5, + "MinLines": 1, + "dimensionType": "PRIMARY" + }, + { + "Label": "\"Foo\"", + "dimensionType": "MEASURE" + } + ] + }, + "ClarificationQuestion": [] + } + ], + "Label": [ + "\"Sequence 1\"" + ], + "depth": 1, + "Control": [], + "TargetMode": [ + "CAPI", + "CATI", + "CAWI", + "PAPI" + ], + "Declaration": [], + "FlowControl": [], + "genericName": "MODULE" + }, + { + "id": "m332os3s", + "Name": "S2", + "type": "SequenceType", + "Child": [ + { + "id": "m333cu10", + "Name": "HOW_MANY", + "type": "QuestionType", + "Label": [ + "\"How many lines in the next table?\"" + ], + "depth": 2, + "Control": [], + "Response": [ + { + "id": "m333g4uu", + "Datatype": { + "Unit": "", + "type": "NumericDatatypeType", + "Maximum": "10", + "Minimum": "1", + "Decimals": "", + "typeName": "NUMERIC" + }, + "mandatory": false, + "CollectedVariableReference": "m333r0sf" + } + ], + "TargetMode": [ + "CAPI", + "CATI", + "CAWI", + "PAPI" + ], + "Declaration": [], + "FlowControl": [], + "questionType": "SIMPLE" + }, + { + "id": "m333nmhe", + "Name": "DYNAMIC_TABLE_VTL_SIZE", + "type": "QuestionType", + "Label": [ + "\"Dynamic table with size defined by a VTL expression\"" + ], + "depth": 2, + "Control": [], + "Response": [ + { + "id": "m333qxeo", + "Datatype": { + "type": "TextDatatypeType", + "Pattern": "", + "typeName": "TEXT", + "MaxLength": 249 + }, + "CollectedVariableReference": "m333bep2" + } + ], + "TargetMode": [ + "CAPI", + "CATI", + "CAWI", + "PAPI" + ], + "Declaration": [], + "FlowControl": [], + "questionType": "TABLE", + "ResponseStructure": { + "Mapping": [ + { + "MappingSource": "m333qxeo", + "MappingTarget": "1 1" + } + ], + "Attribute": [], + "Dimension": [ + { + "dynamic": "FIXED_LENGTH", + "FixedLength": "cast($HOW_MANY$, integer)", + "dimensionType": "PRIMARY" + }, + { + "Label": "\"Bar\"", + "dimensionType": "MEASURE" + } + ] + }, + "ClarificationQuestion": [] + } + ], + "Label": [ + "\"Sequence 2\"" + ], + "depth": 1, + "Control": [], + "TargetMode": [ + "CAPI", + "CATI", + "CAWI", + "PAPI" + ], + "Declaration": [], + "FlowControl": [], + "genericName": "MODULE" + }, + { + "id": "idendquest", + "Name": "QUESTIONNAIRE_END", + "type": "SequenceType", + "Child": [], + "Label": [ + "QUESTIONNAIRE_END" + ], + "depth": 1, + "Control": [], + "TargetMode": [ + "CAPI", + "CATI", + "CAWI", + "PAPI" + ], + "Declaration": [], + "FlowControl": [], + "genericName": "MODULE" + } + ], + "Label": [ + "Eno - Dynamic table with size expression" + ], + "final": false, + "owner": "ENO-INTEGRATION-TESTS", + "agency": "fr.insee", + "CodeLists": { + "CodeList": [] + }, + "Variables": { + "Variable": [ + { + "id": "m332noyi", + "Name": "DYNAMIC_TABLE_MIN_MAX1", + "type": "CollectedVariableType", + "Label": "Foo", + "Scope": "m332raks", + "Datatype": { + "type": "TextDatatypeType", + "Pattern": "", + "typeName": "TEXT", + "MaxLength": 249 + } + }, + { + "id": "m333r0sf", + "Name": "HOW_MANY", + "type": "CollectedVariableType", + "Label": "HOW_MANY label", + "Datatype": { + "Unit": "", + "type": "NumericDatatypeType", + "Maximum": "10", + "Minimum": "1", + "Decimals": "", + "typeName": "NUMERIC" + } + }, + { + "id": "m333bep2", + "Name": "DYNAMIC_TABLE_VTL_SIZE1", + "type": "CollectedVariableType", + "Label": "Bar", + "Scope": "m333nmhe", + "Datatype": { + "type": "TextDatatypeType", + "Pattern": "", + "typeName": "TEXT", + "MaxLength": 249 + } + } + ] + }, + "flowLogic": "FILTER", + "TargetMode": [ + "CAPI", + "CATI", + "CAWI", + "PAPI" + ], + "FlowControl": [], + "genericName": "QUESTIONNAIRE", + "ComponentGroup": [ + { + "id": "m333sumk", + "Name": "PAGE_1", + "Label": [ + "Components for page 1" + ], + "MemberReference": [ + "m332sbit", + "m332raks", + "m332os3s", + "m333cu10", + "m333nmhe", + "idendquest" + ] + } + ], + "DataCollection": [ + { + "id": "s2106-dc", + "uri": "http://ddi:fr.insee:DataCollection.s2106-dc" + } + ], + "lastUpdatedDate": "Mon Nov 04 2024 15:37:40 GMT+0100 (heure normale d’Europe centrale)", + "formulasLanguage": "VTL", + "childQuestionnaireRef": [] +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 3a7e8ed72..ab6e8a47b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -9,7 +9,7 @@ dependencyResolutionManagement { versionCatalogs { create("libs") { version("lunatic-model", "3.15.1") - version("pogues-model", "1.3.14") + version("pogues-model", "1.4.0") library("lunatic-model", "fr.insee.lunatic", "lunatic-model").versionRef("lunatic-model") library("pogues-model", "fr.insee.pogues", "pogues-model").versionRef("pogues-model") }