How to Create a Hook To Extend SEPA Framework Functionalities module

From InfiniteERP Wiki
Jump to: navigation, search

Introduction

Hooks provide an easy mechanism to extend functionality from external modules. It basically consists on a lightweight mechanism (build using WELD) that allows to inject dependencies from third party modules. Since 1.0.100 version of SEPA Framework and Utilities module it's possible to extend the SEPA XML file generation from external modules using hooks. These hooks allow to easily develop customizations required by concrete countries or banks without affecting the original module, this way it's possible to modify, add or even delete any node or tag of the XML generated by the base process.

The main purpose of this how-to is to explain the way of make these customizations in external modules.

Objective

In this article we will explain a detailed example of how to create and package an external module that extends current SEPA functionalities using hooks. We are going to do a customization that fulfills the following requirements:

  • Depending on the remittance type and scheme definition version being processed, additional information should be included (or not) to every Payment Information node. Nodes to be added will be: <CtrlSum> and <NbOfTxs>.
  • The <CtrlSum> node will be added if the PmtInf_CtrlSum parameter is defined for the remittance type, is active and has a value = Y.
  • The <NbOfTxs> node will be added if the PmtInf_ NbOfTxs parameter is defined for the remittance type, is active and has a value = Y.
  • The module must add the PmtInf_CtrlSum and PmtInf_NbOfTxs parameters to the remittance types included in SEPA Credit Transfer and SEPA Direct Debit modules datasets. A new dataset including this information should be created to make it available when the module is installed.

In next sections of this how-to, necessary steps to implement this kinds of hooks will be described. Specifically, we are going to explain how to extend the SEPA XML files according to the requirements described above.

Recommended articles

Before reading this howto it is important to have a clear understanding about the Modularity Concepts, specially the process of creating and packing modules.

As in this how-to we are extending functionalities of SEPA modules, will be necessary to set up and know concepts of SEPA Credit Transfer and SEPA Direct Debit modules.

Also we are going to create a dataset including two new parameters to the Remittance Types defined in the SEPA datasets, which will be used inside the hook to add the new nodes to the XML, that’s why it is recommended to read the How to create a Dataset article to get a general idea before doing in our example.

Creating the Module

The first step in this development process is to create a new module. From the Application menu, select Application Dictionary || Module.

001-CreateNewModule.jpg

In our case it's important to highlight the Java Package we are using should be a unique identifier of your module and has to match the Java package naming rules as described in the Java Naming Conventions (names and package names). Package used in this example will be org.openbravo.sepa.iso20022.extension.

We are going to extend functionalities of SEPA Credit Transfer and Direct Debit modules, so we need to add them as dependencies of our module. Also we will provide extra functionality to the base one existing in SEPA Framework.

2-Dependencies.jpg

Important note: Hooks were included in SEPA Framework module since 1.0.100 version, so you need to create a Major version dependency enforcement to this version to implement and extend functionality using hooks.


Creating a Source Directory

To develop manual Java code you need a src directory inside your specific module:

03-SourceFolder.jpg

The Java package in the source directory should start with the Java package of the module. So for this case org.openbravo.sepa.iso20022.extension.hook is a valid package and will be used to create our implementation of the hook.

If using Eclipse, add the newly created module's src folder to the build path of the Eclipse project (Java Build Path):

04-EclipseBuildPath.jpg

Implementing the Hook

To create a hook, you just need to create a new class (for instance SEPA_RemittanceHook) implementing the SEPA_RemittanceProcessHook interface provided in the 1.0.100 version of SEPA Freamework module to extend the SEPA XML generated file:

