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/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/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/AmpMEDisaggregationActualValuesPanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationActualValuesPanel.java index 4314196fa0f..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 @@ -1,23 +1,27 @@ 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.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; +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.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 org.dgfoundation.amp.onepager.converters.CustomDoubleConverter; -import java.util.*; +import java.util.Date; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; /** * Panel rendering and editing ACTUAL values (AmpIndicatorGlobalValue entries with type ACTUAL) @@ -25,31 +29,33 @@ */ public class AmpMEDisaggregationActualValuesPanel extends AmpFeaturePanel { - private final ListView listView; + private final ListEditor listEditor; - public AmpMEDisaggregationActualValuesPanel(String id, IModel model) { + public AmpMEDisaggregationActualValuesPanel(String id, IModel model, + IModel location) { super(id, model, "Disaggregation Actual Values", true); setOutputMarkupId(true); - // Use a List model for ListView (was Set, causing type mismatch) - IModel> listModel = new LoadableDetachableModel>() { + // ListEditor.updateModel() writes submitted rows back into this backing set. + IModel> parentModel = new PropertyModel<>(model, "actualValues"); + IModel> setModel = new AbstractMixedSetModel(parentModel) { @Override - protected List load() { - AmpIndicatorDisaggregationValue disagg = AmpMEDisaggregationActualValuesPanel.this.getModel().getObject(); - if (disagg.getActualValues() == null) { - disagg.setActualValues(new java.util.HashSet<>()); + public boolean condition(AmpIndicatorGlobalValue item) { + AmpActivityLocation currentLocation = location != null ? location.getObject() : null; + if (currentLocation == null) { + return item.getActivityLocation() == null; } - return new java.util.ArrayList<>(disagg.getActualValues()); + return item.getActivityLocation() != null + && Objects.equals(item.getActivityLocation().getId(), currentLocation.getId()); } }; - listView = new ListView("rows", listModel) { + listEditor = new ListEditor("rows", setModel) { @Override - protected void populateItem(ListItem item) { - AmpIndicatorGlobalValue val = item.getModelObject(); + protected void onPopulateItem(ListItem 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; } }); @@ -57,27 +63,32 @@ 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); + listEditor.setOutputMarkupId(true); + add(listEditor); AmpAjaxLinkField addActual = new AmpAjaxLinkField("addDisaggActualValue", "Add Actual Value", "Add Actual Value") { @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 java.util.HashSet<>()); + disaggVal.setActualValues(new HashSet<>()); } AmpIndicatorGlobalValue val = new AmpIndicatorGlobalValue(AmpIndicatorGlobalValue.ACTUAL); val.setIndicator(disaggVal.getIndicator()); + if (location != null) { + val.setActivityLocation(location.getObject()); + } 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/components/features/items/AmpMEDisaggregationValuesFeaturePanel.java b/amp/src/main/java/org/dgfoundation/amp/onepager/components/features/items/AmpMEDisaggregationValuesFeaturePanel.java index b59593c6038..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 @@ -10,9 +10,9 @@ 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.AmpActivityLocation; import org.digijava.module.aim.dbentity.AmpIndicator; import org.digijava.module.aim.dbentity.AmpIndicatorDisaggregationValue; import org.digijava.module.aim.dbentity.AmpIndicatorGlobalValue; @@ -35,12 +35,14 @@ public class AmpMEDisaggregationValuesFeaturePanel extends AmpFeaturePanel 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 20d45c50cd3..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 @@ -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; @@ -49,8 +48,10 @@ public AmpMEIndicatorFeaturePanel(String id, String fmName, final IModel(indicator, "name")); add(indicatorNameLabel); - final boolean hasDisaggregation = indicator.getObject().getDisaggregation() != null - && !indicator.getObject().getDisaggregation().isEmpty(); + 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) { @@ -70,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); @@ -137,15 +138,19 @@ 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); add(valuesTable); - 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) { @@ -158,32 +163,41 @@ public void onClick(AjaxRequestTarget target) { target.add(valuesTable); target.appendJavaScript(QuarterInformationPanel.getJSUpdate(getSession())); } + + @Override + protected void onConfigure() { + super.onConfigure(); + setVisible(isVisible() && !hasDisaggregation); + } }; - logger.info("Button" + addActualValue.getMarkupId()); - logger.info("Id " + addActualValue.getId()); + addActualValue.setOutputMarkupId(true); addActualValue.setOutputMarkupPlaceholderTag(true); add(addActualValue); + + 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 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/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()); } }; 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/dgfoundation/amp/onepager/util/ActivityUtil.java b/amp/src/main/java/org/dgfoundation/amp/onepager/util/ActivityUtil.java index dce0a8c1061..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 @@ -245,7 +245,13 @@ 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()); + 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 +300,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 +332,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); @@ -337,6 +354,47 @@ public static AmpActivityVersion saveActivityNewVersion(AmpActivityVersion a, return a; } + + private static void saveIndicatorDisaggregationActualValues(AmpActivityVersion activity, Session session) { + if (activity.getIndicators() == null) { + 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) { + continue; + } + + 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); + } + // Use merge instead of saveOrUpdate to handle detached objects safely + session.merge(disaggregationValue); + } + } + + if (hasDisaggregationValues) { + session.flush(); + } + } + private static void cleanObjectFromSession(Session session, Class objectClass, Long id) { T object = session.get(objectClass, id); 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..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)); } } @@ -432,19 +445,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); 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/java/org/digijava/module/aim/dbentity/IndicatorActivity.java b/amp/src/main/java/org/digijava/module/aim/dbentity/IndicatorActivity.java index 09a1a173715..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 @@ -142,12 +142,37 @@ public Object prepareMerge(AmpActivityVersion newActivity) throws CloneNotSuppor aux.activity = newActivity; aux.setId(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.setActivityLocation(newLoc); + break; + } + } + } + } + if (aux.values != null && aux.values.size() > 0){ HashSet set = new HashSet(); for (AmpIndicatorValue value : aux.values) { AmpIndicatorValue ampIndicatorValue = (AmpIndicatorValue) value.clone(); ampIndicatorValue.setIndValId(null); ampIndicatorValue.setIndicatorConnection(aux); + 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; 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 @@ + +