How to create a new Payment Method for Liferay Commerce (Part 1)

NOTICE: This blog  post has Spanish and English version.

Hello Liferayers, here I am again, this time with a step by step on how to create a new “Payment Method” for Liferay Commerce easily. In this example we’ll use the Redsys Service (a payment provider known in Spain) as a payment gateway.

If you are new to the world of Liferay Commerce, I advise you to look at all possible extensions in Commerce. They will help you save a lot of time when customizing any aspect on the platform.

  • Step 1, creating our new Payment Method extension for Liferay Commerce:

1.  With Blade CLI, we can start by creating a Liferay Workspace, if you don't already have one for Liferay 7.3 (I also recommend that you review instructions 3 and 4 of this previous blog post of mine to configure your Liferay Workspace, if you don't have it configured for the deployment):

blade init -v 7.3 liferay-workspace-7-3

2.  In your "Liferay Workspace", we’ll create a new module for a new payment method:

blade create -t api -p com.liferay.commerce.payment.method.redsys -c RedsysCommercePaymentMethod commerce-payment-method-redsys

3.  Now, rename the package from “com.liferay.commerce.payment.method.redsys.api” to “com.liferay.commerce.payment.method.redsys” to remove the word “api” that “blade CLI” generates automatically ( this is because we used the "api" template previously).

4. In the file "bnd.bnd" delete the line "Export-Package: com.liferay.commerce.payment.method.redsys.api".

5.  Open the folder "resources" (i.e.:liferay-workspace-7-3/modules/commerce-discount-rule-by-age/src/main/resources) and delete everything in it.

6.  Now internationalize your module, creating the folder "content" in "src main/resources/" and add the file "Language.properties". To facilitate, copy the keys below and paste into the created Language.properties that we will use throughout the tutorial.

#################-----Labels from Payment Method module-----#####################
redsys-payment-with-card=Redsys
this-is-payment-method-with-card-redsys=Redsys Payment Method
redsys-commerce-payment-method-card-group-service-configuration-name=Redsys Payment Engine Method Group Service
payment-attempts-max-count=Payment Attempts Max Count
redsys-configuration-help= The "Signature Secret" there is on Redsys, "Administration Module > Commerce Consult Data > See Key".
ds-signature-version=DS Signature Version
signature-secret=Signature Secret
merchant-code=Merchant Code
terminal=Terminal
type-of-transaction=Type of Transaction
authentication=Authentication
prod=Production
test=Test Integration
t0=Authorization

7.  Now add the dependencies to our project. Open the file build.gradle, remove all the content of this file and add the following dependencies:

 dependencies {
  compileOnly group: "com.liferay.portal", name: "release.portal.api"
  compileOnly group: "com.liferay.commerce", name: "com.liferay.commerce.api", version: "22.2.4"
}

8.  Open the file "RedsysCommercePaymentMethod.java" and change the interface type to class that implements the interface "CommercePaymentMethod" and implement the following methods:

@Override
public String getDescription(Locale locale) {...}

@Override
public String getKey() {...}

@Override
public String getName(Locale locale) {...}

@Override
public int getPaymentType() {...}

@Override
public String getServletPath() {...}

@Override
public boolean isCancelEnabled() {...}

@Override
public boolean isCompleteEnabled() {...}

@Override
public boolean isProcessPaymentEnabled() {...}

@Override
public CommercePaymentResult cancelPayment(CommercePaymentRequest commercePaymentRequest) throws Exception {...}

@Override
public CommercePaymentResult completePayment(CommercePaymentRequest commercePaymentRequest) throws Exception {...}

@Override
public CommercePaymentResult processPayment(CommercePaymentRequest commercePaymentRequest) throws Exception {...}

 

9.  Create the following variable (KEY):

public static final String KEY = "redsys";
Please note: "This KEY will identify your module, it is important to provide a different key for each new module (payment method extension), so that Liferay Commerce can distinguish one from the other. If you reuse an existing key that is already in use, you will replace the existing module "

