[Delivery Rates] [Delivery Rates] Enhanced Services Price Rules configuration
authorAaron Calero <aaron.calero@openbravo.com>
Tue, 27 Nov 2018 18:06:43 +0100
changeset 32605 dd0bd06bd93f
parent 32604 fc8dbbcb6d2d
child 32606 99dd7187d063
[Delivery Rates] [Delivery Rates] Enhanced Services Price Rules configuration
src/org/openbravo/common/actionhandler/ServiceRelatedLinePriceActionHandler.java
src/org/openbravo/event/ProductPriceRuleVersionEventHandler.java
src/org/openbravo/materialmgmt/ServicePriceUtils.java
web/js/productServices.js
--- a/src/org/openbravo/common/actionhandler/ServiceRelatedLinePriceActionHandler.java	Wed Nov 07 09:42:12 2018 +0100
+++ b/src/org/openbravo/common/actionhandler/ServiceRelatedLinePriceActionHandler.java	Tue Nov 27 18:06:43 2018 +0100
@@ -56,6 +56,7 @@
       BigDecimal priceamount = new BigDecimal(jsonRequest.getString("priceamount"));
       BigDecimal relatedQty = new BigDecimal(jsonRequest.getString("relatedqty"));
       BigDecimal unitDiscountsAmt = new BigDecimal(jsonRequest.getString("unitdiscountsamt"));
+      JSONObject relatedInfo = jsonRequest.optJSONObject("relatedLinesInfo");
       final OrderLine orderLineToRelate = OBDal.getInstance().get(OrderLine.class,
           jsonRequest.getString("orderLineToRelateId"));
       String tabId = jsonRequest.getString("tabId");