<source lang="java">@ApplicationScoped public class SEPA_RemittanceHook implements SEPA_RemittanceProcessHook {

 private static final String PARAM_PMTINF_CTRLSUM = "PmtInf_CtrlSum";
 private static final String PARAM_PMTINF_NBOFTXS = "PmtInf_NbOfTxs";

</source>

You need to override the exec() method to implement your logic inside the hook. This method receives the remittance to be processed and the XML representation of the document according the schema definition used in the remittance type. According this representation and the instance of the document you will know the necessary API to use for a correct processing of the XML schema definition and your development requirements.

The @ApplicationScoped annotation will inject this class implementation of the hook when SEPA XML file is processed.

<source lang="java">@Override

 public <T> void exec(Remittance remittance, JAXBElement<T> doc) throws Exception {
   if (doc.getValue() instanceof org.openbravo.sepa.iso20022.coredirectdebit.customertobank.pain.x008.x001.x02.Document) {
     processCoreDirectDebitx008x001x002(remittance, doc);
   } else if (doc.getValue() instanceof org.openbravo.sepa.iso20022.coredirectdebit.customertobank.pain.x008.x001.x03.Document) {
     processCoreDirectDebitx008x001x003(remittance, doc);
   } else if (doc.getValue() instanceof org.openbravo.sepa.iso20022.credittransfer.customertobank.pain.x001.x001.x03.Document) {
     processCreditTransferx001x001x003(remittance, doc);
   } else if (doc.getValue() instanceof org.openbravo.sepa.iso20022.credittransfer.customertobank.pain.x001.x001.x04.Document) {
     processCreditTransferx001x001x004(remittance, doc);
   }
 }

</source>

In this concrete example, our logic will be: If the remittance type of the document being processed has the PmtInf_CtrlSum or NbOfTxs parameters active and with value = Y then we add the <CtrlSum> and <NbOfTxs> tags to every payment information of the XML file.

We will use two methods to know if parameters are active or not:

<source lang="java">

 /**
  * Get if PmtInf_CrtrlSum PARAM is defined in the remittance type used in the remittance param
  * 
  * @param remittance
  *          Remittance being processed
  * @return TRUE if parameter is defined, is active and has value = 'Y'
  */
 private boolean getPmtInf_CrtrlSum(final Remittance remittance) {
   return SEPAUtil.getBooleanPropertyValue(remittance, PARAM_PMTINF_CTRLSUM);
 }
 /**
  * Get if PmtInf_NbOfTxs PARAM is defined in the remittance type used in the remittance param
  * 
  * @param remittance
  *          Remittance being processed
  * @return TRUE if parameter is defined, is active and has value = 'Y'
  */
 private boolean getPmtInf_NbOfTxs(final Remittance remittance) {
   return SEPAUtil.getBooleanPropertyValue(remittance, PARAM_PMTINF_NBOFTXS);
 }

</source>

Taking into account the document type being processed we will process the XML according to the schema defined for this type of document.

<source lang="java"> private <T> void processCoreDirectDebitx008x001x002(Remittance remittance, JAXBElement<T> doc) {

   boolean pmtInf_CtrlSum = getPmtInf_CrtrlSum(remittance);
   boolean pmtInf_NbOfTxs = getPmtInf_NbOfTxs(remittance);
   // 2.4 Número de transacciones y 2.5 Control de la suma por información de pago - Number of
   // transactions and ControlSum per Payment Information
   // Not mandatory
   // If any of the pmtInf_CtrlSum || pmtInf_NbOfTxs parameters are defined in AD, are active and
   // has value = Y then:
   // Iterate and add NbOfTxs and CtrlSum tags to all payment instructions nodes
   if (pmtInf_CtrlSum || pmtInf_NbOfTxs) {
     org.openbravo.sepa.iso20022.coredirectdebit.customertobank.pain.x008.x001.x02.Document document = (org.openbravo.sepa.iso20022.coredirectdebit.customertobank.pain.x008.x001.x02.Document) doc
         .getValue();
     // Iterates all payment instructions (pmtInf nodes)
     for (PaymentInstructionInformation4 paymentInstruction : document.getCstmrDrctDbtInitn()
         .getPmtInf()) {
       if (pmtInf_CtrlSum) {
         BigDecimal totalAmtInf = BigDecimal.ZERO;
         // Per each pmtInf node, calculate the total amount of credits related to the current
         // payment instruction
         for (DirectDebitTransactionInformation9 dbtTrfTxInf : paymentInstruction
             .getDrctDbtTxInf()) {
           totalAmtInf = totalAmtInf.add(dbtTrfTxInf.getInstdAmt().getValue());
         }
         // Update the CtrlSum of the payment instruction
         paymentInstruction.setCtrlSum(totalAmtInf.setScale(CreditTransferConstant.AMOUNT_SCALE,
             RoundingMode.HALF_UP));
       }
       if (pmtInf_NbOfTxs) {
         // Update the number of credit transactions related to the payment instruction
         int nbOfTxs = paymentInstruction.getDrctDbtTxInf().size();
         paymentInstruction.setNbOfTxs(String.valueOf(nbOfTxs));
       }
     }
   }
 }

</source>

It is important to highlight that any exception thrown by the hook, will make the XML to be not generated. You must take this into account when implementing your solutions.

Executing the Hook

When a remittance is created related with any of the Remittance types used in our example, the hook will be injected by Weld into SEPA Framework and the XML will be generated with changes applied by our hook.

For example, with PmtInf_CtrlSum and PmtInf_NbOfTxs parameters set as Y, we will generate an XML file like this:

05-SEPAXMLFile.jpg

Creating the dataset

As a requirement of developed hook, it checks for PmtInf_CtrlSum and PmtInf_NbOfTxs parameters values to add respectively nodes to the Payment Information nodes when generating the SEPA XML file. Due that we are going to include these new parameters into module dataset to make them available for environments using this hook.

This section describes necessary steps to create and export the dataset.

Adding new parameters to existing remittance types

Now we are going to add the new parameters to all Remittance types we are processing in our hook. To do that, go to Remittance Type window. Select all SEPA Core Direct Debit and SEPA Credit Transfer remittance types and add two new parameters to all of them, like in the screenshot below .

007-AddingParamsToRemittanceTypes.jpg

Exporting the dataset

Before creating and exporting our dataset, we must make sure that our module is marked as Has reference data.

008-HasReferenceDataSelected.jpg

Next step is to create the dataset in our module. To do that, go to Dataset window and create new one as shown below:

009-CreateDataset.jpg

You must take into account that:

  • The dataset must belong to your SEPA-Remittance extension module
  • Try to avoid strange characters in the dataset name. This string is used for generating the XML file name that stores the dataset.
  • The Data Access Level must be set to Client/Organization, which means we allow users to apply the taxes configuration either at Client level (Organization *) or at Organization level.
  • The Export allowed flag must be set.
  • Inside the Table tab we must include all the tables to be included into the dataset. The list of tables that we must include is:
    • REM_Remittance_Type_Param, which is related with the Remittance Type parameters created.
  • The HQL/SQL Where clause is a very important field, because it allows us to filter the records we want to include into the dataset. In this example we created the new parameters related to the Remittance types we are extending so we will filtering by them, using the name IN ('PmtInf_CtrlSum','PmtInf_NbOfTxs') clause to get only the records with these names which are the only ones we want to distribute in our module dataset.

The dataset definition is ready, so we just need to export it to a file pressing the Export Reference Data button. This process queries the previous tables and gets all the records that fulfill the HQL/SQL Where clause, generating a XML file inside the module's referencedata/standard directory. As a fast check, you can open this file using any plain text editor and you can verify that it contains a total of 2 entries for each remittance type treated inside the hook.

In case the file is empty, you should double check the dataset definition, specially the HQL/SQL Where clause used for each table.

Example of external module

You can find a complete example of the external module created in this how-to article in the following link: http://centralrepository.openbravo.com/openbravo/org.openbravo.forge.ui/sso/ForgeModuleDetail/SEPARemittance-Extensions

With provided sources you should be able to adapt it (or use it as basis) to implement your own solution, adding new nodes or updating the information of the existing ones to get a customized SEPA XML file.