10.  Annotate this class with @Component and set 3 properties. It should look like this:

@Component(
  immediate = true,
  property = "commerce.payment.engine.method.key="+ RedsysCommercePaymentMethod.KEY,
  service = CommercePaymentMethod.class
)
  • In the property array, set 1 value necessary to register our payment method, using the KEY variable:
    • "commerce.payment.engine.method.key="+ RedsysCommercePaymentMethod.KEY
  • As a service, declare the interface:
    • service = CommercePaymentMethod.class

11.  Now in the method "getKey", include the statement "return KEY" to return the key that we declared before.

12. The "getDescription" and "getName" methods will be the name and description that will be presented in the Control Panel when activating the payment method. We’ll use the “ResourceBundleUtil” and “LanguageUtil” to return the value of the key according to each necessary language (and that is translated, of course).

@Override
public String getDescription(Locale locale) {
   ResourceBundle resourceBundle = ResourceBundleUtil.getBundle(
           "content.Language", locale, getClass());
   return LanguageUtil.get(
           resourceBundle, "this-is-payment-method-with-card-redsys");
}

@Override
public String getName(Locale locale) {
       ResourceBundle resourceBundle = ResourceBundleUtil.getBundle(
               "content.Language", locale, getClass());
       return LanguageUtil.get(resourceBundle, "redsys-payment-with-card");
}

13.  Save the changes and deploy the module by executing the following command within the directory of your module in the Liferay Workspace:

commerce-payment-method-redsys% ./../../gradlew deploy