@@ -65,7 +66,7 @@
       }
       JSONObject deferredSale = null;
       BigDecimal serviceTotalAmount = ServicePriceUtils.getServiceAmount(serviceOrderline, amount,
-          discounts, priceamount, relatedQty, unitDiscountsAmt);
+          discounts, priceamount, relatedQty, unitDiscountsAmt, relatedInfo);
       if (jsonRequest.has("orderLineToRelateId")
           && jsonRequest.get("orderLineToRelateId") != JSONObject.NULL
           && !RFC_ORDERLINE_TAB_ID.equals(tabId) && state) {
--- a/src/org/openbravo/event/ProductPriceRuleVersionEventHandler.java	Wed Nov 07 09:42:12 2018 +0100
+++ b/src/org/openbravo/event/ProductPriceRuleVersionEventHandler.java	Tue Nov 27 18:06:43 2018 +0100
@@ -31,7 +31,8 @@
 
   private void linkProduct(EntityNewEvent event, ServicePriceRuleVersion pcprv) {
     final Product product = pcprv.getRelatedProductCategory() != null ? pcprv
-        .getRelatedProductCategory().getProduct() : pcprv.getRelatedProduct().getProduct();
+        .getRelatedProductCategory().getProduct() : (pcprv.getRelatedProduct() != null ? pcprv
+        .getRelatedProduct().getProduct() : null);
 
     if (product != null) {
       final Entity priceRuleVersionEntity = ModelProvider.getInstance().getEntity(
--- a/src/org/openbravo/materialmgmt/ServicePriceUtils.java	Wed Nov 07 09:42:12 2018 +0100
+++ b/src/org/openbravo/materialmgmt/ServicePriceUtils.java	Tue Nov 27 18:06:43 2018 +0100
@@ -26,6 +26,7 @@
 import java.util.HashMap;
 
 import org.apache.commons.lang.time.DateUtils;
+import org.codehaus.jettison.json.JSONArray;
 import org.codehaus.jettison.json.JSONException;
 import org.codehaus.jettison.json.JSONObject;
 import org.hibernate.Query;
@@ -37,6 +38,7 @@
 import org.openbravo.erpCommon.utility.OBDateUtils;
 import org.openbravo.erpCommon.utility.OBMessageUtils;
 import org.openbravo.model.common.order.OrderLine;
+import org.openbravo.model.common.order.OrderlineServiceRelation;
 import org.openbravo.model.common.plm.Product;
 import org.openbravo.model.common.plm.ServicePriceRuleVersion;
 import org.openbravo.model.materialmgmt.transaction.ShipmentInOutLine;
@@ -58,15 +60,100 @@
    * Method to obtain Service Amount to be added for a certain service order line based on selected
    * product lines amount
    */
+  public static BigDecimal getServiceAmount(OrderLine orderline, BigDecimal linesTotalAmount,
+      BigDecimal totalDiscounts, BigDecimal totalPrice, BigDecimal relatedQty,
+      BigDecimal unitDiscountsAmt) {
+    JSONObject relatedInfo = new JSONObject();
+    JSONArray relatedLines = new JSONArray();
+    JSONArray relatedAmounts = new JSONArray();
+    JSONArray relatedDiscounts = new JSONArray();
+    JSONArray relatedPrices = new JSONArray();
+    JSONArray relatedQuantities = new JSONArray();
+    JSONArray relatedUnitDiscounts = new JSONArray();
+    try {
+      for (OrderlineServiceRelation olsr : orderline.getOrderlineServiceRelationList()) {
+        relatedLines.put(olsr.getOrderlineRelated().getId());
+        relatedAmounts.put(olsr.getAmount());
+        relatedDiscounts.put(JSONObject.NULL);
+        relatedPrices.put(olsr.getQuantity().compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO
+            : olsr.getAmount().divide(olsr.getQuantity()));
+        relatedQuantities.put(olsr.getQuantity());
+        relatedUnitDiscounts.put(JSONObject.NULL);
+      }
+
+      if (relatedLines.length() == 0) {
+        return getServiceAmount(orderline, linesTotalAmount, totalDiscounts, totalPrice,
+            relatedQty, unitDiscountsAmt, null);
+
+      } else {
+        relatedInfo.put("relatedLines", relatedLines);
+        relatedInfo.put("lineAmount", relatedAmounts);
+        relatedInfo.put("lineDiscounts", relatedDiscounts);
+        relatedInfo.put("linePriceamount", relatedPrices);
+        relatedInfo.put("lineRelatedqty", relatedQuantities);
+        relatedInfo.put("lineUnitdiscountsamt", relatedUnitDiscounts);
+
+        return getServiceAmount(orderline, linesTotalAmount, totalDiscounts, totalPrice,
+            relatedQty, unitDiscountsAmt, relatedInfo);
+      }
+    } catch (JSONException e) {
+      throw new OBException(e);
+    }
+  }
 
   public static BigDecimal getServiceAmount(OrderLine orderline, BigDecimal linesTotalAmount,
       BigDecimal totalDiscounts, BigDecimal totalPrice, BigDecimal relatedQty,
-      BigDecimal unitDiscountsAmt) {
+      BigDecimal unitDiscountsAmt, JSONObject relatedInfo) {
+    if (relatedInfo == null || !relatedInfo.has("relatedLines")) {
+      return getServiceAmountByLine(orderline, linesTotalAmount, totalDiscounts, totalPrice,
+          relatedQty, unitDiscountsAmt, null, linesTotalAmount, totalDiscounts, totalPrice,
+          unitDiscountsAmt);
+    } else {
+      try {
+        JSONArray relatedLines = relatedInfo.getJSONArray("relatedLines");
+        JSONArray relatedAmounts = relatedInfo.getJSONArray("lineAmount");
+        JSONArray relatedDiscounts = relatedInfo.getJSONArray("lineDiscounts");
+        JSONArray relatedPrices = relatedInfo.getJSONArray("linePriceamount");
+        JSONArray relatedQuantities = relatedInfo.getJSONArray("lineRelatedqty");
+        JSONArray relatedUnitDiscounts = relatedInfo.getJSONArray("lineUnitdiscountsamt");
+
+        BigDecimal serviceAmount = BigDecimal.ZERO;
+        BigDecimal partialAmount;
+        for (int i = 0; i < relatedLines.length(); i++) {
+          BigDecimal amount = BigDecimal.valueOf(relatedAmounts.optDouble(i, 0));
+          if (amount.compareTo(BigDecimal.ZERO) == 0) {
+            continue;
+          }
+
+          BigDecimal discount = BigDecimal.valueOf(relatedDiscounts.optDouble(i, 0));
+          BigDecimal price = BigDecimal.valueOf(relatedPrices.optDouble(i, 0));
+          BigDecimal relatedLineQty = BigDecimal.valueOf(relatedQuantities.optDouble(i, 0));
+          BigDecimal unitDiscount = BigDecimal.valueOf(relatedUnitDiscounts.optDouble(i, 0));
+
+          String relatedLineId = relatedLines.getString(i);
+
+          partialAmount = getServiceAmountByLine(orderline, amount, discount, price,
+              relatedLineQty, unitDiscount, relatedLineId, linesTotalAmount, totalDiscounts,
+              totalPrice, unitDiscountsAmt);
+          serviceAmount = serviceAmount.add(partialAmount);
+        }
+
+        return serviceAmount;
+      } catch (JSONException e) {
+        throw new OBException(e);
+      }
+    }
+  }
+
+  private static BigDecimal getServiceAmountByLine(OrderLine orderline, BigDecimal lineAmount,
+      BigDecimal lineDiscounts, BigDecimal linePrice, BigDecimal relatedQty,
+      BigDecimal lineUnitDiscount, String relatedLineId, BigDecimal totalLineAmount,
+      BigDecimal totalDiscounts, BigDecimal totalLinePrice, BigDecimal totalUnitDiscounts) {
     BigDecimal localRelatedQty = relatedQty;
     final Product serviceProduct = orderline.getProduct();
     OBContext.setAdminMode(true);
     try {
-      if (linesTotalAmount != null && linesTotalAmount.compareTo(BigDecimal.ZERO) == 0) {
+      if (lineAmount != null && lineAmount.compareTo(BigDecimal.ZERO) == 0) {
         return BigDecimal.ZERO;
       }
       BigDecimal serviceBasePrice = getProductPrice(orderline.getOrderDate(), orderline
@@ -82,7 +169,7 @@
         return BigDecimal.ZERO;
       } else {
         ServicePriceRule servicePriceRule = getServicePriceRule(serviceProduct,
-            orderline.getOrderDate());
+            orderline.getOrderDate(), relatedLineId);
         if (servicePriceRule == null) {
           throw new OBException("@ServicePriceRuleVersionNotFound@ "
               + orderline.getProduct().getIdentifier() + ", @Date@: "
@@ -90,44 +177,43 @@
         }
         BigDecimal relatedAmount = BigDecimal.ZERO;
         BigDecimal findRangeAmount = BigDecimal.ZERO;
-        if (linesTotalAmount != null) {
-          relatedAmount = linesTotalAmount;
+        if (lineAmount != null) {
+          relatedAmount = lineAmount;
         } else {
           HashMap<String, BigDecimal> relatedAmountAndQuatity = getRelatedAmountAndQty(orderline);
           relatedAmount = relatedAmountAndQuatity.get("amount");
-          // TODO: APPLY quantities
           localRelatedQty = relatedAmountAndQuatity.get("quantity");
         }
 
         if (PERCENTAGE.equals(servicePriceRule.getRuletype())) {
-          if (!servicePriceRule.isAfterdiscounts() && totalDiscounts != null
-              && unitDiscountsAmt != null) {
+          if (!servicePriceRule.isAfterdiscounts() && lineDiscounts != null
+              && lineUnitDiscount != null) {
             relatedAmount = UNIQUE_QUANTITY.equals(serviceProduct.getQuantityRule()) ? relatedAmount
-                .add(totalDiscounts) : relatedAmount.add(unitDiscountsAmt);
+                .add(lineDiscounts) : relatedAmount.add(lineUnitDiscount);
           }
           serviceRelatedPrice = relatedAmount.multiply(new BigDecimal(servicePriceRule
               .getPercentage()).divide(new BigDecimal("100.00")));
         } else {
           if (!servicePriceRule.isAfterdiscounts() && totalDiscounts != null
-              && unitDiscountsAmt != null) {
-            findRangeAmount = UNIQUE_QUANTITY.equals(serviceProduct.getQuantityRule()) ? linesTotalAmount
-                .add(totalDiscounts) : totalPrice.add(unitDiscountsAmt);
+              && totalUnitDiscounts != null) {
+            findRangeAmount = UNIQUE_QUANTITY.equals(serviceProduct.getQuantityRule()) ? totalLineAmount
+                .add(totalDiscounts) : totalLinePrice.add(totalUnitDiscounts);
           } else {
-            findRangeAmount = UNIQUE_QUANTITY.equals(serviceProduct.getQuantityRule()) ? linesTotalAmount
-                : totalPrice;
+            findRangeAmount = UNIQUE_QUANTITY.equals(serviceProduct.getQuantityRule()) ? totalLineAmount
+                : totalLinePrice;
           }
           ServicePriceRuleRange range = getRange(servicePriceRule, findRangeAmount);
           if (range == null) {
             throw new OBException("@ServicePriceRuleRangeNotFound@. @ServicePriceRule@: "
-                + servicePriceRule.getIdentifier() + ", @AmountUpTo@: " + linesTotalAmount);
+                + servicePriceRule.getIdentifier() + ", @AmountUpTo@: " + lineAmount);
           }
           if (PERCENTAGE.equals(range.getRuleType())) {
-            if (!range.isAfterDiscounts() && totalDiscounts != null && unitDiscountsAmt != null) {
-              relatedAmount = UNIQUE_QUANTITY.equals(serviceProduct.getQuantityRule()) ? linesTotalAmount
-                  .add(totalDiscounts) : totalPrice.add(unitDiscountsAmt);
+            if (!range.isAfterDiscounts() && lineDiscounts != null && lineUnitDiscount != null) {
+              relatedAmount = UNIQUE_QUANTITY.equals(serviceProduct.getQuantityRule()) ? lineAmount
+                  .add(lineDiscounts) : linePrice.add(lineUnitDiscount);
             } else {
-              relatedAmount = UNIQUE_QUANTITY.equals(serviceProduct.getQuantityRule()) ? linesTotalAmount
-                  : totalPrice;
+              relatedAmount = UNIQUE_QUANTITY.equals(serviceProduct.getQuantityRule()) ? lineAmount
+                  : linePrice;
             }
             serviceRelatedPrice = relatedAmount.multiply(new BigDecimal(range.getPercentage())
                 .divide(new BigDecimal("100.00")));
@@ -261,21 +347,64 @@
    *          Order Date of the Sales Order
    */
   public static ServicePriceRule getServicePriceRule(Product serviceProduct, Date orderDate) {
+    return getServicePriceRule(serviceProduct, orderDate, null);
+  }
+
+  /**
+   * Method that returns for a "Price Rule Based" Service product the Service Price Rule on the
+   * given date
+   * 
+   * @param serviceProduct
+   *          Service Product
+   * @param orderDate
+   *          Order Date of the Sales Order
+   * @param relatedLines
+   *          List of lines related to the service
+   */
+  public static ServicePriceRule getServicePriceRule(Product serviceProduct, Date orderDate,
+      String relatedLine) {
+    OrderLine ol = null;
     OBContext.setAdminMode(true);
     try {
+      if (relatedLine != null) {
+        ol = OBDal.getInstance().get(OrderLine.class, relatedLine);
+      }
       StringBuffer where = new StringBuffer();
-      where.append(" select " + ServicePriceRuleVersion.PROPERTY_SERVICEPRICERULE);
+      where.append(" select sprv." + ServicePriceRuleVersion.PROPERTY_SERVICEPRICERULE);
       where.append(" from " + ServicePriceRuleVersion.ENTITY_NAME + " as sprv");
+      where.append(" left join sprv.relatedProduct rp ");
+      where.append(" left join sprv.relatedProductCategory rpc ");
       where.append(" where sprv." + ServicePriceRuleVersion.PROPERTY_PRODUCT
           + ".id = :serviceProductId");
       where
           .append(" and sprv." + ServicePriceRuleVersion.PROPERTY_VALIDFROMDATE + " <= :orderDate");
       where.append("   and sprv." + ServicePriceRuleVersion.PROPERTY_ACTIVE + " = true");
-      where.append(" order by sprv." + ServicePriceRuleVersion.PROPERTY_VALIDFROMDATE
-          + " desc, sprv." + ServicePriceRuleVersion.PROPERTY_CREATIONDATE + " desc");
+
+      if ("N".equals(serviceProduct.getIncludedProducts()) && relatedLine != null) {
+        where.append(" and rp is null or rp.relatedProduct.id = :relatedProductId ");
+      } else {
+        where.append(" and rp is null ");
+      }
+
+      if ("N".equals(serviceProduct.getIncludedProductCategories()) && relatedLine != null) {
+        where.append(" and rpc is null or rpc.productCategory.id = :relatedProdCatId ");
+      } else {
+        where.append(" and rpc is null ");
+      }
+
+      where.append(" order by case when rp is not null then 1 else 0 end desc, "
+          + " case when rpc is not null then 1 else 0 end desc, sprv."
+          + ServicePriceRuleVersion.PROPERTY_VALIDFROMDATE + " desc, sprv."
+          + ServicePriceRuleVersion.PROPERTY_CREATIONDATE + " desc");
       Query sprvQry = OBDal.getInstance().getSession().createQuery(where.toString());
       sprvQry.setParameter("serviceProductId", serviceProduct.getId());
       sprvQry.setParameter("orderDate", orderDate);
+      if ("N".equals(serviceProduct.getIncludedProducts()) && relatedLine != null) {
+        sprvQry.setParameter("relatedProductId", ol.getProduct().getId());
+      }
+      if ("N".equals(serviceProduct.getIncludedProductCategories()) && relatedLine != null) {
+        sprvQry.setParameter("relatedProdCatId", ol.getProduct().getProductCategory().getId());
+      }
       sprvQry.setMaxResults(1);
       return (ServicePriceRule) sprvQry.uniqueResult();
     } finally {
--- a/web/js/productServices.js	Wed Nov 07 09:42:12 2018 +0100
+++ b/web/js/productServices.js	Tue Nov 27 18:06:43 2018 +0100
@@ -148,7 +148,7 @@
 OB.ProductServices.updateServicePrice = function (view, record, state) {
   var callback, totalServiceAmount = view.theForm.getItem('totalserviceamount'),
       orderLinesGrid = view.theForm.getItem('grid').canvas.viewGrid,
-      recordId, contextInfo;
+      recordId, contextInfo, parameters;
   if (record) {
     recordId = record.id;
   } else {
@@ -174,7 +174,7 @@
     }
   };
 
-  OB.RemoteCallManager.call('org.openbravo.common.actionhandler.ServiceRelatedLinePriceActionHandler', {
+  parameters = {
     orderlineId: view.theForm.getItem('orderlineId').getValue(),
     amount: view.theForm.getItem('totallinesamount').getValue(),
     discounts: view.theForm.getItem('totaldiscountsamount').getValue(),
@@ -183,6 +183,25 @@
     unitdiscountsamt: view.theForm.getItem('totalUnitDiscountsAmt').getValue(),
     orderLineToRelateId: recordId,
     tabId: contextInfo.inpTabId,
-    state: state
-  }, {}, callback);
-};
+    state: state,
+    relatedLinesInfo: {
+      lineAmount: [],
+      lineDiscounts: [],
+      linePriceamount: [],
+      lineRelatedqty: [],
+      lineUnitdiscountsamt: [],
+      relatedLines: []
+    }
+  }
+
+  orderLinesGrid.getSelectedRecords().forEach(function (selectedRecord) {
+    parameters.relatedLinesInfo.lineAmount.push(orderLinesGrid.getEditedCell(selectedRecord, orderLinesGrid.getFieldByColumnName('amount')));
+    parameters.relatedLinesInfo.lineDiscounts.push(orderLinesGrid.getEditedCell(selectedRecord, orderLinesGrid.getFieldByColumnName('discountsAmt')));
+    parameters.relatedLinesInfo.linePriceamount.push(orderLinesGrid.getEditedCell(selectedRecord, orderLinesGrid.getFieldByColumnName('price')));
+    parameters.relatedLinesInfo.lineRelatedqty.push(orderLinesGrid.getEditedCell(selectedRecord, orderLinesGrid.getFieldByColumnName('relatedQuantity')));
+    parameters.relatedLinesInfo.lineUnitdiscountsamt.push(orderLinesGrid.getEditedCell(selectedRecord, orderLinesGrid.getFieldByColumnName('unitDiscountsAmt')));
+    parameters.relatedLinesInfo.relatedLines.push(selectedRecord.id);
+  });
+
+  OB.RemoteCallManager.call('org.openbravo.common.actionhandler.ServiceRelatedLinePriceActionHandler', parameters, {}, callback);
+};
\ No newline at end of file