use of org.compiere.model.MOrderLine in project adempiere by adempiere.
the class PromotionRule method applyPromotions.
public static void applyPromotions(MOrder order) throws Exception {
//key = C_OrderLine, value = Qty to distribution
Map<Integer, BigDecimal> orderLineQty = new LinkedHashMap<Integer, BigDecimal>();
Map<Integer, MOrderLine> orderLineIndex = new HashMap<Integer, MOrderLine>();
MOrderLine[] lines = order.getLines();
boolean hasDeleteLine = false;
for (MOrderLine ol : lines) {
if (ol.getM_Product_ID() > 0) {
if (ol.getQtyOrdered().signum() > 0) {
orderLineQty.put(ol.getC_OrderLine_ID(), ol.getQtyOrdered());
orderLineIndex.put(ol.getC_OrderLine_ID(), ol);
}
} else if (ol.getC_Charge_ID() > 0) {
Number id = (Number) ol.get_Value("M_Promotion_ID");
if (id != null && id.intValue() > 0) {
ol.delete(false);
hasDeleteLine = true;
}
}
}
if (orderLineQty.isEmpty())
return;
//refresh order
if (hasDeleteLine) {
order.getLines(true, null);
order.getTaxes(true);
order.setGrandTotal(DB.getSQLValueBD(order.get_TrxName(), "SELECT GrandTotal From C_Order WHERE C_Order_ID = ?", order.getC_Order_ID()));
}
Map<Integer, List<Integer>> promotions = PromotionRule.findM_Promotion_ID(order);
if (promotions == null || promotions.isEmpty())
return;
BigDecimal orderAmount = order.getGrandTotal();
//key = M_PromotionDistribution_ID, value = C_OrderLine_ID and Qty
Map<Integer, DistributionSet> distributions = new LinkedHashMap<Integer, DistributionSet>();
//<M_PromotionDistribution_ID, DistributionSorting>
Map<Integer, String> sortingType = new HashMap<Integer, String>();
OrderLineComparator olComparator = new OrderLineComparator(orderLineIndex);
//distribute order lines
for (Map.Entry<Integer, List<Integer>> entry : promotions.entrySet()) {
Query query = new Query(Env.getCtx(), MTable.get(order.getCtx(), I_M_PromotionDistribution.Table_ID), "M_PromotionDistribution.M_Promotion_ID = ? AND M_PromotionDistribution.IsActive = 'Y'", order.get_TrxName());
query.setParameters(new Object[] { entry.getKey() });
query.setOrderBy("SeqNo");
List<MPromotionDistribution> list = query.<MPromotionDistribution>list();
Query rewardQuery = new Query(Env.getCtx(), MTable.get(order.getCtx(), I_M_PromotionReward.Table_ID), "M_PromotionReward.M_Promotion_ID = ? AND M_PromotionReward.IsActive = 'Y'", order.get_TrxName());
rewardQuery.setParameters(new Object[] { entry.getKey() });
rewardQuery.setOrderBy("SeqNo");
List<MPromotionReward> rewardList = rewardQuery.<MPromotionReward>list();
List<MPromotionLine> promotionLines = new ArrayList<MPromotionLine>();
for (Integer M_PromotionLine_ID : entry.getValue()) {
MPromotionLine promotionLine = new MPromotionLine(order.getCtx(), M_PromotionLine_ID, order.get_TrxName());
promotionLines.add(promotionLine);
}
while (true) {
boolean hasDistributionSet = false;
Set<Integer> promotionLineSet = new HashSet<Integer>();
Set<Integer> mandatoryLineSet = new HashSet<Integer>();
boolean mandatoryLineNotFound = false;
List<Integer> validPromotionLineIDs = new ArrayList<Integer>();
for (MPromotionLine promotionLine : promotionLines) {
if (promotionLine.getM_PromotionGroup_ID() == 0 && promotionLine.getMinimumAmt() != null && promotionLine.getMinimumAmt().signum() >= 0) {
if (orderAmount.compareTo(promotionLine.getMinimumAmt()) >= 0) {
orderAmount = orderAmount.subtract(promotionLine.getMinimumAmt());
validPromotionLineIDs.add(promotionLine.getM_PromotionLine_ID());
} else if (promotionLine.isMandatoryPL()) {
mandatoryLineNotFound = true;
break;
}
}
}
if (mandatoryLineNotFound) {
break;
}
for (MPromotionDistribution pd : list) {
if (entry.getValue().contains(pd.getM_PromotionLine_ID())) {
//sort available orderline base on distribution sorting type
List<Integer> orderLineIdList = new ArrayList<Integer>();
orderLineIdList.addAll(orderLineQty.keySet());
if (pd.getDistributionSorting() != null) {
Comparator<Integer> cmp = olComparator;
if (pd.getDistributionSorting().equals(MPromotionDistribution.DISTRIBUTIONSORTING_Descending))
cmp = Collections.reverseOrder(cmp);
Collections.sort(orderLineIdList, cmp);
}
DistributionSet prevSet = distributions.get(pd.getM_PromotionDistribution_ID());
DistributionSet distributionSet = PromotionRule.calculateDistributionQty(pd, prevSet, validPromotionLineIDs, orderLineQty, orderLineIdList, order.get_TrxName());
if (distributionSet != null && distributionSet.setQty.signum() > 0) {
hasDistributionSet = true;
promotionLineSet.add(pd.getM_PromotionLine_ID());
} else {
if (pd.getM_PromotionLine().isMandatoryPL()) {
mandatoryLineSet.add(pd.getM_PromotionLine_ID());
}
}
distributions.put(pd.getM_PromotionDistribution_ID(), distributionSet);
sortingType.put(pd.getM_PromotionDistribution_ID(), pd.getDistributionSorting());
}
}
if (!hasDistributionSet)
break;
if (mandatoryLineSet != null) {
mandatoryLineNotFound = false;
for (Integer id : mandatoryLineSet) {
if (!promotionLineSet.contains(id)) {
mandatoryLineNotFound = true;
break;
}
}
if (mandatoryLineNotFound) {
break;
}
}
for (MPromotionReward pr : rewardList) {
if (pr.isForAllDistribution()) {
Collection<DistributionSet> all = distributions.values();
BigDecimal totalPrice = BigDecimal.ZERO;
for (DistributionSet distributionSet : all) {
for (Map.Entry<Integer, BigDecimal> olMap : distributionSet.orderLines.entrySet()) {
BigDecimal qty = (BigDecimal) olMap.getValue();
int C_OrderLine_ID = (Integer) olMap.getKey();
for (MOrderLine ol : lines) {
if (ol.getC_OrderLine_ID() == C_OrderLine_ID) {
totalPrice = totalPrice.add(ol.getPriceActual().multiply(qty));
break;
}
}
distributionSet.orderLines.put(olMap.getKey(), BigDecimal.ZERO);
}
}
BigDecimal discount = BigDecimal.ZERO;
if (pr.getRewardType().equals(MPromotionReward.REWARDTYPE_AbsoluteAmount)) {
if (pr.getAmount().compareTo(totalPrice) < 0) {
discount = totalPrice.subtract(pr.getAmount());
}
} else if (pr.getRewardType().equals(MPromotionReward.REWARDTYPE_FlatDiscount)) {
discount = pr.getAmount();
} else if (pr.getRewardType().equals(MPromotionReward.REWARDTYPE_Percentage)) {
discount = pr.getAmount().divide(BigDecimal.valueOf(100.00)).multiply(totalPrice);
}
if (discount.signum() > 0) {
addDiscountLine(order, null, discount, BigDecimal.valueOf(1.00), pr.getC_Charge_ID(), pr.getM_Promotion());
}
} else {
int M_PromotionDistribution_ID = pr.getM_PromotionDistribution_ID();
if (!distributions.containsKey(M_PromotionDistribution_ID))
continue;
int targetDistributionID = M_PromotionDistribution_ID;
if (!pr.isSameDistribution()) {
targetDistributionID = pr.getM_TargetDistribution_ID();
if (!distributions.containsKey(targetDistributionID))
continue;
}
DistributionSet distributionSet = distributions.get(targetDistributionID);
//sort by reward distribution sorting
if (pr.getDistributionSorting() != null) {
Comparator<Integer> cmp = new OrderLineComparator(orderLineIndex);
if (pr.getDistributionSorting().equals(MPromotionReward.DISTRIBUTIONSORTING_Descending))
cmp = Collections.reverseOrder(cmp);
Set<Integer> keySet = distributionSet.orderLines.keySet();
List<Integer> keyList = new ArrayList<Integer>();
keyList.addAll(keySet);
Collections.sort(keyList, cmp);
Map<Integer, BigDecimal> sortedMap = new LinkedHashMap<Integer, BigDecimal>();
for (Integer id : keyList) {
sortedMap.put(id, distributionSet.orderLines.get(id));
}
distributionSet.orderLines = sortedMap;
}
BigDecimal setBalance = distributionSet.setQty;
BigDecimal toApply = pr.getQty();
if (toApply == null || toApply.signum() == 0)
toApply = BigDecimal.valueOf(-1.0);
BigDecimal totalPrice = BigDecimal.ZERO;
for (Map.Entry<Integer, BigDecimal> olMap : distributionSet.orderLines.entrySet()) {
BigDecimal qty = olMap.getValue();
int C_OrderLine_ID = olMap.getKey();
if (qty == null || qty.signum() <= 0)
continue;
if (qty.compareTo(setBalance) >= 0) {
qty = setBalance;
setBalance = BigDecimal.ZERO;
} else {
setBalance = setBalance.subtract(qty);
}
if (toApply.signum() > 0) {
if (toApply.compareTo(qty) <= 0) {
qty = toApply;
toApply = BigDecimal.ZERO;
} else {
toApply = toApply.subtract(qty);
}
BigDecimal newQty = olMap.getValue();
newQty = newQty.subtract(qty);
distributionSet.orderLines.put(olMap.getKey(), newQty);
}
for (MOrderLine ol : lines) {
if (ol.getC_OrderLine_ID() == C_OrderLine_ID) {
if (pr.getRewardType().equals(MPromotionReward.REWARDTYPE_Percentage)) {
BigDecimal priceActual = ol.getPriceActual();
BigDecimal discount = priceActual.multiply(pr.getAmount().divide(BigDecimal.valueOf(100.00)));
addDiscountLine(order, ol, discount, qty, pr.getC_Charge_ID(), pr.getM_Promotion());
} else if (pr.getRewardType().equals(MPromotionReward.REWARDTYPE_FlatDiscount)) {
addDiscountLine(order, ol, pr.getAmount(), BigDecimal.valueOf(1.00), pr.getC_Charge_ID(), pr.getM_Promotion());
} else if (pr.getRewardType().equals(MPromotionReward.REWARDTYPE_AbsoluteAmount)) {
BigDecimal priceActual = ol.getPriceActual();
totalPrice = totalPrice.add(priceActual.multiply(qty));
} else {
// : Gift line
BigDecimal qtyreward = pr.getM_PromotionDistribution().getQty();
BigDecimal qtymodulo = ol.getQtyOrdered().divide(qtyreward, 0);
addGiftLine(order, ol, pr.getAmount(), pr.getQty().multiply(qtymodulo), pr.getC_Charge_ID(), pr.getM_Promotion());
}
}
}
if (toApply.signum() == 0)
break;
if (setBalance.signum() == 0)
break;
}
if (pr.getRewardType().equals(MPromotionReward.REWARDTYPE_AbsoluteAmount)) {
if (pr.getAmount().compareTo(totalPrice) < 0) {
addDiscountLine(order, null, totalPrice.subtract(pr.getAmount()), BigDecimal.valueOf(1.00), pr.getC_Charge_ID(), pr.getM_Promotion());
}
}
}
}
}
}
}
use of org.compiere.model.MOrderLine in project adempiere by adempiere.
the class PromotionValidator method increasePromotionCounter.
private void increasePromotionCounter(MOrder order) {
MOrderLine[] lines = order.getLines(false, null);
String promotionCode = (String) order.get_Value("PromotionCode");
for (MOrderLine ol : lines) {
if (ol.getC_Charge_ID() > 0) {
Integer promotionID = (Integer) ol.get_Value("M_Promotion_ID");
if (promotionID != null && promotionID.intValue() > 0) {
int M_PromotionPreCondition_ID = findPromotionPreConditionId(order, promotionCode, promotionID);
if (M_PromotionPreCondition_ID > 0) {
String update = "UPDATE M_PromotionPreCondition SET PromotionCounter = PromotionCounter + 1 WHERE M_PromotionPreCondition_ID = ?";
DB.executeUpdate(update, M_PromotionPreCondition_ID, order.get_TrxName());
}
}
}
}
}
use of org.compiere.model.MOrderLine in project adempiere by adempiere.
the class PromotionValidator method decreasePromotionCounter.
private void decreasePromotionCounter(MOrder order) {
MOrderLine[] lines = order.getLines(false, null);
String promotionCode = (String) order.get_Value("PromotionCode");
for (MOrderLine ol : lines) {
if (ol.getC_Charge_ID() > 0) {
Integer promotionID = (Integer) ol.get_Value("M_Promotion_ID");
if (promotionID != null && promotionID.intValue() > 0) {
int M_PromotionPreCondition_ID = findPromotionPreConditionId(order, promotionCode, promotionID);
if (M_PromotionPreCondition_ID > 0) {
String update = "UPDATE M_PromotionPreCondition SET PromotionCounter = PromotionCounter - 1 WHERE M_PromotionPreCondition_ID = ?";
DB.executeUpdate(update, M_PromotionPreCondition_ID, order.get_TrxName());
}
}
}
}
}
use of org.compiere.model.MOrderLine in project adempiere by adempiere.
the class PromotionValidator method modelChange.
public String modelChange(PO po, int type) throws Exception {
if (po instanceof MOrderLine) {
if (type == TYPE_AFTER_DELETE) {
MOrderLine ol = (MOrderLine) po;
MOrder order = ol.getParent();
String promotionCode = (String) order.get_Value("PromotionCode");
if (ol.getC_Charge_ID() > 0) {
Integer promotionID = (Integer) ol.get_Value("M_Promotion_ID");
if (promotionID != null && promotionID.intValue() > 0) {
int M_PromotionPreCondition_ID = findPromotionPreConditionId(order, promotionCode, promotionID);
if (M_PromotionPreCondition_ID > 0) {
String update = "UPDATE M_PromotionPreCondition SET PromotionCounter = PromotionCounter - 1 WHERE M_PromotionPreCondition_ID = ?";
DB.executeUpdate(update, M_PromotionPreCondition_ID, order.get_TrxName());
}
}
}
}
}
return null;
}
use of org.compiere.model.MOrderLine in project adempiere by adempiere.
the class Doc_Order method getCommitmentsSales.
// getCommitmentRelease
/**
* Get Commitments Sales
* @param doc document
* @param maxQty Qty invoiced/matched
* @param C_OrderLine_ID invoice line
* @return commitments (order lines)
*/
protected static DocLine[] getCommitmentsSales(Doc doc, BigDecimal maxQty, int M_InOutLine_ID) {
int precision = -1;
//
ArrayList<DocLine> list = new ArrayList<DocLine>();
String sql = "SELECT * FROM C_OrderLine ol " + "WHERE EXISTS " + "(SELECT * FROM M_InOutLine il " + "WHERE il.C_OrderLine_ID=ol.C_OrderLine_ID" + " AND il.M_InOutLine_ID=?)";
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = DB.prepareStatement(sql, null);
pstmt.setInt(1, M_InOutLine_ID);
rs = pstmt.executeQuery();
while (rs.next()) {
if (maxQty.signum() == 0)
continue;
MOrderLine line = new MOrderLine(doc.getCtx(), rs, null);
DocLine docLine = new DocLine(line, doc);
// Currency
if (precision == -1) {
doc.setC_Currency_ID(docLine.getC_Currency_ID());
precision = MCurrency.getStdPrecision(doc.getCtx(), docLine.getC_Currency_ID());
}
// Qty
BigDecimal Qty = line.getQtyOrdered().max(maxQty);
docLine.setQty(Qty, false);
//
BigDecimal PriceActual = line.getPriceActual();
BigDecimal PriceCost = line.getPriceCost();
BigDecimal LineNetAmt = null;
if (PriceCost != null && PriceCost.signum() != 0)
LineNetAmt = Qty.multiply(PriceCost);
else if (Qty.equals(maxQty))
LineNetAmt = line.getLineNetAmt();
else
LineNetAmt = Qty.multiply(PriceActual);
maxQty = maxQty.subtract(Qty);
// DR
docLine.setAmount(LineNetAmt);
BigDecimal PriceList = line.getPriceList();
int C_Tax_ID = docLine.getC_Tax_ID();
// Correct included Tax
if (C_Tax_ID != 0 && line.getParent().isTaxIncluded()) {
MTax tax = MTax.get(doc.getCtx(), C_Tax_ID);
if (!tax.isZeroTax()) {
BigDecimal LineNetAmtTax = tax.calculateTax(LineNetAmt, true, precision);
s_log.fine("LineNetAmt=" + LineNetAmt + " - Tax=" + LineNetAmtTax);
LineNetAmt = LineNetAmt.subtract(LineNetAmtTax);
BigDecimal PriceListTax = tax.calculateTax(PriceList, true, precision);
PriceList = PriceList.subtract(PriceListTax);
}
}
// correct included Tax
docLine.setAmount(LineNetAmt, PriceList, Qty);
list.add(docLine);
}
} catch (Exception e) {
s_log.log(Level.SEVERE, sql, e);
} finally {
DB.close(rs, pstmt);
rs = null;
pstmt = null;
}
// Return Array
DocLine[] dl = new DocLine[list.size()];
list.toArray(dl);
return dl;
}
Aggregations