RFQAllocationCalculation.java
package com.tradecloud.domain.model.requestforquote;
import com.tradecloud.domain.base.utils.MathUtils;
import org.apache.commons.collections.map.HashedMap;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
public class RFQAllocationCalculation {
// private final BigDecimal totalSupplied;
private final RFQStyle rfqStyle;
private final List<RFQProduct> awardedProducts = new ArrayList<>();
private final Map<Long, BigDecimal> awardPerSupplierId = new HashedMap();
private final List<RFQProduct> suppliedProducts;
private BigDecimal allocationMaxValue;
private BigDecimal totalAwarded = BigDecimal.ZERO;
private final List<BigDecimal> percentRules;
public RFQAllocationCalculation(RFQStyle rfqStyle, List<RFQProduct> suppliedProducts, List<BigDecimal> percentRule) {
this.rfqStyle = rfqStyle;
this.suppliedProducts = suppliedProducts;
suppliedProducts.sort(Comparator.comparing(RFQProduct::getPrice).thenComparing(RFQProduct::getPosition));
this.percentRules = percentRule;
}
private void setPercentRule(BigDecimal percentRule) {
if(isStyleQuantity()) {
allocationMaxValue = rfqStyle.getQuantity().multiply(MathUtils.toPercent(percentRule));
allocationMaxValue = BigDecimal.valueOf(Math.min(allocationMaxValue.doubleValue(), rfqStyle.getQuantity()
.subtract(totalAwarded).doubleValue()));
}
}
private void generateAwards() {
for (RFQProduct suppliedProduct : suppliedProducts) {
if(!isStyleQuantity()){
if(suppliedProduct.getQuantitySupplied()!=null && suppliedProduct.getQuantitySupplied().intValue()>0) {
suppliedProduct.setAwardedQuantity(suppliedProduct.getQuantitySupplied());
awardedProducts.add(suppliedProduct);
}
continue;
}
if (allocationMaxValue.doubleValue() > 0
&& isSupplierNotFullyAwardedBaseOnPercentageRule(suppliedProduct)
&& productQuantityNotFullyAwarded(suppliedProduct)) {
BigDecimal reamingQuantitySupplied = suppliedProduct.getReamingQuantitySupplied();
if (reamingQuantitySupplied.doubleValue() <= allocationMaxValue.doubleValue()) {
suppliedProduct.setAwardedQuantity(suppliedProduct.getAwardedQuantity().add(reamingQuantitySupplied));
allocationMaxValue = allocationMaxValue.subtract(reamingQuantitySupplied);
totalAwarded = totalAwarded.add(reamingQuantitySupplied);
} else {
suppliedProduct.setAwardedQuantity(suppliedProduct.getAwardedQuantity().add(allocationMaxValue));
totalAwarded = totalAwarded.add(allocationMaxValue);
allocationMaxValue = BigDecimal.ZERO;
}
if (!awardPerSupplierId.containsKey(suppliedProduct.getSupplierStyle().getRfqOrganisationalUnitSupplier().getId())) {
awardPerSupplierId.computeIfAbsent(suppliedProduct.getSupplierStyle().getRfqOrganisationalUnitSupplier().getId(),
rfqOrganisationalUnitSupplier -> suppliedProduct.getAwardedQuantity());
} else {
awardPerSupplierId.computeIfPresent(suppliedProduct.getSupplierStyle().getRfqOrganisationalUnitSupplier().getId(),
(rfqOrganisationalUnitSupplier, awarded) -> awarded.add(suppliedProduct.getAwardedQuantity()));
}
addAwardedProduct(suppliedProduct);
}
}
}
private boolean isStyleQuantity() {
return rfqStyle.getQuantity() != null && rfqStyle.getQuantity().doubleValue() > 0;
}
private boolean productQuantityNotFullyAwarded(RFQProduct suppliedProduct) {
return suppliedProduct.getReamingQuantitySupplied().doubleValue() > 0;
}
private double getNotRewardedQuantity(RFQProduct suppliedProduct) {
return suppliedProduct.getQuantitySupplied().doubleValue() - suppliedProduct.getAwardedQuantity().doubleValue();
}
private boolean isSupplierNotFullyAwardedBaseOnPercentageRule(RFQProduct suppliedProduct) {
BigDecimal award = awardPerSupplierId.get(suppliedProduct.getSupplierStyle().getRfqOrganisationalUnitSupplier().getId());
return award == null || award.doubleValue() < allocationMaxValue.doubleValue();
}
public List<RFQProduct> getAwardedProductsBasedOnRule() {
if(!isStyleQuantity()){
generateAwards();
return awardedProducts;
}
for (BigDecimal rule : percentRules) {
setPercentRule(rule);
generateAwards();
}
BigDecimal styleNotAwarded = getStyleNotAwarded();
if (styleNotAwarded.doubleValue() > 0) {
assignStyleNotAwarded(styleNotAwarded);
}
return awardedProducts;
}
public BigDecimal getStyleNotAwarded() {
return rfqStyle.getQuantity().subtract(totalAwarded);
}
private void assignStyleNotAwarded(BigDecimal styleNotAwarded) {
for (RFQProduct suppliedProduct : suppliedProducts) {
double notRewardedQuanity = getNotRewardedQuantity(suppliedProduct);
if (notRewardedQuanity > 0 && notRewardedQuanity >= styleNotAwarded.doubleValue()) {
suppliedProduct.setAwardedQuantity(suppliedProduct.getAwardedQuantity().add(styleNotAwarded));
totalAwarded = totalAwarded.add(styleNotAwarded);
addAwardedProduct(suppliedProduct);
styleNotAwarded = BigDecimal.ZERO;
} else if (notRewardedQuanity > 0 && notRewardedQuanity < styleNotAwarded.doubleValue()) {
BigDecimal notRewarded = BigDecimal.valueOf(notRewardedQuanity);
suppliedProduct.setAwardedQuantity(suppliedProduct.getAwardedQuantity().add(notRewarded));
styleNotAwarded = styleNotAwarded.subtract(notRewarded);
totalAwarded = totalAwarded.add(notRewarded);
addAwardedProduct(suppliedProduct);
}
}
}
private void addAwardedProduct(RFQProduct rfqProduct) {
if (totalAwarded.doubleValue() > rfqStyle.getQuantity().doubleValue()) {
throw new IllegalStateException(String.format("Awarding of %s cannot exceed Style Quantity of %s"
, totalAwarded, rfqStyle.getQuantity()));
}
if (!awardedProducts.contains(rfqProduct)) {
awardedProducts.add(rfqProduct);
}
}
}