From 60041cbffd4bccf4f86e4809094677489c993cf9 Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 19 Jun 2026 00:11:27 +0300 Subject: [PATCH 01/17] AMP-31133 : Activity form not saving disaggregated values --- .../AmpMEDisaggregationActualValuesPanel.java | 41 +++++++---------- .../amp/onepager/util/ActivityUtil.java | 44 +++++++++++++++++++ 2 files changed, 59 insertions(+), 26 deletions(-) diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java index 4314196fa0f..c8d77ebe3de 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java @@ -1,23 +1,23 @@ package org.dgfoundation.amp.onepager.components.features.items; import org.apache.wicket.ajax.AjaxRequestTarget; -import org.apache.wicket.markup.html.list.ListItem; -import org.apache.wicket.markup.html.list.ListView; import org.apache.wicket.model.IModel; -import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.PropertyModel; import org.dgfoundation.amp.onepager.OnePagerUtil; +import org.dgfoundation.amp.onepager.components.ListEditor; import org.dgfoundation.amp.onepager.components.ListEditorRemoveButton; +import org.dgfoundation.amp.onepager.components.ListItem; import org.dgfoundation.amp.onepager.components.features.AmpFeaturePanel; -import org.dgfoundation.amp.onepager.components.features.me.singlecountry.AmpMEActualValuesFormTableFeaturePanel; import org.dgfoundation.amp.onepager.components.fields.AmpAjaxLinkField; import org.dgfoundation.amp.onepager.components.fields.AmpDatePickerFieldPanel; import org.dgfoundation.amp.onepager.components.fields.AmpTextFieldPanel; import org.digijava.module.aim.dbentity.AmpIndicatorDisaggregationValue; import org.digijava.module.aim.dbentity.AmpIndicatorGlobalValue; import org.dgfoundation.amp.onepager.converters.CustomDoubleConverter; +import org.apache.wicket.util.convert.IConverter; -import java.util.*; +import java.util.Date; +import java.util.Set; /** * Panel rendering and editing ACTUAL values (AmpIndicatorGlobalValue entries with type ACTUAL) @@ -25,31 +25,21 @@ */ public class AmpMEDisaggregationActualValuesPanel extends AmpFeaturePanel { - private final ListView listView; + private final ListEditor listEditor; public AmpMEDisaggregationActualValuesPanel(String id, IModel model) { super(id, model, "Disaggregation Actual Values", true); setOutputMarkupId(true); - // Use a List model for ListView (was Set, causing type mismatch) - IModel> listModel = new LoadableDetachableModel>() { - @Override - protected List load() { - AmpIndicatorDisaggregationValue disagg = AmpMEDisaggregationActualValuesPanel.this.getModel().getObject(); - if (disagg.getActualValues() == null) { - disagg.setActualValues(new java.util.HashSet<>()); - } - return new java.util.ArrayList<>(disagg.getActualValues()); - } - }; + IModel> actualValuesModel = new PropertyModel<>(model, "actualValues"); - listView = new ListView("rows", listModel) { + listEditor = new ListEditor("rows", actualValuesModel) { @Override - protected void populateItem(ListItem item) { - AmpIndicatorGlobalValue val = item.getModelObject(); - item.setOutputMarkupId(true); + protected void onPopulateItem(ListItem item) { item.add(new AmpTextFieldPanel("actualValue", new PropertyModel<>(item.getModel(), "originalValue"), "Actual Value") { - public org.apache.wicket.util.convert.IConverter getInternalConverter(java.lang.Class type) { + @Override + @SuppressWarnings("rawtypes") + public IConverter getInternalConverter(Class type) { return CustomDoubleConverter.INSTANCE; } }); @@ -57,15 +47,14 @@ public org.apache.wicket.util.convert.IConverter getInternalConverter(java.lang. item.add(new ListEditorRemoveButton("delActualValue", "Delete", "Delete") { @Override public void onClick(AjaxRequestTarget target) { - AmpMEDisaggregationActualValuesPanel.this.getModel().getObject().getActualValues().remove(val); + super.onClick(target); target.appendJavaScript(OnePagerUtil.getToggleChildrenJS(AmpMEDisaggregationActualValuesPanel.this)); target.add(AmpMEDisaggregationActualValuesPanel.this); } }); } }; - listView.setOutputMarkupId(true); - add(listView); + add(listEditor); AmpAjaxLinkField addActual = new AmpAjaxLinkField("addDisaggActualValue", "Add Actual Value", "Add Actual Value") { @Override @@ -77,7 +66,7 @@ public void onClick(AjaxRequestTarget target) { AmpIndicatorGlobalValue val = new AmpIndicatorGlobalValue(AmpIndicatorGlobalValue.ACTUAL); val.setIndicator(disaggVal.getIndicator()); val.setOriginalValueDate(new Date()); - disaggVal.getActualValues().add(val); + listEditor.addItem(val); target.add(AmpMEDisaggregationActualValuesPanel.this); } }; diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java b/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java index dce0a8c1061..b193ea2cdf0 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java @@ -321,6 +321,9 @@ public static AmpActivityVersion saveActivityNewVersion(AmpActivityVersion a, // session.saveOrUpdate(a); session.merge(a); } + if (isActivityForm) { + saveIndicatorDisaggregationActualValues(a, session); + } session.flush(); updatePerformanceRules(oldA, a); @@ -337,6 +340,47 @@ public static AmpActivityVersion saveActivityNewVersion(AmpActivityVersion a, return a; } + + private static void saveIndicatorDisaggregationActualValues(AmpActivityVersion activity, Session session) { + if (activity.getIndicators() == null) { + return; + } + + Set mergedDisaggregationIds = new HashSet<>(); + for (IndicatorActivity indicatorActivity : activity.getIndicators()) { + if (indicatorActivity == null || indicatorActivity.getIndicator() == null) { + continue; + } + + AmpIndicator indicator = indicatorActivity.getIndicator(); + if (indicator.getDisaggregationValues() == null) { + continue; + } + + for (AmpIndicatorDisaggregationValue disaggregationValue : indicator.getDisaggregationValues()) { + if (disaggregationValue == null) { + continue; + } + + Long disaggregationValueId = disaggregationValue.getId(); + if (disaggregationValueId != null && !mergedDisaggregationIds.add(disaggregationValueId)) { + continue; + } + + for (AmpIndicatorGlobalValue actualValue : disaggregationValue.getActualValues()) { + if (actualValue == null) { + continue; + } + actualValue.setType(AmpIndicatorGlobalValue.ACTUAL); + if (actualValue.getIndicator() == null) { + actualValue.setIndicator(indicator); + } + } + session.merge(disaggregationValue); + } + } + } + private static void cleanObjectFromSession(Session session, Class objectClass, Long id) { T object = session.get(objectClass, id); From a032e15b0a29c2b3a54c49d5a4969e00098398a6 Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 19 Jun 2026 00:42:31 +0300 Subject: [PATCH 02/17] AMP-31133 : Activity form not saving disaggregated values --- .../AmpMEDisaggregationActualValuesPanel.java | 17 +++---- .../amp/onepager/util/ActivityUtil.java | 44 ------------------- 2 files changed, 9 insertions(+), 52 deletions(-) diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java index c8d77ebe3de..6a66db34f9f 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java @@ -11,12 +11,12 @@ import org.dgfoundation.amp.onepager.components.fields.AmpAjaxLinkField; import org.dgfoundation.amp.onepager.components.fields.AmpDatePickerFieldPanel; import org.dgfoundation.amp.onepager.components.fields.AmpTextFieldPanel; +import org.dgfoundation.amp.onepager.converters.CustomDoubleConverter; import org.digijava.module.aim.dbentity.AmpIndicatorDisaggregationValue; import org.digijava.module.aim.dbentity.AmpIndicatorGlobalValue; -import org.dgfoundation.amp.onepager.converters.CustomDoubleConverter; -import org.apache.wicket.util.convert.IConverter; import java.util.Date; +import java.util.HashSet; import java.util.Set; /** @@ -31,15 +31,15 @@ public AmpMEDisaggregationActualValuesPanel(String id, IModel> actualValuesModel = new PropertyModel<>(model, "actualValues"); + // PropertyModel on the backing Set — ListEditor.updateModel() will write items back here on form submit + IModel> setModel = new PropertyModel<>(model, "actualValues"); - listEditor = new ListEditor("rows", actualValuesModel) { + listEditor = new ListEditor("rows", setModel) { @Override protected void onPopulateItem(ListItem item) { + item.setOutputMarkupId(true); item.add(new AmpTextFieldPanel("actualValue", new PropertyModel<>(item.getModel(), "originalValue"), "Actual Value") { - @Override - @SuppressWarnings("rawtypes") - public IConverter getInternalConverter(Class type) { + public org.apache.wicket.util.convert.IConverter getInternalConverter(java.lang.Class type) { return CustomDoubleConverter.INSTANCE; } }); @@ -54,6 +54,7 @@ public void onClick(AjaxRequestTarget target) { }); } }; + listEditor.setOutputMarkupId(true); add(listEditor); AmpAjaxLinkField addActual = new AmpAjaxLinkField("addDisaggActualValue", "Add Actual Value", "Add Actual Value") { @@ -61,7 +62,7 @@ public void onClick(AjaxRequestTarget target) { public void onClick(AjaxRequestTarget target) { AmpIndicatorDisaggregationValue disaggVal = AmpMEDisaggregationActualValuesPanel.this.getModel().getObject(); if (disaggVal.getActualValues() == null) { - disaggVal.setActualValues(new java.util.HashSet<>()); + disaggVal.setActualValues(new HashSet<>()); } AmpIndicatorGlobalValue val = new AmpIndicatorGlobalValue(AmpIndicatorGlobalValue.ACTUAL); val.setIndicator(disaggVal.getIndicator()); diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java b/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java index b193ea2cdf0..dce0a8c1061 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java @@ -321,9 +321,6 @@ public static AmpActivityVersion saveActivityNewVersion(AmpActivityVersion a, // session.saveOrUpdate(a); session.merge(a); } - if (isActivityForm) { - saveIndicatorDisaggregationActualValues(a, session); - } session.flush(); updatePerformanceRules(oldA, a); @@ -340,47 +337,6 @@ public static AmpActivityVersion saveActivityNewVersion(AmpActivityVersion a, return a; } - - private static void saveIndicatorDisaggregationActualValues(AmpActivityVersion activity, Session session) { - if (activity.getIndicators() == null) { - return; - } - - Set mergedDisaggregationIds = new HashSet<>(); - for (IndicatorActivity indicatorActivity : activity.getIndicators()) { - if (indicatorActivity == null || indicatorActivity.getIndicator() == null) { - continue; - } - - AmpIndicator indicator = indicatorActivity.getIndicator(); - if (indicator.getDisaggregationValues() == null) { - continue; - } - - for (AmpIndicatorDisaggregationValue disaggregationValue : indicator.getDisaggregationValues()) { - if (disaggregationValue == null) { - continue; - } - - Long disaggregationValueId = disaggregationValue.getId(); - if (disaggregationValueId != null && !mergedDisaggregationIds.add(disaggregationValueId)) { - continue; - } - - for (AmpIndicatorGlobalValue actualValue : disaggregationValue.getActualValues()) { - if (actualValue == null) { - continue; - } - actualValue.setType(AmpIndicatorGlobalValue.ACTUAL); - if (actualValue.getIndicator() == null) { - actualValue.setIndicator(indicator); - } - } - session.merge(disaggregationValue); - } - } - } - private static void cleanObjectFromSession(Session session, Class objectClass, Long id) { T object = session.get(objectClass, id); From 37a911ab4e086e6844af3204d892a1104c73b600 Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 19 Jun 2026 01:26:33 +0300 Subject: [PATCH 03/17] AMP-31133 : Activity form not saving disaggregated values --- .../AmpMEDisaggregationActualValuesPanel.java | 2 ++ .../amp/onepager/util/ActivityUtil.java | 20 +++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java index 6a66db34f9f..2b19ad471d6 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java @@ -61,6 +61,8 @@ public void onClick(AjaxRequestTarget target) { @Override public void onClick(AjaxRequestTarget target) { AmpIndicatorDisaggregationValue disaggVal = AmpMEDisaggregationActualValuesPanel.this.getModel().getObject(); + logger.info("Adding new ACTUAL value for disaggregation value: " + disaggVal); + logger.info("Current actual values: " + disaggVal.getActualValues()); if (disaggVal.getActualValues() == null) { disaggVal.setActualValues(new HashSet<>()); } diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java b/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java index dce0a8c1061..133eb735e51 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java @@ -245,7 +245,12 @@ public static AmpActivityVersion saveActivityNewVersion(AmpActivityVersion a, prepareToSave(a, oldA, ampCurrentMember, draft, context); } logger.info("Object after prepare :" + a); - + a.getIndicators().forEach(x-> + { + logger.info("Indicator q: " + x.getIndicator().getIndicatorId() + " - " + x.getIndicator().getName()); + x.getIndicator().getDisaggregationValues().forEach(y -> logger.info("Disaggregation: " + y.getActualValues().size() + " - " + y.getBaseValue().getValue())); + } + ); if (a.getAmpActivityGroup() == null) { //we need to create a group for this activity AmpActivityGroup tmpGroup = new AmpActivityGroup(); @@ -294,7 +299,12 @@ public static AmpActivityVersion saveActivityNewVersion(AmpActivityVersion a, group.setAmpActivityLastVersion(a); } } - + a.getIndicators().forEach(x-> + { + logger.info("Indicator 1: " + x.getIndicator().getIndicatorId() + " - " + x.getIndicator().getName()); + x.getIndicator().getDisaggregationValues().forEach(y -> logger.info("Disaggregation: " + y.getActualValues().size() + " - " + y.getBaseValue().getValue())); + } + ); if (isActivityForm) { saveActivityResources(a, session); saveActivityGPINiResources(a, session); @@ -321,6 +331,12 @@ public static AmpActivityVersion saveActivityNewVersion(AmpActivityVersion a, // session.saveOrUpdate(a); session.merge(a); } + a.getIndicators().forEach(x-> + { + logger.info("Indicator x: " + x.getIndicator().getIndicatorId() + " - " + x.getIndicator().getName()); + x.getIndicator().getDisaggregationValues().forEach(y -> logger.info("Disaggregation: " + y.getActualValues().size() + " - " + y.getBaseValue().getValue())); + } + ); session.flush(); updatePerformanceRules(oldA, a); From 4298b6c02e23ace10f76ab62898db22fa9da84aa Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 19 Jun 2026 01:52:01 +0300 Subject: [PATCH 04/17] AMP-31133 : Activity form not saving disaggregated values --- .../AmpMEDisaggregationActualValuesPanel.java | 5 ++-- .../amp/onepager/util/ActivityUtil.java | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java index 2b19ad471d6..26ec6729aed 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java @@ -3,6 +3,7 @@ import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.model.IModel; import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.util.convert.IConverter; import org.dgfoundation.amp.onepager.OnePagerUtil; import org.dgfoundation.amp.onepager.components.ListEditor; import org.dgfoundation.amp.onepager.components.ListEditorRemoveButton; @@ -31,7 +32,7 @@ public AmpMEDisaggregationActualValuesPanel(String id, IModel> setModel = new PropertyModel<>(model, "actualValues"); listEditor = new ListEditor("rows", setModel) { @@ -39,7 +40,7 @@ public AmpMEDisaggregationActualValuesPanel(String id, IModel item) { item.setOutputMarkupId(true); item.add(new AmpTextFieldPanel("actualValue", new PropertyModel<>(item.getModel(), "originalValue"), "Actual Value") { - public org.apache.wicket.util.convert.IConverter getInternalConverter(java.lang.Class type) { + public IConverter getInternalConverter(Class type) { return CustomDoubleConverter.INSTANCE; } }); diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java b/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java index 133eb735e51..3d11ec25e6b 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java @@ -245,6 +245,7 @@ public static AmpActivityVersion saveActivityNewVersion(AmpActivityVersion a, prepareToSave(a, oldA, ampCurrentMember, draft, context); } logger.info("Object after prepare :" + a); + saveIndicatorDisaggregationActualValues(a, session); a.getIndicators().forEach(x-> { logger.info("Indicator q: " + x.getIndicator().getIndicatorId() + " - " + x.getIndicator().getName()); @@ -353,6 +354,34 @@ public static AmpActivityVersion saveActivityNewVersion(AmpActivityVersion a, return a; } + + private static void saveIndicatorDisaggregationActualValues(AmpActivityVersion activity, Session session) { + if (activity.getIndicators() == null) { + return; + } + + boolean hasDisaggregationValues = false; + for (IndicatorActivity indicatorActivity : activity.getIndicators()) { + AmpIndicator indicator = indicatorActivity.getIndicator(); + if (indicator == null || indicator.getDisaggregationValues() == null) { + continue; + } + + for (AmpIndicatorDisaggregationValue disaggregationValue : indicator.getDisaggregationValues()) { + hasDisaggregationValues = true; + for (AmpIndicatorGlobalValue actualValue : disaggregationValue.getActualValues()) { + actualValue.setType(AmpIndicatorGlobalValue.ACTUAL); + actualValue.setIndicator(indicator); + } + session.saveOrUpdate(disaggregationValue); + } + } + + if (hasDisaggregationValues) { + session.flush(); + } + } + private static void cleanObjectFromSession(Session session, Class objectClass, Long id) { T object = session.get(objectClass, id); From b92347d07eea9b14c1a5d4274fa2f97e7037ec0c Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 19 Jun 2026 07:36:51 +0300 Subject: [PATCH 05/17] AMP-31133 : Mismatched indicator actual values in multicountry --- amp/TEMPLATE/reamp/package-lock.json | 8 ++--- amp/TEMPLATE/reamp/package.json | 2 +- .../activity/ActivityInterchangeUtils.java | 34 +++++++++++++------ 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/amp/TEMPLATE/reamp/package-lock.json b/amp/TEMPLATE/reamp/package-lock.json index 79e681c1863..e0c9f36b9ed 100644 --- a/amp/TEMPLATE/reamp/package-lock.json +++ b/amp/TEMPLATE/reamp/package-lock.json @@ -22,7 +22,7 @@ "uglifyjs-webpack-plugin": "^1.3.0" }, "devDependencies": { - "amp-ui": "github:devgateway/amp-ui#add-missing-me-fields-to-preview-and-api", + "amp-ui": "github:devgateway/amp-ui#fix/AMP-31133/Indicator-values-display-fixes", "babel-core": "^6.26.3", "babel-jest": "^6.0.1", "babel-loader": "^6.3.2", @@ -309,7 +309,7 @@ }, "node_modules/amp-ui": { "version": "2.1.1", - "resolved": "git+ssh://git@github.com/devgateway/amp-ui.git#4fcbaa11e90187b93ce6b980d4e9e8045abdb614", + "resolved": "git+ssh://git@github.com/devgateway/amp-ui.git#b033cf93099abd3fd308a1d3080f95ac9ddbb5fd", "dev": true, "license": "MIT", "dependencies": { @@ -9493,9 +9493,9 @@ "dev": true }, "amp-ui": { - "version": "git+ssh://git@github.com/devgateway/amp-ui.git#4fcbaa11e90187b93ce6b980d4e9e8045abdb614", + "version": "git+ssh://git@github.com/devgateway/amp-ui.git#b033cf93099abd3fd308a1d3080f95ac9ddbb5fd", "dev": true, - "from": "amp-ui@github:devgateway/amp-ui#add-missing-me-fields-to-preview-and-api", + "from": "amp-ui@github:devgateway/amp-ui#fix/AMP-31133/Indicator-values-display-fixes", "requires": { "docx": "^4.7.1", "file-saver": "github:devgateway/FileSaver.js", diff --git a/amp/TEMPLATE/reamp/package.json b/amp/TEMPLATE/reamp/package.json index 7d081023c55..fceef280486 100644 --- a/amp/TEMPLATE/reamp/package.json +++ b/amp/TEMPLATE/reamp/package.json @@ -23,7 +23,7 @@ "author": "Alexei Savca", "license": "inherit", "devDependencies": { - "amp-ui": "github:devgateway/amp-ui#add-missing-me-fields-to-preview-and-api", + "amp-ui": "github:devgateway/amp-ui#fix/AMP-31133/Indicator-values-display-fixes", "babel-core": "^6.26.3", "babel-jest": "^6.0.1", "babel-loader": "^6.3.2", diff --git a/amp/src/main/java/org/digijava/kernel/ampapi/endpoints/activity/ActivityInterchangeUtils.java b/amp/src/main/java/org/digijava/kernel/ampapi/endpoints/activity/ActivityInterchangeUtils.java index 3b46a1afdb5..f4b967f5eed 100644 --- a/amp/src/main/java/org/digijava/kernel/ampapi/endpoints/activity/ActivityInterchangeUtils.java +++ b/amp/src/main/java/org/digijava/kernel/ampapi/endpoints/activity/ActivityInterchangeUtils.java @@ -432,19 +432,33 @@ private static void addActualIndicatorValues(Optional indicatorsObject, } results = IndicatorUtil.findActivityIndicatorConnections(activity, ind); + Object rawLocId = indicator.get("activity_location"); + Long activityLocationId = rawLocId != null + ? (rawLocId instanceof Long ? (Long) rawLocId : Long.valueOf(rawLocId.toString())) + : null; + for (IndicatorActivity result : results) { - if (result != null && result.getValues() != null) { - for (AmpIndicatorValue indicatorValue : result.getValues()) { - actualValues.add(new HashMap() {{ - put("comment", indicatorValue.getComment()); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // Customize format as needed - Date valueDate = indicatorValue.getValueDate(); - String formattedDate = dateFormat.format(valueDate); - put("date", formattedDate); - put("value", indicatorValue.getValue()); - }}); + if (result == null || result.getValues() == null) { + continue; + } + // Filter by location when the serialized indicator has one. + if (activityLocationId != null) { + AmpActivityLocation aal = result.getActivityLocation(); + Long resultLocId = aal != null ? aal.getId() : null; + if (!activityLocationId.equals(resultLocId)) { + continue; } } + for (AmpIndicatorValue indicatorValue : result.getValues()) { + actualValues.add(new HashMap() {{ + put("comment", indicatorValue.getComment()); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // Customize format as needed + Date valueDate = indicatorValue.getValueDate(); + String formattedDate = dateFormat.format(valueDate); + put("date", formattedDate); + put("value", indicatorValue.getValue()); + }}); + } } indicator.put("actual", actualValues); From 553c9f1b6f56da85b3e798b87ba0cb2a56f0a990 Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 19 Jun 2026 08:25:08 +0300 Subject: [PATCH 06/17] AMP-31133 : Missing values in ME section --- .../components/features/items/AmpMEItemFeaturePanel.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEItemFeaturePanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEItemFeaturePanel.java index 21fa24046cc..ce9414e9e76 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEItemFeaturePanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEItemFeaturePanel.java @@ -27,6 +27,7 @@ import org.digijava.module.aim.dbentity.*; import org.digijava.module.aim.util.DbUtil; +import java.util.Objects; import org.apache.log4j.Logger; @@ -85,7 +86,9 @@ protected List load() { List filteredIndicators = new ArrayList<>(); for (IndicatorActivity indicatorActivity : allIndicators) { - if (indicatorActivity.getActivityLocation() != null && indicatorActivity.getActivityLocation() == location.getObject()) { + if (indicatorActivity.getActivityLocation() != null + && Objects.equals(indicatorActivity.getActivityLocation().getId(), + location.getObject().getId())) { filteredIndicators.add(indicatorActivity); } } @@ -99,7 +102,8 @@ protected List load() { setModel = new AbstractMixedSetModel(parentModel) { @Override public boolean condition(IndicatorActivity item) { - return item.getActivityLocation() == location.getObject(); + return item.getActivityLocation() != null + && Objects.equals(item.getActivityLocation().getId(), location.getObject().getId()); } }; From 0fad79a9eb872ac03b7a5c8bfa74efa6a821ffa6 Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 19 Jun 2026 09:12:56 +0300 Subject: [PATCH 07/17] AMP-31133 : Missing values in ME section --- .../module/aim/dbentity/IndicatorActivity.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java b/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java index 09a1a173715..422a0f09d15 100644 --- a/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java +++ b/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java @@ -142,6 +142,19 @@ public Object prepareMerge(AmpActivityVersion newActivity) throws CloneNotSuppor aux.activity = newActivity; aux.setId(null); + if (aux.activityLocation != null && newActivity.getLocations() != null) { + Long oldInnerLocId = aux.activityLocation.getLocation() != null + ? aux.activityLocation.getLocation().getId() : null; + if (oldInnerLocId != null) { + for (AmpActivityLocation newLoc : newActivity.getLocations()) { + if (newLoc.getLocation() != null && oldInnerLocId.equals(newLoc.getLocation().getId())) { + aux.activityLocation = newLoc; + break; + } + } + } + } + if (aux.values != null && aux.values.size() > 0){ HashSet set = new HashSet(); for (AmpIndicatorValue value : aux.values) { From 5074370bfdea2aca0f65c55f18f20f01bb05613f Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 19 Jun 2026 09:36:06 +0300 Subject: [PATCH 08/17] AMP-31133 : Missing values in ME section in form --- .../digijava/module/aim/dbentity/IndicatorActivity.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java b/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java index 422a0f09d15..fa149ad388c 100644 --- a/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java +++ b/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java @@ -142,13 +142,13 @@ public Object prepareMerge(AmpActivityVersion newActivity) throws CloneNotSuppor aux.activity = newActivity; aux.setId(null); - if (aux.activityLocation != null && newActivity.getLocations() != null) { - Long oldInnerLocId = aux.activityLocation.getLocation() != null - ? aux.activityLocation.getLocation().getId() : null; + if (aux.getActivityLocation() != null && newActivity.getLocations() != null) { + Long oldInnerLocId = aux.getActivityLocation().getLocation() != null + ? aux.getActivityLocation().getLocation().getId() : null; if (oldInnerLocId != null) { for (AmpActivityLocation newLoc : newActivity.getLocations()) { if (newLoc.getLocation() != null && oldInnerLocId.equals(newLoc.getLocation().getId())) { - aux.activityLocation = newLoc; + aux.setActivityLocation(newLoc); break; } } From 29d8e5a8c37700ba47b7343904c4b64d8f5f5602 Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 19 Jun 2026 10:30:27 +0300 Subject: [PATCH 09/17] AMP-31133 : Missing values in ME section in form --- .../tables/AmpMEValuesFormTableFeaturePanel.java | 9 +++++++-- .../module/aim/dbentity/IndicatorActivity.java | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/tables/AmpMEValuesFormTableFeaturePanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/tables/AmpMEValuesFormTableFeaturePanel.java index bb40f4e972d..f62c87988c3 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/tables/AmpMEValuesFormTableFeaturePanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/tables/AmpMEValuesFormTableFeaturePanel.java @@ -14,6 +14,7 @@ import org.digijava.module.aim.dbentity.AmpIndicator; import org.digijava.module.aim.dbentity.AmpIndicatorValue; import org.digijava.module.aim.dbentity.IndicatorActivity; +import java.util.Objects; import java.util.Set; public abstract class AmpMEValuesFormTableFeaturePanel extends AmpMEFormTableFeaturePanel { @@ -35,14 +36,18 @@ public AmpMEValuesFormTableFeaturePanel( setModel = new AbstractMixedSetModel(parentModel) { @Override public boolean condition(AmpIndicatorValue item) { - return item.getValueType() == AmpIndicatorValue.ACTUAL && item.getActivityLocation() == location.getObject(); + return item.getValueType() == AmpIndicatorValue.ACTUAL + && item.getActivityLocation() != null + && Objects.equals(item.getActivityLocation().getId(), location.getObject().getId()); } }; setBaseTargetModel = new AbstractMixedSetModel(parentModel) { @Override public boolean condition(AmpIndicatorValue item) { - return (item.getValueType() == AmpIndicatorValue.BASE || item.getValueType() == AmpIndicatorValue.TARGET) && item.getActivityLocation() == location.getObject(); + return (item.getValueType() == AmpIndicatorValue.BASE || item.getValueType() == AmpIndicatorValue.TARGET) + && item.getActivityLocation() != null + && Objects.equals(item.getActivityLocation().getId(), location.getObject().getId()); } }; } diff --git a/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java b/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java index fa149ad388c..a851af1fccc 100644 --- a/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java +++ b/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java @@ -161,6 +161,20 @@ public Object prepareMerge(AmpActivityVersion newActivity) throws CloneNotSuppor AmpIndicatorValue ampIndicatorValue = (AmpIndicatorValue) value.clone(); ampIndicatorValue.setIndValId(null); ampIndicatorValue.setIndicatorConnection(aux); + // Re-point the value's activityLocation to the new version's AmpActivityLocation, + // matched by the stable inner AmpCategoryValueLocations id. + if (ampIndicatorValue.getActivityLocation() != null && newActivity.getLocations() != null) { + Long oldInnerLocId = ampIndicatorValue.getActivityLocation().getLocation() != null + ? ampIndicatorValue.getActivityLocation().getLocation().getId() : null; + if (oldInnerLocId != null) { + for (AmpActivityLocation newLoc : newActivity.getLocations()) { + if (newLoc.getLocation() != null && oldInnerLocId.equals(newLoc.getLocation().getId())) { + ampIndicatorValue.setActivityLocation(newLoc); + break; + } + } + } + } set.add(ampIndicatorValue); } aux.values = set; From e207e52da085ea7b7226639664fdee7bb8aebdab Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 19 Jun 2026 11:03:25 +0300 Subject: [PATCH 10/17] AMP-31133 : Missing values in ME section in form --- .../features/items/AmpMEIndicatorFeaturePanel.java | 10 ++++------ .../module/aim/dbentity/IndicatorActivity.java | 2 -- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java index 20d45c50cd3..26e780ae7bb 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java @@ -49,8 +49,8 @@ public AmpMEIndicatorFeaturePanel(String id, String fmName, final IModel(indicator, "name")); add(indicatorNameLabel); - final boolean hasDisaggregation = indicator.getObject().getDisaggregation() != null - && !indicator.getObject().getDisaggregation().isEmpty(); + final boolean hasDisaggregation = indicator.getObject().getDisaggregationValues() != null + && !indicator.getObject().getDisaggregationValues().isEmpty(); String indCodeString = ""; if (indicator.getObject().getCode() != null && indicator.getObject().getCode().trim().compareTo("") != 0) { @@ -140,6 +140,7 @@ protected String load() { AmpMEActualValuesFormTableFeaturePanel valuesTable = new AmpMEActualValuesFormTableFeaturePanel("valuesSubsection", indicator, conn, location,"Actual Values", false, 7); valuesTable.setOutputMarkupId(true); valuesTable.setOutputMarkupPlaceholderTag(true); + valuesTable.setVisible(!hasDisaggregation); add(valuesTable); @@ -165,6 +166,7 @@ public void onClick(AjaxRequestTarget target) { logger.info("Id " + addActualValue.getId()); addActualValue.setOutputMarkupId(true); addActualValue.setOutputMarkupPlaceholderTag(true); + addActualValue.setVisible(!hasDisaggregation); add(addActualValue); @@ -180,10 +182,6 @@ public void onClick(AjaxRequestTarget target) { AmpMEDisaggregationValuesFeaturePanel disaggPanel = new AmpMEDisaggregationValuesFeaturePanel("disaggregationValuesSubsection", "Disaggregation Values", indicator); disaggPanel.setOutputMarkupId(true); disaggPanel.setVisible(hasDisaggregation); - // Add disaggregation values subsection - if (indicator.getObject().getDisaggregation()== null || indicator.getObject().getDisaggregation().isEmpty()) { - disaggPanel.setVisible(false); - } add(disaggPanel); diff --git a/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java b/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java index a851af1fccc..2ea14c9f415 100644 --- a/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java +++ b/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java @@ -161,8 +161,6 @@ public Object prepareMerge(AmpActivityVersion newActivity) throws CloneNotSuppor AmpIndicatorValue ampIndicatorValue = (AmpIndicatorValue) value.clone(); ampIndicatorValue.setIndValId(null); ampIndicatorValue.setIndicatorConnection(aux); - // Re-point the value's activityLocation to the new version's AmpActivityLocation, - // matched by the stable inner AmpCategoryValueLocations id. if (ampIndicatorValue.getActivityLocation() != null && newActivity.getLocations() != null) { Long oldInnerLocId = ampIndicatorValue.getActivityLocation().getLocation() != null ? ampIndicatorValue.getActivityLocation().getLocation().getId() : null; From c42db3b01c94aede8b8f200cb44263aebd6c2483 Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 19 Jun 2026 11:31:11 +0300 Subject: [PATCH 11/17] AMP-31133 : Missing disagg form panel in ME section in form --- .../components/features/items/AmpMEIndicatorFeaturePanel.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java index 26e780ae7bb..5ee3dea04c7 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java @@ -49,8 +49,10 @@ public AmpMEIndicatorFeaturePanel(String id, String fmName, final IModel(indicator, "name")); add(indicatorNameLabel); + logger.info("Indicator disagg: " + indicator.getObject().getDisaggregationValues()); final boolean hasDisaggregation = indicator.getObject().getDisaggregationValues() != null && !indicator.getObject().getDisaggregationValues().isEmpty(); + logger.info("Has disaggregation: " + hasDisaggregation); String indCodeString = ""; if (indicator.getObject().getCode() != null && indicator.getObject().getCode().trim().compareTo("") != 0) { From a4bb027ac4ab94c16ebd80fbf02e6bf85652eefe Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 19 Jun 2026 11:56:48 +0300 Subject: [PATCH 12/17] AMP-31133 : Missing disagg form panel in ME section in form --- .../features/items/AmpMEDisaggregationValuesFeaturePanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationValuesFeaturePanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationValuesFeaturePanel.java index b59593c6038..0d9ff19a185 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationValuesFeaturePanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationValuesFeaturePanel.java @@ -35,7 +35,7 @@ public class AmpMEDisaggregationValuesFeaturePanel extends AmpFeaturePanel Date: Fri, 19 Jun 2026 12:24:29 +0300 Subject: [PATCH 13/17] AMP-31133 : Missing disagg form panel in ME section in form --- .../amp/onepager/components/ListItem.java | 11 +++++++++-- .../components/features/AmpActivityFormFeature.java | 2 ++ .../features/items/AmpMEIndicatorFeaturePanel.java | 7 +++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/ListItem.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/ListItem.java index d6c66d44c68..dac810f2fe6 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/ListItem.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/ListItem.java @@ -11,8 +11,15 @@ public ListItem(String id, int index){ private class ListItemModel extends AbstractReadOnlyModel{ public T getObject(){ - return ((ListEditor)ListItem.this.getParent()) - .items.get(getIndex()); + ListEditor editor = (ListEditor) ListItem.this.getParent(); + if (editor == null || editor.items == null) { + return null; + } + int idx = getIndex(); + if (idx < 0 || idx >= editor.items.size()) { + return null; + } + return editor.items.get(idx); } } } diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/AmpActivityFormFeature.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/AmpActivityFormFeature.java index d04c46e95a1..3dedfe3aa93 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/AmpActivityFormFeature.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/AmpActivityFormFeature.java @@ -1384,6 +1384,7 @@ public void component(Component component, IVisit visit) { if ("commitments".equals(id)) { AmpFunding funding = (AmpFunding) component.getDefaultModel().getObject(); + if (funding == null) { visit.dontGoDeeper(); return; } boolean commitmentsRequired = FMUtil.isFmVisible(findComponentById(form, "requireCommitments")); logger.info("Commitments required: " + commitmentsRequired); setErrorWHenItemMissing(component, funding, commitmentsRequired, Constants.COMMITMENT, errors, target); @@ -1391,6 +1392,7 @@ public void component(Component component, IVisit visit) { } if ("disbursements".equals(id)) { AmpFunding funding = (AmpFunding) component.getDefaultModel().getObject(); + if (funding == null) { visit.dontGoDeeper(); return; } boolean disbursementsRequired = FMUtil.isFmVisible(findComponentById(form, "requireDisbursements")); logger.info("Disbursements required: " + disbursementsRequired); setErrorWHenItemMissing(component, funding, disbursementsRequired, Constants.DISBURSEMENT, errors, target); diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java index 5ee3dea04c7..ae63aaf335a 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java @@ -171,6 +171,13 @@ public void onClick(AjaxRequestTarget target) { addActualValue.setVisible(!hasDisaggregation); add(addActualValue); + if (Boolean.FALSE.equals(hasDisaggregation)) + { + addActualValue.setVisible(false); + logger.info("Button visble" + addActualValue.isVisible()); + valuesTable.setVisible(false); + logger.info("Table visble" + valuesTable.isVisible()); + } AmpMEIndicatorBaseFeaturePanel baseValues = null; From 3e2e1e16fc584ffc9a047275ef8a0a14ad5b93de Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 19 Jun 2026 13:23:36 +0300 Subject: [PATCH 14/17] AMP-31133 : Missing disagg form panel in ME section in form --- .../items/AmpMEIndicatorFeaturePanel.java | 8 +++++--- .../amp/onepager/util/ActivityUtil.java | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java index ae63aaf335a..e960e9e6b25 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java @@ -171,13 +171,15 @@ public void onClick(AjaxRequestTarget target) { addActualValue.setVisible(!hasDisaggregation); add(addActualValue); - if (Boolean.FALSE.equals(hasDisaggregation)) + if (Boolean.TRUE.equals(hasDisaggregation)) { addActualValue.setVisible(false); - logger.info("Button visble" + addActualValue.isVisible()); valuesTable.setVisible(false); - logger.info("Table visble" + valuesTable.isVisible()); } + logger.info("Has disaggregation: " + hasDisaggregation); + logger.info("Button visble" + addActualValue.isVisible()); + logger.info("Table visble" + valuesTable.isVisible()); + AmpMEIndicatorBaseFeaturePanel baseValues = null; diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java b/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java index 3d11ec25e6b..e9db7404d94 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java @@ -360,7 +360,12 @@ private static void saveIndicatorDisaggregationActualValues(AmpActivityVersion a return; } + // Collect unique disaggregation values across all IndicatorActivity rows (which may share the same + // AmpIndicator and therefore the same AmpIndicatorDisaggregationValue instances). Deduplication by + // id prevents Hibernate NonUniqueObjectException when the same row appears more than once. + Set processedDisaggIds = new HashSet<>(); boolean hasDisaggregationValues = false; + for (IndicatorActivity indicatorActivity : activity.getIndicators()) { AmpIndicator indicator = indicatorActivity.getIndicator(); if (indicator == null || indicator.getDisaggregationValues() == null) { @@ -368,12 +373,20 @@ private static void saveIndicatorDisaggregationActualValues(AmpActivityVersion a } for (AmpIndicatorDisaggregationValue disaggregationValue : indicator.getDisaggregationValues()) { + Long dvId = disaggregationValue.getId(); + if (dvId != null && processedDisaggIds.contains(dvId)) { + continue; // already handled for this indicator + } + if (dvId != null) { + processedDisaggIds.add(dvId); + } hasDisaggregationValues = true; for (AmpIndicatorGlobalValue actualValue : disaggregationValue.getActualValues()) { actualValue.setType(AmpIndicatorGlobalValue.ACTUAL); actualValue.setIndicator(indicator); } - session.saveOrUpdate(disaggregationValue); + // Use merge instead of saveOrUpdate to handle detached objects safely + session.merge(disaggregationValue); } } From 22f9cd652369f39525911c5f948c29a821757094 Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 19 Jun 2026 13:58:00 +0300 Subject: [PATCH 15/17] AMP-31133 : Missing disagg form panel in ME section in form --- ...AmpMEDisaggregationValuesFeaturePanel.java | 8 +++---- .../items/AmpMEIndicatorFeaturePanel.java | 24 +++++++++++-------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationValuesFeaturePanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationValuesFeaturePanel.java index 0d9ff19a185..1da31b2b99a 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationValuesFeaturePanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationValuesFeaturePanel.java @@ -10,7 +10,6 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.Model; -import org.apache.wicket.model.PropertyModel; import org.dgfoundation.amp.onepager.components.features.AmpFeaturePanel; import org.digijava.kernel.persistence.PersistenceManager; import org.digijava.module.aim.dbentity.AmpIndicator; @@ -35,9 +34,10 @@ public class AmpMEDisaggregationValuesFeaturePanel extends AmpFeaturePanel indicatorModel) { diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java index e960e9e6b25..90b6063957f 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java @@ -10,7 +10,6 @@ import org.dgfoundation.amp.onepager.components.QuarterInformationPanel; import org.dgfoundation.amp.onepager.components.features.AmpFeaturePanel; import org.dgfoundation.amp.onepager.components.features.tables.AmpMEActualValuesFormTableFeaturePanel; -import org.dgfoundation.amp.onepager.components.features.items.AmpMEDisaggregationValuesFeaturePanel; import org.dgfoundation.amp.onepager.components.fields.AmpAjaxLinkField; import org.dgfoundation.amp.onepager.components.fields.AmpCategorySelectFieldPanel; import org.dgfoundation.amp.onepager.components.fields.AmpSelectFieldPanel; @@ -72,7 +71,7 @@ public AmpMEIndicatorFeaturePanel(String id, String fmName, final IModel riskSelect = new AmpSelectFieldPanel("risk", + final AmpSelectFieldPanel riskSelect = new AmpSelectFieldPanel("risk", new PropertyModel<>(conn, "risk"), MEIndicatorsUtil.getAllIndicatorRisks(), "Risk", false, false, new TranslatedChoiceRenderer(), false); add(riskSelect); @@ -139,10 +138,15 @@ protected String load() { }); add(indicatorTargetDateLabel); - AmpMEActualValuesFormTableFeaturePanel valuesTable = new AmpMEActualValuesFormTableFeaturePanel("valuesSubsection", indicator, conn, location,"Actual Values", false, 7); + AmpMEActualValuesFormTableFeaturePanel valuesTable = new AmpMEActualValuesFormTableFeaturePanel("valuesSubsection", indicator, conn, location,"Actual Values", false, 7) { + @Override + protected void onConfigure() { + super.onConfigure(); + setVisible(isVisible() && !hasDisaggregation); + } + }; valuesTable.setOutputMarkupId(true); valuesTable.setOutputMarkupPlaceholderTag(true); - valuesTable.setVisible(!hasDisaggregation); add(valuesTable); @@ -161,6 +165,12 @@ public void onClick(AjaxRequestTarget target) { target.add(valuesTable); target.appendJavaScript(QuarterInformationPanel.getJSUpdate(getSession())); } + + @Override + protected void onConfigure() { + super.onConfigure(); + setVisible(isVisible() && !hasDisaggregation); + } }; @@ -168,14 +178,8 @@ public void onClick(AjaxRequestTarget target) { logger.info("Id " + addActualValue.getId()); addActualValue.setOutputMarkupId(true); addActualValue.setOutputMarkupPlaceholderTag(true); - addActualValue.setVisible(!hasDisaggregation); add(addActualValue); - if (Boolean.TRUE.equals(hasDisaggregation)) - { - addActualValue.setVisible(false); - valuesTable.setVisible(false); - } logger.info("Has disaggregation: " + hasDisaggregation); logger.info("Button visble" + addActualValue.isVisible()); logger.info("Table visble" + valuesTable.isVisible()); From e9fcfb146b4355fc4956f0482091adeb844a2f42 Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 19 Jun 2026 14:54:10 +0300 Subject: [PATCH 16/17] AMP-31133 : Multicountry ME not separating disaggregated values --- .../AmpMEDisaggregationActualValuesPanel.java | 22 +++++++++++++++++-- ...AmpMEDisaggregationValuesFeaturePanel.java | 10 +++++++-- .../items/AmpMEIndicatorFeaturePanel.java | 10 +++++++-- .../activity/ActivityInterchangeUtils.java | 13 +++++++++++ .../aim/dbentity/AmpIndicatorGlobalValue.java | 12 ++++++++++ .../dbentity/AmpIndicatorGlobalValue.hbm.xml | 3 +++ 6 files changed, 64 insertions(+), 6 deletions(-) diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java index 26ec6729aed..f7fd54eb730 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java @@ -13,11 +13,14 @@ import org.dgfoundation.amp.onepager.components.fields.AmpDatePickerFieldPanel; import org.dgfoundation.amp.onepager.components.fields.AmpTextFieldPanel; import org.dgfoundation.amp.onepager.converters.CustomDoubleConverter; +import org.dgfoundation.amp.onepager.models.AbstractMixedSetModel; +import org.digijava.module.aim.dbentity.AmpActivityLocation; import org.digijava.module.aim.dbentity.AmpIndicatorDisaggregationValue; import org.digijava.module.aim.dbentity.AmpIndicatorGlobalValue; import java.util.Date; import java.util.HashSet; +import java.util.Objects; import java.util.Set; /** @@ -28,12 +31,24 @@ public class AmpMEDisaggregationActualValuesPanel extends AmpFeaturePanel listEditor; - public AmpMEDisaggregationActualValuesPanel(String id, IModel model) { + public AmpMEDisaggregationActualValuesPanel(String id, IModel model, + IModel location) { super(id, model, "Disaggregation Actual Values", true); setOutputMarkupId(true); // ListEditor.updateModel() writes submitted rows back into this backing set. - IModel> setModel = new PropertyModel<>(model, "actualValues"); + IModel> parentModel = new PropertyModel<>(model, "actualValues"); + IModel> setModel = new AbstractMixedSetModel(parentModel) { + @Override + public boolean condition(AmpIndicatorGlobalValue item) { + AmpActivityLocation currentLocation = location != null ? location.getObject() : null; + if (currentLocation == null) { + return item.getActivityLocation() == null; + } + return item.getActivityLocation() != null + && Objects.equals(item.getActivityLocation().getId(), currentLocation.getId()); + } + }; listEditor = new ListEditor("rows", setModel) { @Override @@ -69,6 +84,9 @@ public void onClick(AjaxRequestTarget target) { } AmpIndicatorGlobalValue val = new AmpIndicatorGlobalValue(AmpIndicatorGlobalValue.ACTUAL); val.setIndicator(disaggVal.getIndicator()); + if (location != null) { + val.setActivityLocation(location.getObject()); + } val.setOriginalValueDate(new Date()); listEditor.addItem(val); target.add(AmpMEDisaggregationActualValuesPanel.this); diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationValuesFeaturePanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationValuesFeaturePanel.java index 1da31b2b99a..44c3d90ab2a 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationValuesFeaturePanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationValuesFeaturePanel.java @@ -12,6 +12,7 @@ import org.apache.wicket.model.Model; import org.dgfoundation.amp.onepager.components.features.AmpFeaturePanel; import org.digijava.kernel.persistence.PersistenceManager; +import org.digijava.module.aim.dbentity.AmpActivityLocation; import org.digijava.module.aim.dbentity.AmpIndicator; import org.digijava.module.aim.dbentity.AmpIndicatorDisaggregationValue; import org.digijava.module.aim.dbentity.AmpIndicatorGlobalValue; @@ -40,7 +41,8 @@ protected void onConfigure() { setVisible(isVisible() && hasDisaggregationValues); } - public AmpMEDisaggregationValuesFeaturePanel(String id, String fmName, IModel indicatorModel) { + public AmpMEDisaggregationValuesFeaturePanel(String id, String fmName, IModel indicatorModel, + IModel locationModel) { super(id, fmName, true); this.indicatorModel = indicatorModel; logger.info("Initializing AmpMEDisaggregationValuesFeaturePanel for indicator: " + (indicatorModel.getObject() != null ? indicatorModel.getObject().getName() : "null")); @@ -150,7 +152,7 @@ protected void populateItem(ListItem childItem) actualValuesContainer.setOutputMarkupId(true); childItem.add(actualValuesContainer); - AmpMEDisaggregationActualValuesPanel actualPanel = new AmpMEDisaggregationActualValuesPanel("actualValuesPanel", Model.of(disaggVal)); + AmpMEDisaggregationActualValuesPanel actualPanel = new AmpMEDisaggregationActualValuesPanel("actualValuesPanel", Model.of(disaggVal), locationModel); actualPanel.setOutputMarkupId(true); actualPanel.setOutputMarkupPlaceholderTag(true); actualValuesContainer.add(actualPanel); @@ -170,4 +172,8 @@ protected void onEvent(AjaxRequestTarget target) { parentList.setOutputMarkupId(true); add(parentList); } + + public AmpMEDisaggregationValuesFeaturePanel(String id, String fmName, IModel indicatorModel) { + this(id, fmName, indicatorModel, null); + } } diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java index 90b6063957f..80637a646a0 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java @@ -188,13 +188,19 @@ protected void onConfigure() { AmpMEIndicatorBaseFeaturePanel baseValues = null; try { - baseValues = new AmpMEIndicatorBaseFeaturePanel("addBaseTargetValue", "Add Base Target Values", conn, indicator, values, location); + baseValues = new AmpMEIndicatorBaseFeaturePanel("addBaseTargetValue", "Add Base Target Values", conn, indicator, values, location) { + @Override + protected void onConfigure() { + super.onConfigure(); + setVisible(isVisible() && !hasDisaggregation); + } + }; } catch (Exception e) { throw new RuntimeException(e); } add(baseValues); - AmpMEDisaggregationValuesFeaturePanel disaggPanel = new AmpMEDisaggregationValuesFeaturePanel("disaggregationValuesSubsection", "Disaggregation Values", indicator); + AmpMEDisaggregationValuesFeaturePanel disaggPanel = new AmpMEDisaggregationValuesFeaturePanel("disaggregationValuesSubsection", "Disaggregation Values", indicator, location); disaggPanel.setOutputMarkupId(true); disaggPanel.setVisible(hasDisaggregation); add(disaggPanel); diff --git a/amp/src/main/java/org/digijava/kernel/ampapi/endpoints/activity/ActivityInterchangeUtils.java b/amp/src/main/java/org/digijava/kernel/ampapi/endpoints/activity/ActivityInterchangeUtils.java index f4b967f5eed..2761d873f04 100644 --- a/amp/src/main/java/org/digijava/kernel/ampapi/endpoints/activity/ActivityInterchangeUtils.java +++ b/amp/src/main/java/org/digijava/kernel/ampapi/endpoints/activity/ActivityInterchangeUtils.java @@ -362,6 +362,10 @@ private static void addDisaggregationValues(Optional indicatorsObject) { indicator.put("disaggregation_values", Collections.emptyList()); continue; } + Object rawLocId = indicator.get("activity_location"); + Long activityLocationId = rawLocId != null + ? (rawLocId instanceof Long ? (Long) rawLocId : Long.valueOf(rawLocId.toString())) + : null; List> disaggList = new ArrayList<>(); for (AmpIndicatorDisaggregationValue dv : ampIndicator.getDisaggregationValues()) { Map dvMap = new LinkedHashMap<>(); @@ -379,6 +383,15 @@ private static void addDisaggregationValues(Optional indicatorsObject) { List> actualValues = new ArrayList<>(); if (dv.getActualValues() != null) { for (AmpIndicatorGlobalValue av : dv.getActualValues()) { + AmpActivityLocation avLocation = av.getActivityLocation(); + if (activityLocationId != null) { + Long avLocationId = avLocation != null ? avLocation.getId() : null; + if (!activityLocationId.equals(avLocationId)) { + continue; + } + } else if (avLocation != null) { + continue; + } actualValues.add(serializeGlobalValue(av)); } } diff --git a/amp/src/main/java/org/digijava/module/aim/dbentity/AmpIndicatorGlobalValue.java b/amp/src/main/java/org/digijava/module/aim/dbentity/AmpIndicatorGlobalValue.java index 172bee11ccf..d8c18962533 100644 --- a/amp/src/main/java/org/digijava/module/aim/dbentity/AmpIndicatorGlobalValue.java +++ b/amp/src/main/java/org/digijava/module/aim/dbentity/AmpIndicatorGlobalValue.java @@ -62,6 +62,9 @@ public class AmpIndicatorGlobalValue implements Serializable { @JsonIgnore private AmpIndicator indicator; + @JsonIgnore + private AmpActivityLocation activityLocation; + public AmpIndicatorGlobalValue() { } @@ -93,6 +96,14 @@ public void setIndicator(AmpIndicator indicator) { this.indicator = indicator; } + public AmpActivityLocation getActivityLocation() { + return activityLocation; + } + + public void setActivityLocation(AmpActivityLocation activityLocation) { + this.activityLocation = activityLocation; + } + public Double getOriginalValue() { return originalValue; } @@ -152,6 +163,7 @@ public void copyValuesTo(AmpIndicatorGlobalValue r) { r.setOriginalValueDate(originalValueDate); r.setRevisedValue(revisedValue); r.setRevisedValueDate(revisedValueDate); + r.setActivityLocation(activityLocation); r.setId(id); } } diff --git a/amp/src/main/resources/org/digijava/module/aim/dbentity/AmpIndicatorGlobalValue.hbm.xml b/amp/src/main/resources/org/digijava/module/aim/dbentity/AmpIndicatorGlobalValue.hbm.xml index fe5d2dfe03e..69a589c15d4 100644 --- a/amp/src/main/resources/org/digijava/module/aim/dbentity/AmpIndicatorGlobalValue.hbm.xml +++ b/amp/src/main/resources/org/digijava/module/aim/dbentity/AmpIndicatorGlobalValue.hbm.xml @@ -12,6 +12,9 @@ + + From de39609056fa83c39c487a08179a15f9494820e3 Mon Sep 17 00:00:00 2001 From: brianbrix Date: Fri, 19 Jun 2026 15:59:49 +0300 Subject: [PATCH 17/17] AMP-31133 : Multicountry ME not separating disaggregated values --- .../dgfoundation/amp/onepager/components/ListEditor.java | 6 ++++++ .../features/items/AmpMEIndicatorFeaturePanel.java | 9 ++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/ListEditor.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/ListEditor.java index a5b8b5d7485..977f7803d93 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/ListEditor.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/ListEditor.java @@ -72,6 +72,12 @@ protected final void onBeforeRender(){ @Override public void updateModel(){ + // items is transient — it is null after page deserialization (e.g. on form submit). + // In that case re-populate from the model so we don't wipe the backing collection. + if (items == null) { + Set current = model.getObject(); + items = current != null ? new ArrayList(current) : new ArrayList(); + } Set set = model.getObject(); if (set == null) set = new LinkedHashSet(); diff --git a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java index 80637a646a0..5d545ef8dc3 100644 --- a/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java +++ b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEIndicatorFeaturePanel.java @@ -151,8 +151,6 @@ protected void onConfigure() { - logger.info("Table" + valuesTable.getMarkupId()); - logger.info("Id " + valuesTable.getId()); AmpAjaxLinkField addActualValue = new AmpAjaxLinkField("addActualValue", "Add Actual Value", "Add Actual Value") { @Override public void onClick(AjaxRequestTarget target) { @@ -174,15 +172,12 @@ protected void onConfigure() { }; - logger.info("Button" + addActualValue.getMarkupId()); - logger.info("Id " + addActualValue.getId()); + addActualValue.setOutputMarkupId(true); addActualValue.setOutputMarkupPlaceholderTag(true); add(addActualValue); - logger.info("Has disaggregation: " + hasDisaggregation); - logger.info("Button visble" + addActualValue.isVisible()); - logger.info("Table visble" + valuesTable.isVisible()); + AmpMEIndicatorBaseFeaturePanel baseValues = null;