How to create a Discount Rule extension to Liferay Commerce - DEV24 - (part 2)

                           

DISCLAIMER: This blog  post has Spanish and English version.

                      ...Done the part 1, we can continue our journey through the module extension...

Step 4 - Make the age configurable

In order to have a reusable module, we can make the “Age value” configurable and eliminate the hardcoded age from the module, following these steps you will learn how to create it:

1.  In resources folder (i.e.: liferay-workspace-7-3/modules/commerce-discount-rule-by-age/src/main/resources), create two new folders: the first one called “META-INF” and the second one into the first, called “resources”.

2.  Inside “META-INF/resources create a new JSP file called “init.jsp” and another JSP file called “view.jsp” 

3.  In the “init.jsp”, copy and paste the following line, to import the aui taglib (which will be used in the view.jsp):

<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui" %>

4.  In the “view.jsp”, copy and paste the following line (which there is the input for age): 

<%@ include file="/init.jsp" %>
<div class="col-12">
    <div class="card d-flex flex-column">
        <h4 class="align-items-center card-header d-flex justify-content-between py-3">
        <liferay-ui:message key="add-minimum-age-to-discount" />
        </h4>
        <div class="card-body flex-fill">
        <aui:input label="minimum-age-to-discount" name="typeSettings" type="text">
          <aui:validator name="digits" />
          <aui:validator name="min">30</aui:validator>
        </aui:input>
        </div>
    </div>
</div>

5.  Include the language keys  “add-minimum-age-to-discount” and “minimum-age-to-discount” in the JSP above. Include the translation in the 3 properties files (below the key with each translation).

  • In  Language.properties: 
  • add-minimum-age-to-discount=Add the minimum age to discount
    
    minimum-age-to-discount=Minimum age to apply the discount
  •  In Language_es_ES.properties 
  • add-minimum-age-to-discount=Añada la edad mínima para el descuento
    
    minimum-age-to-discount=Edad mínima a aplicar el descuento
  • In Language_pt_BR.properties 
  • add-minimum-age-to-discount=Adicione a idade mínima para o desconto
    
    minimum-age-to-discount=Idade mínima para dar o desconto

6.  Create a new package on your project “com.liferay.commerce.discount.rule.by.age.render”.

7.  Create a java class “CommerceDiscountRuleTypeJSPContributorRuleByAge” which implements the “CommerceDiscountRuleTypeJSPContributor” interface.

8.  Implement the “render” method.

9.  Inside the class create a Key:

public static final String KEY = "key-rule-gold-person";
Remember: “This KEY will identify our JSP Contributor, so it is important to provide a distinct key for each discount rule type JSP Contributor registry, so Liferay Commerce can distinguish the new JSP from others.If you reuse an existing key that is already in use, you will override the existing JSP.

10.  Mark this class as a @Component and inside, include 3 properties. It should look like the below:

@Component(
      immediate = true,
      property = {
              "commerce.discount.rule.type.jsp.contributor.key=" + CommerceDiscountRuleTypeJSPContributorRuleByAge.KEY,
              },service = CommerceDiscountRuleTypeJSPContributor.class
)
  •  On property array, setup 1 needed parameter for our JSP
    • contributor:"commerce.discount.rule.type.jsp.contributor.key=" + CommerceDiscountRuleTypeJSPContributorRuleByAge.KEY

 

  • On service, declare the interface which we are implementing in this class:
    • service = CommerceDiscountRuleTypeJSPContributor.class

 

11.  Add new dependencies to your project. Open the “build.gradle” file, and copy and paste the following line (this dependency is needed to use the JSPRenderer):

compileOnly group: "com.liferay", name: "com.liferay.frontend.taglib", version: "5.4.3"

12.  In the “CommerceDiscountRuleTypeJSPContributorRuleByAge.java”, at the bottom of class, inject the service “JSPRenderer” with the @Reference annotation,

@Reference
private JSPRenderer _jspRenderer;

13.  After, inject the service “ServletContext” with the @Reference annotation, and use the “target” parameter to reference the “Bundle-SymbolicName” (located in the bnd.bnd file) from your module to locate the JSP.

@Reference(target="(osgi.web.symbolicname=com.liferay.commerce.discount.rule.by.age)")
private ServletContext _servletContext;

14.  Open the “bnd.bnd” file (located on “liferay-workspace-7-3/modules/commerce-discount-rule-by-age”) and declare a “Web-ContextPath” (the value should be unique). This way, your ServletContext will be generated correctly.

Web-ContextPath: /discount-rule-by-age

15.  Now, in the component class “CommerceDiscountRuleTypeJSPContributorRuleByAge”, in the render method implement the logic for your custom input value (for the age) with the “_jspRenderer” service to “view.jsp”, like in the code snippet below: 

@Override
public void render(long commerceDiscountId, long commerceDiscountRuleId, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
  _jspRenderer.renderJSP(
          _servletContext, httpServletRequest, httpServletResponse,
          "/view.jsp");
}

16.  To finish this step, go back to the component class “CommerceDiscountRuleByAge”, in the evaluatemethod we will retrieve the value setting to change the age value “70” hardcoded to your settings variable. 

String settingsProperty = commerceDiscountRule.getSettingsProperty(
      commerceDiscountRule.getType());

int ageSetting = Integer.valueOf(settingsProperty);