These steps above are the minimum necessary to have a Payment Method module, deployed in Liferay Commerce. Now if you open your Liferay Portal (ex: localhost: 8080), open the Menu> Commerce> Channels> click on a Channel (or create one if you don't have it), in the "Payment Methods" section, You should already present your module as an option:

Remember: since version 2.1 of Liferay Commerce, the payment options are related to the channels, so to see the payment method module, open any “Channel” created.

The code used in this step is available in a tag named "payment-redsys-step-1" in my github repo. 

  • Step 2, making the Payment Method configurable

To have a reusable module and with the configurations according to their respective environments, we must make all the necessary inputs configurable. In the case of this blog post, we will use the Redsys settings for payment with redirection connection. If you read the documentation you will be able to identify that we will need some configurations.

By following these steps, you will learn how to do it and you can apply the same logic for other payment methods that you want to create:

1.  Create three new packages:

  • com.liferay.commerce.payment.method.redsys.constants
  • Com.liferay.commerce.payment.method.redsys.connector
  • com.liferay.commerce.payment.method.redsys.configuration

2.  In “com.liferay.commerce.payment.method.redsys.constants” create an enum class called "RedsysTypeOfTransaction", to list the types of transactions.

Important: in this tutorial we are only going to implement  one type of transaction, the "Authorization", I leave the comments of the other types of transaction as a TODO in case you want to implement other types of Redsys. In this way, it can be useful when estimating the construction of a payment method. Bear in mind that a single type of transaction will not always be implemented and that each "new transaction" needs a new implementation (the vast majority, within the "processPayment" method).

3.  For greater ease in the process, copy and paste the enumerations defined below into the enum "RedsysTypeOfTransaction":

 T0("0");
/**
* TODO
T1("1"),
T2("2"),
T3("3"),
T5("5"),
T6("6"),
T7("7"),
T8("8"),
T9("9"),
TO("O"),
TP("P"),
TQ("Q"),
TR("R"),
TS("S");
*/

private RedsysTypeOfTransaction(String transaction) {
_transaction = transaction;
}

public String getTypeOfTransaction() {
return _transaction;
}

private String _transaction;

4.  In “com.liferay.commerce.payment.method.redsys.connector” create another enum class called "RedsysEnvironment", to list the two environment links for redsys, copy and paste the code below into the enum

 PROD("https://sis.redsys.es/sis/realizarPago"),
TEST("https://sis-t.redsys.es:25443/sis/realizarPago");

public String getUrl() {
return _url;
}

private RedsysEnvironment(String url) {
_url = url;
}

private final String _url;

5.  In “com.liferay.commerce.payment.method.redsys.constants” create a new class "RedsysCommercePaymentMethodConstants" for the constants that we will use. For greater ease, copy and paste the constants that we are going to use throughout the tutorial, in this class:

public static final String[] MODES = {
StringUtil.toLowerCase(RedsysEnvironment.PROD.name()),
StringUtil.toLowerCase(RedsysEnvironment.TEST.name())
};

public static final String[] TYPES_OF_TRANSACTION = {
StringUtil.toLowerCase(RedsysTypeOfTransaction.T0.name())
/**
* TODO
StringUtil.toLowerCase(RedsysTypeOfTransaction.T1.name()),
StringUtil.toLowerCase(RedsysTypeOfTransaction.T2.name()),
StringUtil.toLowerCase(RedsysTypeOfTransaction.T3.name()),
StringUtil.toLowerCase(RedsysTypeOfTransaction.T5.name()),
StringUtil.toLowerCase(RedsysTypeOfTransaction.T6.name()),
StringUtil.toLowerCase(RedsysTypeOfTransaction.T7.name()),
StringUtil.toLowerCase(RedsysTypeOfTransaction.T8.name()),
StringUtil.toLowerCase(RedsysTypeOfTransaction.T9.name()),
StringUtil.toLowerCase(RedsysTypeOfTransaction.TO.name()),
StringUtil.toLowerCase(RedsysTypeOfTransaction.TP.name()),
StringUtil.toLowerCase(RedsysTypeOfTransaction.TQ.name()),
StringUtil.toLowerCase(RedsysTypeOfTransaction.TR.name()),
StringUtil.toLowerCase(RedsysTypeOfTransaction.TS.name())
*/
};

public static final String SERVICE_NAME = "com.liferay.commerce.payment.engine.method.redsys";
public static final String SERVLET_PATH = "redsys-commerce-payment";
public static final String COMMERCE_CHANNEL_ID = "commerceChannelId";
public static final String REDIRECT_PARAM = "redirect=";
public static final String DS_MERCHANT_AMOUNT = "DS_MERCHANT_AMOUNT";
public static final String DS_MERCHANT_ORDER = "DS_MERCHANT_ORDER";
public static final String DS_MERCHANT_MERCHANTCODE = "DS_MERCHANT_MERCHANTCODE";
public static final String DS_MERCHANT_CURRENCY = "DS_MERCHANT_CURRENCY";
public static final String DS_MERCHANT_TRANSACTIONTYPE = "DS_MERCHANT_TRANSACTIONTYPE";
public static final String DS_MERCHANT_TERMINAL = "DS_MERCHANT_TERMINAL";
public static final String DS_MERCHANT_MERCHANTURL = "DS_MERCHANT_MERCHANTURL";
public static final String DS_MERCHANT_URLOK = "DS_MERCHANT_URLOK";
public static final String DS_MERCHANT_URLKO = "DS_MERCHANT_URLKO";
public static final String SETTINGS_DS_SIGNATURE_VERSION = "settings--ds_signature_version--";
public static final String SETTINGS_CLIENT_SECRET = "settings--clientSecret--";
public static final String SETTINGS_MERCHANT_CODE = "settings--merchantCode--";
public static final String SETTINGS_TERMINAL = "settings--terminal--";
public static final String SETTINGS_MODE = "settings--mode--";
public static final String SETTINGS_TYPES_OF_TRANSACTION = "settings--type-of-transaction--";
public static final String DS_MERCHANT_PARAMETERS = "Ds_MerchantParameters";
public static final String DS_SIGNATURE_VERSION = "Ds_SignatureVersion";
public static final String DS_SIGNATURE = "Ds_Signature";
public static final String REDIRECT_URL = "redirectUrl";
public static final String PARAMS = "params";
public static final String SIGNATURE = "signature";
public static final String DS_SIGNATURE_VERSION_PARAM = "dsSignatureVersion";
public static final String COD_RESPONSE_REDSYS =  "codResponseRedsys";
public static final String ERROR_SIGNATURE =  "Signature Calculed it's not equal Signature from Response";
public static final String ERROR_PARAMETERS_COMPARE= "Parameters from Order it's not equal Parameters from Response";

6.  In “com.liferay.commerce.payment.method.redsys.configuration” create a new interface “RedsysPaymentMethodCardGroupServiceConfiguration”

7.  Use the "@ExtendedObjectClassDefinition" to specify the category and scope of the setting.

@ExtendedObjectClassDefinition(
      category = "payment", scope = ExtendedObjectClassDefinition.Scope.GROUP
)
  • category = with the value "payment" our payment method is categorized along with the other payment methods in the "System Settings" section.
  • scope = We define it as "Scope.GROUP" to leave the configuration at the website level.

8.  Then we register that interface as a configuration with the annotation "@Meta.OCD" and configure the properties "id", "localization" and "name". 

@Meta.OCD(
id = "com.liferay.commerce.payment.method.redsys.configuration.RedsysPaymentMethodCardGroupServiceConfiguration",
localization = "content/Language",
name = "redsys-commerce-payment-method-card-group-service-configuration-name"
)

9.  Now inside the interface we define the input fields that we need to be configurable and with the annotation "@Meta.AD" their respective metadata:

@Meta.AD(deflt="HMAC_SHA256_V1",name = "ds-signature-version", required = false)
public String dsSignatureVersion();

@Meta.AD(deflt="https://sis-t.redsys.es:25443/sis/realizarPag", name = "mode", required = false)
public String mode();

@Meta.AD(deflt="sq7HjrUOBfKmC576ILgskD5srU870gJ7",name = "client-secret", required = false)
public String clientSecret();

@Meta.AD(deflt = "999008881", name = "merchant-code", required = false)
public String merchantCode();

@Meta.AD(deflt = "0",name = "type-of-transaction", required = false)
public String typeTransaction();

@Meta.AD(deflt = "01",name = "terminal", required = false)
public String terminal();

10.  Save the changes and deploy the module by executing the following command within the directory of your module in the Liferay Workspace:

commerce-payment-method-redsys% ./../../gradlew deploy

11.   Now open your Liferay Portal (ex: localhost: 8080), open the Menu> Control Panel> System Settings. In the "Commerce" section, click on "Payments" and there, in the list of payment methods, you should already have your configuration generated:

Ok, but if you go to "Channel", where we have activated the payment method, we do not have the independent configuration yet for each channel created. This is what we are going to see next.

  • Step 2.1, making the Payment Method configurable per channel

Now in this step, we will use the "Screen Navigation Framework" to be able to add a second tab in the payment method configuration, when we activate it from the "Channel" and configure it there at channel level.

1.  In the “resources” folder (ie: commerce-payment-method-redsys/src/main/resources), create two new folders: the first with name “META-INF” and the second and within the previous one, with name "resources".

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

3.  In the file "init.jsp", copy and paste the following lines to import some classes and taglibs that will be used in the file "configuration.jsp"

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>

<%@ taglib uri="http://liferay.com/tld/aui" prefix="aui" %><%@
taglib uri="http://liferay.com/tld/commerce-ui" prefix="commerce-ui" %><%@
taglib uri="http://liferay.com/tld/frontend" prefix="liferay-frontend" %><%@
taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %>

<%@
page import="com.liferay.commerce.payment.method.redsys.configuration.RedsysPaymentMethodCardGroupServiceConfiguration" %><%@
page import="com.liferay.commerce.payment.method.redsys.constants.RedsysCommercePaymentMethodConstants" %><%@
page import="com.liferay.portal.kernel.language.LanguageUtil" %><%@
page import="com.liferay.portal.kernel.util.Constants" %><%@
page import="com.liferay.portal.kernel.util.ParamUtil" %><%@
page import="com.liferay.portal.kernel.util.URLCodec" %><%@
page import="com.liferay.petra.string.StringPool"%>
<liferay-frontend:defineObjects />
<liferay-theme:defineObjects />
<%
String redirect = ParamUtil.getString(request, "redirect");
%>

4.  Open the file "build.gradle" and add the following dependency:

compileOnly group: 'com.liferay.commerce', name: 'com.liferay.commerce.payment.api', version: '5.0.0'
compileOnly group: "com.liferay.commerce", name: "com.liferay.commerce.product.api", version: "29.0.2"

5.  Create a new package:

  • Com.liferay.commerce.payment.method.redsys.taglib.ui

6.  In “com.liferay.commerce.payment.method.redsys.taglib.ui” create a new class called “RedsysCommercePaymentMethodConfigurationScreenNavigationEntry” and implement the interface “ScreenNavigationEntry<CommercePaymentMethodGroupRel>”, then implement all the methods as well.

7.  Annotate this class with @Component and set 2 properties. It should look like this:

@Component(
      property = "screen.navigation.category.order:Integer=20",
      service = ScreenNavigationEntry.class
)

8.  Create the following variable (KEY), and return it in the "getEntryKey" method:

public static final String ENTRY_KEY_CARD_COMMERCE_PAYMENT_METHOD_CONFIGURATION = "redsys-configuration";

@Override
public String getEntryKey() {
   return ENTRY_KEY_CARD_COMMERCE_PAYMENT_METHOD_CONFIGURATION;
}

9.  In the following three methods ("getCategory", "getScreenNavigationKey", "getLabel") return the following values from the constants of the class "CommercePaymentScreenNavigationConstants".

@Override
    public String getCategoryKey() {
        return CommercePaymentScreenNavigationConstants.CATEGORY_KEY_COMMERCE_PAYMENT_METHOD_CONFIGURATION;
    }

    @Override
    public String getScreenNavigationKey() {
        return CommercePaymentScreenNavigationConstants.SCREEN_NAVIGATION_KEY_COMMERCE_PAYMENT_METHOD;
    }

    @Override
    public String getLabel(Locale locale) {
        return LanguageUtil.get(locale, CommercePaymentScreenNavigationConstants.CATEGORY_KEY_COMMERCE_PAYMENT_METHOD_CONFIGURATION);   
    }

10.  In the "isVisible" method, we validate when that second tab should be presented for the configuration of our payment method:

@Override
public boolean isVisible(User user, CommercePaymentMethodGroupRel commercePaymentMethod) {
     
        if (commercePaymentMethod == null) {
            return false;
        }

        if (RedsysCommercePaymentMethod.KEY.equals(commercePaymentMethod.getEngineKey())) {
            return true;
        }
        return false;   
    }

11.  Now before implementing the logic in the "render" method, at the end of the class, inject the "JSPRenderer" service with the @Reference annotation.

@Reference
private JSPRenderer _jspRenderer;

12.  Next, inject the "ServletContext" service with the @Reference annotation, and use the "target" parameter to reference the "Bundle-SymbolicName" (set in the bnd.bnd file) of your module to locate the JSP.

@Reference(target="(osgi.web.symbolicname=com.liferay.commerce.payment.method.redsys)")
private ServletContext _servletContext;

13.  Open the file "bnd.bnd" and declare a "Web-ContextPath" (the value should be unique). This way, your ServletContext will be generated correctly.

Web-ContextPath: /redsys-commerce-payment-method

14.  Now we inject 2 more services and the logs for our class that we will use in the render:

@Reference
private CommerceChannelService _commerceChannelService;

@Reference
private ConfigurationProvider _configurationProvider;

private static final Log _log = LogFactoryUtil.getLog(RedsysCommercePaymentMethodConfigurationScreenNavigationEntry.class);

15.  In the “render” method, we implement the logic to retrieve the configuration values at the Channel level if it exists and we save it in the “httpServletRequest”. So whenever we are going to edit the fields, the previously saved values will be presented in the inputs.

try {

  long commerceChannelId = ParamUtil.getLong(httpServletRequest, RedsysCommercePaymentMethodConstants.COMMERCE_CHANNEL_ID);

  CommerceChannel commerceChannel =_commerceChannelService.fetchCommerceChannel(commerceChannelId);

  if (Validator.isNotNull(commerceChannel)) {

      RedsysPaymentMethodCardGroupServiceConfiguration redsysPaymentMethodCardGroupServiceConfiguration =
              _configurationProvider.getConfiguration(
                      RedsysPaymentMethodCardGroupServiceConfiguration.class,
                      new ParameterMapSettingsLocator(httpServletRequest.getParameterMap(),
                              new GroupServiceSettingsLocator(commerceChannel.getGroupId(),
                                      RedsysCommercePaymentMethodConstants.SERVICE_NAME))
              );

      httpServletRequest.setAttribute(
              RedsysPaymentMethodCardGroupServiceConfiguration.class.getName(), redsysPaymentMethodCardGroupServiceConfiguration);
  }else {
      if (_log.isDebugEnabled()) {
          _log.debug("CommerceChannel null with the channelId " + commerceChannelId );
      }
  }

}catch (Exception ex) {
  _log.error(ex,ex);
}

16.  Finally, at the end of everything, within the "render" method, we implement our logic to render the JSP "configuration.jsp"

_jspRenderer.renderJSP(
      _servletContext, httpServletRequest, httpServletResponse,
      "/configuration.jsp");

17.  Open the file "configuration.jsp" created earlier, copy and paste the following lines to:

  • Retrieve from the request the configuration values for this payment method in this channel, if it exists.
  • Create a "form action" with the data entry fields for the configuration of our module.
<%@ include file="/init.jsp" %>

<%
  RedsysPaymentMethodCardGroupServiceConfiguration paymentMethodCardGroupServiceConfiguration = (RedsysPaymentMethodCardGroupServiceConfiguration)request.getAttribute(RedsysPaymentMethodCardGroupServiceConfiguration.class.getName());
  long commerceChannelId = ParamUtil.getLong(request, RedsysCommercePaymentMethodConstants.COMMERCE_CHANNEL_ID);
%>

<portlet:actionURL name="editCommercePaymentMethodConfiguration" var="editCommercePaymentMethodActionURL" />
<aui:form action="<%= editCommercePaymentMethodActionURL %>" method="post" name="fm">
<aui:input name="<%= Constants.CMD %>" type="hidden" value="<%= Constants.UPDATE %>" />
<aui:input name="<%= RedsysCommercePaymentMethodConstants.COMMERCE_CHANNEL_ID %>" type="hidden" value="<%= commerceChannelId %>" />
<aui:input name="redirect" type="hidden" value="<%= currentURL %>" />

  <commerce-ui:panel>
     <commerce-ui:info-box title="authentication">
        <div class="alert alert-info">
           <%= LanguageUtil.format(resourceBundle, "redsys-configuration-help", new Object[] {"<a href=\"https://pagosonline.redsys.es\" target=\"_blank\">", "</a>"}, false) %>
        </div>

        <aui:input id="redsys-ds-signature-version" label="ds-signature-version" name="<%= RedsysCommercePaymentMethodConstants.SETTINGS_DS_SIGNATURE_VERSION %>" value="<%= paymentMethodCardGroupServiceConfiguration.dsSignatureVersion() %>" />
        <aui:input id="redsys-signature-secret" label="signature-secret" name="<%= RedsysCommercePaymentMethodConstants.SETTINGS_CLIENT_SECRET %>" value="<%= paymentMethodCardGroupServiceConfiguration.clientSecret() %>" />
        <aui:input id="redsys-merchant-code" label="merchant-code" name="<%= RedsysCommercePaymentMethodConstants.SETTINGS_MERCHANT_CODE %>"  value="<%= paymentMethodCardGroupServiceConfiguration.merchantCode() %>" />
        <aui:input id="redsys-terminal" label="terminal" name="<%= RedsysCommercePaymentMethodConstants.SETTINGS_TERMINAL %>"  value="<%= paymentMethodCardGroupServiceConfiguration.terminal() %>" />
        <aui:select id="redsys-settings--mode" label="mode" name="<%= RedsysCommercePaymentMethodConstants.SETTINGS_MODE %>">
           <%
              for (String mode : RedsysCommercePaymentMethodConstants.MODES) {
           %>
              <aui:option label="<%= mode %>" selected="<%= mode.equals(paymentMethodCardGroupServiceConfiguration.mode()) %>" value="<%= mode %>" />
           <%
           }
           %>
        </aui:select>
        <aui:select id="redsys-settings--type-of-transaction" label="type-of-transaction" name="<%= RedsysCommercePaymentMethodConstants.SETTINGS_TYPES_OF_TRANSACTION %>">
           <%
              for (String typeTransaction : RedsysCommercePaymentMethodConstants.TYPES_OF_TRANSACTION) {
           %>
              <aui:option label="<%= typeTransaction %>" selected="<%= typeTransaction.equals(paymentMethodCardGroupServiceConfiguration.typeTransaction()) %>" value="<%= typeTransaction %>" />
           <%
          }
           %>
        </aui:select>
     </commerce-ui:info-box>
  </commerce-ui:panel>

  <aui:button-row>
     <aui:button cssClass="btn-lg" type="submit" />
     <aui:button cssClass="btn-lg" href="<%= redirect %>" type="cancel" />
  </aui:button-row>
</aui:form>
Remember: all the input fields (inputs) will be to fill in the configuration that we have previously created in “RedsysPaymentMethodCardGroupServiceConfiguration”.

18.  Save the changes and deploy the module by executing the following command within the directory of your module in the Liferay Workspace:

commerce-payment-method-redsys% ./../../gradlew deploy

Now open your Liferay Portal (ex: localhost: 8080), open the Menu> Commerce> Channels> click on the Channel created previously. In the "Payment Methods" section, in the list click on "edit" of Redsys, you should already have a new tab for configuration (as in the image below):

Remember: all the input fields are empty, because we have no configuration values saved for this channel. 

Now if we want to fill the fields with the values and save them, we need to implement our “Action” called by the form when launching a submit.

19.  Create a new package:

  • Com.liferay.commerce.payment.method.redsys.portlet.action

20.  Create a class called “EditRedsysCommercePaymentMethodConfigurationMVCActionCommand” that extends “BaseMVCActionCommand” and implements the “doProcessAction” method.

21.  Annotate this class with @Component and set 3 properties. It should look like this:

@Component(
      immediate = true,
      property = {
              "javax.portlet.name=" + CPPortletKeys.COMMERCE_PAYMENT_METHODS,
              "mvc.command.name=editCommercePaymentMethodConfiguration"
      },
      service = MVCActionCommand.class
)
  • In the properties array, set the following 2 necessary values for our action portlet:
    • "javax.portlet.name=" + CPPortletKeys.COMMERCE_PAYMENT_METHODS
    •  "mvc.command.name=editCommercePaymentMethodConfiguration"
  • As a service, declare the interface implemented by abstract class "BaseMVCActionCommand":
    • service = MVCActionCommand.class
Note: this “MVCActionCommand” is execute in the payment portlet configurations, so the parameter "javax.portlet.name” should be named the same as the payment portlet.

22.  At the end of the class, inject the "UserLocalService" service with the @Reference annotation.

 @Reference
private CommerceChannelService _commerceChannelService;

@Reference
private SettingsFactory _settingsFactory;

23.  Inside the class, create the following method:

private void _updateCommercePaymentMethod(ActionRequest actionRequest)
throws Exception {

long commerceChannelId = ParamUtil.getLong(
actionRequest, RedsysCommercePaymentMethodConstants.COMMERCE_CHANNEL_ID);

CommerceChannel commerceChannel =
_commerceChannelService.getCommerceChannel(commerceChannelId);

Settings settings = _settingsFactory.getSettings(
new GroupServiceSettingsLocator(
commerceChannel.getGroupId(),
RedsysCommercePaymentMethodConstants.SERVICE_NAME));

ModifiableSettings modifiableSettings =
settings.getModifiableSettings();

String dsSignatureVersion = ParamUtil.getString(
actionRequest, RedsysCommercePaymentMethodConstants.SETTINGS_DS_SIGNATURE_VERSION);

modifiableSettings.setValue("dsSignatureVersion", dsSignatureVersion);

String clientSecret = ParamUtil.getString(
actionRequest, RedsysCommercePaymentMethodConstants.SETTINGS_CLIENT_SECRET);

modifiableSettings.setValue("clientSecret", clientSecret);

String mode = ParamUtil.getString(actionRequest, RedsysCommercePaymentMethodConstants.SETTINGS_MODE);

modifiableSettings.setValue("mode", mode);

String merchantCode = ParamUtil.getString(
actionRequest, RedsysCommercePaymentMethodConstants.SETTINGS_MERCHANT_CODE);

modifiableSettings.setValue("merchantCode", merchantCode);

String terminal = ParamUtil.getString(actionRequest, RedsysCommercePaymentMethodConstants.SETTINGS_TERMINAL);

modifiableSettings.setValue("terminal", terminal);

String typeTransaction = ParamUtil.getString(actionRequest, RedsysCommercePaymentMethodConstants.SETTINGS_TYPES_OF_TRANSACTION);

modifiableSettings.setValue("typeTransaction", typeTransaction);

modifiableSettings.store();
} 

24.  Finally, within the "doProcessAction", perform the validation of the "command" that comes in the request and being equal to "update", we will call the updated method. The method should be like this:

 @Override
    protected void doProcessAction(ActionRequest actionRequest, ActionResponse actionResponse) throws Exception {

        String cmd = ParamUtil.getString(actionRequest, Constants.CMD);

        if (cmd.equals(Constants.UPDATE)) {
            _updateCommercePaymentMethod(actionRequest);
        } 
    }

25.  Save the changes and deploy the module by executing the following command within the directory of your module in the Liferay Workspace:

commerce-payment-method-redsys% ./../../gradlew deploy

Now open your Liferay Portal (ex: localhost: 8080), open the Menu> Commerce> Channels> click on the Channel created previously. In the “Payment Methods” section, in the list click on “edit” of Redsys, on the "Details" tab, "active" your "payment method" and save it, so the “configuration” tab will show up. Fill in the fields for the “Test Integration” environment of Redsys and save (as in the image below ):

                          Very good, now we have the module with independent configurations per Channel.

 In the next step, we will begin to implement all the logic for communication with the payment gateway that is configured (in this case, Redsys).

            The code used in this step is available in a tag named "payment-redsys-step-2.1" in my github repo.

Blogs

Hi Roselaine Marques,I follow the steps and but I cannot showing the configuration tag,

Because CommercePaymentMethodGroupRel on isVisible method of class RedsysCommercePaymentMethodConfigurationScreenNavigationEntry always null.

Even I tried the code from your git. Could you help me?

Thank you

Hello Tran, 

To show the "configuration" the Payment Method need to be "active" (maybe is not so clear this point in my blog).

Do you have activated your "Payment Method"? 

I've fixed on "task 25 from Step 2"  this point ;) 

...In the “Payment Methods” section, in the list click on “edit” of Redsys, on the "Details" tab, "active" your "payment method" and save it, so the “configuration” tab will show up...

Please, let me know if your problem persist.