Skip to content

Commit

Permalink
Solve different issues wrt M_Transaction handling
Browse files Browse the repository at this point in the history
* M_Transactions's ASIs are not "reliable" for storage, so we now gather the attributes of our associated HUs
* M_Transaction deletes are now handled too
* also rename HUOnHandQtyChangeDescriptor to HUDescriptor since it now also contains a ProductDescriptor
* also minor improvements (javadoc, other cleanups) here and there

Material Dispo wrong Quantities after Material receipt #3935
  • Loading branch information
metas-ts committed Apr 25, 2018
1 parent f0f2da4 commit d10813e
Show file tree
Hide file tree
Showing 25 changed files with 785 additions and 412 deletions.
Expand Up @@ -31,10 +31,10 @@
import org.compiere.model.I_M_Attribute;

/**
* To get an instance from an attribute set instance, one can use in a storage context.
* Goal of this interface: get an instance from an attribute set instance, one can use in a storage context.
*
* @see ImmutableAttributeSet
* @author metas-dev <dev@metasfresh.com>
*
*/
public interface IAttributeSet
{
Expand Down Expand Up @@ -86,7 +86,7 @@ public interface IAttributeSet
int getValueAsInt(I_M_Attribute attribute);

Date getValueAsDate(I_M_Attribute attribute);

String getValueAsString(I_M_Attribute attribute);

/**
Expand Down
Expand Up @@ -8,6 +8,7 @@
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Predicate;

import javax.annotation.Nullable;

Expand Down Expand Up @@ -79,15 +80,15 @@ public static final ImmutableAttributeSet ofValuesIndexByAttributeId(
return new ImmutableAttributeSet(attributes.build(), valuesByAttributeId.build());
}

public static ImmutableAttributeSet copyOf(final IAttributeSet attributeSet)
public static ImmutableAttributeSet createSubSet(
@NonNull final IAttributeSet attributeSet,
@NonNull final Predicate<I_M_Attribute> filter)
{
if (attributeSet instanceof ImmutableAttributeSet)
{
return (ImmutableAttributeSet)attributeSet;
}

final Builder builder = builder();
attributeSet.getAttributes()
.stream()
.filter(filter)
.forEach(attribute -> {
final Object value = attributeSet.getValue(attribute);
builder.attributeValue(attribute, value);
Expand Down
Expand Up @@ -130,10 +130,8 @@ public I_M_AttributeValue retrieveAttributeValueOrNull(final I_M_Attribute attri
}

@Override
public boolean isHighVolumeValuesList(final I_M_Attribute attribute)
public boolean isHighVolumeValuesList(@NonNull final I_M_Attribute attribute)
{
Check.assumeNotNull(attribute, "attribute not null");

if (!X_M_Attribute.ATTRIBUTEVALUETYPE_List.equals(attribute.getAttributeValueType()))
{
return false;
Expand All @@ -149,7 +147,7 @@ public List<I_M_AttributeInstance> retrieveAttributeInstances(final I_M_Attribut
{
return ImmutableList.of();
}

final Properties ctx = InterfaceWrapperHelper.getCtx(attributeSetInstance);
final String trxName = InterfaceWrapperHelper.getTrxName(attributeSetInstance);
final int asiId = attributeSetInstance.getM_AttributeSetInstance_ID();
Expand Down
Expand Up @@ -10,12 +10,12 @@
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of the
* License, or (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-2.0.html>.
Expand All @@ -40,12 +40,6 @@
import de.metas.handlingunits.attribute.strategy.IHUAttributeTransferStrategy;
import de.metas.handlingunits.model.X_M_HU_PI_Attribute;

/**
* Defines an {@link I_M_Attribute} - Value pair
*
* @author tsa
*
*/
public interface IAttributeValue
{
/**
Expand Down Expand Up @@ -217,7 +211,7 @@ public interface IAttributeValue
boolean isUseInASI();

/**
*
*
* @return
* <ul>
* <li>true if this attribute was defined by the standard template
Expand Down
Expand Up @@ -51,18 +51,13 @@

/**
* Defines a Attribute Storage pool. Use e.g. {@link IAttributeStorageFactory#getAttributeStorage(Object)} do get an instance.
*
* @author tsa
*
*/
public interface IAttributeStorage extends IAttributeSet
{
/**
* Get's storage unique identifier.
*
* This identifier is used to uniquely identify an {@link IAttributeStorage} in children {@link IAttributeStorage} collection (internally).
*
* @return ID
*/
String getId();

Expand Down Expand Up @@ -191,7 +186,7 @@ public interface IAttributeStorage extends IAttributeSet
* @return true if given attribute is readonly for user
*/
boolean isReadonlyUI(final IAttributeValueContext ctx, I_M_Attribute attribute);

boolean isDisplayedUI(final I_M_Attribute attribute);

/**
Expand Down Expand Up @@ -323,7 +318,7 @@ public interface IAttributeStorage extends IAttributeSet

/**
* Enables/Disables automatic saving when an attribute value is changed
*
*
* @param saveOnChange
* @throws UnsupportedOperationException in case the operation is not supported
*/
Expand Down
@@ -0,0 +1,164 @@
package de.metas.handlingunits.material.interceptor;

import java.math.BigDecimal;
import java.util.List;

import org.adempiere.mm.attributes.api.AttributesKeys;
import org.adempiere.mm.attributes.api.IAttributeSet;
import org.adempiere.mm.attributes.api.IAttributeSetInstanceBL;
import org.adempiere.mm.attributes.api.ImmutableAttributeSet;
import org.adempiere.util.Services;
import org.adempiere.util.lang.IPair;
import org.adempiere.util.lang.ImmutablePair;
import org.compiere.model.I_M_Attribute;
import org.compiere.model.I_M_AttributeSetInstance;
import org.compiere.model.I_M_InOutLine;
import org.compiere.model.I_M_InventoryLine;
import org.compiere.model.I_M_MovementLine;
import org.eevolution.model.I_PP_Cost_Collector;

import com.google.common.collect.ImmutableList;

import de.metas.handlingunits.IHUAssignmentDAO;
import de.metas.handlingunits.IHUAssignmentDAO.HuAssignment;
import de.metas.handlingunits.IHUContextFactory;
import de.metas.handlingunits.IMutableHUContext;
import de.metas.handlingunits.attribute.storage.IAttributeStorage;
import de.metas.handlingunits.model.I_M_HU;
import de.metas.handlingunits.storage.IHUProductStorage;
import de.metas.handlingunits.storage.IHUStorage;
import de.metas.material.event.commons.AttributesKey;
import de.metas.material.event.commons.HUDescriptor;
import de.metas.material.event.commons.HUDescriptor.HUDescriptorBuilder;
import de.metas.material.event.commons.ProductDescriptor;
import lombok.NonNull;

/*
* #%L
* de.metas.handlingunits.base
* %%
* Copyright (C) 2018 metas GmbH
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-2.0.html>.
* #L%
*/

public class M_Transaction_HuDescriptor
{
public static final M_Transaction_HuDescriptor INSTANCE = new M_Transaction_HuDescriptor();

private M_Transaction_HuDescriptor()
{
}

public ImmutableList<HUDescriptor> createHuDescriptorsForInOutLine(
@NonNull final I_M_InOutLine inOutLine,
final boolean deleted)
{
return createHUDescriptorsForModel(inOutLine, deleted);
}

public ImmutableList<HUDescriptor> createHuDescriptorsForCostCollector(
@NonNull final I_PP_Cost_Collector costCollector,
final boolean deleted)
{
return createHUDescriptorsForModel(costCollector, deleted);
}

public ImmutableList<HUDescriptor> createHuDescriptorsForMovementLine(
@NonNull final I_M_MovementLine movementLine,
final boolean deleted)
{
return createHUDescriptorsForModel(movementLine, deleted);
}

public ImmutableList<HUDescriptor> createHuDescriptorsForInventoryLine(
@NonNull final I_M_InventoryLine inventoryLine,
final boolean deleted)
{
return createHUDescriptorsForModel(inventoryLine, deleted);
}

private static ImmutableList<HUDescriptor> createHUDescriptorsForModel(
@NonNull final Object huReferencedModel,
final boolean deleted)
{
final IHUAssignmentDAO huAssignmentDAO = Services.get(IHUAssignmentDAO.class);
final List<HuAssignment> huAssignments = huAssignmentDAO
.retrieveHUAssignmentPojosForModel(huReferencedModel);

final ImmutableList.Builder<HUDescriptor> result = ImmutableList.builder();
for (final HuAssignment huAssignment : huAssignments)
{
result.addAll(createHuDescriptors(huAssignment.getLowestLevelHU(), deleted));
}

return result.build();
}

private static ImmutableList<HUDescriptor> createHuDescriptors(
@NonNull final I_M_HU hu,
final boolean deleted)
{
final HUDescriptorBuilder builder = HUDescriptor.builder()
.huId(hu.getM_HU_ID());

final IMutableHUContext huContext = Services.get(IHUContextFactory.class).createMutableHUContext();
final IHUStorage storage = huContext.getHUStorageFactory().getStorage(hu);

// note that we could have the AttributesKey without making an ASI, but we need the ASI-ID for display reasons in the material dispo window.
final IPair<AttributesKey, Integer> attributesKeyAndAsiId = createAttributesKeyAndAsiId(hu);

final List<IHUProductStorage> productStorages = storage.getProductStorages();
final ImmutableList.Builder<HUDescriptor> descriptors = ImmutableList.builder();
for (final IHUProductStorage productStorage : productStorages)
{
final ProductDescriptor productDescriptor = ProductDescriptor
.forProductAndAttributes(
productStorage.getM_Product_ID(),
attributesKeyAndAsiId.getLeft(),
attributesKeyAndAsiId.getRight());

final BigDecimal quantity = productStorage.getQtyInStockingUOM();

final HUDescriptor descriptor = builder
.productDescriptor(productDescriptor)
.quantity(deleted ? BigDecimal.ZERO : quantity)
.quantityDelta(deleted ? quantity.negate() : quantity)
.build();
descriptors.add(descriptor);
}
return descriptors.build();
}

private static IPair<AttributesKey, Integer> createAttributesKeyAndAsiId(@NonNull final I_M_HU hu)
{
final IMutableHUContext huContext = Services.get(IHUContextFactory.class).createMutableHUContext();
final IAttributeStorage attributeStorage = huContext.getHUAttributeStorageFactory().getAttributeStorage(hu);

// we don't want all the non-storage-relevant attributes to pollute the ASI we will display in the material disposition window
final IAttributeSet storageRelevantSubSet = ImmutableAttributeSet.createSubSet(attributeStorage, I_M_Attribute::isStorageRelevant);

final IAttributeSetInstanceBL attributeSetInstanceBL = Services.get(IAttributeSetInstanceBL.class);
final I_M_AttributeSetInstance asi = attributeSetInstanceBL.createASIFromAttributeSet(storageRelevantSubSet);

final AttributesKey attributesKey = AttributesKeys
.createAttributesKeyFromASIStorageAttributes(asi.getM_AttributeSetInstance_ID())
.orElse(AttributesKey.NONE);

return ImmutablePair.of(attributesKey, asi.getM_AttributeSetInstance_ID());
}

}

0 comments on commit d10813e

Please sign in to comment.