if(period.getYears() >= ageSetting){
  return true;
}

17.  Save and deploy it by executing the following command into your Liferay Workspace.

liferay-workspace-7-3 % ./gradlew deploy

The code used in the previous step is available on a tag called “step-4” on github. 

Testing:

  • In Liferay Portal/DXP,  go to: Open Menu > Commerce > Discounts > Click on discount created before, at the bottom, there will be a box for “Rules”, click on “Edit”

  • Fill with the value “70” and save it.

  • Go to your commerce site and test it, adding some products to your cart and check that everything keeps working as expected.

  • Go back to “edit” your rule again and you will see the input empty.

In the next step we will see how to retrieve the stored value.  

Last step - Retrieving the configuration value stored.

1.  Add two new dependencies to your project. Open the “build.gradle” file, and copy and paste the following lines (these dependencies are necessary to use the StringPool and the BeanParamUtil classes):

compileOnly group: "com.liferay", name: "com.liferay.petra.string"
compileOnly group: "javax.portlet", name: "portlet-api", version: "3.0.0"

​​​​​2.  Create a new package in your project “com.liferay.commerce.discount.rule.by.age.display.context”.

3.  Create a class “CommerceTrainingDiscountRuleDisplayContext.java”.

4.  At the bottom on your class, declare the 3 variables:

private CommerceDiscountRule _commerceDiscountRule;
private final HttpServletRequest _httpServletRequest;
private final CommerceDiscountRuleService _commerceDiscountRuleService;

5.  Create a constructor for your class, which will receive as parameters the “CommerceDiscountRuleService” and “HttpServletRequest”.

public CommerceTrainingDiscountRuleDisplayContext(CommerceDiscountRuleService commerceDiscountRuleService,
    HttpServletRequest httpServletRequest){

  _commerceDiscountRuleService = commerceDiscountRuleService;
  _httpServletRequest = httpServletRequest;
}

6.  Create a method to get the “CommerceDiscountRule”, like in the code snippet below.

public CommerceDiscountRule getCommerceDiscountRule()
    throws PortalException {

    if (_commerceDiscountRule != null) {
        return _commerceDiscountRule;
    }

    long commerceDiscountRuleId = ParamUtil.getLong(
        _httpServletRequest, "commerceDiscountRuleId");

    if (commerceDiscountRuleId > 0) {
        _commerceDiscountRule =
          _commerceDiscountRuleService.getCommerceDiscountRule(
              commerceDiscountRuleId);
    }

    return _commerceDiscountRule;
  }

7.  Finally in this class, create a method to get the “getTypeSettings”, which will retrieve the value stored in your custom configuration. 

public String getTypeSettings() throws PortalException {
  CommerceDiscountRule commerceDiscountRule = getCommerceDiscountRule();

  if (commerceDiscountRule == null) {
    return StringPool.BLANK;
  }

  String type = BeanParamUtil.getString(
    commerceDiscountRule, _httpServletRequest, "type");

  return commerceDiscountRule.getSettingsProperty(type);
}

8.  Open the “CommerceDiscountRuleTypeJSPContributorRuleByAge.java”, and at the bottom of class, inject the service “CommerceDiscountRuleService” with the @Reference annotation.

@Reference
    private CommerceDiscountRuleService _commerceDiscountRuleService;

9.  Even in this class, go to the render method, create an instance of “CommerceDiscountRuleByAgeDisplayContext” and set it to “httpServletRequest”.

CommerceDiscountRuleByAgeDisplayContext CommerceDiscountRuleByAgeDisplayContext =
      new CommerceDiscountRuleByAgeDisplayContext(_commerceDiscountRuleService,httpServletRequest);

httpServletRequest.setAttribute("view.jsp-commerceDiscountRuleByAgeDisplayContext",CommerceDiscountRuleByAgeDisplayContext);

10.  In the “init.jsp”, import the “CommerceDiscountRuleByAgeDisplayContext” (which you will use in the view.jsp)

<%@ page import="com.liferay.commerce.discount.rule.by.age.display.context.CommerceDiscountRuleByAgeDisplayContext" %>

11.  In the “view.jsp”, below at the include, retrieve the “CommerceDiscountRuleByAgeDisplayContext” from the request, and through the method “getTypeSetting” retrieve the stored value.

<%@ include file="/init.jsp" %>

<%
CommerceDiscountRuleByAgeDisplayContext commerceDiscountRuleByAgeDisplayContext = (CommerceDiscountRuleByAgeDisplayContext)request.getAttribute("view.jsp-commerceDiscountRuleByAgeDisplayContext");
String value = commerceDiscountRuleByAgeDisplayContext.getTypeSettings();
%>

12.  Finally, add the value parameter to the input with the variable.

<aui:input label="minimum-age-to-discount" name="typeSettings" type="text" value="<%= value %>">

13.  Save and deploy it by executing the following command in your Liferay Workspace.

liferay-workspace-7-3 % ./gradlew deploy 

14.  Now, if you go back to “edit” your rule, you will see the input with the value stored.

The code used in the previous step is available on a tag called “last-step” on github. 

                                                                               ...And this is the end...

I hope you have enjoyed it. In this tutorial, I tried to explain everything step by step, so that all developers are able to understand it (to the newbies , welcome! XD ).