Source code documentation

Contracts

1. Introduction

The contracts describe the terms (ACTUS contract terms) of the contract agreed upon between counterparties as one part, and the payment details (payment gateways) of each of the counterparties involved in the contractual agreement.

The contracts endpoints allows adding new and managing existing contracts. The contract is described in terms of one or multiple ACTUS contract templates. For each attribute of a template is according to the ACTUS data dictionary

2. Tables and relations

Establishing relationships

  • In relational databases like PostgreSQL, relationships between tables are crucial for organizing and querying data effectively. These relationships are typically established using foreign key constraints, which define links between tables based on the values of specific columns. Common types of relationships include one-to-one, one-to-many, and many-to-many relationships, each serving different data modeling needs.

contracts ERD
Figure 1. Contracts Entity-relationship diagram

Tables

  • Schema

    1. Table business_events

      Index Name Data type

      * πŸ”‘ ⬋

      eventid

      uuid

      *

      event_time

      timestamp

      * πŸ”Ž

      event_type

      varchar(10)

      event_body

      json

      * πŸ”Ž

      status

      varchar(10)

      * πŸ”Ž

      execution_type

      varchar(20)

      contractid

      varchar(255)

      *

      userid

      uuid

      * πŸ”Ž ⬈

      contractuuid

      uuid

      value

      numeric

      remaining_value

      numeric

      credit_payment_channel_id

      uuid

      debit_payment_channel_id

      uuid

      units

      varchar(10)

      1. Foreign keys

        Type Name On

        fk_business_events_contracts_contractuuid

        contractuuid

      2. Constraints

        Name Definition

        business_events_event_type_check

        ((event_type)::text ~* ’^(AD/IED/FP/PR/PD/PRF/PY/PP/IP/IPCI/CE/RRF/RR/DV/PRD/MR/TD/SC/IPCB/MD/XD/STD/PI/IPFX/IPFL/ME/TP/OPS)$'::text)

        business_events_status_check

        ((status)::text ~* ’^(scheduled

        pending

        processed)$'::text)

    2. Table contracts

      Index Name Data type

      * πŸ”‘ ⬋

      contractuuid

      uuid

      ⬈

      productid

      bigint

      *

      createdby

      uuid

      executedby

      uuid

      *

      system_time

      timestamp

      selection

      json

      1. Foreign keys

        Type Name On

        contracts_product_fk

        productid

    3. Table contracts_history

      Index Name Data type

      * πŸ”‘ ⬋

      contractuuid

      uuid

      * πŸ”‘ ⬋

      status_date

      timestamp

      productid

      bigint

      selection

      json

      *

      system_time

      timestamp

    4. Table payment_channels

      Index Name Data type

      * πŸ”‘ ⬋

      payment_channelid

      uuid

      contractid

      uuid

      details

      json

      *

      identifier

      varchar(100)

      label

      varchar(100)

      *

      type

      varchar(50)

      * πŸ”Ž

      owner_type

      varchar(10)

      *

      units

      varchar(10)

      *

      system

      varchar(50)

      account_characteristic

      varchar(50)

      * πŸ”Ž

      ownerid

      uuid

      * πŸ”Ž

      userid

      uuid

      1. Constraints

        Name Definition

        payment_channels_owner_type_check

        ((owner_type)::text ~* ’^(root/profile)$'::text)

    5. Table payment_details

      Index Name Data type

      * πŸ”‘

      id

      bigint GENERATED BY DEFAULT AS IDENTITY

      ⬈

      contract_uuid

      uuid

      ⬈

      record_creator_paymentchannel_id

      uuid

      ⬈

      counterparty_paymentchannel_id

      uuid

      ⬈

      contract_paymentchannel_id

      uuid

      1. Foreign keys

        Type Name On

        paymentdetails_contractuuid_fk

        contract_uuid

        paymentdetails_contract_payment_fk

        contract_paymentchannel_id

        paymentdetails_counterparty_fk

        counterparty_paymentchannel_id

        paymentdetails_record_creator_fk

        record_creator_paymentchannel_id

    6. Table products

      Idx Name Data Type

      * πŸ”‘ ⬋

      productid

      bigint GENERATED BY DEFAULT AS IDENTITY

      *

      status

      varchar(10)

      *

      template

      json

      * πŸ”Ž

      userid

      uuid

      1. Constraints

        Name Definition

        products_status_check

        ((status)::text ~* ’^(active/inactive)$'::text)

    7. Table profile_forms

      Idx Name Data Type

      * πŸ”‘ ⬋

      profile_formid

      bigint GENERATED BY DEFAULT AS IDENTITY

      *

      profile_form_details

      json

      *

      userid

      uuid

    8. Table profiles

      Index Name Data type

      * πŸ”‘ ⬋

      profileid

      uuid

      profile_details

      json

      *

      status

      varchar(10)

      *

      userid

      uuid

      * ⬈

      profile_formid

      bigint

      1. Foreign keys

        Type Name On

        fk_profiles_profile_forms_profile_formid

        profile_formid

      2. Constraints

        Name Definition

        profiles_status_check

        ((status)::text ~* ’^(active/inactive)$'::text)

    9. Table terms

      Index Name Data type

      * πŸ”‘

      id

      integer GENERATED BY DEFAULT AS IDENTITY

      accrued_interest

      numeric

      amortization_date

      timestamp

      array_cycle_anchor_date_of_interest_payment

      varchar(255)

      array_cycle_anchor_date_of_principal_redemption

      varchar(255)

      array_cycle_anchor_date_of_rate_reset

      varchar(255)

      array_cycle_of_interest_payment

      varchar(255)

      array_cycle_of_principal_redemption

      varchar(255)

      array_cycle_of_rate_reset

      varchar(255)

      array_fixed_variable

      varchar(255)

      array_increase_decrease

      varchar(255)

      array_next_principal_redemption_payment

      varchar(255)

      array_rate

      varchar(255)

      business_day_convention

      varchar(5)

      calendar

      varchar(2)

      capitalization_end_date

      timestamp

      contract_deal_date

      timestamp

      contractid

      varchar(255)

      *

      contract_role

      varchar(6)

      contract_performance

      varchar(10)

      *

      contract_type

      varchar(15)

      *

      currency

      varchar(10)

      currency2

      varchar(10)

      cycle_anchor_date_of_dividend_payment

      timestamp

      cycle_anchor_date_of_fee

      timestamp

      cycle_anchor_date_of_interest_calculation_base

      timestamp

      cycle_anchor_date_of_interest_payment

      timestamp

      cycle_anchor_date_of_optionality

      timestamp

      cycle_anchor_date_of_principal_redemption

      timestamp

      cycle_anchor_date_of_rate_reset

      timestamp

      cycle_anchor_date_of_scaling_index

      timestamp

      cycle_of_dividend_payment

      varchar(10)

      cycle_of_fee

      varchar(10)

      cycle_of_interest_calculation_base

      varchar(10)

      cycle_of_interest_payment

      varchar(10)

      cycle_of_optionality

      varchar(10)

      cycle_of_principal_redemption

      varchar(10)

      cycle_of_rate_reset

      varchar(10)

      cycle_of_scaling_index

      varchar(10)

      cycle_point_of_interest_payment

      varchar(1)

      cycle_point_of_rate_reset

      varchar(1)

      *

      day_count_convention

      varchar(10)

      delivery_settlement

      varchar(1)

      end_of_month_convention

      varchar(5)

      fee_accrued

      numeric

      fee_basis

      varchar(1)

      fee_rate

      numeric

      fixing_period

      varchar(255)

      initial_exchange_date

      timestamp

      interest_calculation_base

      varchar(10)

      interest_calculation_base_amount

      numeric

      life_cap

      numeric

      life_floor

      numeric

      market_object_code

      varchar(255)

      market_object_code_of_dividend_rate

      varchar(255)

      market_object_code_of_rate_reset

      varchar(255)

      market_object_code_of_scaling_index

      varchar(255)

      market_value_observed

      numeric

      maturity_date

      timestamp

      maximum_penalty_free_disbursement

      varchar(255)

      next_principal_redemption_payment

      numeric

      next_reset_rate

      numeric

      nominal_interest_rate

      numeric

      nominal_interest_rate2

      numeric

      notional_principal

      numeric

      notional_principal2

      numeric

      object_code_of_prepayment_model

      varchar(255)

      penalty_rate

      numeric

      penalty_type

      varchar(1)

      period_cap

      numeric

      period_floor

      numeric

      premium_discount_atied

      numeric

      price_at_purchase_date

      numeric

      price_at_termination_date

      numeric

      purchase_date

      timestamp

      quantity

      numeric

      rate_spread

      numeric

      rounding_convention

      varchar(255)

      scaling_effect

      varchar(5)

      scaling_index_at_contract_deal_date

      numeric

      settlement_period

      varchar(255)

      status_date

      timestamp

      x_day_notice

      varchar(255)

      termination_date

      timestamp

      delinquency_period

      varchar(255)

      grace_period

      varchar(255)

      market_object_code_of_dividends

      varchar(255)

      rate_multiplier

      numeric

      * ⬈

      contract_uuid

      uuid

      ⬈

      counterparty_id

      uuid

      * πŸ”Ž

      creator_id

      uuid

      1. Foreign keys

        Type Name On

        terms_contractuuid_fk

        contract_uuid

        terms_counterparty_id_fk

        counterparty_id

      2. Constraints

        Name Definition

        terms_business_day_convention_check

        ((business_day_convention)::text ~* ’^(NOS/SCF/SCMF/CSF/CSMF/SCP/SCMP/CSP/SCMP)$'::text)

        terms_calendar_check

        ((calendar)::text ~* ’^(NC/MF)$'::text)

        terms_fee_basis_check

        ((fee_basis)::text ~* ’^(A/N)$'::text)

        terms_delivery_settlement_check

        ((delivery_settlement)::text ~* ’^(D/S)$'::text)

        terms_cycle_of_dividend_payment_check

        cycle_of_dividend_payment)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_cycle_of_interest_calculation_base_check

        cycle_of_interest_calculation_base)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_cycle_of_interest_payment_check

        cycle_of_interest_payment)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_cycle_of_principal_redemption_check

        cycle_of_principal_redemption)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_cycle_of_rate_reset_check

        cycle_of_rate_reset)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_cycle_of_scaling_index_check

        cycle_of_scaling_index)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_cycle_point_of_interest_payment_check

        ((cycle_point_of_interest_payment)::text ~* ’^(B/E)$'::text)

        terms_contract_performance_check

        ((contract_performance)::text ~* ’^(PF/DL/DQ/DF/MA/TE/PreDeal)$'::text)

        terms_penalty_type_check

        ((penalty_type)::text ~* ’^(N/A/R/I)$'::text)

    10. Table terms_history

      Index Name Data type

      * πŸ”‘

      terms_history_id

      bigint GENERATED BY DEFAULT AS IDENTITY

      accrued_interest

      numeric

      amortization_date

      timestamp

      array_cycle_anchor_date_of_interest_payment

      varchar(255)

      array_cycle_anchor_date_of_principal_redemption

      varchar(255)

      array_cycle_anchor_date_of_rate_reset

      varchar(255)

      array_cycle_of_interest_payment

      varchar(255)

      array_cycle_of_principal_redemption

      varchar(255)

      array_cycle_of_rate_reset

      varchar(255)

      array_fixed_variable

      varchar(255)

      array_increase_decrease

      varchar(255)

      array_next_principal_redemption_payment

      varchar(255)

      array_rate

      varchar(255)

      business_day_convention

      varchar(5)

      calendar

      varchar(2)

      capitalization_end_date

      timestamp

      contract_deal_date

      timestamp

      contractid

      varchar(255)

      *

      contract_role

      varchar(6)

      contract_performance

      varchar(10)

      *

      contract_type

      varchar(15)

      *

      currency

      varchar(10)

      currency2

      varchar(10)

      cycle_anchor_date_of_dividend_payment

      timestamp

      cycle_anchor_date_of_fee

      timestamp

      cycle_anchor_date_of_interest_calculation_base

      timestamp

      cycle_anchor_date_of_interest_payment

      timestamp

      cycle_anchor_date_of_optionality

      timestamp

      cycle_anchor_date_of_principal_redemption

      timestamp

      cycle_anchor_date_of_rate_reset

      timestamp

      cycle_anchor_date_of_scaling_index

      timestamp

      cycle_of_dividend_payment

      varchar(10)

      cycle_of_fee

      varchar(10)

      cycle_of_interest_calculation_base

      varchar(10)

      cycle_of_interest_payment

      varchar(10)

      cycle_of_optionality

      varchar(10)

      cycle_of_principal_redemption

      varchar(10)

      cycle_of_rate_reset

      varchar(10)

      cycle_of_scaling_index

      varchar(10)

      cycle_point_of_interest_payment

      varchar(1)

      cycle_point_of_rate_reset

      varchar(1)

      *

      day_count_convention

      varchar(10)

      delivery_settlement

      varchar(1)

      end_of_month_convention

      varchar(5)

      fee_accrued

      numeric

      fee_basis

      varchar(1)

      fee_rate

      numeric

      fixing_period

      varchar(255)

      initial_exchange_date

      timestamp

      interest_calculation_base

      varchar(10)

      interest_calculation_base_amount

      numeric

      life_cap

      numeric

      life_floor

      numeric

      market_object_code

      varchar(255)

      market_object_code_of_dividend_rate

      varchar(255)

      market_object_code_of_rate_reset

      varchar(255)

      market_object_code_of_scaling_index

      varchar(255)

      market_value_observed

      numeric

      maturity_date

      timestamp

      maximum_penalty_free_disbursement

      varchar(255)

      next_principal_redemption_payment

      numeric

      next_reset_rate

      numeric

      nominal_interest_rate

      numeric

      nominal_interest_rate2

      numeric

      notional_principal

      numeric

      notional_principal2

      numeric

      object_code_of_prepayment_model

      varchar(255)

      penalty_rate

      numeric

      penalty_type

      varchar(1)

      period_cap

      numeric

      period_floor

      numeric

      premium_discount_atied

      numeric

      price_at_purchase_date

      numeric

      price_at_termination_date

      numeric

      purchase_date

      timestamp

      quantity

      numeric

      rate_spread

      numeric

      rounding_convention

      varchar(255)

      scaling_effect

      varchar(5)

      scaling_index_at_contract_deal_date

      numeric

      settlement_period

      varchar(255)

      x_day_notice

      varchar(255)

      termination_date

      timestamp

      delinquency_period

      varchar(255)

      grace_period

      varchar(255)

      market_object_code_of_dividends

      varchar(255)

      rate_multiplier

      numeric

      *

      creator_id

      uuid

      ⬈

      contractuuid

      uuid

      ⬈

      status_date

      timestamp

      1. Foreign keys

        Type Name On

        fk-contracts_history-terms_history

        contractuuid, status_date

      2. Constraints

    Name Definition

    terms_history_business_day_convention_check

    ((business_day_convention)::text ~* ’^(NOS/SCF/SCMF/CSF/CSMF/SCP/SCMP/CSP/SCMP)$'::text)

    terms_history_calendar_check

    ((calendar)::text ~* ’^(NC/MF)$'::text)

    terms_history_fee_basis_check

    ((fee_basis)::text ~* ’^(A/N)$'::text)

    terms_history_delivery_settlement_check

    ((delivery_settlement)::text ~* ’^(D/S)$'::text)

    terms_history_cycle_of_dividend_payment_check

    cycle_of_dividend_payment)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

    terms_history_cycle_of_interest_calculation_base_check

    cycle_of_interest_calculation_base)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

    terms_history_cycle_of_interest_payment_check

    cycle_of_interest_payment)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

    terms_history_cycle_of_principal_redemption_check

    cycle_of_principal_redemption)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

    terms_history_cycle_of_rate_reset_check

    cycle_of_rate_reset)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

    terms_history_cycle_of_scaling_index_check

    cycle_of_scaling_index)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

    terms_history_cycle_point_of_interest_payment_check

    ((cycle_point_of_interest_payment)::text ~* ’^(B/E)$'::text)

    terms_history_contract_performance_check

    ((contract_performance)::text ~* ’^(PF/DL/DQ/DF/MA/TE/PreDeal)$'::text)

    terms_history_penalty_type_check

    ((penalty_type)::text ~* ’^(N/A/R/I)$'::text)

    terms_history_scaling_effect_check

    ((scaling\_effect)::text ~* '^(OOO/IOO/ONO/INO)$'::text)

(πŸ”‘) - Primary key

(*) - Mandatory

(⬈) - Foreign key

(πŸ”Ž) - Constraint

3. Dependencies and libraries

3.1. Dependencies

Description

The following dependencies are used in the project to provide various functionalities and features:

  1. spring-kafka

    • Purpose: Spring for Apache Kafka for building Kafka-based messaging systems.

    • Usage: Producing and consuming messages from Kafka topics.

  2. spring-cloud-starter-openfeign

    • Purpose: The spring-cloud-starter-openfeign dependency is used in Spring Boot applications to simplify the process of creating REST clients. It integrates the Feign client library into your application, providing a declarative way to define RESTful service clients.

    • Usage: Use spring-cloud-starter-openfeign to define interfaces for RESTful services and easily make HTTP requests to those services. Feign handles the creation of the HTTP request and mapping of the response to Java objects, reducing the boilerplate code typically required for REST client implementations.

  3. spring-cloud-starter-loadbalancer

    • Purpose: The spring-cloud-starter-loadbalancer dependency is used in Spring Boot applications to provide client-side load balancing. It integrates with Spring Cloud’s load balancing features, allowing applications to distribute traffic across multiple instances of a service.

    • Usage: Use spring-cloud-starter-loadbalancer to enable client-side load balancing in your application. It provides a simple API for making requests to services registered with a service registry (e.g., Eureka), automatically handling the load balancing logic. This helps improve the availability and scalability of your application by distributing traffic evenly across service instances.

  4. modelmapper (version 0.7.5)

    • Purpose: The modelmapper dependency simplifies the process of mapping objects between different data models by automatically determining how properties should be mapped from one object to another.

    • Usage: Use modelmapper to streamline the mapping process between DTOs (Data Transfer Objects), entities, and other data models, reducing the need for manual mapping code and improving code maintainability.

  • Dependency versions are specified to ensure compatibility and stability.

  • Additional dependencies may be added or removed based on project requirements and architecture.

3.2. Libraries

Description

The following libraries are used in the project to provide various functionalities and features:

  1. actus-core (version 1.0.1)

    • Purpose: The actus-core library provides core functionality and utilities for working with financial contracts and cash flow projections based on the ACTUS standard.

    • Usage: Use to perform calculations, projections, and analysis of financial contracts and cash flows according to the ACTUS (Algorithmic Contract Types Unified Standards) standard.

  2. ariadne-contracts (version 0.0.2)

    • Purpose: The ariadne-contracts library offers functionality and utilities for working with contract data and management within financial applications.

    • Usage: Use ariadne-contracts to handle contract data, perform contract management tasks, and integrate contract-related functionalities into financial applications.

  • Library versions are specified to ensure compatibility and stability.

  • Additional libraries may be added or removed based on project requirements and architecture.

4. Exception handling

Description

The RestExceptionHandler class is responsible for handling various exceptions that may occur during the execution of RESTful API endpoints. It provides centralized exception handling to ensure consistent error responses across the application.

Exception handlers

Example usage

@ControllerAdvice
public class RestExceptionHandler {

	@ExceptionHandler({ContractsException.class, IllegalArgumentException.class}) (1)
	public ResponseEntity<ResponseDto> exceptionToDoHandler(Exception ex) {
		final ResponseDto error = new ResponseDto();
		error.setStatus(HttpStatus.BAD_REQUEST.value());
		error.setMessage(ex.getMessage());
		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

	@ExceptionHandler(value = { AccessDeniedException.class }) (2)
	public ResponseEntity<ResponseDto> exceptionHandler(Exception ex) {
		final ResponseDto error = new ResponseDto();
		error.setStatus(HttpStatus.UNAUTHORIZED.value());
		error.setMessage("Access Denied...");
		return new ResponseEntity<>(error, HttpStatus.UNAUTHORIZED);
	}

	@ExceptionHandler(value = { Exception.class, }) (3)
	public ResponseEntity<ResponseDto> exceptionHandlerr(Exception ex) {

		final ResponseDto error = new ResponseDto();
		error.setStatus(HttpStatus.BAD_REQUEST.value());
		error.setMessage("The request could not be understood by the server due to malformed syntax.");
		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

}
1 ContractsException and IllegalArgumentException handler
  • Handles exceptions of type ContractsException and IllegalArgumentException.

  • Returns a ResponseEntity with a status code of 400 Bad Request and an error message derived from the exception’s message.

2 AccessDeniedException handler
  • Handles exceptions of type AccessDeniedException, typically thrown when a user lacks the necessary permissions to access a resource.

  • Returns a ResponseEntity with a status code of 401 Unauthorized and a generic "Access Denied" message.

3 Generic exception handler
  • Handles any other uncaught exceptions that may occur during the execution of API endpoints.

  • Returns a ResponseEntity with a status code of 400 Bad Request and a generic error message indicating malformed syntax.

Customization

  • Additional exception handlers can be added to address specific use cases or domain-specific exceptions.

  • Error messages and status codes can be customized based on application requirements and error scenarios.

6. ContractsServiceController

6.1. Create contract

6.1.1. Sequential flow

create-contract.puml

Contract creation process

The below business process / method β€˜createContract’ enables creation of a Loan account / Checking account. Here below are process steps -

  1. To fetch the product form (Product Template) with ProductID as specified in the contract object.

  2. Product template this is fetched is validated with request payload (Contract terms)

  3. Counterparty and PaymentDetails are validated.

The validation that are performed at this stage are

  1. If counterpartyIDs (Profile IDs) and Counterparty payment channel exists

  2. If creator ID (user ID) and creator payment channel ID exist

  3. If contract terms are compliant with ACTUS data dictionary

  4. If applicability rules of ACTUS are valid for the contract terms provided

After the necessary contract creation process steps and validations are completed, a new contracts with ContractStatus = β€œPreDeal” is created.

6.1.2. Endpoint

Description

This endpoint allows users with the appropriate permissions to create contracts based on the provided data.

URL

/contracts

Method

POST

Request body

The request body should contain a JSON array of objects, each representing data for creating a contract. The structure of each object should adhere to the CreateContractsDto format.

Example request body

[
  {
    "productID": 1,
    "terms": [
      {
        "contractPerformance": "PreDeal",
        "businessDayConvention": "SCF",
        "contractType": "ANN",
        "statusDate": "2023-07-31T06:30:00",
        "contractRole": "RPA",
        "creatorID": "a43c22ed-27df-4324-a453-3e7707c9b82d",
        "counterpartyID": "e548956c-1f3b-493e-952e-00cdcca6b599",
        "contractID": "a6b799db-c448-4aad-9382-3ae47383f5b2",
        "cycleAnchorDateOfInterestPayment": "2023-09-01T06:30:00",
        "cycleOfInterestPayment": "P1ML1",
        "nominalInterestRate": 0.02,
        "dayCountConvention": "30E360",
        "currency": "CHF",
        "contractDealDate": "2023-07-31T06:30:00",
        "initialExchangeDate": "2023-08-01T06:30:00",
        "maturityDate": "2024-08-01T06:30:00",
        "notionalPrincipal": 50000,
        "cycleAnchorDateOfPrincipalRedemption": "2023-09-01T06:30:00",
        "cycleOfPrincipalRedemption": "P1ML1",
        "nextPrincipalRedemptionPayment": 2312.7827499791606
      }
    ],
    "paymentDetails": {
      "recordCreatorPaymentChannelID": "e03c2694-71f8-48e0-a68d-8328630fd0c5",
      "counterpartyPaymentChannelID": "6963c361-1c1f-40b6-b8b4-47f604be36ef"
    },
    "selection": {
      "productCategory": "Loans",
      "department": "DeptB",
      "profitCenter": "A",
      "tenure": "12M"
    }
  }
]

Responses

  • 201 CREATED: Success. Returns a JSON response containing details of the created contracts.

Example response body

{
  "status": 201,
  "message": "Success",
  "data": [
    {
      "productID": 1,
      "terms": [
        {
          "contractPerformance": "PreDeal",
          "businessDayConvention": "SCF",
          "contractType": "ANN",
          "statusDate": "2023-07-31T06:30:00",
          "contractRole": "RPA",
          "creatorID": "a43c22ed-27df-4324-a453-3e7707c9b82d",
          "counterpartyID": "e548956c-1f3b-493e-952e-00cdcca6b599",
          "contractID": "a6b799db-c448-4aad-9382-3ae47383f5b2",
          "cycleAnchorDateOfInterestPayment": "2023-09-01T06:30:00",
          "cycleOfInterestPayment": "P1ML1",
          "nominalInterestRate": 0.02,
          "dayCountConvention": "30E360",
          "currency": "CHF",
          "contractDealDate": "2023-07-31T06:30:00",
          "initialExchangeDate": "2023-08-01T06:30:00",
          "maturityDate": "2024-08-01T06:30:00",
          "notionalPrincipal": 50000,
          "cycleAnchorDateOfPrincipalRedemption": "2023-09-01T06:30:00",
          "cycleOfPrincipalRedemption": "P1ML1",
          "nextPrincipalRedemptionPayment": 2312.7827499791606
        }
      ],
      "paymentDetails": {
        "recordCreatorPaymentChannelID": "e03c2694-71f8-48e0-a68d-8328630fd0c5",
        "counterpartyPaymentChannelID": "6963c361-1c1f-40b6-b8b4-47f604be36ef"
      },
      "selection": {
        "productCategory": "Loans",
        "department": "DeptB",
        "profitCenter": "A",
        "tenure": "12M"
      }
    }
  ]
}
  • 400 bad request: If the request body is not in the correct format or if there are validation errors.

  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to create contracts.

  • 5xx server error: If there is a server-side error while processing the request.

Example

{
  "status": 400,
  "message": "Contract creation failed",
  "data": [
    {
      "contractUUID": null,
      "contractID": null,
      "errors": [
        {
          "Product data": "Specified result type [java.lang.String] did not match Query selection type [com.solitx.contracts.entity.Terms] - multiple selections: use Tuple or array"
        }
      ]
    }
  ]
}

6.1.3. Methods

Description

The method createContract is responsible for creating contracts based on the provided list of contract data. It iterates through each contract data object, validates it using a validator (createContractValidator), and then creates the contract if there are no validation errors. It returns a list of ContractsResponseDto objects containing the result of each contract creation attempt.

Parameters

  • contractDataList (List<CreateContractsDto>): A list of objects representing contract data to be used for creating contracts.

Returns

  • List<ContractsResponseDto>: A list of ContractsResponseDto objects containing the result of each contract creation attempt.

Example usage

public List<ContractsResponseDto> createContract(List<CreateContractsDto> contractDataList) {
		List<ContractsResponseDto> contractResponseDtoList = new ArrayList<>();
		ContractsResponseDto contractResponseDto;
		for (CreateContractsDto createContractDto : contractDataList) { (1)
			// Validate the contract data using the createContractValidator. (2)
			contractResponseDto = createContractValidator.validateContractData(createContractDto);
			if (contractResponseDto.getErrors().isEmpty()) {
				// If there are no validation errors, create the contract.
				contractResponseDto = contractsWorker.createContract(createContractDto); (3)
			}
			contractResponseDtoList.add(contractResponseDto); (4)
		}
		return contractResponseDtoList; (5)
	}
Internal workflow
1 Iterates through each CreateContractsDto object in the provided contractDataList.
2 Validates the contract data using the createContractValidator.
3 If there are no validation errors (errors list in the ContractsResponseDto is empty), the contract is created using the contractsWorker.
4 Adds the resulting ContractsResponseDto object to the contractResponseDtoList.
5 Returns the list of ContractsResponseDto objects containing the result of each contract creation attempt.

Exceptions

  • None explicitly thrown by this method. However, exceptions may occur within the validator or worker methods, which are handled internally.

6.1.4. Model classes

Description

The CreateContractsDto class represents the data transfer object (DTO) used for creating contracts in the system. It encapsulates the necessary information required to initialize and configure a contract, including product ID, contract terms, payment details, and selection criteria.

Attributes
  1. productId

    • Type: Long

    • Description:Identifier of the product associated with the contract.

    • Constraints: Required field.

    • Example: 1

  2. terms

    • Type: List<Map<String, Object>>

    • Description: Collection of contract terms represented as key-value pairs.

    • Constraints: Required field.

    • Example

    {
      "terms": [
        {
          "contractPerformance": "PreDeal",
          "businessDayConvention": "SCF",
          "contractType": "ANN",
          "statusDate": "2023-07-31T06:30:00",
          "contractRole": "RPA",
          "creatorID": "a43c22ed-27df-4324-a453-3e7707c9b82d",
          "counterpartyID": "e548956c-1f3b-493e-952e-00cdcca6b599",
          "contractID": "a6b799db-c448-4aad-9382-3ae47383f5b2",
          "cycleAnchorDateOfInterestPayment": "2023-09-01T06:30:00",
          "cycleOfInterestPayment": "P1ML1",
          "nominalInterestRate": 0.02,
          "dayCountConvention": "30E360",
          "currency": "CHF",
          "contractDealDate": "2023-07-31T06:30:00",
          "initialExchangeDate": "2023-08-01T06:30:00",
          "maturityDate": "2024-08-01T06:30:00",
          "notionalPrincipal": 50000,
          "cycleAnchorDateOfPrincipalRedemption": "2023-09-01T06:30:00",
          "cycleOfPrincipalRedemption": "P1ML1",
          "nextPrincipalRedemptionPayment": 2312.7827499791606
        }
      ]
    }
  3. paymentDetails

    • Type: Map<String, Object>

    • Description: Details of the payment associated with the contract.

    • Constraints: Required field.

    • Example

    {
      "paymentDetails": {
        "recordCreatorPaymentChannelID": "e03c2694-71f8-48e0-a68d-8328630fd0c5",
        "counterpartyPaymentChannelID": "6963c361-1c1f-40b6-b8b4-47f604be36ef"
      }
    }
  4. selection

    • Type: Map<String, Object>

    • Description: Additional selection criteria or parameters for the contract (optional).

    • Example

{
  "selection": {
    "productCategory": "Loans",
    "department": "DeptB",
    "profitCenter": "A",
    "tenure": "12M"
  }
}

Constructors

  • Default Constructor: Initializes an empty CreateContractsDto object.

  • All-args Constructor: Initializes a CreateContractsDto object with all attributes.

  • Getter and Setter Methods: Accessors and mutators for the attributes of the class.

Example usage

// Create a new instance of CreateContractsDto
CreateContractsDto contractDto = new CreateContractsDto();
contractDto.setProductId((long) 1);
contractDto.setTerms(termsList);
contractDto.setPaymentDetails(paymentDetailsMap);
contractDto.setSelection(selectionMap);

Serialization and deserialization

  • The CreateContractsDto class can be serialized to and deserialized from JSON format using libraries like Jackson, Gson, or JSON-B.

6.1.5. Validation

Description

The validateContractData method is responsible for validating contract data before the creation of contracts. It ensures that the provided contract data meets the necessary criteria and constraints, performing various checks on the product associated with the contract, the contract itself, and its terms. If any validation errors are encountered, they are collected and returned in a structured format.

Parameters

  • createContractDto (CreateContractsDto): An object representing the contract data to be validated.

Returns

  • ContractsResponseDto: An object containing the result of the validation process, including any encountered errors.

Example usage

public ContractsResponseDto validateContractData(CreateContractsDto createContractDto) {
		// Initialize data structures to store validation errors.
		HashMap<String, Object> createContractErrors = new HashMap<>();
		List<Map<String, Object>> errorList = new ArrayList<>();
		String contractID;

		try {
			// Validate the product associated with the contract.
			Products products = contractsValidator.validateProduct(createContractDto.getProductId()); (1)

			// Validate the contract and product template size.
			contractsValidator.validateContractAndProductTemplateSize(products, createContractDto.getTerms()); (2)

			// Extract contract terms and ID.
			Map<String, Object> contractTerms = createContractDto.getTerms().get(0);
			contractID = String.valueOf(contractTerms.get(Constants.CONTRACTID));

			// Perform selection validation and add any errors to the error list.
			Map<String, Object> selectionValidationErrors = this.contractSelectionValidation(products,
					createContractDto); (3)
			if (!selectionValidationErrors.isEmpty()) {
				errorList.add(selectionValidationErrors);
			}

			// Perform terms validation and add any errors to the error list.
			List<Map<String, Object>> termsValidationErrors = validateContractTerms(products, createContractDto); (4)
			errorList.addAll(termsValidationErrors);

		} catch (Exception e) { (5)
			// If an exception occurs during validation, add an error entry to the error
			// list.
			createContractErrors.put("Product data", e.getMessage());
			errorList.add(createContractErrors);
			return new ContractsResponseDto(null, null, errorList);
		}

		return new ContractsResponseDto(null, contractID, errorList);

	}
Validation steps
1 Product validation
  • Validates the product associated with the contract using the contractsValidator.validateProduct method.

2 Contract and product template size validation
  • Ensures that the contract and product template sizes meet the required criteria using the contractsValidator.validateContractAndProductTemplateSize method.

3 Contract selection validation
  • Performs selection validation by invoking the contractSelectionValidation method, which validates the contract’s selection against the product’s selection template.

4 Terms validation
  • Validates the contract terms using the validateContractTerms method, checking for any discrepancies or errors and also the required terms like counterPartyID, recordCreatorID and other formats.

5 Error handling
  • If any exception occurs during the validation process, an error entry is added to the error list, indicating the nature of the issue.

  • All encountered validation errors are collected and returned in a structured format within the ContractsResponseDto object.

6.1.6. Testing

Description

This section provides an overview of the testing strategy and objectives for the create contract method.

Test methods

Example usage

@SuppressWarnings("unchecked")
	@Test
	void evaluateContractTest() throws ParseException { (1)
		CreateContractsDto createContractsDto = createContractsDtoList.get(0);
		createContractValidator.validateContractData(createContractsDto);
		final List<Map<String, Object>> productTermsList = (List<Map<String, Object>>) product.getTemplate()
				.get(Constants.TERMS);
		List<Map<String, Object>> contractTermsList = createContractsDto.getTerms();
		Map<String, Object>   selectionMap =  createContractsDto.getSelection();
		contractsHelper.evaluateContractTerms(contractTermsList, productTermsList, selectionMap);
		contracts = contractsWorker.computeContract(product, createContractsDto);
		Terms masterTerms = contracts.getContractTerms().get(0);
		PaymentDetails paymentDetails = contracts.getPaymentDetails();

		Assertions.assertEquals(contracts.getProductID().toString(), product.getProductID().toString());
		Assertions.assertEquals(50000, masterTerms.getNotionalPrincipal().doubleValue(), 0.0);
		Assertions.assertEquals(2312.7827499791606, masterTerms.getNextPrincipalRedemptionPayment().doubleValue(), 0.01);
		Assertions.assertEquals(LocalDateTime.parse("2023-08-01T00:00:00"), masterTerms.getInitialExchangeDate());
		Assertions.assertEquals(LocalDateTime.parse("2023-07-31T00:00:00"), masterTerms.getStatusDate());
		Assertions.assertEquals(profile.getProfileID(), masterTerms.getCounterpartyID());
		Assertions.assertEquals(paymentDetails.getCounterpartyPaymentChannelID(), counterPartyPaymentChannel.getPaymentChannelID());
		Assertions.assertEquals(paymentDetails.getRecordCreatorPaymentChannelID(), recordCreatorPaymentChannel.getPaymentChannelID());

	}

	@Test
	void createContractTest() { (2)

		List<ContractsResponseDto> createContractList = contractServiceImpl.createContract(createContractsDtoList);
		System.out.println("createContractList :"+createContractList);
		String contractUUID = createContractList.get(0).getContractUUID();
		Assertions.assertEquals(contracts.getContractUUID(), UUID.fromString(contractUUID));

	}
1 evaluateContractTest
  • Purpose : This test evaluates the contract creation process by validating contract terms and computing contract details.

  • Test steps

    1. Validates the contract data using the createContractValidator.

    2. Retrieves product terms and contract terms for evaluation.

    3. Evaluates contract terms using the contractsHelper.

    4. Computes the contract details using the contractsWorker.

  • Assertions

    • Validates various properties of the computed contract, such as notional principal, next principal redemption payment, initial exchange date, status date, counterparty ID, creator ID, and payment channel IDs.

2 createContractTest
  • Purpose : This test verifies the functionality of the createContract method in the ContractService implementation.

  • Test steps

    1. Invokes the createContract method with a list of contract data objects.

    2. Retrieves the created contract list.

  • Assertions

    • Verifies that the contract creation process is successful by comparing the UUID of the created contract with the expected contract UUID.

Test environment

Coverage

  • Test coverage includes both positive and negative scenarios to ensure comprehensive validation of contract creation and evaluation processes.

  • Additional test cases may be added to cover edge cases, boundary conditions, and error handling scenarios.

6.2. Get computed schedule

6.2.1. Sequential flow

get-computed-schedule-contract.puml

Getting the computed contract schedule

  • User requests the computed schedule for a contract.

  • Controller validates the contract UUID.

  • If contract not found, return error.

  • If contract status is not "PreDeal", return error.

  • Retrieve contract from repository.

  • Use FactoryWorker to generate schedule based on contract and risk factor model.

  • Return the computed schedule or error message to the user.

6.2.2. Endpoint

Description

The endpoint computes and returns the schedule of a contract based on the provided contractUUID.

URL

/contracts/compute

Method

GET

Request parameters

Parameters

Type

Required

Description

contractUUID

UUID

Yes

The UUID of the existing contract for which the schedule needs to be computed.

Responses

  • 200 OK

    • Returns a list of business events comprising the schedule.

    • Response body

      {
        "status": 200,
        "message": "Success",
        "data": [
          {
            "eventID": "23a83225-007e-47f2-8dcd-21534a0b92f4",
            "eventTime": "2023-01-01T00:00:00",
            "eventType": "IED",
            "eventBody": {
              "transaction": {
                "nominalValue": 50000.0,
                "nominalAccrued": 0.0
              }
            },
            "status": "pending",
            "executionType": "transaction",
            "value": -50000.0,
            "remainingValue": -50000.0,
            "creditPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "debitPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "2d904008-f6d4-4740-8a9f-8723ff03fd45",
            "contractID": "75361862-baec-4bf1-9e05-b87539196d5b",
            "units": "INR"
          },
          {
            "eventID": "423ec885-8af4-4a19-8f1f-7d707fd5eefe",
            "eventTime": "2023-01-01T00:00:00",
            "eventType": "FP",
            "eventBody": {
              "transaction": {
                "nominalValue": 0.0,
                "nominalAccrued": 0.0
              }
            },
            "status": "pending",
            "executionType": "transaction",
            "value": 5000.0,
            "remainingValue": 5000.0,
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "2d904008-f6d4-4740-8a9f-8723ff03fd45",
            "contractID": "Loan processing fee",
            "units": "INR"
          },
          {
            "eventID": "adbca86d-95a9-4327-bddc-71c69af1a1dc",
            "eventTime": "2023-01-01T00:00:00",
            "eventType": "FP",
            "eventBody": {
              "transaction": {
                "nominalValue": 0.0,
                "nominalAccrued": 0.0
              }
            },
            "status": "pending",
            "executionType": "transaction",
            "value": 2500.0,
            "remainingValue": 2500.0,
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "2d904008-f6d4-4740-8a9f-8723ff03fd45",
            "contractID": "Insurance Fee",
            "units": "INR"
          },
          {
            "eventID": "433a60c6-2429-40d1-9783-2484c90ac987",
            "eventTime": "2023-02-01T00:00:00",
            "eventType": "IP",
            "eventBody": {
              "transaction": {
                "nominalValue": 45833.0,
                "nominalAccrued": 0.0
              }
            },
            "status": "pending",
            "executionType": "transaction",
            "value": 833.0,
            "remainingValue": 833.0,
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "2d904008-f6d4-4740-8a9f-8723ff03fd45",
            "contractID": "75361862-baec-4bf1-9e05-b87539196d5b",
            "units": "INR"
          },
          {
            "eventID": "1b062381-3b44-404a-afb7-d6296ca95b9e",
            "eventTime": "2023-02-01T00:00:00",
            "eventType": "PR",
            "eventBody": {
              "transaction": {
                "nominalValue": 45833.0,
                "nominalAccrued": 833.0
              }
            },
            "status": "pending",
            "executionType": "transaction",
            "value": 4167.0,
            "remainingValue": 4167.0,
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "2d904008-f6d4-4740-8a9f-8723ff03fd45",
            "contractID": "75361862-baec-4bf1-9e05-b87539196d5b",
            "units": "INR"
          },
          {
            "eventID": "e0ac4b65-4584-4437-a8e3-2c4c5e3e5d67",
            "eventTime": "2023-03-01T00:00:00",
            "eventType": "IP",
            "eventBody": {
              "transaction": {
                "nominalValue": 41597.0,
                "nominalAccrued": 0.0
              }
            },
            "status": "pending",
            "executionType": "transaction",
            "value": 764.0,
            "remainingValue": 764.0,
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "2d904008-f6d4-4740-8a9f-8723ff03fd45",
            "contractID": "75361862-baec-4bf1-9e05-b87539196d5b",
            "units": "INR"
          },
          {
            "eventID": "f71cbff0-1708-48d6-9ed2-d15c6534f69d",
            "eventTime": "2023-03-01T00:00:00",
            "eventType": "PR",
            "eventBody": {
              "transaction": {
                "nominalValue": 41597.0,
                "nominalAccrued": 764.0
              }
            },
            "status": "pending",
            "executionType": "transaction",
            "value": 4236.0,
            "remainingValue": 4236.0,
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "2d904008-f6d4-4740-8a9f-8723ff03fd45",
            "contractID": "75361862-baec-4bf1-9e05-b87539196d5b",
            "units": "INR"
          },
          {
            "eventID": "0afd9e04-8a31-4826-886d-bdb2489dd28c",
            "eventTime": "2023-04-01T00:00:00",
            "eventType": "IP",
            "eventBody": {
              "transaction": {
                "nominalValue": 37291.0,
                "nominalAccrued": 0.0
              }
            },
            "status": "pending",
            "executionType": "transaction",
            "value": 693.0,
            "remainingValue": 693.0,
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "2d904008-f6d4-4740-8a9f-8723ff03fd45",
            "contractID": "75361862-baec-4bf1-9e05-b87539196d5b",
            "units": "INR"
          }
        ]
      }
  • 400 bad request

    • If the provided contractUUID is invalid or not found, the endpoint will return an HTTP status code 404 Not Found.

  • 403 forbidden

    • If the user does not have the necessary permissions to execute contracts.

  • 404 not found

    • If the contract with the provided UUID does not exist.

  • 500 internal server error

    • If there is an unexpected error executing the contract.

Example error response

  • 400 bad request

    • If the provided contractUUID is invalid or does not exist.

    • Response body

        {
          "status": 400,
          "message": "Invalid contractUUID " + 36c7d13e-55dc-4b89-a1b8-98f1f8716698,
          "data": "null"
        }

6.2.3. Methods

Description

This method is responsible for creating a dynamic event associated with a contract.

  1. Method : computeContract

    • Purpose

      • This method computes the schedule of business events for a given contract identified by its UUID.

    • Parameters

      • contractUUID (UUID) : The UUID of the contract for which the schedule is to be computed.

    • Return type

      • List<BusinessEvents> : A list of business events representing the schedule for the contract.

        public List<BusinessEvents> computeContract(UUID contractUUID) throws ContractsException {
        		List<BusinessEvents> contractSchedule;
        		Contracts contract = contractsServiceRepo.findById(contractUUID)
        				.orElseThrow(() -> new IllegalArgumentException(CONTRACT_ERROR)); (1)
        
        		try {
        			// Compute the contract schedule.
        			contractSchedule = getContractSchedule(contract); (2)
        
        		} catch (Exception e) {
        			throw new ContractsException(e.getMessage()); (3)
        		}
        		return contractSchedule;
        	}
    • Behavior

    1 Retrieves contract information from the contracts service repository.
    2 Calls the getContractSchedule method to compute the contract schedule.
    3 Throws a ContractsException if any error occurs during computation.
  2. Method : getContractSchedule

    • Purpose

      • This method generates the schedule of business events for a given contract.

    • Parameters

      • contract (Contracts) : The contract object for which the schedule is to be generated.

    • Return type

      • List<BusinessEvents> : A list of business events representing the schedule for the contract.

        public List<BusinessEvents> getContractSchedule(Contracts contract) throws ParseException {
        		// Get the risk factor model provider for the contract.
        		RiskFactorModelProvider riskFactorModelProvider = getRiskFactorModelProvider(contract); (1)
        
        		// Generate the schedule of business events using the actusFactoryWorker.
        		return actusFactoryWorker.generateSchedule(contract, riskFactorModelProvider); (2)
        
        	}
    • Behavior

    1 Retrieves the risk factor model provider for the contract.
    2 Calls the generateSchedule method to generate the contract schedule.
  3. Method : generateSchedule

    • Purpose

      • This method generates the schedule of business events for a given contract using the provided risk factor model.

    • Parameters

      • contract (Contracts) : The contract object for which the schedule is to be generated.

      • riskFactorModelProvider (RiskFactorModelProvider) : The risk factor model provider used for generating the schedule.

    • Return type

      • List<BusinessEvents> : A list of business events representing the schedule for the contract.

        public List<BusinessEvents> generateSchedule(Contracts contract, RiskFactorModelProvider riskFactorModelProvider) {
        		List<ContractEvent> contractEvents;
        		log.info("Contract generate schedule started by UserId : {}, ContractUUID : {}", usersHelper.getUserID(),
        				contract.getContractUUID());
        		final Terms masterTerm = contract.getContractTerms().get(0);
        		LocalDateTime statusDate = masterTerm.getStatusDate();
        		LocalDateTime maturityDate = masterTerm.getMaturityDate();
        		final List<String> specialContractTypes = Arrays.asList("AINV", "ARES", "AEQT");
        		List<BusinessEvents> businessEventsList = new ArrayList<>();
        
        		if (specialContractTypes.contains(masterTerm.getContractType())) {
        			// Need to implement
        			return businessEventsList;
        
        		} else {
        			for (final Terms contractTerms : contract.getContractTerms()) {
        
        				Map<String, Object> termsMap = ContractsMapper.termsToMap(contractTerms);
        
        				// Mapping terms object to ContractModel object
        				ContractModelProvider model = getContractModel(termsMap);
        
        				// Get contract events based on the model, status date, and risk factor model
        				// provider.
        				contractEvents = getContractEvents(model, maturityDate, statusDate, riskFactorModelProvider); (1)
        
        				// Mapping contractEvent to BusinessEvents
        				List<BusinessEvents> businessEvents = getBusinessEvents(contract, contractTerms, contractEvents); (2)
        				businessEventsList.addAll(businessEvents);
        			}
        
        			Collections.sort(businessEventsList, new SortByEventTime()); (3)
        			log.info("Contract generate schedule finihed by UserId : {}, ContractUUID : {}", usersHelper.getUserID(),
        					contract.getContractUUID());
        			return businessEventsList; (4)
        		}
        
        	}
    • Behavior

    1 Processes the contract terms and generates contract events based on the provided model, maturity date, and status date.
    2 Maps contract events to business events and adds them to the list of business events.
    3 Sorts the list of business events by event time.
    4 Returns business events list.

6.2.4. Validation

Description

The method validateContract(String contractUUID) is responsible for validating a contract identified by its UUID.

  • Parameters

    • contractUUID : The UUID of the contract to validate.

  • Returns

    • This method does not return any value (void).

  • Functionality

    • Validates the contract UUID to ensure it is valid.

    • Validates the status of the contract to ensure it is in the "PreDeal" state.

  • Exceptions

    • Throws IllegalArgumentException if the contract UUID is invalid or if the contract status is not "PreDeal".

  • Example usage

/**
	 * Retrieves a contract based on its UUID.
	 *
	 * @param contractUUID The UUID of the contract to retrieve.
	 * @return The Contracts object representing the retrieved contract.
	 * @throws IllegalArgumentException If the contract UUID is invalid.
	 */
	public Contracts validateContractUUID(String contractUUID) {
		// Provides contract information based on contractUUID
		final Optional<Contracts> optionalContract = contractsRepo.findById(UUID.fromString(contractUUID)); (1)

		Assert.isTrue(optionalContract.isPresent(), "Invalid contractUUID " + contractUUID);
		return optionalContract.get(); (2)

	}
/**
	 * Validates the status of a contract.
	 *
	 * @param contract The Contracts object representing the contract data to
	 *                 validate.
	 * @throws IllegalArgumentException If the contract status is not "PreDeal".
	 */
	public void validateContractStatus(Contracts contract) {
		final Terms term = contract.getContractTerms().get(0);
		Assert.isTrue(term.getContractPerformance().equals("PreDeal"), "Contract already executed"); (3)
	}
Validation steps
1 Validating contract UUID
  • This step ensures that the provided contract UUID is valid and corresponds to an existing contract in the system.

2 Retrieving contract
  • Once the contract UUID is validated, the method retrieves the contract object associated with the UUID.

3 Validating contract status
  • The contract status is then validated to ensure it is in the "PreDeal" state, indicating that the contract has not been executed yet.

  • Ensure that the contract UUID provided is valid and corresponds to an existing contract.

  • Handle any exceptions thrown during the validation process, particularly IllegalArgumentException.

  • Developers should be aware that this method does not return any value (void), and the validation results are communicated through exceptions.

  • It is recommended to call this method before performing any operations related to a contract to ensure its validity and status.

  • Ensure that the Contracts object and its associated data structures (Terms, etc.) are properly initialized and populated before invoking the validateContract method.

  • Developers should have a clear understanding of the contract status and its implications in the system before using this method.

6.2.5. Testing

Description

This section provides an overview of the testing strategy and objectives for the get computed contract schedule method.

Test methods

Example usage

@Test
	void computeContractTest() throws ContractsException { (1)

		List<BusinessEvents> eventsList = contractServiceImpl
				.computeContract(contracts.getContractUUID());
		Assertions.assertEquals(25, eventsList.size());

	}

	@TestFactory
	Stream<DynamicTest> computeContractScheduleTest() throws IOException, ContractsException { (2)
		List<DynamicTest> dynamicTests = new ArrayList<>();

		List<BusinessEventsDto> expectedEventsList = MappingUtils
				.mapToEventsList("./src/test/resources/events/events-contract-ann.json");

		List<BusinessEvents> computedEventsList = contractServiceImpl
				.computeContract(contracts.getContractUUID());

		Assertions.assertEquals(expectedEventsList.size(), computedEventsList.size(), "Number of events should match.");

		for (int i = 0; i < expectedEventsList.size(); i++) {
			BusinessEventsDto expectedEvent = expectedEventsList.get(i);
			BusinessEvents computedEvent = computedEventsList.get(i);

			dynamicTests.add(contractUtils.createDynamicTest(expectedEvent, computedEvent));
		}

		return dynamicTests.stream();
	}
1 computeContractTest()
  • Purpose : To validate that the computeContract method produces the correct output, specifically checking the size of the generated events list.

  • Test steps

    1. Invoke the computeContract method with a known contract UUID.

    2. Retrieve the list of generated business events.

  • Assertions

    • Assert that the size of the computed events list matches the expected size (25 in this case).

2 computeContractScheduleTest()
  • Purpose : To ensure that the computeContractSchedule method generates the correct list of business events, validating against a predefined set of expected events.

  • Test steps

    1. Read the expected list of business events from a JSON file.

    2. Invoke the computeContract method with the contract UUID.

    3. Compare the expected and computed lists of business events.

    4. Create dynamic tests for each pair of expected and computed events.

  • Assertions

    • Assert that the size of the computed events list matches the size of the expected events list.

    • For each pair of expected and computed events, assert their equality.

6.3. Execute contracts

6.3.1. Sequential flow

execute-contract.puml

Contract execution process

  1. This method executes a contract identified by the given contract UUID.

  2. It validates the contract, sets its performance to "PF" (Performant).

  3. Saves the contract schedule.

  4. Creates a Metaco account for the contract, only if the contract’s selection contains a "Ledger ID" key.

  5. Updates contract payment channels, and sends a Kafka event signaling the contract execution.

  6. If successful, it returns a list of business events associated with the execution.

6.3.2. Endpoint

Description

This endpoint executes a contract and returns its schedule based on the provided contractUUID.

URL

/contracts/execute

Method

POST

Request parameters

Parameters

Type

Required

Description

contractUUID

UUID

Yes

The UUID of an existing contract to be executed.

Responses

  • 200 OK

    • Returns the schedule of the executed contract.

    • Response body

      {
        "status": 200,
        "message": "Success",
        "data": [
          {
            "eventID": "23a83225-007e-47f2-8dcd-21534a0b92f4",
            "eventTime": "2023-01-01T00:00:00",
            "eventType": "IED",
            "eventBody": {
              "transaction": {
                "nominalValue": 50000.0,
                "nominalAccrued": 0.0
              }
            },
            "status": "pending",
            "executionType": "transaction",
            "value": -50000.0,
            "remainingValue": -50000.0,
            "creditPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "debitPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "2d904008-f6d4-4740-8a9f-8723ff03fd45",
            "contractID": "75361862-baec-4bf1-9e05-b87539196d5b",
            "units": "INR"
          },
          {
            "eventID": "423ec885-8af4-4a19-8f1f-7d707fd5eefe",
            "eventTime": "2023-01-01T00:00:00",
            "eventType": "FP",
            "eventBody": {
              "transaction": {
                "nominalValue": 0.0,
                "nominalAccrued": 0.0
              }
            },
            "status": "pending",
            "executionType": "transaction",
            "value": 5000.0,
            "remainingValue": 5000.0,
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "2d904008-f6d4-4740-8a9f-8723ff03fd45",
            "contractID": "Loan processing fee",
            "units": "INR"
          },
          {
            "eventID": "adbca86d-95a9-4327-bddc-71c69af1a1dc",
            "eventTime": "2023-01-01T00:00:00",
            "eventType": "FP",
            "eventBody": {
              "transaction": {
                "nominalValue": 0.0,
                "nominalAccrued": 0.0
              }
            },
            "status": "pending",
            "executionType": "transaction",
            "value": 2500.0,
            "remainingValue": 2500.0,
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "2d904008-f6d4-4740-8a9f-8723ff03fd45",
            "contractID": "Insurance Fee",
            "units": "INR"
          },
          {
            "eventID": "433a60c6-2429-40d1-9783-2484c90ac987",
            "eventTime": "2023-02-01T00:00:00",
            "eventType": "IP",
            "eventBody": {
              "transaction": {
                "nominalValue": 45833.0,
                "nominalAccrued": 0.0
              }
            },
            "status": "pending",
            "executionType": "transaction",
            "value": 833.0,
            "remainingValue": 833.0,
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "2d904008-f6d4-4740-8a9f-8723ff03fd45",
            "contractID": "75361862-baec-4bf1-9e05-b87539196d5b",
            "units": "INR"
          },
          {
            "eventID": "1b062381-3b44-404a-afb7-d6296ca95b9e",
            "eventTime": "2023-02-01T00:00:00",
            "eventType": "PR",
            "eventBody": {
              "transaction": {
                "nominalValue": 45833.0,
                "nominalAccrued": 833.0
              }
            },
            "status": "pending",
            "executionType": "transaction",
            "value": 4167.0,
            "remainingValue": 4167.0,
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "2d904008-f6d4-4740-8a9f-8723ff03fd45",
            "contractID": "75361862-baec-4bf1-9e05-b87539196d5b",
            "units": "INR"
          },
          {
            "eventID": "e0ac4b65-4584-4437-a8e3-2c4c5e3e5d67",
            "eventTime": "2023-03-01T00:00:00",
            "eventType": "IP",
            "eventBody": {
              "transaction": {
                "nominalValue": 41597.0,
                "nominalAccrued": 0.0
              }
            },
            "status": "pending",
            "executionType": "transaction",
            "value": 764.0,
            "remainingValue": 764.0,
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "2d904008-f6d4-4740-8a9f-8723ff03fd45",
            "contractID": "75361862-baec-4bf1-9e05-b87539196d5b",
            "units": "INR"
          },
          {
            "eventID": "f71cbff0-1708-48d6-9ed2-d15c6534f69d",
            "eventTime": "2023-03-01T00:00:00",
            "eventType": "PR",
            "eventBody": {
              "transaction": {
                "nominalValue": 41597.0,
                "nominalAccrued": 764.0
              }
            },
            "status": "pending",
            "executionType": "transaction",
            "value": 4236.0,
            "remainingValue": 4236.0,
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "2d904008-f6d4-4740-8a9f-8723ff03fd45",
            "contractID": "75361862-baec-4bf1-9e05-b87539196d5b",
            "units": "INR"
          },
          {
            "eventID": "0afd9e04-8a31-4826-886d-bdb2489dd28c",
            "eventTime": "2023-04-01T00:00:00",
            "eventType": "IP",
            "eventBody": {
              "transaction": {
                "nominalValue": 37291.0,
                "nominalAccrued": 0.0
              }
            },
            "status": "pending",
            "executionType": "transaction",
            "value": 693.0,
            "remainingValue": 693.0,
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "2d904008-f6d4-4740-8a9f-8723ff03fd45",
            "contractID": "75361862-baec-4bf1-9e05-b87539196d5b",
            "units": "INR"
          }
        ]
      }
  • 400 bad request

    • If the required parameter contractUUID is missing or invalid.

  • 403 forbidden

    • If the user does not have the necessary permissions to execute contracts.

  • 404 not found

    • If the contract with the provided UUID does not exist.

  • 500 internal server error

    • If there is an unexpected error executing the contract.

Example error response

  • 400 bad request

    • If the provided contractUUID is invalid or does not exist.

    • Response body

        {
          "status": 400,
          "message": "Invalid contractUUID provided.",
          "data": "null"
        }

6.3.3. Methods

Description

The method executeContract executes a contract identified by the given UUID. It performs various actions related to contract execution, including setting contract performance status, saving contract schedule, updating contract payment channels, saving contract execution details, and sending a Kafka event for contract execution.

Method signature

public List<BusinessEvents> executeContract(String contractUUID) throws ContractsException

Parameters

  • contractUUID (String): The UUID of the contract to execute.

Returns

  • List<BusinessEvents> : A list of BusinessEvents representing the business events generated by executing the contract.

Exceptions

  • ContractsException : Thrown if there’s an error executing the contract.

Usage example

contractsValidator.validateContract(contractUUID); (1)

public List<BusinessEvents> executeContract(String contractUUID) throws ContractsException {
		log.info("Contract execution started by UserId : {}, ContractUUID : {}", usersHelper.getUserID(), contractUUID);
		List<BusinessEvents> businessEvents;
		Contracts contract = contractsServiceRepo.findById(UUID.fromString(contractUUID))
				.orElseThrow(() -> new IllegalArgumentException(CONTRACT_ERROR)); (2)
		Terms contractTerms = contract.getContractTerms().get(0);
		// Set the contract status to "PF".
		contractTerms.setContractPerformance("PF"); (3)
		try {

			// Save the contract schedule.
			businessEvents = saveContractSchedule(contract); (4)

			// Create a Metaco account for the contract.
			contractsHelper.createMetacoAccount(contract); (5)

			// Update contract payment channels(Linking contract to paymentChannel).
			updateContractPaymentChannel(contract); (6)

			contract.setExecutedBy(usersHelper.getUserID());
			contract.setTimeStamp(UtilityHelper.dateTime());
			contractsServiceRepo.save(contract); (7)

			// Send a request to Kafka for contract execution.
			sendKafkaContractExecutedEvent(contract); (8)

			log.info("Contract execution finished by UserId : {}, ContractUUID : {}", usersHelper.getUserID(),
					contractUUID);

		} catch (Exception e) {
			throw new ContractsException(e.getMessage()); (9)
		}

		return businessEvents;
	}
Internal workflow:
1 The method validates the contract identified by contractUUID using the contractsValidator.validateContract method.
2 Retrieves the contract details from the repository based on the provided UUID.
3 Sets the contract performance status to "PF".
4 Saves the contract schedule.
5 If the contract selection contains a LedgerID key, then it creates a Metaco account for the contract.
6 Updates contract payment channels.
7 Saves contract execution details including the executor’s user ID and timestamp.
8 Sends a Kafka event indicating contract execution.
9 If any exception occurs during the execution, it is caught, and a ContractsException is thrown with the corresponding error message.
  • Ensure that the contractUUID provided is valid and corresponds to an existing contract.

  • Handle any potential errors gracefully by catching and handling the ContractsException.

  • Business events returned may vary based on the specific contract implementation.

6.3.4. Validation

Description

The method validateContract(String contractUUID) is responsible for validating a contract identified by its UUID.

  • Parameters

    • contractUUID : The UUID of the contract to validate.

  • Returns

    • This method does not return any value (void).

  • Functionality

    • Validates the contract UUID to ensure it is valid.

    • Validates the status of the contract to ensure it is in the "PreDeal" state.

  • Exceptions

    • Throws IllegalArgumentException if the contract UUID is invalid or if the contract status is not "PreDeal".

  • Example usage

/**
	 * Retrieves a contract based on its UUID.
	 *
	 * @param contractUUID The UUID of the contract to retrieve.
	 * @return The Contracts object representing the retrieved contract.
	 * @throws IllegalArgumentException If the contract UUID is invalid.
	 */
	public Contracts validateContractUUID(String contractUUID) {
		// Provides contract information based on contractUUID
		final Optional<Contracts> optionalContract = contractsRepo.findById(UUID.fromString(contractUUID)); (1)

		Assert.isTrue(optionalContract.isPresent(), "Invalid contractUUID " + contractUUID);
		return optionalContract.get(); (2)

	}
/**
	 * Validates the status of a contract.
	 *
	 * @param contract The Contracts object representing the contract data to
	 *                 validate.
	 * @throws IllegalArgumentException If the contract status is not "PreDeal".
	 */
	public void validateContractStatus(Contracts contract) {
		final Terms term = contract.getContractTerms().get(0);
		Assert.isTrue(term.getContractPerformance().equals("PreDeal"), "Contract already executed"); (3)
	}
Validation steps
1 Validating contract UUID
  • This step ensures that the provided contract UUID is valid and corresponds to an existing contract in the system.

2 Retrieving contract
  • Once the contract UUID is validated, the method retrieves the contract object associated with the UUID.

3 Validating contract status
  • The contract status is then validated to ensure it is in the "PreDeal" state, indicating that the contract has not been executed yet.

  • Ensure that the contract UUID provided is valid and corresponds to an existing contract.

  • Handle any exceptions thrown during the validation process, particularly IllegalArgumentException.

  • Developers should be aware that this method does not return any value (void), and the validation results are communicated through exceptions.

  • It is recommended to call this method before performing any operations related to a contract to ensure its validity and status.

  • Ensure that the Contracts object and its associated data structures (Terms, etc.) are properly initialized and populated before invoking the validateContract method.

  • Developers should have a clear understanding of the contract status and its implications in the system before using this method.

6.3.5. Testing

Description

This section provides an overview of the testing strategy and objectives for the execute contract method.

Test methods

Example usage

	@Test
	void executeContractTest() throws ContractsException { (1)

		List<BusinessEvents> executeContract = contractServiceImpl.executeContract(contracts.getContractUUID());
		System.err.println("gfjfg "+executeContract);
		Contracts contracts1 = contractsRepo.findById(contracts.getContractUUID()).get();
		String contractStatus = contracts1.getContractTerms().get(0).getContractPerformance();

		Assertions.assertEquals("PF", contractStatus);

	}

	@TestFactory
	Stream<DynamicTest> executeContractAfterTest() throws IOException, ContractsException { (2)
		List<DynamicTest> dynamicTests = new ArrayList<>();

		List<BusinessEventsDto> expectedEventsList = MappingUtils
				.mapToEventsList("./src/test/resources/events/events-contract-ann.json");

		List<BusinessEvents> computedEventsList = contractServiceImpl
				.executeContract(contracts.getContractUUID());

		Assertions.assertEquals(expectedEventsList.size(), computedEventsList.size(), "Number of events should match.");

		for (int i = 0; i < expectedEventsList.size(); i++) {
			int eventIndex = i;
			BusinessEventsDto expectedEvent = expectedEventsList.get(eventIndex);
			BusinessEvents computedEvent = computedEventsList.get(eventIndex);

			dynamicTests.add(contractUtils.createDynamicTest(expectedEvent, computedEvent));
		}

		return dynamicTests.stream();
	}
1 executeContractTest()
  • Purpose : To verify that executing a contract updates its status correctly.

  • Test steps

    1. Execute a contract.

    2. Retrieve the updated contract from the repository.

    3. Check that the contract performance status is updated as expected.

  • Assertions

    • Assert that the contract performance status is updated to "PF".

2 executeContractAfterTest()
  • Purpose : This test verified and validates the correctness of business events generated after executing a contract.

  • Test steps

    1. Execute a contract.

    2. Compare the generated business events with expected events.

  • Assertions

    • Assert that the number and details of computed business events match the expected events.

6.4. Get contracts

6.4.1. Sequential flow

get-contract.puml

Contract retrieval process

  1. Retrieve contracts entities : The getContracts method starts by fetching a list of Contracts entities from the data source based on the provided filtering criteria and pagination parameters.

  2. Iterate through contracts list

    • For each contract in the retrieved list

  3. Retrieve contract terms : The terms associated with each contract are retrieved to provide additional details.

  4. Optional: Update notional principle

    • If the contract’s performance is not "PreDeal" and the contract type is "COM" (commodity contract), the notional principal of the contract is updated.

  5. Map terms to DTO

    • The terms associated with each contract are mapped to a list of TermsDto objects using a mapping function.

  6. Create ContractsDto object

    • A ContractsDto object is created and populated with relevant contract information:

      • contractUUID

      • productID

      • terms (mapped to a list of TermsDto)

      • selection

      • paymentDetails

      • createdBy

      • executedBy

      • timeStamp

  7. Add ContractsDto to list : The created ContractsDto object is added to the list of ContractsDto objects representing the retrieved contracts.

  8. Return contracts list : The list of ContractsDto objects representing the retrieved contracts is returned.

6.4.2. Endpoint

Description

Retrieves a list of contract information based on specified filter parameters and pagination.

URL

/contracts

Method

GET

Request filter parameters

Parameters

Type

Required

Description

ContractsFilterDto

JSON object

No

Provided based on the requirements.

pageNumber

Integer

No

Default value is 0.

pageSize

Integer

No

Default value is 100.

Responses

  • 200 OK

    • Returns the contracts information.

    • Response body

      {
          "status": 200,
          "message": "Success",
          "data": [
              {
                  "contractUUID": "28ee9eb5-e4b9-491c-98ce-a451abbedae9",
                  "productID": 4,
                  "paymentDetails": {
                      "recordCreatorPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
                      "counterpartyPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
                      "contractPaymentChannelID": null
                  },
                  "terms": [
                      {
                          "contractPerformance": "PreDeal",
                          "businessDayConvention": "SCF",
                          "contractType": "ANN",
                          "statusDate": "2023-01-01T00:00:00",
                          "contractRole": "RPA",
                          "creatorID": "902375cc-4f72-428f-8db0-95a7baa69b51",
                          "counterpartyID": "d2c87ded-489e-4510-8fe1-95f12c048a5d",
                          "contractID": "9ec8997e-70b5-4fa1-82fe-56cbc0fc8149",
                          "cycleAnchorDateOfInterestPayment": "2023-02-02T00:00:00",
                          "cycleOfInterestPayment": "P1ML1",
                          "nominalInterestRate": 0.01,
                          "dayCountConvention": "30E360",
                          "currency": "CHF",
                          "contractDealDate": "2023-01-01T00:00:00",
                          "initialExchangeDate": "2023-01-02T00:00:00",
                          "maturityDate": "2024-01-02T00:00:00",
                          "notionalPrincipal": 20000.0,
                          "cycleAnchorDateOfPrincipalRedemption": "2023-02-02T00:00:00",
                          "cycleOfPrincipalRedemption": "P1ML1",
                          "nextPrincipalRedemptionPayment": 1260.9478399993018
                      }
                  ],
                  "selection": {
                      "tenure": "12M",
                      "department": "DeptB",
                      "profitCenter": "A",
                      "remainingValue": 5000,
                      "productCategory": "Microfinance Loan"
                  },
                  "createdBy": "902375cc-4f72-428f-8db0-95a7baa69b51",
                  "executedBy": null,
                  "timeStamp": "2024-02-26T17:15:10"
              }
          ]
      }
  • 403 forbidden

    • If the user does not have the necessary permissions to execute contracts.

  • 500 internal server error

    • If there is an unexpected error executing the contract.

6.4.3. Methods

Description

This method is responsible for retrieving a list of contract data based on specified filtering criteria and pagination.

  1. Method : getContracts

    • Purpose

      • Retrieve a list of contract data based on specified filtering criteria and pagination.

    • Parameters

      • contractsFilterDto : An object containing filtering criteria for contracts.

      • pageable : An object representing pagination settings.

    • Return type

      • List<ContractsDto> : A list of contract data transfer objects (ContractsDto).

        public List<ContractsDto> getContracts(ContractsFilterDto contractsFilterDto, Pageable pageable) {
        		List<ContractsDto> contractsModelList = new ArrayList<>();
        
        		// Retrieve a list of Contracts entities based on the filtering criteria and
        		// pagination.
        		List<Contracts> contractsList = getContractsList(contractsFilterDto, pageable);(1)
        
        		for (final Contracts contract : contractsList) { (2)
        			final Terms term = contract.getContractTerms().get(0);
        
        			// Notional principle update for commodity contracts
        			if (!term.getContractPerformance().equalsIgnoreCase("PreDeal")
        					&& term.getContractType().equalsIgnoreCase("COM")) {
        				Contracts updatedContract = contractsHelper.updateNotionalPrincipal(contract); (3)
        				contractsServiceRepo.save(updatedContract);
        
        			}
        
        			// Map terms to a list of TermsDto objects
        			List<TermsDto> termsDtoList = ContractsMapper.mapToTermsDto(contract.getContractTerms()); (4)
        			Map<String, Object> termsMap = new HashMap<>();
        			termsMap.put("Terms", termsDtoList);
        
        			// Create a ContractsDto object for the contract
        			ContractsDto contractsModel = new ContractsDto(); (5)
        			contractsModel.setContractUUID(contract.getContractUUID());
        			contractsModel.setProductUUID(contract.getProductUUID());
        			contractsModel.setTerms(termsMap);
        			contractsModel.setSelection(contract.getSelection());
        			contractsModel.setPaymentDetails(contract.getPaymentDetails());
        			contractsModel.setCreatedBy(contract.getCreatedBy());
        			contractsModel.setExecutedBy(contract.getExecutedBy());
        			contractsModel.setProfileId(contract.getProfileId());
        			contractsModel.setTimeStamp(contract.getTimeStamp());
        
        			contractsModelList.add(contractsModel);
        
        		}
        		return contractsModelList; (6)
        	}
    • Behavior

    1 Retrieves a list of contract entities based on the provided filtering criteria and pagination.
    2 Iterates through each contract entity.
    3 Updates the notional principle for commodity contracts if certain conditions are met.
    4 Maps contract terms to a list of term data transfer objects (TermsDto).
    5 Constructs a ContractsDto object for each contract entity with mapped data.
    6 Returns a list of constructed ContractsDto objects.
  2. Method : getContractsList

    • Purpose

      • Retrieve a list of contract entities based on specified filtering criteria and pagination.

    • Parameters

      • contractsFilterDto : An object containing filtering criteria for contracts.

      • pageable : An object representing pagination settings.

    • Return type

      • List<Contracts> : A list of contract entities.

        public List<Contracts> getContractsList(ContractsFilterDto contractsFilterDto, Pageable pageable) {
        		// Build a JPA query using the buildContractsQuery method.
        		TypedQuery<Tuple> contractsQuery = buildContractsQuery(contractsFilterDto, pageable); (1)
        
        		// Execute the query and retrieve a list of contract UUIDs.
        		List<UUID> contractUUIDs = contractsQuery.getResultList().stream().map(tuple -> tuple.get(0, UUID.class))
        				.toList(); (2)
        
        		return contractsServiceRepo.findByContractUUIDIn(contractUUIDs); (3)
        	}
    • Behavior

    1 Builds a JPA query using the provided filtering criteria and pagination.
    2 Executes the query to retrieve a list of contract UUIDs.
    3 Retrieves contract entities based on the retrieved UUIDs and returns the list of entities.
  3. Method : buildContractsQuery

    • Purpose

      • Build a JPA query for retrieving contract entities based on specified filtering criteria and pagination.

    • Parameters

      • contractsFilterDto : An object containing filtering criteria for contracts.

      • pageable : An object representing pagination settings.

    • Return type

      • TypedQuery<Tuple> : A typed query for retrieving contract entities.

      private TypedQuery<Tuple> buildContractsQuery(ContractsFilterDto contractsFilterDto, Pageable pageable) { (1)
      		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
      		CriteriaQuery<Tuple> query = cb.createTupleQuery();
      		Root<Contracts> rootContracts = query.from(Contracts.class);
      		Join<Contracts, Terms> joinTerms = rootContracts.join("contractTerms", JoinType.INNER);
      
      		// Select specific columns (contractUUID and timeStamp)
      		query.multiselect(rootContracts.get("contractUUID"), rootContracts.get("timeStamp"));
      
      		Predicate predicate = cb.conjunction();
      
      		predicate = cb.and(predicate, cb.equal(joinTerms.get("creatorID"), usersHelper.getUserID()));
      
      		// Apply additional filter conditions based on ContractsFilterDto
      		if (!UtilityHelper.isNullorEmpty(contractsFilterDto.getContractUUID())) { (2)
      			predicate = cb.and(predicate,
      					cb.equal(rootContracts.get("contractUUID"), contractsFilterDto.getContractUUID()));
      		}
      
      		if (!UtilityHelper.isNullorEmpty(contractsFilterDto.getProductID())) {
      			predicate = cb.and(predicate, cb.equal(rootContracts.get("productID"), contractsFilterDto.getProductID()));
      		}
      
      		if (!UtilityHelper.isNullorEmpty(contractsFilterDto.getTimestamp())) {
      			predicate = cb.and(predicate,
      					cb.like(rootContracts.get("timeStamp"), "%" + contractsFilterDto.getTimestamp() + "%"));
      		}
      
      		query.where(predicate);
      
      		// Apply ordering
      		query.orderBy(cb.desc(rootContracts.get("timeStamp"))); (3)
      		query.distinct(true);
      
      		// Create the TypedQuery
      		TypedQuery<Tuple> typedQuery = entityManager.createQuery(query);
      
      		// Apply pagination if provided
      		if (pageable != null) { (4)
      			typedQuery.setFirstResult(pageable.getPageNumber() * pageable.getPageSize());
      			typedQuery.setMaxResults(pageable.getPageSize());
      		}
      		return typedQuery; (5)
      	}
    • Behavior

1 Constructs a JPA query for retrieving contract entities.
2 Applies filtering conditions based on the provided criteria.
3 Orders the results by timestamp in descending order.
4 Applies pagination settings if provided.
5 Returns the constructed typed query.

6.4.4. Model classes

Description

The ContractsFilterDto represents a data transfer object (DTO) used for filtering contracts based on specific criteria.

Attributes
  1. contractUUID

    • Description: Represents the unique identifier of a contract.

    • Usage: Used to filter contracts by a specific UUID.

    • Type: UUID

    • Example: ad3a03d5-d109-440a-8d70-619c780d471a

  2. timestamp

    • Type: LocalDateTime

    • Description: Represents the timestamp associated with contracts.

    • Usage: Used to filter contracts by a specific timestamp.

    • Example: 2024-02-19 16:02:51

  3. productId

    • Type: Long

    • Description: Represents the identifier of the product associated with contracts.

    • Usage: Used to filter contracts by a specific product ID.

    • Example: 1

ContractsFilterDto

@Setter
@Getter
@NoArgsConstructor
@ToString
public class ContractsFilterDto {

	private UUID contractUUID;

	private LocalDateTime timestamp;

	private Long productID;

}

6.5. Update contracts

6.5.1. Sequential flow

update-contract.puml

Contract updation process

Validation process

  • The validation process ensures the accuracy and integrity of contract update requests.

  • Here, the Validator meticulously examines contract data for consistency and adherence to predefined rules.

  • If the contract UUID is valid, the updation process proceeds.

Updation process

  • The contract status and terms are verified against product specifications.

  • Error handling mechanisms swiftly address issues such as invalid UUIDs or contract term discrepancies, guaranteeing a robust validation process.

  • Subsequently, the business process meticulously executes contract updates, involving validation against product specifications and computation of contract terms.

  • This ensures accuracy and integrity throughout the operation.

6.5.2. Endpoint

Description

This endpoint allows users with the appropriate permissions to update contracts based on the provided data.

URL

/contracts

Method

PUT

Request body

The request body should contain a JSON array of objects, each representing data for updating a contract. The structure of each object should adhere to the UpdateContractDto format.

Example request body

[
  {
    "contractUUID": "28ee9eb5-e4b9-491c-98ce-a451abbedae9",
    "productID": 4,
    "terms": [
      {
        "initialExchangeDate": "2023-01-02T00:00:00",
        "notionalPrincipal": "20000"
      }
    ],
    "selection": {
      "remainingValue": 5000,
      "tenure": "18M"
    }
  }
]

Responses

  • 200 : Success. Returns a JSON response containing details of the updated contracts.

Example response body

{
    "status": 200,
    "message": "Contracts updated successfully",
    "data": [
        {
            "contractUUID": "28ee9eb5-e4b9-491c-98ce-a451abbedae9",
            "contractID": "9ec8997e-70b5-4fa1-82fe-56cbc0fc8149",
            "errors": []
        }
    ]
}
  • 400 bad request: If the request body is not in the correct format or if there are validation errors.

  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to create contracts.

  • 5xx server error: If there is a server-side error while processing the request.

Example

{
  "status": 400,
  "message": "Invalid ContractUUID 28ee9eb5-e4b9-491c-98ce-a451abbedae9",
  "data": "28ee9eb5-e4b9-491c-98ce-a451abbedae9"
}

6.5.3. Methods

Description

The method updateContract updates contracts based on the provided contract data list.

Method signature

public List<ContractsResponseDto> updateContract(List<UpdateContractDto> contractDataList)

Parameters

  • contractDataList : List of UpdateContractDto objects containing contract update information.

Returns

  • List<ContractsResponseDto> : List of ContractsResponseDto objects representing the response for each contract update.

Example usage

public List<ContractsResponseDto> updateContract(List<UpdateContractDto> contractDataList) {
		List<ContractsResponseDto> contractResponseDtoList = new ArrayList<>();
		ContractsResponseDto contractResponseDto;

		for (UpdateContractDto updateContractData : contractDataList) { (1)
			// Validate the contract data using the updateContractValidator.
			contractResponseDto = updateContractValidator.validateContractData(updateContractData); (2)

			// If there are no validation errors, proceed with the contract update.
			if (contractResponseDto.getErrors().isEmpty()) {
				contractResponseDto = contractsWorker.updateContract(updateContractData); (3)
			}
			contractResponseDtoList.add(contractResponseDto);
		}
		return contractResponseDtoList; (4)
	}
Internal workflow
1 This method iterates through the provided list of contract data.
2 It validates each contract data using the updateContractValidator.
3 If there are no validation errors, it proceeds with the contract update using the contractsWorker.
4 The method returns a list of ContractsResponseDto objects containing the response for each contract update.

Exceptions

  • None explicitly thrown by this method. However, exceptions may occur within the validator or worker methods, which are handled internally.

6.5.4. Model classes

Description

The UpdateContractDto class represents the data transfer object used for updating contract information. It encapsulates details such as the contract UUID, product ID, and terms to be updated.

Attributes
  1. contractUUID

    • Type: UUID

    • Description: Represents the universally unique identifier (UUID) of the contract to be updated.

    • Example: 3539ebf7-e93f-4e38-90d5-8c4729ed493c

  2. productID

    • Type: Long

    • Description: Represents the identifier of the product associated with the contract.

    • Example: 1

  3. terms

    • Type: List<Map<String, Object>>

    • Description: Collection of contract terms represented as key-value pairs.

    • Example:

    {
      "terms": [
        {
          "contractPerformance": "PreDeal",
          "businessDayConvention": "SCF",
          "contractType": "ANN",
          "statusDate": "2023-07-31T06:30:00",
          "contractRole": "RPA",
          "creatorID": "a43c22ed-27df-4324-a453-3e7707c9b82d",
          "counterpartyID": "e548956c-1f3b-493e-952e-00cdcca6b599",
          "contractID": "a6b799db-c448-4aad-9382-3ae47383f5b2",
          "cycleAnchorDateOfInterestPayment": "2023-09-01T06:30:00",
          "cycleOfInterestPayment": "P1ML1",
          "nominalInterestRate": 0.02,
          "dayCountConvention": "30E360",
          "currency": "CHF",
          "contractDealDate": "2023-07-31T06:30:00",
          "initialExchangeDate": "2023-08-01T06:30:00",
          "maturityDate": "2024-08-01T06:30:00",
          "notionalPrincipal": 50000,
          "cycleAnchorDateOfPrincipalRedemption": "2023-09-01T06:30:00",
          "cycleOfPrincipalRedemption": "P1ML1",
          "nextPrincipalRedemptionPayment": 2312.7827499791606
        }
      ]
    }

6.5.5. Validation

Description

The validateContractData method is responsible for validating the contract data before proceeding with the contract update process. It ensures that the contract UUID is valid and then delegates further validation to the validateContractTerms method.

  • Parameters

    • updateContractData : An instance of the UpdateContractDto class containing the contract data to be validated.

  • Returns

  • ContractsResponseDto : A data transfer object containing the result of the validation process.

  • Example usage

public ContractsResponseDto validateContractData(UpdateContractDto updateContractData) {
		String contractID = null;
		HashMap<String, Object> contractErrors = new HashMap<>();
		List<Map<String, Object>> errorList = new ArrayList<>();

		try {
			// Validate the contract UUID by calling the contractsValidator.
			contractsValidator.validateContract(updateContractData.getContractUUID()); (1)

			// If there are no errors related to the contract UUID, proceed with further
			// validation.
			return validateContractTerms(updateContractData); (2)

		} catch (Exception e) { (3)
			contractErrors.put("Contract data", e.getMessage());
			errorList.add(contractErrors);
			return new ContractsResponseDto(null, contractID, errorList);
		}

	}
Validation steps
1 Contract UUID validation
  • The method invokes the validateContract method of the contractsValidator to validate the contract UUID.

  • If no errors are encountered, the method proceeds with further validation.

  • If an exception occurs during validation, an error message is added to the error list.

2 Contract terms validation
  • Further validation of contract terms is performed by calling the validateContractTerms method.

  • The validation result is returned as a ContractsResponseDto object.

3 Error handling
  • If an exception occurs during contract UUID validation, an error message is added to the error list.

  • The method returns a ContractsResponseDto object containing any validation errors encountered.

6.5.6. Testing

Description

This section comprises two test methods: updateContractBeforeTest and updateContractAfterTest. These methods validate the behavior of the contract update process before and after execution, respectively.

Test methods

Example usage

@Test
	void updateContractBeforeTest() { (1)

		Terms masterTerms = contracts.getContractTerms().get(0);
		PaymentDetails paymentDetails = contracts.getPaymentDetails();

		System.err.println("paymentDetails"+paymentDetails);
		BigDecimal NotionalPrincipal = new BigDecimal("50000.0");
		BigDecimal NextPrincipalRedemptionPayment = new BigDecimal("2312.7827499791606");
		Assertions.assertEquals(contracts.getProductID(), 1L);
		Assertions.assertEquals(NotionalPrincipal, masterTerms.getNotionalPrincipal(), "0.0");
		Assertions.assertEquals(NextPrincipalRedemptionPayment, masterTerms.getNextPrincipalRedemptionPayment(), "0.01");
		Assertions.assertEquals(LocalDateTime.parse("2023-08-01T00:00:00"), masterTerms.getInitialExchangeDate());
		Assertions.assertEquals(LocalDateTime.parse("2023-07-31T00:00:00"), masterTerms.getStatusDate());
		Assertions.assertEquals(profile.getProfileID(), masterTerms.getCounterpartyID());
		Assertions.assertEquals(paymentDetails.getCounterpartyPaymentChannelID(),
				counterPartyPaymentChannel.getPaymentChannelID());
		Assertions.assertEquals(paymentDetails.getRecordCreatorPaymentChannelID(),
				recordCreatorPaymentChannel.getPaymentChannelID());

	}

	@Test
	void updateContractAfterTest() { (2)
		when(usersHelper.getUserID()).thenReturn(UUID.fromString("a43c22ed-27df-4324-a453-3e7707c9b82d"));
		when(productRepo.findById(product.getProductID())).thenReturn(Optional.of(product));
		BigDecimal NotionalPrincipal = new BigDecimal("47771.0");
		BigDecimal NextPrincipalRedemptionPayment = new BigDecimal("2312.7827499791606");
		Map<String, Object> termsMap = new HashMap<>();
		List<Map<String, Object>> termsList = new ArrayList<>();
		List<UpdateContractDto> updateContractDtoList = new ArrayList<>();
		termsMap.put("initialExchangeDate", "2023-01-01T00:00:00");
		termsMap.put("notionalPrincipal", "47771.0");
		termsMap.put("remainingValue", "2000");
		termsMap.put("remainingValue", "2000");

		UpdateContractDto updateContractDto = new UpdateContractDto();
		contracts.setContractUUID(contractUUID);
		updateContractDto.setContractUUID(contracts.getContractUUID());


		updateContractDto.setProductID(contracts.getProductID());
		termsList.add(termsMap);
		updateContractDto.setTerms(termsList);
		updateContractDtoList.add(updateContractDto);


		List<ContractsResponseDto> updateContractsResponse = contractServiceImpl.updateContract(updateContractDtoList);

		Contracts contracts2 = contractsRepo.findById(UUID.fromString(updateContractsResponse.get(0).getContractUUID()))
				.get();
		Terms masterTerms = contracts2.getContractTerms().get(0);
		PaymentDetails paymentDetails = contracts2.getPaymentDetails();

		Assertions.assertEquals(contracts2.getProductID(), 1L);
		Assertions.assertEquals(NotionalPrincipal, masterTerms.getNotionalPrincipal(), "0.0");
		Assertions.assertEquals(NextPrincipalRedemptionPayment, masterTerms.getNextPrincipalRedemptionPayment(), "0.01");
		Assertions.assertEquals(LocalDateTime.parse("2023-01-01T00:00"), masterTerms.getInitialExchangeDate());
		Assertions.assertEquals(LocalDateTime.parse("2022-12-31T00:00"), masterTerms.getStatusDate());
		Assertions.assertEquals(profile.getProfileID(), masterTerms.getCounterpartyID());

		Assertions.assertEquals(paymentDetails.getCounterpartyPaymentChannelID(),
				counterPartyPaymentChannel.getPaymentChannelID());
		Assertions.assertEquals(paymentDetails.getRecordCreatorPaymentChannelID(),
				recordCreatorPaymentChannel.getPaymentChannelID());

	}
1 updateContractBeforeTest
  • Purpose : Validates the contract attributes before the update process.

  • Test steps

    1. Retrieve the contract attributes before the update process.

    2. Extract and store various contract properties such as notional principal, next principal redemption payment, dates, counterparty ID, and creator ID.

  • Assertions

    • Assert that the notional principal matches the expected value.

    • Assert that the next principal redemption payment matches the expected value.

    • Assert that the dates (e.g., initial exchange date, status date) are correct.

    • Assert that the counterparty ID and creator ID are as expected.

2 updateContractAfterTest
  • *Purpose :*Verifies the updated contract attributes after the update process.

  • Test steps

    1. Construct an UpdateContractDto object with updated contract terms.

    2. Execute the updateContract method to trigger the contract update process.

    3. Retrieve the updated contract from the repository.

    4. Extract and store the updated contract attributes.

  • Assertions

    • Assert that the notional principal has been updated correctly.

    • Assert that the next principal redemption payment reflects the updated terms.

    • Assert that the dates (e.g., initial exchange date, status date) have been modified as expected.

    • Assert that the counterparty ID and creator ID remain unchanged.

6.6. Update executed contract

6.6.1. Sequential flow

update-executed-contract.puml

Executed contract updation process

  1. The User triggers the "updateExecutedContract" operation by providing updation data and the contract UUID.

  2. The Controller receives the request and activates.

  3. The Controller forwards the request to the ContractService.

  4. The ContractService activates to process the update.

  5. The ContractService delegates validation of the executed contract data to the UpdateContractValidator.

  6. If the validation of executed contract data is successful

    • The UpdateContractValidator verifies the contract UUID using ContractsValidator.

    • ContractsValidator retrieves the contract from ContractsRepository by its UUID.

    • UpdateContractValidator checks if the contract update terms are valid against master contract terms using ContractService.

    • If the validation of contract update terms is successful:

      • ContractsWorker updates the executed contract.

      • Updated contract is saved in ContractsRepository.

      • The ContractService responds with a success message to the Controller.

      • The Controller sends a ResponseEntity<ResponseDto> containing the success message to the User.

    • If the validation of contract update terms fails:

      • The ContractService responds with an error message indicating invalid contract data to the Controller.

      • The Controller sends a ResponseEntity<ResponseDto> containing the error message to the User.

  7. If the validation of executed contract data fails

    • The UpdateContractValidator responds with an error message indicating invalid contract UUID to the ContractService.

    • The ContractService responds with a ResponseEntity<ResponseDto> containing the error message to the Controller.

    • The Controller sends a ResponseEntity<ResponseDto> containing the error message to the User.

6.6.2. Endpoint

Description

This endpoint allows you to update an executed contract based on the provided contract data.

URL

/contracts/updateContract/{contractUUID}

Method

POST

Request parameters

Parameters

Type

Required

Description

contractUUID

UUID

Yes

The UUID of the contract to be updated.

Request body

The request body should contain a JSON array of objects, each representing data for updating a contract. The structure of each object should adhere to the TermsDto format.

Example request body

{
  "notionalPrincipal": 60000
}

Response

  • 200 : Success. Returns a JSON response containing details of the updated contracts.

Example response body

{
  "status": 200,
  "message": "Contract Rescheduled",
  "data": "36c7d13e-55dc-4b89-a1b8-98f1f8716698"
}
  • 400 bad request

Example

{
  "status": 400,
  "message": "Invalid contractUUID",
  "data": "36c7d13e-55dc-4b89-a1b8-98f1f8716698"
}
  • 400 bad request: If the request body is not in the correct format or if there are validation errors.

  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to create contracts.

  • 5xx server error: If there is a server-side error while processing the request.

  • The updationData should contain the necessary fields required for updating the contract.

  • The request body json only allows the values which are in the TermsDto model class.

6.6.3. Methods

Description

The updateExecutedContract method updates an executed contract based on the provided contract UUID and data.

Method signature

public void updateExecutedContract(String contractUUID, TermsDto updationData)
    throws ContractsException, IllegalAccessException, ParseException

Parameters

  • contractUUID (UUID): The UUID of the contract to be updated.

  • updationData (TermsDto): The data used for updating the contract

Returns

  • contractUUID (UUID): The contractUUID of which the contract has been updated.

Exceptions

  • ContractsException : Thrown if there is an issue with the contract.

  • IllegalAccessException : Thrown if there is illegal access during contract update.

  • ParseException : Thrown if there is an error while parsing data.

Usage example

public void updateExecutedContract(UUID contractUUID, TermsDto updationData)
			throws ContractsException, IllegalAccessException, ParseException {

		// Validate the executed contract data before updating.
		updateContractValidator.validateExecutedContractData(contractUUID, updationData); (1)

		// Perform the actual contract update.
		contractsWorker.updateExecutedContract(contractUUID, updationData); (2)

	}


public void updateExecutedContract(UUID contractUUID, TermsDto updationData)
			throws IllegalAccessException, ParseException {
		log.info("Contract update started by UserId : {}, ContractUUID : {}, Request : {}", usersHelper.getUserID(),
				contractUUID, updationData);
		// Retrieve the executed contract by its UUID.
		Contracts contract = contractsServiceRepo.findById(contractUUID)
				.orElseThrow(() -> new IllegalArgumentException(CONTRACT_ERROR)); (3)

		// Save a history snapshot of the contract before updating.
		saveContractHistory(contract); (4)

		// Update the contract data based on the provided data.
		updateContractData(contract, updationData); (5)

		// Reschedule events associated with the updated contract.
		rescheduleEvents(contract); (6)
		contractsServiceRepo.save(contract); (7)

		log.info("Contract update finished by UserId : {}, ContractUUID : {}", usersHelper.getUserID(), contractUUID);
	}
Internal workflow
1 Validates the executed contract data before updating.
2 Performs the actual contract update.
3 Retrieves the executed contract by its UUID.
4 Saves a history snapshot of the contract before updating.
5 Updates the contract data based on the provided data.
6 Reschedules events associated with the updated contract.
7 Saves the updated contract.

6.6.4. Model classes

Description

The TermsDto class serves as a data transfer object (DTO) that encapsulates various terms and details associated with a contract. It is designed to facilitate the transfer of contract-related information between different components of the application.

Attributes
  1. contractPerformance

    • Type: String

    • Description: Indicates the performance status of the contract.

    • Example: "PreDeal"

  2. calendar

    • Type: String

    • Description: Specifies the calendar system used for scheduling events related to the contract.

    • Example: "Monday to Friday"

  3. businessDayConvention

    • Type: String

    • Description: Defines the method for adjusting dates that fall on non-business days.

    • Example: "SCF"

  4. endOfMonthConvention

    • Type: String

    • Description: Specifies how end-of-month dates are handled in calculations.

    • Example: "EOM"

  5. contractType

    • Type: String

    • Description: Identifies the type or category of the contract.

    • Example: "PAM"

  6. statusDate

    • Type: LocalDateTime

    • Description: Represents the date at which the status of the contract was last updated.

    • Example: "2022-12-31 00:00:00"

  7. contractRole

    • Type: String

    • Description: Specifies the role of the contract in a transaction or relationship.

    • Example: "RPA"

  8. creatorID

    • Type: String

    • Description: Identifier of the user or system that created the contract.

    • Example: "902375cc-4f72-428f-8db0-95a7baa69b51"

  9. counterpartyID

    • Type: String

    • Description: Identifier of the counterparty involved in the contract.

    • Example: "d2c87ded-489e-4510-8fe1-95f12c048a5d"

  10. contractID

    • Type: String

    • Description: Unique identifier for the contract.

    • Example: "9ec8997e-70b5-4fa1-82fe-56cbc0fc8149"

click to see more…​.
  1. marketObjectCodeOfDividends

    • Type: String

    • Description: Code or identifier for the market object related to dividends.

    • Example: "DIV"

  2. cycleAnchorDateOfFee

    • Type: LocalDateTime

    • Description: Date used as a reference point for fee calculation cycles.

    • Example: "2023-01-01T00:00:00"

  3. cycleOfFee

    • Type: String

    • Description: Specifies the frequency or pattern of fee payments.

    • Example: "1M"

  4. feeBasis

    • Type: String

    • Description: Basis or method used for calculating fees.

    • Example: "A"

  5. feeRate

    • Type: BigDecimal

    • Description: Rate at which fees are applied, usually expressed as a percentage.

    • Example: 2500.00

  6. feeAccrued

    • Type: BigDecimal

    • Description: Total amount of fees accrued up to the present time.

    • Example: 1000.0

  7. cycleAnchorDateOfInterestPayment

    • Type: LocalDateTime

    • Description: Date serving as a reference point for interest payment cycles.

    • Example: "2023-01-21T06:30:00"

  8. arrayCycleAnchorDateOfInterestPayment

    • Type: String

    • Description: An array containing multiple cycle anchor dates of interest payments.

    • Example: ["2023-01-21T06:30:00", "2023-06-01T06:30:00", "2023-07-26T06:30:00"]

  9. cycleOfInterestPayment

    • Type: String

    • Description: Frequency or pattern of interest payments.

    • Example: "P1ML1"

  10. arrayCycleOfInterestPayment

    • Type: String

    • Description: An array containing multiple cycles of interest payments.

    • Example: ["1M", "6M"]

  11. nominalInterestRate

    • Type: BigDecimal

    • Description: Nominal interest rate applied to the principal.

    • Example: 0.01

  12. nominalInterestRate2

    • Type: BigDecimal

    • Description: Additional nominal interest rate, if applicable.

    • Example: 0.03

  13. dayCountConvention

    • Type: String

    • Description: Method used for calculating the number of days between two dates.

    • Example: "30E360"

  14. accruedInterest

    • Type: BigDecimal

    • Description: Total amount of interest accrued up to the present time.

    • Example: 500.0

  15. capitalizationEndDate

    • Type: LocalDateTime

    • Description: Date when interest capitalization ends.

    • Example: "2024-12-31T23:59:59"

  16. cycleAnchorDateOfInterestCalculationBase

    • Type: LocalDateTime

    • Description: Date used as a reference point for interest calculation.

    • Example: "2024-03-01T00:00:00"

  17. cycleOfInterestCalculationBase

    • Type: String

    • Description: Frequency or pattern of interest calculation.

    • Example: "P1ML1"

  18. interestCalculationBase

    • Type: String

    • Description: Specifies the base amount or balance used for interest calculation.

    • Example: "NT"

  19. interestCalculationBaseAmount

    • Type: BigDecimal

    • Description: Amount used as the base for interest calculation.

    • Example: 10000.0

  20. cyclePointOfInterestPayment

    • Type: String

    • Description: Specifies the point within each interest period when interest payments are made.

    • Example: "E"

  21. currency

    • Type: String

    • Description: The currency in which monetary values are expressed.

    • Example: "USD"

  22. currency2

    • Type: String

    • Description: Another currency, if applicable.

    • Example: "EUR"

  23. amortizationDate

    • Type: LocalDateTime

    • Description: Date when the principal is scheduled to be repaid.

    • Example: "2024-12-31T23:59:59"

  24. contractDealDate

    • Type: LocalDateTime

    • Description: Date when the contract was executed or agreed upon.

    • Example: "2024-03-01T00:00:00"

  25. initialExchangeDate

    • Type: LocalDateTime

    • Description: Date of the initial exchange or transaction related to the contract.

    • Example: "2024-03-01T00:00:00"

  26. maturityDate

    • Type: LocalDateTime

    • Description: Date when the contract reaches maturity or expires.

    • Example: "2024-12-31T23:59:59"

  27. notionalPrincipal

    • Type: BigDecimal

    • Description: The principal amount on which interest is calculated.

    • Example: 100000.0

  28. notionalPrincipal2

    • Type: BigDecimal

    • Description: Another principal amount, if applicable.

    • Example: 50000.0

  29. quantity

    • Type: String

    • Description: Quantity or amount associated with the contract.

    • Example: "3"

  30. cycleAnchorDateOfPrincipalRedemption

    • Type: LocalDateTime

    • Description: Date used as a reference point for principal redemption cycles.

    • Example: "2024-03-01T00:00:00"

  31. arrayCycleAnchorDateOfPrincipalRedemption

    • Type: String

    • Description: An array containing multiple cycle anchor dates of principal redemption.

    • Example: ["2024-01-01", "2024-04-01", "2024-07-01"]

  32. cycleOfPrincipalRedemption

    • Type: String

    • Description: Frequency or pattern of principal redemption.

    • Example: "P1ML1"

  33. arrayCycleOfPrincipalRedemption

    • Type: String

    • Description: An array containing multiple cycles of principal redemption.

    • Example: ["1M", "6M"]

  34. nextPrincipalRedemptionPayment

    • Type: BigDecimal

    • Description: Next scheduled payment for principal redemption.

    • Example: 1000.0

  35. arrayNextPrincipalRedemptionPayment

    • Type: String

    • Description: An array containing multiple next principal redemption payments.

    • Example: ["1000.0", "500.50", "750.25"]

  36. arrayIncreaseDecrease

    • Type: String

    • Description: An array containing information about increases or decreases in certain aspects of the contract.

    • Example: "INC"

  37. purchaseDate

    • Type: LocalDateTime

    • Description: Date when the contract was purchased or acquired.

    • Example: "2024-03-01T00:00:00"

  38. priceAtPurchaseDate

    • Type: BigDecimal

    • Description: Price of the contract at the time of purchase.

    • Example: 100.0

  39. terminationDate

    • Type: LocalDateTime

    • Description: Date when the contract is terminated or ends.

    • Example: "2024-12-31T23:59:59"

  40. priceAtTerminationDate

    • Type: BigDecimal

    • Description: Price of the contract at the time of termination.

    • Example: 90.0

  41. marketObjectCodeOfScalingIndex

    • Type: String

    • Description: Code or identifier for the market object related to scaling index.

    • Example: "SCAL-001"

  42. scalingIndexAtContractDealDate

    • Type: BigDecimal

    • Description: Scaling index value at the contract deal date.

    • Example: 120.0

  43. cycleAnchorDateOfScalingIndex

    • Type: LocalDateTime

    • Description: Date used as a reference point for scaling index cycles.

    • Example: "2024-03-01T00:00:00"

  44. cycleOfScalingIndex

    • Type: String

    • Description: Frequency or pattern of scaling index adjustments.

    • Example: "3M"

  45. scalingEffect

    • Type: String

    • Description: Effect or impact of scaling on the contract.

    • Example: "0N0"

  46. cycleAnchorDateOfRateReset

    • Type: LocalDateTime

    • Description: Date used as a reference point for rate reset cycles.

    • Example: "2024-03-01T00:00:00"

  47. arrayCycleAnchorDateOfRateReset

    • Type: String

    • Description: An array containing multiple cycle anchor dates of rate reset.

    • Example: ["2024-01-01", "2024-04-01", "2024-07-01"]

  48. cycleOfRateReset

    • Type: String

    • Description: Frequency or pattern of rate resets.

    • Example: "Monthly", "Quarterly", "Annually"

  49. arrayCycleOfRateReset

    • Type: String

    • Description: An array containing multiple cycles of rate resets.

    • Example: ["1M","1Y"]

  50. rateSpread

    • Type: BigDecimal

    • Description: Additional interest rate spread applied to a benchmark rate.

    • Example: 0.02

  51. arrayRate

    • Type: String

    • Description: An array containing multiple interest rates.

    • Example: ["0.05", "0.06", "0.04"]

  52. arrayFixedVariable

    • Type: String

    • Description: An array indicating whether interest rates are fixed or variable.

    • Example: "F"

  53. marketObjectCodeOfRateReset

    • Type: String

    • Description: Code or identifier for the market object related to rate reset.

    • Example: "e4d7d42c-f11a-4ff3-886f-5bf36db3bac9"

  54. cyclePointOfRateReset

    • Type: String

    • Description: Specifies the point within each interest period when rate resets occur.

    • Example: "B"

  55. fixingPeriod

    • Type: String

    • Description: Period during which interest rates are fixed.

    • Example: "3M"

  56. nextResetRate

    • Type: BigDecimal

    • Description: Next scheduled rate after a reset.

    • Example: 0.07

  57. rateMultiplier

    • Type: BigDecimal

    • Description: Multiplier applied to a reference rate to determine the interest rate.

    • Example: 1.5

  58. settlementPeriod

    • Type: LocalDateTime

    • Description: Period during which settlement occurs.

    • Example: "2024-03-01T00:00:00"

  59. deliverySettlement

    • Type: String

    • Description: Method or process used for delivery settlement.

    • Example: "S"

  60. marketValueObserved

    • Type: BigDecimal

    • Description: Observed market value of the contract.

    • Example: 10000.0

  61. premiumDiscountAtIED

    • Type: BigDecimal

    • Description: Premium or discount applied at the initial exchange date (IED).

    • Example: 500.0

  62. cycleAnchorDateOfOptionality

    • Type: LocalDateTime

    • Description: Date used as a reference point for optionality cycles.

    • Example: "2024-03-01T00:00:00"

  63. cycleOfOptionality

    • Type: String

    • Description: Frequency or pattern of optionality.

    • Example: "P1ML1"

  64. lifeCap

    • Type: BigDecimal

    • Description: Maximum cap on interest rates over the life of the contract.

    • Example: 0.08

  65. lifeFloor

    • Type: BigDecimal

    • Description: Minimum floor on interest rates over the life of the contract.

    • Example: 0.03

  66. penaltyType

    • Type: String

    • Description: Type or category of penalty associated with the contract.

    • Example: "N"

  67. penaltyRate

    • Type: BigDecimal

    • Description: Rate at which penalties are applied, usually expressed as a percentage.

    • Example: 0.05

  68. objectCodeOfPrepaymentModel

    • Type: String

    • Description: Code or identifier for the prepayment model object.

    • Example: "PREPAY-MODEL"

  69. periodCap

    • Type: BigDecimal

    • Description: Maximum cap on interest rates for a specific period.

    • Example: 0.08

  70. periodFloor

    • Type: BigDecimal

    • Description: Minimum floor on interest rates for a specific period.

    • Example: 0.03

  71. marketObjectCode

    • Type: String

    • Description: Code or identifier for the market object associated with the contract.

    • Example: "YC.USA.TREASURY"

  72. cycleAnchorDateOfDividendPayment

    • Type: LocalDateTime

    • Description: Date used as a reference point for dividend payment cycles.

    • Example: "2024-03-01T00:00:00"

  73. cycleOfDividendPayment

    • Type: String

    • Description: Frequency or pattern of dividend payments.

    • Example: "1Q"

  74. tenure

    • Type: String

    • Description: Duration or term of the contract.

    • Example: "5Y"

  75. roundingConvention

    • Type: String

    • Description: Method used for rounding numerical values in calculations.

    • Example: "Half Up"

  76. xDayNotice

    • Type: String

    • Description: Notice period required for certain actions or events.

    • Example: "30D"

  77. maximumPenaltyFreeDisbursement

    • Type: String

    • Description: Maximum amount that can be disbursed without incurring penalties.

    • Example: "10000"

  78. delinquencyPeriod

    • Type: String

    • Description: Period during which a payment is considered delinquent.

    • Example: "30D"

  79. gracePeriod

    • Type: String

    • Description: Period of time after a payment is due before penalties are applied.

    • Example: "7D"

  • Not all attributes may be necessary for every contract scenario, and developers should tailor the usage of attributes based on specific contract requirements.

6.6.5. Validation

Description

The validateExecutedContractData method is responsible for validating the data associated with an executed contract. This ensures the integrity and accuracy of the contract information before any further processing is performed.

Parameters

  • Contract UUID (Type: UUID) : The UUID of the executed contract to be validated.

  • updationContractTerms (Type: TermsDto) : Contains the updated contract terms to be validated.

Returns

  • Returns the master contract terms associated with the provided UUID.

Example usage

public void validateExecutedContractData(UUID contractUUID, TermsDto updationContractTerms)
			throws ContractsException {
		// Validate the contract UUID and retrieve the contract.
		Contracts contract = contractsValidator.validateContractUUID(contractUUID); (1)
		Terms masterContractTerms = contract.getContractTerms().get(0);

		// Validate the updated contract terms against the master contract terms.
		validateContractUpdateTerms(masterContractTerms, updationContractTerms); (2)
	}
1 Contract UUID validation
  • Verify that the provided contract UUID exists in the system.

  • Retrieve the master contract terms associated with the provided UUID.

2 Updated contract terms validation
  • Compare the updated contract terms (updationContractTerms) against the master contract terms (masterContractTerms) retrieved from the database.

    1. InitialExchangeDate update restriction

      1. If InitialExchangeDate is being updated, the update is disallowed.

    2. ContractDealDate update restriction

      1. If ContractDealDate is being updated, the update is disallowed.

    3. StatusDate validation

      1. If StatusDate is provided:

      2. It must not be set to a date before the current StatusDate.

      3. It must not be set to a date before InitialExchangeDate.

Error handling

  • If the contract UUID is invalid or does not exist, a ContractsException is thrown with an appropriate error message.

  • If the updated contract terms do not align with the master contract terms, validation fails and a ContractsException is thrown.

6.6.6. Testing

Description

This section provides an overview of the testing strategy and objectives for the update executed contract method.

Test methods

Example usage

@TestFactory
	Stream<DynamicTest> updatePFContractBeforeTest() throws IOException { (1)
		List<DynamicTest> dynamicTests = new ArrayList<>();

		List<BusinessEventsDto> expectedEventsList = MappingUtils
				.mapToEventsList("./src/test/resources/events/events-contract-ann.json");

		List<BusinessEvents> computedEventsList = eventsRepo.findByContractUUID(contracts);
		Assertions.assertEquals(expectedEventsList.size(), computedEventsList.size(), "Number of events should match.");

		for (int i = 0; i < expectedEventsList.size(); i++) {
			BusinessEventsDto expectedEvent = expectedEventsList.get(i);
			BusinessEvents computedEvent = computedEventsList.get(i);

			dynamicTests.add(contractUtils.createDynamicTest(expectedEvent, computedEvent));
		}

		return dynamicTests.stream();
	}

	@TestFactory
	Stream<DynamicTest> updatePFContractAfterTest()
			throws IOException, ParseException, IllegalAccessException, ContractsException, InterruptedException { (2)
		List<DynamicTest> dynamicTests = new ArrayList<>();

		List<BusinessEventsDto> expectedEventsList = MappingUtils
				.mapToEventsList("./src/test/resources/events/updated-events-contract-ann.json");

		updatePFContractTest();
		List<BusinessEvents> computedEventsList = eventsRepo.findByContractUUID(contracts);

		Assertions.assertEquals(expectedEventsList.size(), computedEventsList.size(), "Number of events should match.");

		for (int i = 0; i < expectedEventsList.size(); i++) {
			BusinessEventsDto expectedEvent = expectedEventsList.get(i);
			BusinessEvents computedEvent = computedEventsList.get(i);

			dynamicTests.add(contractUtils.createDynamicTest(expectedEvent, computedEvent));
		}

		return dynamicTests.stream();
	}
1 updatePFContractBeforeTest
  • Purpose : This test evaluates the behavior of updating a PF contract before specific events.

  • Test steps

    1. Data preparation: Load expected business events from a JSON file (events-contract-ann.json).

    2. Retrieve computed events: Fetch computed business events associated with contracts from the repository.

    3. Assertion: Verify that the number of expected events matches the number of computed events.

    4. Dynamic test generation: Iterate through each pair of expected and computed events, creating dynamic tests to compare their properties.

2 updatePFContractAfterTest
  • Purpose : This test evaluates the behavior of updating a PF contract after specific events.

  • Test steps

    1. Data preparation: Load expected business events after contract updates from a JSON file (updated-events-contract-ann.json).

    2. Invoke contract update: Call the updatePFContractTest() method to perform the contract update operation.

    3. Retrieve computed events: Fetch computed business events associated with contracts from the repository after the update.

    4. Assertion: Verify that the number of expected events matches the number of computed events.

    5. Dynamic test generation: Iterate through each pair of expected and computed events, creating dynamic tests to compare their properties.

  • Assertions

    • Number of events: Assert that the number of expected business events matches the number of computed events. This ensures that all events associated with the contracts are generated and handled correctly.

    • Properties comparison: For each pair of expected and computed events, dynamically generated tests compare their properties (e.g., event type, timestamp, associated contract UUID). Any discrepancies between expected and computed events will result in test failures, indicating potential issues with the contract update process or event handling logic.

6.7. Create dynamic event

6.7.1. Sequential flow

create-dynamic-event.puml

Steps to create dynamic event

  1. Receive request

    • The system receives a request from the user to create a dynamic event.

  2. Validate data

    • The system validates the provided contract UUID and event date.

      • If the contract UUID is invalid or doesn’t exist, an error is returned.

      • If the event date is after the maturity date or future events are already processed, an error is returned.

  3. Create dynamic event

    • If the data is valid, the system creates a dynamic event based on the provided data.

  4. Save event

    • The system saves the created dynamic event.

  5. Respond to user

    • A response containing information about the created dynamic event is sent back to the user.

6.7.2. Endpoint

Description

This endpoint is used to create a dynamic event associated with a contract.

URL

/contracts/newEvent/{contractUUID}

Method

POST

Request parameters

Parameters

Type

Required

Description

contractUUID

UUID

Yes

The unique identifier of the contract.

Request body

The request body should contain a JSON array of objects, each representing data for creating a dynamic event. The structure of each object should adhere to the DynamicEventDto format.

Example request body

{
  "time": "2024-02-23T06:30",
  "type": "TP",
  "value": 5000
}

Response

  • 200 : Success. Returns a JSON response containing UUID of the created dynamic event.

Example response body

{
  "status": 200,
  "message": "Event created successfully",
  "data": "36c7d13e-55dc-4b89-a1b8-98f1f8716698"
}
  • 400 bad request

Example

{
  "status": 400,
  "message": "Invalid contractUUID 36c7d13e-55dc-4b89-a1b8-98f1f8716698",
  "data": null
}
  • 400 bad request: If the request body is not in the correct format or if there are validation errors.

  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to create contracts.

  • 5xx server error: If there is a server-side error while processing the request.

  • Ensure the contract UUID is valid and exists in the system before creating the dynamic event.

  • The request body json only allows the values which are in the DynamicEventDto model class.

6.7.3. Methods

Description

This method is responsible for creating a dynamic event associated with a contract.

  1. Method : validateDynamicEventData

    • Purpose

      • This method validates the dynamic event data and checks for any future events already processed.

    • Parameters

      • dynamicEventData (Type: DynamicEventDto) : JSON data representing the dynamic event.

      • contractUUID (Type: String) : The unique identifier of the contract.

    • Return type

      • Contracts - The validated contract associated with the dynamic event.

        public Contracts validateDynamicEventData(DynamicEventDto dynamicEventData, UUID contractUUID) {
        		Contracts contract = validateContractUUID(contractUUID); (1)
        
        		validateEventDateWithMaturityDate(dynamicEventData, contract); (2)
        
        		final Integer futureProcessed = eventsRepo.countByContractUUIDAndStatusAndEventTimeGreaterThan(contract,
        				"processed", dynamicEventData.getTime());
        		// Check if there are any future events already processed. If so, throw an
        		// exception.
        		Assert.isTrue(futureProcessed == 0, "Future events already processed"); (3)
        		return contract; (4)
        	}
    • Behavior

    1 Calls validateContractUUID method to validate the contract UUID.
    2 Validates the event date with the maturity date of the contract.
    3 Checks if there are any future events already processed.
    4 Returns the validated contract.
  2. Method : createDynamicEvent

    • Purpose

      • This method creates a dynamic event based on the provided data and contract.

    • Parameters

      • dynamicEventData (Type: DynamicEventDto) : JSON data representing the dynamic event.

      • contract (Type: Contracts) : The contract associated with the dynamic event.

    • Return type

      • DynamicEventResponseDto : Response containing information about the created dynamic event.

        public DynamicEventResponseDto createDynamicEvent(DynamicEventDto dynamicEventData, Contracts contract) {
        		log.info("Dynamic event creation started by UserId : {}, ContractUUID : {}, Request : {} ",
        				usersHelper.getUserID(), contract.getContractUUID(), dynamicEventData);
        
        		// Create a dynamic event based on the provided data and contract.
        		BusinessEvents dynamicEvent = eventsHelper.createDynamicEvent(dynamicEventData, contract); (1)
        
        		// Update the status of the dynamic event.
        		eventsHelper.updateEventStatus(dynamicEvent); (2)
        
        		// Save the dynamic event .
        		businessEventsService.save(dynamicEvent); (3)
        
        		log.info("Dynamic event created by UserId : {}, ContractUUID : {}, EventId: {} ", usersHelper.getUserID(),
        				contract.getContractUUID(), dynamicEvent.getEventID());
        
        		return new DynamicEventResponseDto("Event created", dynamicEvent.getEventID(), dynamicEvent.getEventBody()); (4)
        	}
    • Behavior

    1 Creates a dynamic event using the provided data and contract by calling createDynamicEvent method from the EventsHelper component.
    2 Updates the status of the dynamic event using the EventsHelper component.
    3 Saves the dynamic event using the BusinessEventsService component.
    4 Returns a DynamicEventResponseDto containing information about the created dynamic event.

6.7.4. Model classes

Description

The DynamicEventDto class represents the data transfer object (DTO) for a dynamic event. It encapsulates the attributes necessary to create a dynamic event.

Attributes
  1. time

    • Type: LocalDateTime

    • Description: Represents the time of the dynamic event.

    • Constraints: Cannot be null.

    • Example: "2024-02-23T06:30"

  2. type

    • Type: String

    • Description: Represents the type of the dynamic event.

    • Constraints: Cannot be null.

    • Example: "TP"

  3. value

    • Type: BigDecimal

    • Description: Represents the value associated with the dynamic event.

    • Constraints: Cannot be null.

    • Example: 5000

  4. contractID

    • Type: String

    • Description: Represents the unique identifier of the contract associated with the dynamic event.

    • Constraints: None specified.

    • Example: "1234567890"

Usage example

		BusinessEvents businessEvents = new BusinessEvents();
		businessEvents.setEventTime(UtilityHelper.toLocalDateTime(dynamicEventData.getTime()).toString());
		businessEvents.setEventType(dynamicEventData.getType());
		businessEvents.setEventBody(determineEventBodyForDynamicEvent(contract, term, dynamicEventData));
		businessEvents.setStatus("scheduled");
		businessEvents.setExecutionType(determineExecutionTypeForDynamicEvent(dynamicEventData.getType()));
		businessEvents.setUserID(term.getCreatorID());
		businessEvents.setCreatedBy(contract.getCreatedBy());
		businessEvents.setContractUUID(contract);
		businessEvents.setContractID(contractId);
  • The DynamicEventDto class is used to create a new business events object which is used to create a dynamic event.

6.7.5. Validation

Description

The method validateContract(UUID contractUUID) validates dynamic event data against a given contract.

  • Parameters

    • dynamicEventData : A DTO representing dynamic event data.

    • contractUUID : The UUID of the contract to be validated.

  • Returns

    • Returns the validated Contracts object representing the contract associated with the provided UUID.

  • Functionality

    • It ensures that the event date is valid with respect to the contract’s maturity date.

    • It ensures that no future events have already been processed.

  • Exceptions

    • If future events are found to be already processed, an IllegalStateException is thrown with the message "Future events already processed".

  • Example usage

public Contracts validateDynamicEventData(DynamicEventDto dynamicEventData, UUID contractUUID) {
		Contracts contract = validateContractUUID(contractUUID); (1)

		validateEventDateWithMaturityDate(dynamicEventData, contract); (2)

		final Integer futureProcessed = eventsRepo.countByContractUUIDAndStatusAndEventTimeGreaterThan(contract,
				"processed", dynamicEventData.getTime());
		// Check if there are any future events already processed. If so, throw an
		// exception.
		Assert.isTrue(futureProcessed == 0, "Future events already processed"); (3)
		return contract;
	}
Validation steps
1 Contract UUID validation
  • Validates the existence of the contract associated with the provided UUID.

  • Calls validateContractUUID method to ensure the validity of the contract UUID.

2 Event date validation
  • Validates if the event date is within the maturity date of the contract.

  • Calls validateEventDateWithMaturityDate method to perform this validation.

3 Future processed events check
  • Checks if there are any future events already processed for the contract.

  • Utilizes a repository method (countByContractUUIDAndStatusAndEventTimeGreaterThan) to count the number of future processed events.

  • Throws an exception if any future events are found to be already processed.

6.7.6. Testing

Description

This section provides an overview of the testing strategy and objectives for the create dynamic event method.

Test methods

Example usage

@Test
	void createDynamicEventTest() throws ContractsException { (1)

		Response<UUID> dynamicEventResponseDto = contractServiceImpl.createDynamicEvent(dynamicEventDto,
				contractUUID);
		BusinessEvents dynamicEvent = eventsHelper.createDynamicEvent(dynamicEventDto, contract);
		BigDecimal eventValue = dynamicEvent.getValue() ;
		UUID creditPaymentChannel = dynamicEvent.getCreditPaymentChannelID();
		UUID debitPaymentChannel = dynamicEvent.getDebitPaymentChannelID();

		PaymentDetails paymentDetails = contract.getPaymentDetails();

		assertEquals("Event created successfully", dynamicEventResponseDto.getMessage());
		assertEquals(value.doubleValue(), eventValue.doubleValue(), 0.0);
		assertEquals(paymentDetails.getCounterpartyPaymentChannelID(), creditPaymentChannel);
		assertEquals(paymentDetails.getRecordCreatorPaymentChannelID(), debitPaymentChannel);

	}
1 createDynamicEventTest()
  • Purpose : The purpose of this test is to ensure that the createDynamicEvent() method correctly creates dynamic events and returns the expected response.

  • Test steps

    1. Invoke the createDynamicEvent() method with a dynamicEventDto and a contractUUID converted to string.

    2. Retrieve the event body from the response DTO.

    3. Extract the event value, credit payment channel, and debit payment channel from the event body.

    4. Retrieve payment details from the contract.

  • Assertions

    • Verify that the event value matches the expected value of 500 with a tolerance of 0.0.

    • Assert that the credit payment channel matches the payment channel ID of the counterparty in the payment details.

    • Assert that the debit payment channel matches the payment channel ID of the record creator in the payment details.

Transactions

1. Introduction

The transactions service allows registering or processing events and updating the contract accordingly.

2. Tables and relations

Establishing relationships

  • In relational databases like PostgreSQL, relationships between tables are crucial for organizing and querying data effectively. These relationships are typically established using foreign key constraints, which define links between tables based on the values of specific columns. Common types of relationships include one-to-one, one-to-many, and many-to-many relationships, each serving different data modeling needs.

transactions ERD
Figure 2. Transactions Entity-relationship diagram

Tables

  • Schema

    1. Table business_events

      Index Name Data type

      * πŸ”‘ ⬋

      eventid

      uuid

      *

      event_time

      timestamp

      * πŸ”Ž

      event_type

      varchar(10)

      event_body

      json

      * πŸ”Ž

      status

      varchar(10)

      * πŸ”Ž

      execution_type

      varchar(20)

      contractid

      varchar(255)

      *

      userid

      uuid

      * πŸ”Ž ⬈

      contractuuid

      uuid

      value

      numeric

      remaining_value

      numeric

      credit_payment_channel_id

      uuid

      debit_payment_channel_id

      uuid

      units

      varchar(10)

      1. Foreign keys

        Type Name On

        fk_business_events_contracts_contractuuid

        contractuuid

      2. Constraints

        Name Definition

        business_events_event_type_check

        ((event_type)::text ~* ’^(AD

        business_events_status_check

        ((status)::text ~* ’^(scheduled

    2. Table contracts

      Index Name Data type

      * πŸ”‘ ⬋

      contractuuid

      uuid

      ⬈

      productid

      bigint

      *

      createdby

      uuid

      executedby

      uuid

      *

      system_time

      timestamp

      selection

      json

      1. Foreign keys

        Type Name On

        contracts_product_fk

        productid

    3. Table contracts_history

      Index Name Data type

      * πŸ”‘ ⬋

      contractuuid

      uuid

      * πŸ”‘ ⬋

      status_date

      timestamp

      productid

      bigint

      selection

      json

      *

      system_time

      timestamp

    4. Table payment_channels

      Index Name Data type

      * πŸ”‘ ⬋

      payment_channelid

      uuid

      contractid

      uuid

      details

      json

      *

      identifier

      varchar(100)

      label

      varchar(100)

      *

      type

      varchar(50)

      * πŸ”Ž

      owner_type

      varchar(10)

      *

      units

      varchar(10)

      *

      system

      varchar(50)

      account_characteristic

      varchar(50)

      * πŸ”Ž

      ownerid

      uuid

      * πŸ”Ž

      userid

      uuid

      1. Constraints

        Name Definition

        payment_channels_owner_type_check

        ((owner_type)::text ~* ’^(root

    5. Table payment_details

      Index Name Data type

      * πŸ”‘

      id

      bigint GENERATED BY DEFAULT AS IDENTITY

      ⬈

      contract_uuid

      uuid

      ⬈

      record_creator_paymentchannel_id

      uuid

      ⬈

      counterparty_paymentchannel_id

      uuid

      ⬈

      contract_paymentchannel_id

      uuid

      1. Foreign keys

        Type Name On

        paymentdetails_contractuuid_fk

        contract_uuid

        paymentdetails_contract_payment_fk

        contract_paymentchannel_id

        paymentdetails_counterparty_fk

        counterparty_paymentchannel_id

        paymentdetails_record_creator_fk

        record_creator_paymentchannel_id

    6. Table products

      Index Name Data type

      * πŸ”‘ ⬋

      productid

      bigint GENERATED BY DEFAULT AS IDENTITY

      *

      status

      varchar(10)

      *

      template

      json

      * πŸ”Ž

      userid

      uuid

      1. Constraints

        Name Definition

        products_status_check

        ((status)::text ~* ’^(active

    7. Table profile_forms

      Index Name Data type

      * πŸ”‘ ⬋

      profile_formid

      bigint GENERATED BY DEFAULT AS IDENTITY

      *

      profile_form_details

      json

      *

      userid

      uuid

    8. Table profiles

      Index Name Data type

      * πŸ”‘ ⬋

      profileid

      uuid

      profile_details

      json

      *

      status

      varchar(10)

      *

      userid

      uuid

      * ⬈

      profile_formid

      bigint

      1. Foreign keys

        Type Name On

        fk_profiles_profile_forms_profile_formid

        profile_formid

      2. Constraints

        Name Definition

        profiles_status_check

        ((status)::text ~* ’^(active

    9. Table terms

      Index Name Data type

      * πŸ”‘

      id

      bigint GENERATED BY DEFAULT AS IDENTITY

      accrued_interest

      numeric

      amortization_date

      timestamp

      array_cycle_anchor_date_of_interest_payment

      varchar(255)

      array_cycle_anchor_date_of_principal_redemption

      varchar(255)

      array_cycle_anchor_date_of_rate_reset

      varchar(255)

      array_cycle_of_interest_payment

      varchar(255)

      array_cycle_of_principal_redemption

      varchar(255)

      array_cycle_of_rate_reset

      varchar(255)

      array_fixed_variable

      varchar(255)

      array_increase_decrease

      varchar(255)

      array_next_principal_redemption_payment

      varchar(255)

      array_rate

      varchar(255)

      business_day_convention

      varchar(5)

      calendar

      varchar(2)

      capitalization_end_date

      timestamp

      contract_deal_date

      timestamp

      contractid

      varchar(255)

      *

      contract_role

      varchar(6)

      contract_performance

      varchar(10)

      *

      contract_type

      varchar(15)

      *

      currency

      varchar(10)

      currency2

      varchar(10)

      cycle_anchor_date_of_dividend_payment

      timestamp

      cycle_anchor_date_of_fee

      timestamp

      cycle_anchor_date_of_interest_calculation_base

      timestamp

      cycle_anchor_date_of_interest_payment

      timestamp

      cycle_anchor_date_of_optionality

      timestamp

      cycle_anchor_date_of_principal_redemption

      timestamp

      cycle_anchor_date_of_rate_reset

      timestamp

      cycle_anchor_date_of_scaling_index

      timestamp

      cycle_of_dividend_payment

      varchar(10)

      cycle_of_fee

      varchar(10)

      cycle_of_interest_calculation_base

      varchar(10)

      cycle_of_interest_payment

      varchar(10)

      cycle_of_optionality

      varchar(10)

      cycle_of_principal_redemption

      varchar(10)

      cycle_of_rate_reset

      varchar(10)

      cycle_of_scaling_index

      varchar(10)

      cycle_point_of_interest_payment

      varchar(1)

      cycle_point_of_rate_reset

      varchar(1)

      *

      day_count_convention

      varchar(10)

      delivery_settlement

      varchar(1)

      end_of_month_convention

      varchar(5)

      fee_accrued

      numeric

      fee_basis

      varchar(1)

      fee_rate

      numeric

      fixing_period

      varchar(255)

      initial_exchange_date

      timestamp

      interest_calculation_base

      varchar(10)

      interest_calculation_base_amount

      numeric

      life_cap

      numeric

      life_floor

      numeric

      market_object_code

      varchar(255)

      market_object_code_of_dividend_rate

      varchar(255)

      market_object_code_of_rate_reset

      varchar(255)

      market_object_code_of_scaling_index

      varchar(255)

      market_value_observed

      numeric

      maturity_date

      timestamp

      maximum_penalty_free_disbursement

      varchar(255)

      next_principal_redemption_payment

      numeric

      next_reset_rate

      numeric

      nominal_interest_rate

      numeric

      nominal_interest_rate2

      numeric

      notional_principal

      numeric

      notional_principal2

      numeric

      object_code_of_prepayment_model

      varchar(255)

      penalty_rate

      numeric

      penalty_type

      varchar(1)

      period_cap

      numeric

      period_floor

      numeric

      premium_discount_atied

      numeric

      price_at_purchase_date

      numeric

      price_at_termination_date

      numeric

      purchase_date

      timestamp

      quantity

      numeric

      rate_spread

      numeric

      rounding_convention

      varchar(255)

      scaling_effect

      varchar(5)

      scaling_index_at_contract_deal_date

      numeric

      settlement_period

      varchar(255)

      status_date

      timestamp

      x_day_notice

      varchar(255)

      termination_date

      timestamp

      delinquency_period

      varchar(255)

      grace_period

      varchar(255)

      market_object_code_of_dividends

      varchar(255)

      rate_multiplier

      numeric

      * ⬈

      contract_uuid

      uuid

      ⬈

      counterparty_id

      uuid

      * πŸ”Ž

      creator_id

      uuid

      1. Foreign keys

        Type Name On

        terms_contractuuid_fk

        contract_uuid

        terms_counterparty_id_fk

        counterparty_id

      2. Constraints

        Name Definition

        terms_business_day_convention_check

        ((business_day_convention)::text ~* ’^(NOS

        terms_calendar_check

        ((calendar)::text ~* ’^(NC

        terms_fee_basis_check

        ((fee_basis)::text ~* ’^(A

        terms_delivery_settlement_check

        ((delivery_settlement)::text ~* ’^(D

        terms_cycle_of_dividend_payment_check

        cycle_of_dividend_payment)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_cycle_of_interest_calculation_base_check

        cycle_of_interest_calculation_base)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_cycle_of_interest_payment_check

        cycle_of_interest_payment)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_cycle_of_principal_redemption_check

        cycle_of_principal_redemption)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_cycle_of_rate_reset_check

        cycle_of_rate_reset)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_cycle_of_scaling_index_check

        cycle_of_scaling_index)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_cycle_point_of_interest_payment_check

        ((cycle_point_of_interest_payment)::text ~* ’^(B

        terms_contract_performance_check

        ((contract_performance)::text ~* ’^(PF

        terms_penalty_type_check

        ((penalty_type)::text ~* ’^(N

    10. Table terms_history

      Index Name Data type

      * πŸ”‘

      id

      bigint GENERATED BY DEFAULT AS IDENTITY

      accrued_interest

      numeric

      amortization_date

      timestamp

      array_cycle_anchor_date_of_interest_payment

      varchar(255)

      array_cycle_anchor_date_of_principal_redemption

      varchar(255)

      array_cycle_anchor_date_of_rate_reset

      varchar(255)

      array_cycle_of_interest_payment

      varchar(255)

      array_cycle_of_principal_redemption

      varchar(255)

      array_cycle_of_rate_reset

      varchar(255)

      array_fixed_variable

      varchar(255)

      array_increase_decrease

      varchar(255)

      array_next_principal_redemption_payment

      varchar(255)

      array_rate

      varchar(255)

      business_day_convention

      varchar(5)

      calendar

      varchar(2)

      capitalization_end_date

      timestamp

      contract_deal_date

      timestamp

      contractid

      varchar(255)

      *

      contract_role

      varchar(6)

      contract_performance

      varchar(10)

      *

      contract_type

      varchar(15)

      *

      currency

      varchar(10)

      currency2

      varchar(10)

      cycle_anchor_date_of_dividend_payment

      timestamp

      cycle_anchor_date_of_fee

      timestamp

      cycle_anchor_date_of_interest_calculation_base

      timestamp

      cycle_anchor_date_of_interest_payment

      timestamp

      cycle_anchor_date_of_optionality

      timestamp

      cycle_anchor_date_of_principal_redemption

      timestamp

      cycle_anchor_date_of_rate_reset

      timestamp

      cycle_anchor_date_of_scaling_index

      timestamp

      cycle_of_dividend_payment

      varchar(10)

      cycle_of_fee

      varchar(10)

      cycle_of_interest_calculation_base

      varchar(10)

      cycle_of_interest_payment

      varchar(10)

      cycle_of_optionality

      varchar(10)

      cycle_of_principal_redemption

      varchar(10)

      cycle_of_rate_reset

      varchar(10)

      cycle_of_scaling_index

      varchar(10)

      cycle_point_of_interest_payment

      varchar(1)

      cycle_point_of_rate_reset

      varchar(1)

      *

      day_count_convention

      varchar(10)

      delivery_settlement

      varchar(1)

      end_of_month_convention

      varchar(5)

      fee_accrued

      numeric

      fee_basis

      varchar(1)

      fee_rate

      numeric

      fixing_period

      varchar(255)

      initial_exchange_date

      timestamp

      interest_calculation_base

      varchar(10)

      interest_calculation_base_amount

      numeric

      life_cap

      numeric

      life_floor

      numeric

      market_object_code

      varchar(255)

      market_object_code_of_dividend_rate

      varchar(255)

      market_object_code_of_rate_reset

      varchar(255)

      market_object_code_of_scaling_index

      varchar(255)

      market_value_observed

      numeric

      maturity_date

      timestamp

      maximum_penalty_free_disbursement

      varchar(255)

      next_principal_redemption_payment

      numeric

      next_reset_rate

      numeric

      nominal_interest_rate

      numeric

      nominal_interest_rate2

      numeric

      notional_principal

      numeric

      notional_principal2

      numeric

      object_code_of_prepayment_model

      varchar(255)

      penalty_rate

      numeric

      penalty_type

      varchar(1)

      period_cap

      numeric

      period_floor

      numeric

      premium_discount_atied

      numeric

      price_at_purchase_date

      numeric

      price_at_termination_date

      numeric

      purchase_date

      timestamp

      quantity

      numeric

      rate_spread

      numeric

      rounding_convention

      varchar(255)

      scaling_effect

      varchar(5)

      scaling_index_at_contract_deal_date

      numeric

      settlement_period

      varchar(255)

      x_day_notice

      varchar(255)

      termination_date

      timestamp

      delinquency_period

      varchar(255)

      grace_period

      varchar(255)

      market_object_code_of_dividends

      varchar(255)

      rate_multiplier

      numeric

      *

      creator_id

      uuid

      ⬈

      contractuuid

      uuid

      ⬈

      status_date

      timestamp

      1. Foreign keys

        Type Name On

        fk-contracts_history-terms_history

        contractuuid, status_date

      2. Constraints

        Name Definition

        terms_history_business_day_convention_check

        ((business_day_convention)::text ~* ’^(NOS

        terms_history_calendar_check

        ((calendar)::text ~* ’^(NC

        terms_history_fee_basis_check

        ((fee_basis)::text ~* ’^(A

        terms_history_delivery_settlement_check

        ((delivery_settlement)::text ~* ’^(D

        terms_history_cycle_of_dividend_payment_check

        cycle_of_dividend_payment)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_history_cycle_of_interest_calculation_base_check

        cycle_of_interest_calculation_base)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_history_cycle_of_interest_payment_check

        cycle_of_interest_payment)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_history_cycle_of_principal_redemption_check

        cycle_of_principal_redemption)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_history_cycle_of_rate_reset_check

        cycle_of_rate_reset)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_history_cycle_of_scaling_index_check

        cycle_of_scaling_index)::text ~ `(([-]?)P(?:([-]?)Y)?(?:([-]?)M)?(?:([-]?)W)?(?:([-]?[0-9]+)D)?L(?:([0-1]?)'::text)

        terms_history_cycle_point_of_interest_payment_check

        ((cycle_point_of_interest_payment)::text ~* ’^(B

        terms_history_contract_performance_check

        ((contract_performance)::text ~* ’^(PF

        terms_history_penalty_type_check

        ((penalty_type)::text ~* ’^(N

    11. Table transactions

      Index Name Data type

      * πŸ”‘

      transactionid

      uuid

      additional_information

      json

      *

      user_id

      uuid

      *

      credit_payment_channel_id

      uuid

      *

      debit_payment_channel_id

      uuid

      *

      process_time

      timestamp

      *

      value

      numeric

      *

      system_time

      timestamp

      *

      status

      varchar(15)

      *

      units

      varchar(10)

      * πŸ”‘ ⬈

      eventid

      uuid

      1. Foreign keys

      Type Name On

      fk_transactions_business_events_eventid

      eventid

    (πŸ”‘) - Primary key

    (*) - Mandatory

    (⬈) - Foreign key

    (πŸ”Ž) - Constraint

3. Dependencies and libraries

3.1. Dependencies

Description

The following dependencies are used in the project to provide various functionalities and features:

  1. spring-kafka

    • Purpose: Spring for Apache Kafka for building Kafka-based messaging systems.

    • Usage: Producing and consuming messages from Kafka topics.

  2. spring-cloud-starter-openfeign

    • Purpose: The spring-cloud-starter-openfeign dependency is used in Spring Boot applications to simplify the process of creating REST clients. It integrates the Feign client library into your application, providing a declarative way to define RESTful service clients.

    • Usage: Use spring-cloud-starter-openfeign to define interfaces for RESTful services and easily make HTTP requests to those services. Feign handles the creation of the HTTP request and mapping of the response to Java objects, reducing the boilerplate code typically required for REST client implementations.

  3. spring-cloud-starter-loadbalancer

    • Purpose: The spring-cloud-starter-loadbalancer dependency is used in Spring Boot applications to provide client-side load balancing. It integrates with Spring Cloud’s load balancing features, allowing applications to distribute traffic across multiple instances of a service.

    • Usage: Use spring-cloud-starter-loadbalancer to enable client-side load balancing in your application. It provides a simple API for making requests to services registered with a service registry (e.g., Eureka), automatically handling the load balancing logic. This helps improve the availability and scalability of your application by distributing traffic evenly across service instances.

  4. modelmapper (version 0.7.5)

    • Purpose: The modelmapper dependency simplifies the process of mapping objects between different data models by automatically determining how properties should be mapped from one object to another.

    • Usage: Use modelmapper to streamline the mapping process between DTOs (Data Transfer Objects), entities, and other data models, reducing the need for manual mapping code and improving code maintainability.

  5. BlockCypher (version 2.0)

    • Purpose: Provides access to BlockCypher APIs for blockchain integration.

    • Usage: Requires a Blockcypher API token. Use the library to make API calls for tasks like:

      • Accessing blockchain data (transactions, blocks)

      • Managing wallets and addresses (create, send/receive bitcoins)

  6. iban4j (version 3.2.1)

    • Purpose: Provides utilities for working with International Bank Account Numbers (IBANs).

    • Usage: The iban4j library allows you to:

      • Validate IBANs: Verify if a string is a valid IBAN.

      • (Optional) Generate IBANs: Create a valid IBAN (less common).

      • Extract information from IBANs: Parse an IBAN to retrieve details like country code, bank code, and account number.

  • Dependency versions are specified to ensure compatibility and stability.

  • Additional dependencies may be added or removed based on project requirements and architecture.

3.2. Libraries

Description

The following libraries are used in the project to provide various functionalities and features:

  1. actus-core (version 1.0.1)

    • Purpose: The actus-core library provides core functionality and utilities for working with financial contracts and cash flow projections based on the ACTUS standard.

    • Usage: Use to perform calculations, projections, and analysis of financial contracts and cash flows according to the ACTUS (Algorithmic Contract Types Unified Standards) standard.

  • Library versions are specified to ensure compatibility and stability.

  • Additional libraries may be added or removed based on project requirements and architecture.

4. Exception handling

Description

The RestExceptionHandler class is responsible for handling various exceptions that may occur during the execution of RESTful API endpoints. It provides centralized exception handling to ensure consistent error responses across the application.

Exception handlers

Example usage

@ControllerAdvice
public class RestExceptionHandler {

	@ExceptionHandler({ TransactionException.class, IllegalArgumentException.class, TransactionSystemException.class,
			HttpMessageNotReadableException.class })
	public ResponseEntity<Response<String>> exceptionToDoHandler(Exception ex) { (1)
		final Response<String> error = new Response<>();
		error.setStatus(HttpStatus.BAD_REQUEST.value());
		error.setMessage(ex.getMessage());
		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

	@ExceptionHandler(MethodArgumentNotValidException.class)
	public ResponseEntity<Response<List<String>>> handleValidationException(MethodArgumentNotValidException ex) { (2)
		BindingResult bindingResult = ex.getBindingResult();
		List<FieldError> fieldErrors = bindingResult.getFieldErrors();

		List<String> errorMessages = fieldErrors.stream()
				.map(fieldError -> String.format("%s: %s", fieldError.getField(), fieldError.getDefaultMessage()))
				.toList();

		Response<List<String>> error = new Response<>();
		error.setStatus(HttpStatus.BAD_REQUEST.value());
		error.setMessage("Validation failed due to provided invalid data");
		error.setData(errorMessages);

		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

	@ExceptionHandler(value = { AccessDeniedException.class })
	public ResponseEntity<Response<String>> accessDeniedExceptionHandler(Exception ex) { (3)
		final Response<String> error = new Response<>();
		error.setStatus(HttpStatus.UNAUTHORIZED.value());
		error.setMessage("Access Denied...");
		return new ResponseEntity<>(error, HttpStatus.UNAUTHORIZED);
	}

	@ExceptionHandler(Exception.class)
	public ResponseEntity<ErrorResponse> exceptionHandler(Exception ex) { (4)
		final ErrorResponse error = new ErrorResponse();
		error.setErrorCode(HttpStatus.BAD_REQUEST.value());
		error.setMessage("The request could not be understood by the server due to malformed syntax.");
		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

	@ExceptionHandler(ConstraintViolationException.class)
	public ResponseEntity<Response<List<String>>> handleConstraintViolationException(
			ConstraintViolationException exception) { (5)
		List<String> errorMessages = new ArrayList<>();

		for (ConstraintViolation<?> violation : exception.getConstraintViolations()) {
			String propertyPath = extractPropertyPath(violation.getPropertyPath().toString());
			errorMessages.add(String.format("[%s]: %s", propertyPath, violation.getMessage()));
		}

		Response<List<String>> error = new Response<>();
		error.setStatus(HttpStatus.BAD_REQUEST.value());
		error.setMessage("Validation failed due to provided invalid data");
		error.setData(errorMessages);

		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

}
1 ExceptionToDo handler
  • Handles exceptions of type TransactionException, IllegalArgumentException, HttpMessageNotReadableException and TransactionSystemException.

  • Returns a ResponseEntity with a status code of 400 Bad Request and an error message derived from the exception’s message.

2 handleValidationException handler
  • Handles exceptions of type MethodArgumentNotValidException, typically thrown when the validation fails for method arguments.

  • Returns a ResponseEntity with a status code of 400 Bad Request and a generic "Validation failed due to provided invalid data" message.

3 AccessDeniedException handler
  • Handles exceptions of type AccessDeniedException, typically thrown when a user lacks the necessary permissions to access a resource.

  • Returns a ResponseEntity with a status code of 401 Unauthorized and a generic "Access Denied" message.

4 Generic exception handler
  • Handles any other uncaught exceptions that may occur during the execution of API endpoints.

  • Returns a ResponseEntity with a status code of 400 Bad Request and a generic error message indicating malformed syntax.

5 handleConstraintViolationException handler
  • Handles exceptions of type ConstraintViolationException, typically thrown when the validation fails for constraints.

  • Returns a ResponseEntity with a status code of 400 Bad Request and a generic error message indicating invalid data.

Customization

  • Additional exception handlers can be added to address specific use cases or domain-specific exceptions.

  • Error messages and status codes can be customized based on application requirements and error scenarios.

5. Controllers

5.1. TransactionServiceController

6. TransactionServiceController

6.1. Transfer

6.1.1. Sequential flow

transfer.puml

Transfer process

This process includes transfer of funds from one account to another based on the provided TransferDto. Here below are process steps -

Data validation

  1. The system checks if the transfer data is valid.

  2. It ensures that the transfer amount is greater than zero.

  3. It verifies the existence of sender and receiver contracts and payment channels.

Transfer process

  1. If data is valid, the system proceeds with the transfer process.

  2. It saves transaction details, initializes business events, and updates contract balances.

  3. Finally, it logs the transfer completion.

If the transfer data is invalid or any step fails, appropriate error messages are returned.

6.1.2. Endpoint

Description

This endpoint allows users with the appropriate permissions to transfer funds based on the provided data.

URL

/transfer

Method

POST

Request body

The request body should contain a JSON object. The structure of each object should adhere to the TransferDto format.

Example request body

{
    "value" : 1000,
    "contractUUID" : "a1933b07-a12c-4666-9669-8a1bda511086",
    "receiver" : "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144"
}

Responses

  • 200 OK: Transaction success. Returns a JSON response containing details of the transaction.

Example response body

{
    "status": 200,
    "message": "Transaction success",
    "data": "e9f0e281-ed53-43e4-a8a2-bc191d5e5aa5"
}
  • 400 bad request: If the request body is not in the correct format or if there are validation errors.

  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to transfer.

  • 5xx server error: If there is a server-side error while processing the request.

Example

{
  "status": 400,
  "message": "Invalid sender contactUUID",
  "data": null
}

6.1.3. Methods

Description

This method is responsible for validating a transfer request, updating the notional principal of credit and debit contracts, and saving the transaction details in the system.

Signature

public Response<UUID> transfer(TransferDto transferDto) throws URISyntaxException

Parameters

  • TransferDto (Type: TransferDto): The transfer request data containing information about the contract UUID, receiver, and transfer amount.

Returns

  • Response<UUID>: A response object indicating the success of the transfer operation. It contains the HTTP status code, a message indicating the success of the transaction, and the unique identifier of the transfer event.

Example usage

public Response<UUID> transfer(TransferDto transferDto) throws URISyntaxException {
		log.info("userID : {}, request : {}", usersHelper.getUserID(), transferDto);

		// Transfer data validation
		TransactionDetailsDto transfer = validator.validateEvent(transferDto); (1)

		// Initializing event to process transfer
		BusinessEvents event = transferHelper.initializeEvent(transfer); (2)

		// Updating creditPaymentChannel
		contractUpdateWorker.updateNotionalPrincipal(transfer.getCreditContract(), transfer.getValue(),
				event.getEventTime()); (3)

		// Updating debitPaymentChannel
		BigDecimal debitValue = transfer.getValue().multiply(BigDecimal.valueOf(-1.0));
		contractUpdateWorker.updateNotionalPrincipal(transfer.getDebitContract(), debitValue, event.getEventTime()); (4)

		// Saving transaction
		BusinessEvents transferEvent = transactionWorker.saveTransaction(event, transfer); (5)

		return new Response<>(HttpStatus.OK.value(), Messages.TRANSACTION_SUCCESS, transferEvent.getEventID()); (6)
	}
Internal workflow
1 Validates the transfer request data using the validator.validateEvent() method.
2 The method initializes an event to process the transfer using the transferHelper.initializeEvent() method.
3 It updates the notional principal of the credit payment channel by calling contractUpdateWorker.updateNotionalPrincipal() with the credit contract details, transfer value, and event time.
4 It updates the notional principal of the debit payment channel by calling contractUpdateWorker.updateNotionalPrincipal() with the debit contract details, negative transfer value, and event time.
5 The method saves the transaction details using the transactionWorker.saveTransaction() method.
6 Finally, it returns a response object with HTTP status code 200 (OK), a success message, and the unique identifier of the transfer event.

Exceptions

  • URISyntaxException is thrown by this method when parsing a malformed Uniform Resource Identifier (URI) string. However, exceptions may occur within the validator or worker methods, which are handled internally.

6.1.4. Model classes

Description

The TransferDto class represents a data transfer object used for transferring funds between contracts.

Attributes
  1. value

    • Type: BigDecimal

    • Description: Represents the amount of funds to be transferred.

    • Constraints: Not null.

    • Example: 1000

  2. contractUUID

    • Type: UUID

    • Description: Represents the UUID of the contract initiating the transfer.

    • Constraints: Not null.

    • Example: a1933b07-a12c-4666-9669-8a1bda511086

  3. receiver

    • Type: UUID

    • Description: Represents the UUID of the receiving contract.

    • Constraints: Not null.

    • Example: 2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144

Example usage

TransferDto transfer = new TransferDto();
transfer.setValue(new BigDecimal("100.00"));
transfer.setContractUUID(UUID.randomUUID());
transfer.setReceiver(UUID.randomUUID());

6.1.5. Validation

Description

The validateEvent method is responsible for validating transfer input data, including currency, balance, and contract details. It ensures that the provided transfer information is valid and meets the necessary criteria for processing the transaction.

Parameters

  • transferDto: Contains contractUUID, transaction value, and other relevant information necessary for performing the transfer.

Returns

  • TransactionDetailsDto: Contains transaction details required for processing the transfer.

Example usage

public TransactionDetailsDto validateEvent(TransferDto transferDto) {
		TransactionDetailsDto transfer = new TransactionDetailsDto();

		// Transfer amount validation
		Assert.isTrue(transferDto.getValue().doubleValue() > 0, Messages.INVALID_AMOUNT);
		transfer.setValue(transferDto.getValue()); (1)

		// Sender details validation
		this.validateSender(transferDto, transfer); (2)

		// Receiver details validation
		this.validateReceiver(transferDto, transfer); (3)

		// Sender and receiver accounts currency validation
		Assert.isTrue(validateCurrency(transfer.getDebitPaymentChannel(), transfer.getCreditPaymentChannel()),
				Messages.INVALID_CURRENCY); (4)
		transfer.setUnits(String.valueOf(transfer.getDebitPaymentChannel().getDetails().get(Constants.UNITS)));

		// Sender account balance validation
		Assert.isTrue(validateBalance(transfer.getDebitContract(), transfer.getValue()), Messages.INSUFFICIENT_BALANCE); (5)

		return transfer;
	}
Validation steps
1 Transfer amount validation
  • Validates that the transfer amount is greater than zero.

  • If the transfer amount is invalid, an assertion error with the message "INVALID_AMOUNT" is thrown.

2 Sender details validation
  • Validates the sender’s details, ensuring they meet the necessary criteria.

  • Details such as contract existence, balance, and currency are verified.

3 Receiver details validation
  • Validates the receiver’s details, ensuring they meet the necessary criteria.

  • Similar to sender validation, contract existence and other relevant details are verified.

4 Currency validation
  • Validates the currency of both the sender and receiver accounts.

  • Ensures that the currency of the sender’s account matches the currency of the receiver’s account.

  • If the currencies do not match, an assertion error with the message "INVALID_CURRENCY" is thrown.

5 Sender account balance validation
  • Validates that the sender’s account has sufficient balance to perform the transfer.

  • If the sender’s account balance is insufficient, an assertion error with the message "INSUFFICIENT_BALANCE" is thrown.

6.1.6. Testing

Description

This section provides an overview of the testing strategy and objectives for the transfer method.

Test methods

Example usage

@Test
	void transferTest() throws URISyntaxException { (1)
		TransferDto transferDto = new TransferDto();
		BigDecimal value = new BigDecimal("100");
		transferDto.setContractUUID(debitContract.getContractUUID());
		transferDto.setReceiver(creditPaymentChannel.getPaymentChannelID());
		transferDto.setValue(value);

		Response transferResponse = transferServiceImpl.transfer(transferDto);
		assertEquals(Messages.TRANSACTION_SUCCESS, transferResponse.getMessage());

		Contracts creditContracts1 = contractRepo.findById(creditContract.getContractUUID()).get();
		BigDecimal creditNotionalPrincipal = creditContracts1.getContractTerms().get(0).getNotionalPrincipal();

		Contracts debitContract1 = contractRepo.findById(debitContract.getContractUUID()).get();
		BigDecimal debitNotionalPrincipal = debitContract1.getContractTerms().get(0).getNotionalPrincipal();

		assertEquals(new BigDecimal("600.0"), creditNotionalPrincipal);
		assertEquals(new BigDecimal("400.0"), debitNotionalPrincipal);

	}
1 transferTest()
  • Purpose : The purpose of this test is to verify the functionality of the transfer operation in the TransferServiceImpl class. It ensures that funds are transferred correctly between two contracts, updating their notional principals accordingly.

  • Test steps

    1. Create a TransferDto object and set its attributes including contract UUID, receiver, and value.

    2. Execute the transfer operation using the transfer method from TransferServiceImpl.

    3. Retrieve the updated state of the credit contract’s notional principal from the database.

    4. Retrieve the updated state of the debit contract’s notional principal from the database.

  • Assertions

    • Ensure that the transfer operation is successful by verifying that the message in the response is equal to Messages.TRANSACTION_SUCCESS.

    • Assert that the notional principal of the credit contract is updated correctly to 600.0 after the transfer.

    • Assert that the notional principal of the debit contract is updated correctly to 400.0 after the transfer.

6.2. Transaction

6.2.1. Sequential flow

transaction.puml

Transaction process

This process includes transactions of different event types based on the provided TransactionDto. Here below are process steps -

Data validation

  1. Incoming requests are handled at "/transaction" endpoint.

  2. Transaction data is validated using the @Valid annotation.

  3. Event IDs are retrieved from the transaction data.

  4. Each transaction is individually validated for correctness.

Transaction process

  1. Valid transactions proceed to the processing phase.

  2. Processing involves updating contract information and performing associated event processes.

  3. Transaction details are saved alongside the associated business event.

  4. Responses are generated based on transaction success or failure.

  5. Logs track transaction progress and error handling ensures proper response generation.

6.2.2. Endpoint

Description

This endpoint allows the processing of transactions for various event types across all contract types except UMP. Transactions include events such as IP, PR, FP, IED, and more.

URL

/transaction

Method

POST

Request body

The request body should contain a JSON array. The structure of each object should adhere to the TransactionDto format.

Example request body

[
    {
        "eventID": "4e3723af-ece4-4934-963b-bfbabb510212",
        "value": 3320.8481981622112,
        "processTime": "2023-01-01T00:00"
    }
]

Responses

  • 200 OK: Transaction success. Returns a response containing a list of transaction process responses.

Example response body

{
    "status": 200,
    "message": "Transactions processed successfully",
    "data": [
        {
            "eventID": "4e3723af-ece4-4934-963b-bfbabb510212",
            "valid": "TRUE",
            "details": "Transaction success"
        }
    ]
}
  • 400 bad request: If the request body is not in the correct format or if there are validation errors.

  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions for the transaction.

  • 5xx server error: If there is a server-side error while processing the request.

Example

{
  "status": 400,
  "message": "Invalid eventID",
  "data": null
}

Ensure that the request body is a JSON object containing a list of valid TransactionDto objects. The response body includes a list of TransactionResponseDto objects, providing details about the processed transactions and their validation status.

6.2.3. Methods

  1. Method: transaction

    Description

    This method processes transactions for all contract types except UMP. It receives a list of transaction data objects, executes the transactions, validates them, and returns a list of response objects indicating the status of each transaction.

    Signature

    public ResponseEntity<Response<List<TransactionResponseDto>>> transaction(
    			@Valid @RequestBody List<TransactionDto> transactionDtoList)

    Parameters

    • transactionDtoList (List of TransactionDto): A list containing information about the events to be processed.

      Returns

    • Responses with HTTP status codes indicating the success or failure of the transaction processing.

      Example usage

      public ResponseEntity<Response<List<TransactionResponseDto>>> transaction(
      			@Valid @RequestBody List<TransactionDto> transactionDtoList) {
      
      		// Execute the transactions
      		List<TransactionResponseDto> transactionResponseList = transactionsService
      				.executeTransaction(transactionDtoList); (1)
      
      		// Check if all transactions were valid
      		boolean allTransactionsValid = transactionResponseList.stream()
      				.allMatch(responseDto -> responseDto.getValid().equals(Constants.TRUE)); (2)
      
      		if (allTransactionsValid) {
      			// Return the responses with HTTP status OK
      			return new ResponseEntity<>(new Response<>(HttpStatus.OK.value(), "Transactions processed successfully",
      					transactionResponseList), HttpStatus.OK);
      		} else {
      			// Return the responses with HTTP status BAD_REQUEST
      			return new ResponseEntity<>(new Response<>(HttpStatus.BAD_REQUEST.value(),
      					"Validation failed due to provided invalid data", transactionResponseList), HttpStatus.BAD_REQUEST); (3)
      		}
      	}
      Internal workflow
      1 Executes transactions based on the provided transaction data.
      2 Checks if all transactions are valid.
      3 Returns responses with HTTP status codes indicating the success or failure of the transaction processing.
  2. Method: executeTransaction

    Description

    This method is responsible for executing transactions. It validates the input transaction data, processes valid transactions, and returns a list of response objects indicating the status of each transaction.

    Signature

    public List<TransactionResponseDto> executeTransaction(List<TransactionDto> transactionDtoList)

    Parameters

    • transactionDtoList (List of TransactionDto): The list of transaction data to be processed.

      Returns

    • List of TransactionResponseDto: A list of response objects indicating the status of each transaction.

      Example usage

      public List<TransactionResponseDto> executeTransaction(List<TransactionDto> transactionDtoList) {
      
      		// Retrieve eventIDs from input
      		List<UUID> eventIDList = transactionDtoList.stream().map(TransactionDto::getEventID).toList(); (1)
      
      		// Validate all transactions and accumulate responses
      		List<TransactionResponseDto> transactionResponseDtoList = transactionDtoList.stream()
      				.map(transactionData -> validator.validateTransactionData(transactionData, eventIDList)).toList(); (2)
      
      		// Process transactions only if all are valid
      		if (transactionResponseDtoList.stream()
      				.allMatch(responseDto -> responseDto.getValid().equals(Constants.TRUE))) { (3)
      			transactionResponseDtoList = transactionDtoList.stream().map(this::processTransaction).toList();
      		}
      		return transactionResponseDtoList; (4)
      
      	}
    Internal workflow
    1 Extracts event IDs from the input transaction data.
    2 Validates each transaction data object and accumulates the validation responses.
    3 Processes transactions only if all are valid.
    4 Returns a list of response objects indicating the status of each transaction.

6.2.4. Model classes

  1. TransactionDto

    Description

    The TransactionDto class represents a data transfer object (DTO) for a transaction. It encapsulates information about a transaction including its event ID, value, and process time.

    Attributes
    1. eventID

      • Type: UUID

      • Description: Represents the unique identifier of the event associated with the transaction.

      • Constraints: Not null.

      • Example: 4e3723af-ece4-4934-963b-bfbabb510212

    2. value

      • Type: BigDecimal

      • Description: Represents the value of the transaction.

      • Constraints: Not null.

      • Example: 3320.8481981622112

    3. processTime

      • Type: LocalDateTime

      • Description: Represents the timestamp when the transaction was processed.

      • Constraints: Not null.

      • Example: 2023-01-01T00:00

        Example usage

      TransactionDto transaction = new TransactionDto();
      transaction.setEventID(UUID.randomUUID());
      transaction.setValue(new BigDecimal("100.00"));
      transaction.setProcessTime(LocalDateTime.now());
  2. TransactionResponseDto

    Description

    The TransactionResponseDto class represents a data transfer object (DTO) for a transaction response. It encapsulates information about the status of a transaction along with any additional details.

    Attributes
    1. eventID

      • Type: UUID

      • Description: Represents the unique identifier of the event associated with the transaction.

      • Constraints: Not null.

      • Example: 4e3723af-ece4-4934-963b-bfbabb510212

    2. valid

      • Type: String

      • Description: Indicates whether the transaction is valid or not.

      • Constraints: Can take values "TRUE" or "FALSE".

      • Example: TRUE

    3. details

      • Type: String

      • Description: Provides additional details about the transaction, such as error messages or processing notes.

      • Example: Transaction success

This class is typically used to communicate the outcome of a transaction processing operation, such as whether it was successful or encountered an error.

6.2.5. Validation

Description

The validateTransactionData method is responsible for validating transaction input data, including event ID, event status, and other related parameters. It performs a series of validation checks to ensure that the transaction can be processed successfully.

Parameters

  • transactionDto (TransactionDto): Contains information about the transaction, including event ID, transaction value, etc.

  • eventIDList (List<UUID>): A list of provided event IDs to perform the transaction.

Returns

  • TransactionResponseDto: Represents the result of the transaction validation process, including the validity status and any associated details.

Example usage

public TransactionResponseDto validateTransactionData(TransactionDto transactionDto, List<UUID> eventIDList) {
		BusinessEvents businessEvent = null;
		TransactionResponseDto eventData = new TransactionResponseDto();
		try {
			// EventID validation
			businessEvent = this.validateEventID(transactionDto.getEventID()); (1)

			// Event status validation
			businessEvent = this.validateEventStatus(businessEvent); (2)

			if (!businessEvent.getEventType().equalsIgnoreCase(Constants.OPS)) {
				// Non OPS events validation
				this.validateNonOPSEvents(businessEvent, transactionDto, eventIDList); (3)
			}
			eventData.setEventID(transactionDto.getEventID());
			eventData.setValid(Constants.TRUE);
			eventData.setDetails(Constants.VALID_EVENT); (4)

		} catch (Exception e) {
			e.printStackTrace();
			eventData.setEventID(transactionDto.getEventID());
			eventData.setValid(Constants.FALSE);
			eventData.setDetails(e.getMessage());
		}
		return eventData;

	}
Validation steps
1 EventID validation
  • Validates the event ID provided in the transactionDto.

2 Event status validation
  • Validates the status of the event retrieved based on the event ID.

3 Non-OPS events validation
  • Performs additional validation checks for non-OPS (non-operational) events if applicable.

4 Setting response data
  • Sets the event ID, validity status, and details in the TransactionResponseDto object based on the validation results.

Validate the structure and content of the TransactionDto object before passing it to this method to avoid unexpected behavior.

6.2.6. Testing

Description

This section provides an overview of the testing strategy and objectives for the transaction method.

Test methods

Example usage

@Test
	void testExecuteTransaction6() { (1)
		when(eventsRepo.findById(event.getEventID())).thenReturn(Optional.of(event));
		when(paymentRepo.findById(ArgumentMatchers.<UUID>any())).thenReturn(Optional.of(debitPaymentChannel));
		when(contractRepo.findById(ArgumentMatchers.<UUID>any())).thenReturn(Optional.of(debitContract));
		TransactionResponseDto trasactionResponse = new TransactionResponseDto();
		trasactionResponse.setDetails(Messages.TRANSACTION_SUCCESS);
		trasactionResponse.setValid("TRUE");
		terms.setInitialExchangeDate(LocalDateTime.parse("2023-06-21T23:59:59"));
		BigDecimal NotionalPrincipal = new BigDecimal("20000.0");
		BigDecimal RemainingValue = new BigDecimal("18000.0");
		terms.setNotionalPrincipal(NotionalPrincipal);
		event.setStatus("Pending");
		event.setEventType("IED");
		event.setRemainingValue(RemainingValue);
		TransactionDto transactionDto = new TransactionDto();
		BigDecimal Value = new BigDecimal("-2000");
		transactionDto.setEventID(event.getEventID());
		transactionDto.setProcessTime(LocalDateTime.parse("2023-06-22T23:59:59"));
		transactionDto.setValue(Value);
		ArrayList<TransactionDto> transactionDtoList = new ArrayList<>();
		transactionDtoList.add(transactionDto);

		List<TransactionResponseDto> executeTransaction = transferServiceImpl.executeTransaction(transactionDtoList);

		TransactionResponseDto response = executeTransaction.get(0);

		assertEquals("TRUE", response.getValid());
		assertEquals(Messages.TRANSACTION_SUCCESS, response.getDetails());

	}
1 testExecuteTransaction6()
  • Purpose : This test case aims to verify the correct execution of the executeTransaction method in the TransferServiceImpl class when processing a transaction for an event with a pending status.

  • Test steps

    1. Mock the repository methods (eventsRepo, paymentRepo, contractRepo) to simulate database interactions.

    2. Set up test data including event details, initial exchange date, notional principal, remaining value, transaction details, etc.

    3. Invoke the executeTransaction method with the prepared transaction DTO list.

    4. Extract the response from the list of transaction responses.

    5. Assert that the validity status of the transaction response is "TRUE".

    6. Assert that the details of the transaction response match the expected success message.

  • Assertions

    • The transaction response should indicate a valid transaction (valid = "TRUE").

    • The details of the transaction response should match the expected success message (details = "TRANSACTION_SUCCESS").

6.3. Get transactions

6.3.1. Sequential flow

get-transactions.puml

Get transactions process

This process includes retrieval of a list of transactions based on specified filters and pagination parameters. Here below are process steps -

Data validation

  1. Upon receiving a GET request to the /txs endpoint, the server validates the query parameters including filterDto, page, and size.

Get transactions process

  1. The server parses the query parameters and sets up pagination based on the provided page and size.

  2. It generates a JPA specification from the TransactionFilterDto to filter transactions.

  3. The server executes a database query using the generated specification and pagination settings.

  4. Retrieved transactions are sent back to the client as a response.

6.3.2. Endpoint

Description

This endpoint allows developers to fetch transactions based on specified filters and pagination parameters.

URL

/txs

Method

GET

Request filter parameters

Parameters

Type

Required

Description

TransactionFilterDto

JSON object

Yes

Filter parameters for fetching transactions.

page

Integer

No

Page number for pagination. Default value is 0.

size

Integer

No

Number of transactions per page. Default value is 10.

Responses

  • 200 OK: Success. Returns a list of transactions matching the specified filters.

Example response body

{
    "status": 200,
    "message": "Success",
    "data": [
        {
            "transactionID": "78fe0787-7dd2-44b3-bc13-d67254218848",
            "eventID": "2858d468-d51c-482d-bc0a-a291438045d4",
            "processTime": "2023-01-01T00:00:00",
            "systemTime": "2024-02-19T16:57:39",
            "debitPaymentChannelID": "13c3861e-bcc6-48ed-9db1-91cb6825328a",
            "creditPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "value": 50000,
            "units": "INR",
            "status": "processed",
            "additionalInformation": null,
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
        },
        {
            "transactionID": "18d57dd4-5898-40af-aa06-52eb7cd28ebb",
            "eventID": "f771b128-c948-4dea-8359-6a43e1f4ef3f",
            "processTime": "2023-01-01T00:00:00",
            "systemTime": "2024-02-20T12:01:03",
            "debitPaymentChannelID": "13c3861e-bcc6-48ed-9db1-91cb6825328a",
            "creditPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "value": 50000,
            "units": "INR",
            "status": "processed",
            "additionalInformation": null,
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
        },
        {
            "transactionID": "b0936731-9b0f-4236-8c52-465490d1f6fa",
            "eventID": "61f04124-6a7c-4471-9ea5-70b82dafe225",
            "processTime": "2023-01-01T00:00:00",
            "systemTime": "2024-02-20T12:13:51",
            "debitPaymentChannelID": "13c3861e-bcc6-48ed-9db1-91cb6825328a",
            "creditPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "value": 50000,
            "units": "INR",
            "status": "processed",
            "additionalInformation": null,
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
        },
        {
            "transactionID": "df5bfea5-2e79-475d-96f3-1f98c05286d2",
            "eventID": "bc17d4d1-18f1-464c-8e2a-af9bfa4752be",
            "processTime": "2023-01-01T00:00:00",
            "systemTime": "2024-02-20T13:11:28",
            "debitPaymentChannelID": "13c3861e-bcc6-48ed-9db1-91cb6825328a",
            "creditPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "value": 50000,
            "units": "INR",
            "status": "processed",
            "additionalInformation": null,
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
        },
        {
            "transactionID": "c7d78a3d-9a4a-49d8-919e-459db44f5686",
            "eventID": "d20d11ba-eaeb-4e4c-a89f-8a16ab48f019",
            "processTime": "2023-01-01T00:00:00",
            "systemTime": "2024-02-20T14:58:51",
            "debitPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "creditPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "value": 50000,
            "units": "INR",
            "status": "processed",
            "additionalInformation": null,
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
        },
        {
            "transactionID": "c7c7e576-68a1-46c9-b8d0-55af6e02016e",
            "eventID": "b06f7336-6a2c-42f5-a64e-5358085a7688",
            "processTime": "2023-01-01T00:00:00",
            "systemTime": "2024-02-20T15:00:42",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "value": 2500,
            "units": "INR",
            "status": "processed",
            "additionalInformation": null,
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
        },
        {
            "transactionID": "3c00ed45-3131-4f2e-9351-3a8f0d3508dd",
            "eventID": "b508767f-055c-46f6-a0c4-5ead61aed2b1",
            "processTime": "2023-01-01T00:00:00",
            "systemTime": "2024-02-20T15:01:54",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "value": 3000,
            "units": "INR",
            "status": "processed",
            "additionalInformation": null,
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
        },
        {
            "transactionID": "43eb5e8d-6d66-44e6-be25-c089ed9ed8bb",
            "eventID": "b508767f-055c-46f6-a0c4-5ead61aed2b1",
            "processTime": "2023-01-01T00:00:00",
            "systemTime": "2024-02-20T15:02:35",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "value": 3000,
            "units": "INR",
            "status": "processed",
            "additionalInformation": null,
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
        },
        {
            "transactionID": "7e96e7d6-2b18-4c9c-ba28-4a9ed8f12d10",
            "eventID": "45409163-2c2f-4c06-91a1-5b08c5a05c18",
            "processTime": "2023-01-01T00:00:00",
            "systemTime": "2024-02-20T15:31:02",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "value": 5000,
            "units": "INR",
            "status": "processed",
            "additionalInformation": null,
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
        },
        {
            "transactionID": "6b453065-d29d-4046-ba65-7caea90dac91",
            "eventID": "af4206fb-3cd9-40a9-b654-74fcfa6d118f",
            "processTime": "2023-01-01T00:00:00",
            "systemTime": "2024-02-20T15:35:45",
            "debitPaymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
            "creditPaymentChannelID": "2ae5b30b-3fba-4f4b-a45f-c1d0c03b4144",
            "value": 2000,
            "units": "INR",
            "status": "processed",
            "additionalInformation": null,
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
        }
    ]
}
  • 400 bad request: If the request body is not in the correct format or if there are validation errors.

  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions for retrieving the transactions.

  • 5xx server error: If there is a server-side error while processing the request.

6.3.3. Methods

Description

This method fetches transactions based on filters provided in the TransactionFilterDto object.

Parameters

  • filterDto (Type: TransactionFilterDto, Source: Query Parameter): Filter parameters for fetching transactions. The filter criteria are specified in the TransactionFilterDto object.

  • page (Type: int, Source: Query Parameter, Default Value: 0): Page number for pagination.

  • size (Type: int, Source: Query Parameter, Default Value: 10): Number of transactions per page.

Returns

  • ResponseEntity<Response<List<Transactions>>>: Returns a response entity containing a list of transactions matching the specified filters.

Example usage

public ResponseEntity<Response<List<Transactions>>> getTransactions(
			@Valid @ParameterObject TransactionFilterDto filterDto,
			@RequestParam(name = "page", defaultValue = "0") int page,
			@RequestParam(name = "size", defaultValue = "10") int size) {

		// Create Pageable object
		Pageable pageable = PageRequest.of(page, size); (1)

		// Get transactions based on the provided filters and pagination
		List<Transactions> finalTransactionList = transactionsService.getTransactions(filterDto, pageable); (2)

		// Return the transactions with HTTP status OK
		return new ResponseEntity<>(new Response<>(HttpStatus.OK.value(), Messages.SUCCESS, finalTransactionList),
				HttpStatus.OK); (3)
	}
Internal workflow
1 Pagination is applied to the list of transactions to improve performance and manage large data sets efficiently.
2 The method uses the provided filter parameters and pagination settings to retrieve transactions from the transactionsService.
3 Returns the list of transactions matching the specified filters.

Exceptions

  • None explicitly thrown by this method. However, ensure to handle any potential errors gracefully and provide informative error messages.

6.3.4. Model classes

Description

The TransactionFilterDto class represents a data transfer object (DTO) used for filtering transactions based on various criteria.

Attributes
  1. transactionId

    • Type: UUID

    • Description: Represents the unique identifier of the transaction.

    • Example: 18d57dd4-5898-40af-aa06-52eb7cd28ebb

  2. userID

    • Type: UUID

    • Description: Represents the unique identifier of the user associated with the transaction.

    • Example: 902375cc-4f72-428f-8db0-95a7baa69b51

  3. eventID

    • Type: UUID

    • Description: Represents the unique identifier of the event associated with the transaction.

    • Example: f771b128-c948-4dea-8359-6a43e1f4ef3f

  4. processTime

    • Type: String

    • Description: Represents the timestamp indicating the processing time of the transaction.

    • Example: 2023-01-01T00:00:00

  5. debitPaymentChannelID

    • Type: UUID

    • Description:Represents the unique identifier of the debit payment channel used in the transaction.

    • Example: 13c3861e-bcc6-48ed-9db1-91cb6825328a

  6. creditPaymentChannelID

    • Type: UUID

    • Description: Represents the unique identifier of the credit payment channel used in the transaction.

    • Example: fb0fdb85-87ee-4af2-b39a-f3a23227203c

  7. status

    • Type: String

    • Description: Represents the status of the transaction.

    • Example: processed

Business events

1. Introduction

The events endpoints allows adding new and managing existing events.Cashflow from contract are represented as events.

2. Tables and relations

Establishing relationships:

  • In relational databases like PostgreSQL, relationships between tables are crucial for organizing and querying data effectively. These relationships are typically established using foreign key constraints, which define links between tables based on the values of specific columns. Common types of relationships include one-to-one, one-to-many, and many-to-many relationships, each serving different data modeling needs.

business events ERD
Figure 3. Events Entity-relationship diagram

Tables

  • Schema:

BussinessEvents

  1. Table business_events

    Idx Name Data Type

    * πŸ”‘ ⬋

    eventid

    uuid

    *

    event_time

    timestamp

    * πŸ”Ž

    event_type

    varchar(10)

    event_body

    json

    * πŸ”Ž

    status

    varchar(10)

    * πŸ”Ž

    execution_type

    varchar(20)

    contractid

    varchar(255)

    *

    userid

    uuid

    * πŸ”Ž ⬈

    contractuuid

    uuid

    value

    numeric

    remaining_value

    numeric

    credit_payment_channel_id

    uuid

    debit_payment_channel_id

    uuid

    units

    varchar(10)

    1. Indexes

      Type Name On

      πŸ”Ž

      idx_contractuuid_eventtype

      ON contractuuid, event_type

      πŸ”Ž

      idx_contractuuid_executiontype

      ON contractuuid, execution_type

      πŸ”Ž

      idx_contractuuid_status

      ON contractuuid, status

      πŸ”Ž

      idx_contractuuid_eventtype_status

      ON contractuuid, event_type, status

      πŸ”‘

      events_pkey

      ON eventid

    2. Foreign Keys

      Type Name On

      fk_business_events_contracts_contractuuid

      ( contractuuid ) ref public.contracts (contractuuid)

    3. Constraints

      Name Definition

      business_events_event_type_check

      event_type::text ~* ’^(AD/IED/FP/PR/PD/PRF/PY/PP/IP/IPCI/CE/RRF/RR/DV/PRD/MR/TD/SC/IPCB/MD/XD/STD/PI/IPFX/IPFL/ME/TP/OPS)$'::text

      business_events_status_check

      status::text ~* ’^(scheduled/pending/processed)$'::text

      business_events_execution_type_check

      execution_type::text ~* '^(contractUpdate/transaction)$'::text

  2. Table contracts

    Idx Name Data Type

    * πŸ”‘ ⬋

    contractuuid

    uuid

    ⬈

    productid

    bigint

    *

    createdby

    uuid

    executedby

    uuid

    *

    system_time

    timestamp

    selection

    json

    1. Indexes

      Type Name On

      πŸ”‘

      contracts_pkey

      ON contractuuid

      • Foreign Keys

      Type Name On

      contracts_product_fk

      ( productid ) ref public.products (productid)

  3. Table payment_channels

    Idx Name Data Type

    * πŸ”‘ ⬋

    payment_channelid

    uuid

    contractid

    uuid

    details

    json

    *

    identifier

    varchar(100)

    label

    varchar(100)

    *

    type

    varchar(50)

    * πŸ”Ž

    owner_type

    varchar(10)

    *

    units

    varchar(10)

    *

    system

    varchar(50)

    account_characteristic

    varchar(50)

    * πŸ”Ž

    ownerid

    uuid

    * πŸ”Ž

    userid

    uuid

    1. Indexes

      Type Name On

      πŸ”Ž

      payment_channels_idx_owner_type_owner_id

      ON owner_type, ownerid

      πŸ”‘

      payment_channels_pkey

      ON payment_channelid

      πŸ”Ž

      payment_channels_idx_payment_channel_id_owner_id

      ON payment_channelid, ownerid

      πŸ”Ž

      payment_channels_idx_owner_type_user_id

      ON owner_type, userid

    2. Constraints

      Name Definition

      payment_channels_owner_type_check

      owner_type::text ~* '^(root/profile)$'::text

  4. Table payment_details

    Idx Name Data Type

    * πŸ”‘

    id

    bigint GENERATED BY DEFAULT AS IDENTITY

    ⬈

    contract_uuid

    uuid

    ⬈

    record_creator_paymentchannel_id

    uuid

    ⬈

    counterparty_paymentchannel_id

    uuid

    ⬈

    contract_paymentchannel_id

    uuid

    1. Indexes

      Type Name On

      πŸ”‘

      payment_details_pkey

      ON id

    2. Foreign Keys

      Type Name On

      paymentdetails_contractuuid_fk

      ( contract_uuid ) ref public.contracts (contractuuid)

      paymentdetails_contract_payment_fk

      ( contract_paymentchannel_id ) ref public.payment_channels (payment_channelid)

      paymentdetails_counterparty_fk

      ( counterparty_paymentchannel_id ) ref public.payment_channels (payment_channelid)

      paymentdetails_record_creator_fk

      ( record_creator_paymentchannel_id ) ref public.payment_channels (payment_channelid)

  5. Table products

    Idx Name Data Type

    * πŸ”‘ ⬋

    productid

    bigint GENERATED BY DEFAULT AS IDENTITY

    *

    status

    varchar(10)

    *

    template

    json

    * πŸ”Ž

    userid

    uuid

    1. Indexes

      Type Name On

      πŸ”‘

      products_pkey

      ON productid

      πŸ”Ž

      products_idx_userid

      ON userid

    2. Constraints

      Name Definition

      products_status_check

      status::text ~* '^(active/inactive)$'::text

  6. Table profile_forms

    Idx Name Data Type

    * πŸ”‘ ⬋

    profile_formid

    bigint GENERATED BY DEFAULT AS IDENTITY

    *

    profile_form_details

    json

    *

    userid

    uuid

    1. Indexes

      Type Name On

      πŸ”‘

      profile_forms_pkey

      ON profile_formid

  7. Table profiles

    Idx Name Data Type

    * πŸ”‘ ⬋

    profileid

    uuid

    profile_details

    json

    *

    status

    varchar(10)

    *

    userid

    uuid

    * ⬈

    profile_formid

    bigint

    1. Indexes

      Type Name On

      πŸ”‘

      profiles_pkey

      ON profileid

    2. Foreign Keys

      Type Name On

      fk_profiles_profile_forms_profile_formid

      ( profile_formid ) ref public.profile_forms (profile_formid)

    3. Constraints

      Name Definition

      profiles_status_check

      status::text ~* '^(active/inactive)$'::text

  8. Table terms

    Idx Name Data Type

    * πŸ”‘

    id

    integer GENERATED BY DEFAULT AS IDENTITY

    accrued_interest

    numeric

    amortization_date

    timestamp

    array_cycle_anchor_date_of_interest_payment

    varchar(255)

    array_cycle_anchor_date_of_principal_redemption

    varchar(255)

    array_cycle_anchor_date_of_rate_reset

    varchar(255)

    array_cycle_of_interest_payment

    varchar(255)

    array_cycle_of_principal_redemption

    varchar(255)

    array_cycle_of_rate_reset

    varchar(255)

    array_fixed_variable

    varchar(255)

    array_increase_decrease

    varchar(255)

    array_next_principal_redemption_payment

    varchar(255)

    array_rate

    varchar(255)

    business_day_convention

    varchar(5)

    calendar

    varchar(2)

    capitalization_end_date

    timestamp

    contract_deal_date

    timestamp

    contractid

    varchar(255)

    *

    contract_role

    varchar(6)

    contract_performance

    varchar(10)

    *

    contract_type

    varchar(15)

    *

    currency

    varchar(10)

    currency2

    varchar(10)

    cycle_anchor_date_of_dividend_payment

    timestamp

    cycle_anchor_date_of_fee

    timestamp

    cycle_anchor_date_of_interest_calculation_base

    timestamp

    cycle_anchor_date_of_interest_payment

    timestamp

    cycle_anchor_date_of_optionality

    timestamp

    cycle_anchor_date_of_principal_redemption

    timestamp

    cycle_anchor_date_of_rate_reset

    timestamp

    cycle_anchor_date_of_scaling_index

    timestamp

    cycle_of_dividend_payment

    varchar(10)

    cycle_of_fee

    varchar(10)

    cycle_of_interest_calculation_base

    varchar(10)

    cycle_of_interest_payment

    varchar(10)

    cycle_of_optionality

    varchar(10)

    cycle_of_principal_redemption

    varchar(10)

    cycle_of_rate_reset

    varchar(10)

    cycle_of_scaling_index

    varchar(10)

    cycle_point_of_interest_payment

    varchar(1)

    cycle_point_of_rate_reset

    varchar(1)

    *

    day_count_convention

    varchar(10)

    delivery_settlement

    varchar(1)

    end_of_month_convention

    varchar(5)

    fee_accrued

    numeric

    fee_basis

    varchar(1)

    fee_rate

    numeric

    fixing_period

    varchar(255)

    initial_exchange_date

    timestamp

    interest_calculation_base

    varchar(10)

    interest_calculation_base_amount

    numeric

    life_cap

    numeric

    life_floor

    numeric

    market_object_code

    varchar(255)

    market_object_code_of_dividend_rate

    varchar(255)

    market_object_code_of_rate_reset

    varchar(255)

    market_object_code_of_scaling_index

    varchar(255)

    market_value_observed

    numeric

    maturity_date

    timestamp

    maximum_penalty_free_disbursement

    varchar(255)

    next_principal_redemption_payment

    numeric

    next_reset_rate

    numeric

    nominal_interest_rate

    numeric

    nominal_interest_rate2

    numeric

    notional_principal

    numeric

    notional_principal2

    numeric

    object_code_of_prepayment_model

    varchar(255)

    penalty_rate

    numeric

    penalty_type

    varchar(1)

    period_cap

    numeric

    period_floor

    numeric

    premium_discount_atied

    numeric

    price_at_purchase_date

    numeric

    price_at_termination_date

    numeric

    purchase_date

    timestamp

    quantity

    numeric

    rate_spread

    numeric

    rounding_convention

    varchar(255)

    scaling_effect

    varchar(5)

    scaling_index_at_contract_deal_date

    numeric

    settlement_period

    varchar(255)

    status_date

    timestamp

    x_day_notice

    varchar(255)

    termination_date

    timestamp

    delinquency_period

    varchar(255)

    grace_period

    varchar(255)

    market_object_code_of_dividends

    varchar(255)

    rate_multiplier

    numeric

    * ⬈

    contract_uuid

    uuid

    ⬈

    counterparty_id

    uuid

    * πŸ”Ž

    creator_id

    uuid

    1. Indexes

      Type Name On

      πŸ”‘

      terms_pkey

      ON id

      πŸ”Ž

      terms_idx_creator_id

      ON creator_id

    2. Foreign Keys

      Type Name On

      terms_contractuuid_fk

      ( contract_uuid ) ref public.contracts (contractuuid)

      terms_counterparty_id_fk

      ( counterparty_id ) ref public.profiles (profileid)

    3. Constraints

      Name Definition

      terms_business_day_convention_check

      business_day_convention::text ~* '^(NOS/SCF/SCMF/CSF/CSMF/SCP/SCMP/CSP/SCMP)$'::text

      terms_calendar_check

      calendar::text ~* '^(NC/MF)$'::text

      terms_fee_basis_check

      fee_basis::text ~* '^(A/N)$'::text

      terms_delivery_settlement_check

      delivery_settlement::text ~* '^(D/S)$'::text

      terms_cycle_of_dividend_payment_check

      cycle_of_dividend_payment)::text ~ ‘(([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?L(?:([0-1]?)’::text)

      terms_cycle_of_interest_calculation_base_check

      cycle_of_interest_calculation_base)::text ~ ‘(([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?L(?:([0-1]?)’::text)

      terms_cycle_of_interest_payment_check

      cycle_of_interest_payment)::text ~ ‘(([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?L(?:([0-1]?)’::text)

      terms_cycle_of_principal_redemption_check

      cycle_of_principal_redemption)::text ~ ‘(([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?L(?:([0-1]?)’::text)

      terms_cycle_of_rate_reset_check

      cycle_of_rate_reset)::text ~ ‘(([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?L(?:([0-1]?)’::text)

      terms_cycle_of_scaling_index_check

      cycle_of_scaling_index)::text ~ ‘(([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?L(?:([0-1]?)’::text)

      terms_cycle_point_of_interest_payment_check

      cycle_point_of_interest_payment::text ~* '^(B/E)$'::text

      terms_contract_performance_check

      contract_performance::text ~* '^(PF/DL/DQ/DF/MA/TE/PreDeal)$'::text

      terms_penalty_type_check

      penalty_type::text ~* '^(N/A/R/I)$'::text

3. Dependencies and libraries

3.1. Dependencies

Description

The following dependencies are used in the project to provide various functionalities and features:

  1. spring-kafka

    • Purpose: Spring for Apache Kafka for building Kafka-based messaging systems.

    • Usage: Producing and consuming messages from Kafka topics.

  2. spring-cloud-starter-openfeign

    • Purpose: The spring-cloud-starter-openfeign dependency is used in Spring Boot applications to simplify the process of creating REST clients. It integrates the Feign client library into your application, providing a declarative way to define RESTful service clients.

    • Usage: Use spring-cloud-starter-openfeign to define interfaces for RESTful services and easily make HTTP requests to those services. Feign handles the creation of the HTTP request and mapping of the response to Java objects, reducing the boilerplate code typically required for REST client implementations.

  3. spring-cloud-starter-loadbalancer

    • Purpose: The spring-cloud-starter-loadbalancer dependency is used in Spring Boot applications to provide client-side load balancing. It integrates with Spring Cloud’s load balancing features, allowing applications to distribute traffic across multiple instances of a service.

    • Usage: Use spring-cloud-starter-loadbalancer to enable client-side load balancing in your application. It provides a simple API for making requests to services registered with a service registry (e.g., Eureka), automatically handling the load balancing logic. This helps improve the availability and scalability of your application by distributing traffic evenly across service instances.

  • Dependency versions are specified to ensure compatibility and stability.

  • Additional dependencies may be added or removed based on project requirements and architecture.

3.2. Libraries

Description

The following libraries are used in the project to provide various functionalities and features:

  1. actus-core (version 1.0.1)

    • Purpose: The actus-core library provides core functionality and utilities for working with financial contracts and cash flow projections based on the ACTUS standard.

    • Usage: Use to perform calculations, projections, and analysis of financial contracts and cash flows according to the ACTUS (Algorithmic Contract Types Unified Standards) standard.

4. Exception handling

Description

The RestExceptionHandler class is responsible for handling various exceptions that may occur during the execution of RESTful API endpoints. It provides centralized exception handling to ensure consistent error responses across the application.

Exception handlers

Example usage

@ControllerAdvice
public class RestExceptionHandler {

	@ExceptionHandler({ IllegalArgumentException.class, TransactionSystemException.class,
			HttpMessageNotReadableException.class })
	public ResponseEntity<Response<String>> exceptionToDoHandler(Exception ex) { (1)
		final Response<String> error = new Response<>();
		error.setStatus(HttpStatus.BAD_REQUEST.value());
		error.setMessage(ex.getMessage());
		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

	@ExceptionHandler(MethodArgumentNotValidException.class)
	public ResponseEntity<Response<List<String>>> handleValidationException(MethodArgumentNotValidException ex) { (2)
		BindingResult bindingResult = ex.getBindingResult();
		List<FieldError> fieldErrors = bindingResult.getFieldErrors();

		List<String> errorMessages = fieldErrors.stream()
				.map(fieldError -> String.format("%s: %s", fieldError.getField(), fieldError.getDefaultMessage()))
				.toList();

		Response<List<String>> error = new Response<>();
		error.setStatus(HttpStatus.BAD_REQUEST.value());
		error.setMessage("Validation failed due to provided invalid data");
		error.setData(errorMessages);

		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

	@ExceptionHandler(value = { AccessDeniedException.class })
	public ResponseEntity<Response<String>> exceptionHandler(Exception ex) { (3)
		final Response<String> error = new Response<>();
		error.setStatus(HttpStatus.UNAUTHORIZED.value());
		error.setMessage("Access Denied...");
		return new ResponseEntity<>(error, HttpStatus.UNAUTHORIZED);
	}

	@ExceptionHandler(value = { Exception.class, })
	public ResponseEntity<Response<String>> exceptionHandlerr(Exception ex) {

		final Response<String> error = new Response<>();
		error.setStatus(HttpStatus.BAD_REQUEST.value());
		error.setMessage("The request could not be understood by the server due to malformed syntax.");
		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

	@ExceptionHandler(ConstraintViolationException.class)
	public ResponseEntity<Response<List<String>>> handleConstraintViolationException( (4)
			ConstraintViolationException exception) {
		List<String> errorMessages = new ArrayList<>();

		for (ConstraintViolation<?> violation : exception.getConstraintViolations()) {
			String propertyPath = extractPropertyPath(violation.getPropertyPath().toString());
			errorMessages.add(String.format("[%s]: %s", propertyPath, violation.getMessage()));
		}

		Response<List<String>> error = new Response<>();
		error.setStatus(HttpStatus.BAD_REQUEST.value());
		error.setMessage("Validation failed due to provided invalid data");
		error.setData(errorMessages);

		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

	private String extractPropertyPath(String propertyPath) { (5)
		// Extracting the property path between the first and last square brackets
		int startIndex = propertyPath.indexOf('[');
		int endIndex = propertyPath.lastIndexOf(']');
		return propertyPath.substring(startIndex + 1, endIndex);
	}

}
1 IllegalArgumentException, TransactionSystemException, and HttpMessageNotReadableException handler
  • This section handles exceptions of these specific types, returning a generic error message and a status code of 400 (BAD_REQUEST).

2 MethodArgumentNotValidException handler
  • This section handles validation exceptions, extracting error messages from field errors and returning them along with a status code of 400 (BAD_REQUEST).

3 AccessDeniedException handler
  • This section handles exceptions of type AccessDeniedException, returning a message indicating access denial and a status code of 401 (UNAUTHORIZED).

4 Generic exception handler
  • Handles any other uncaught exceptions that may occur during the execution of API endpoints.

  • Returns a ResponseEntity with a status code of 400 Bad Request and a generic error message indicating malformed syntax.

5 ConstraintViolationException handler
  • This section handles exceptions related to constraint violations, such as those thrown by bean validation annotations. It extracts error messages from constraint violations and returns them along with a status code of 400 (BAD_REQUEST).

Customization

  • Additional exception handlers can be added to address specific use cases or domain-specific exceptions.

  • Error messages and status codes can be customized based on application requirements and error scenarios.

6. API

7. BusinessEventsServiceController

7.1. Get events

7.1.1. Sequential flow

get-events.puml
Figure 4. Get events

Get events process

  • The client sends a request to the BusinessEventsServiceController to retrieve events based on the provided filter criteria (filterDto), pageNumber, and pageSize.

  • The BusinessEventsServiceController activates and calls the getEvents method of BusinessEventsService, passing the filterDto and pagination information.

  • Inside BusinessEventsService, the getEvents method calls the getEvents method of BusinessEventsServiceImpl, passing the filterDto and pagination information.

  • Inside BusinessEventsServiceImpl, the getEvents method activates the SpecificationHelper to build a specification based on the filterDto.

  • The SpecificationHelper first retrieves the contract details based on the contractUUID in the filterDto by calling findById method of ContractsServiceRepo.

  • Depending on the filterDto criteria, the SpecificationHelper extracts filter criteria, checks contractUUID, eventID, eventType, eventTime, and status, and creates specifications accordingly.

  • The SpecificationHelper combines the specifications into a single specification object.

  • The SpecificationHelper returns the specification object to BusinessEventsServiceImpl.

  • If the contractUUID in the filterDto is null or empty, BusinessEventsServiceImpl calls the findAll method of BusinessEventsServiceRepo with the specification and pagination information to retrieve events.

  • If the contractUUID is not null or empty, BusinessEventsServiceImpl calls the findAll method of BusinessEventsServiceRepo with the specification, sorting by "eventTime", to retrieve events.

  • The BusinessEventsServiceImpl returns the formatted events to BusinessEventsService.

  • BusinessEventsService returns the formatted events to BusinessEventsServiceController.

  • BusinessEventsServiceController returns the formatted events to the client.

7.1.2. Endpoint

Description

This endpoint allows users with the appropriate permissions to fetch events based on specified criteria, apply pagination, and return the list of events as a response. URL

/events

Method

GET

Request filter parameters

Parameters

Type

Required

Description

BusinessEventsFilterDto

JSON object

No

Provided based on the requirements.

pageNumber

Integer

No

Default value is 0.

pageSize

Integer

No

Default value is 100.

Responses:

  • 200 OK: Success. Returns a JSON response containing details events.

Example response body

{
    "status": 200,
    "message": "Success",
    "data": [
        {
            "eventID": "7e3f7983-5911-47df-8e67-2d01d46074e2",
            "eventTime": "2022-12-21T06:30:00",
            "eventType": "IP",
            "eventBody": {
                "contractUpdate": {
                    "terms": [
                        {
                            "term": "notionalPrincipal",
                            "value": 50000.0,
                            "operation": "fix",
                            "fixingDays": ""
                        },
                        {
                            "term": "accruedInterest",
                            "value": 0.0,
                            "operation": "fix",
                            "fixingDays": ""
                        },
                        {
                            "term": "feeAccrued",
                            "value": 0.0,
                            "operation": "fix",
                            "fixingDays": ""
                        }
                    ],
                    "contractUUID": "7b1db647-8de5-4c4c-b279-4405c080dc6f"
                }
            },
            "status": "pending",
            "executionType": "contractUpdate",
            "value": 0.0,
            "remainingValue": 0.0,
            "creditPaymentChannelID": "6d484e24-627d-4579-8d61-f6c3107f9eb9",
            "debitPaymentChannelID": "13c3861e-bcc6-48ed-9db1-91cb6825328a",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "7b1db647-8de5-4c4c-b279-4405c080dc6f",
            "contractID": "a73ebd1f-35e8-4adc-876b-034b92d7098c",
            "units": "CHF"
        }
  ]
}
  • 400 Bad Request: If the request body is not in the correct format or if there are validation errors.

  • 401 Unauthorized: If the user is not authenticated or lacks the necessary permissions to create contracts.

  • 5xx Server Error: If there is a server-side error while processing the request.

Example

{
    "status": 400,
    "message": "The request could not be understood by the server due to malformed syntax.",
    "data": null
}

7.1.3. Methods

Description

The getEvents method retrieves a list of BusinessEvents based on the provided BusinessEventsFilterDto and pagination parameters. It uses a Specification to dynamically build query criteria based on the filter criteria in the BusinessEventsFilterDto.

Parameters

  • businessEventsFilterDto: The filter criteria for retrieving BusinessEvents.

  • pageable: Pagination information, such as page number, page size, and sorting.

Returns

  • List<BusinessEvents> : A list of BusinessEvents matching the filter criteria and pagination parameters.

Example usage

public List<BusinessEvents> getEvents(BusinessEventsFilterDto businessEventsFilterDto, Pageable pageable) {

		Specification<BusinessEvents> specification = specificationHelper
				.getEventSpecification(businessEventsFilterDto);  (1)

		List<BusinessEvents> businessEvents;

		// Retrieve events based on the specification and pagination
		if (UtilityHelper.isNullorEmpty(businessEventsFilterDto.getContractUUID())) {
			pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), Sort.by("eventTime")); (2)
			businessEvents = eventsRepo.findAll(specification, pageable).getContent(); (3)
		} else {
			businessEvents = eventsRepo.findAll(specification, Sort.by("eventTime")); (4)
		}

		return businessEvents; (5)
	}

Internal workflow

1 Build a Specification<BusinessEvents> using specificationHelper.getEventSpecification(businessEventsFilterDto).
  • If contractUUID in the businessEventsFilterDto is not null or empty: Create a specification to filter by contractUUID and add it to listSpecification.

  • If eventID in the businessEventsFilterDto is not null or empty: Create a specification to filter by eventID and add it to listSpecification.

  • If eventType in the businessEventsFilterDto is not null or empty: Create a specification to filter by eventType and add it to listSpecification.

  • If eventTime in the businessEventsFilterDto is not null or empty: Create a specification to filter by eventTime and add it to listSpecification.

  • If status in the businessEventsFilterDto is not null or empty: Create a specification to filter by status and add it to listSpecification.

2 Create a new PageRequest with sorting by “eventTime”.
3 Retrieve events using eventsRepo.findAll(specification, pageable).getContent() and assign them to businessEvents.
4 If the contractUUID filter is null or empty: Retrieve events using eventsRepo.findAll(specification, Sort.by("eventTime")) and assign them to businessEvents.
5 Return the list of businessEvents.

Exceptions

  • None explicitly thrown by this method. However, exceptions may occur within the validator or worker methods, which are handled internally.

7.1.4. Model classes

Description The BusinessEventsFilterDto class is a Data Transfer Object (DTO) used for filtering BusinessEvents based on specific criteria. It contains fields representing various filters that can be applied when querying for events.

Attributes
  1. eventID (UUID)

    • Description: The unique identifier of the event.

    • Constraints: None.

    • Example: 123e4567-e89b-12d3-a456-426614174000.

  2. eventTime (LocalDateTime)

    • Description: The timestamp of the event.

    • Constraints: None.

    • Example: "2024-02-29T12:34:56".

  3. eventType (String)

    • Description: The type of the event.

    • Constraints: None.

    • Example: "AD".

  4. status (String)

    • Description: The status of the event.

    • Constraints: None.

    • Example: "scheduled".

  5. contractUUID (UUID)

    • Description: The UUID of the contract associated with the event.

    • Constraints: None.

    • Example: 123e4567-e89b-12d3-a456-426614174000.

  6. Constructors

    • All Args Constructor: Initializes all attributes of the DTO.

    • No Args Constructor: Initializes the DTO with default values.

  7. Serialization and deserialization

    • Lombok annotations (@AllArgsConstructor, @NoArgsConstructor, @ToString, @Getter, @Setter) are used for serialization and deserialization, providing automatic generation of constructors, getters, setters, and toString method.

7.1.5. Testing

Description

This test case verifies the functionality of the getEvents() method within the EventsServiceImpl class. It aims to ensure that the method returns a list of business events filtered by a specific criteria, and it checks whether the first event in the returned list has the expected status and event type.

Test methods

Example usage

    @Test
	void getEvents() throws Exception { (1)

		Pageable pageable = PageRequest.of(1, 10);

		List<BusinessEvents> response = eventsServiceImpl.getEvents(businessEventsFilterDto, pageable);
		assertEquals("pending", response.get(0).getStatus());
		assertEquals("IP", response.get(0).getEventType());

	}
1 getEvents
  • Purpose : The purpose of this test case is to validate that the getEvents() method behaves as expected, returning a list of business events according to the provided filter and pageable parameters. It ensures that the method correctly retrieves and filters events from the underlying data source.

  • Test steps

    1. Instantiate a Pageable object using PageRequest.of(1, 10) to represent the second page with a page size of 10.

    2. Invoke the getEvents() method of the EventsServiceImpl class with the specified businessEventsFilterDto and pageable.

    3. Retrieve the response, which should be a list of BusinessEvents.

  • Assertions

    • Assert that the status of the first event (response.get(0)) in the returned list is equal to "pending".

    • Assert that the event type of the first event (response.get(0)) in the returned list is equal to "IP".

7.2. Register OPS events

7.2.1. Sequential flow

register-ops.puml
Figure 5. registerOPSEvents

Register OPS events process

  • The client sends a request to the BusinessEventsServiceController to register an OPS event using the createOPSeventDto.

  • The BusinessEventsServiceController activates and calls the createOPSevent method of BusinessEventsServiceImpl, passing the createOPSeventDto.

  • Inside BusinessEventsServiceImpl, the createOPSevent method activates the Validator to validate the OPS event data.

  • The Validator first validates the creditPaymentChannelID by checking its existence in the PaymentChannelsRepo.

  • If the creditPaymentChannelID is valid, the Validator continues validation. Otherwise, it throws an IllegalArgumentException.

  • Next, the Validator validates the debitPaymentChannelID by checking its existence in the PaymentChannelsRepo and the ContractsServiceRepo.

  • If both validations are successful, the Validator passes the contracts to BusinessEventsServiceImpl.

  • BusinessEventsServiceImpl then activates the BusinessEventsHelper to create the OPS event.

  • The BusinessEventsHelper first creates the initial event body and ledger details for the OPS event.

  • The BusinessEventsHelper then creates a new BusinessEvents object and sets its properties based on the createOPSeventDto and debitContract.

  • The BusinessEventsHelper passes the created businessEvents object back to BusinessEventsServiceImpl.

  • BusinessEventsServiceImpl saves the businessEvents object in the BusinessEventsServiceRepo and returns the saved businessEvents object to BusinessEventsServiceController.

  • BusinessEventsServiceController returns the createOpsEventResponse to the client.

7.2.2. Endpoint

Description This endpoint allows users to register OPS events by providing the necessary details in a POST request, which are then validated, processed, and saved to the database

URL

/events/ops

Method

POST

Request body

The request body should contain a JSON array of objects, each representing data for register OPS events. The structure of each object should adhere to the CreateOPSeventDto format.

Example request body

 {
  "value": 100.50,
  "dueTime": "2024-03-05T10:00:00",
  "units": "USD",
  "debitPaymentChannelID": "3220799ac-c335-4cc7-aa17-d83b997281da",
  "creditPaymentChannelID": "33ab848d-522b-46ce-8e53-c025ed9caf02",
  "remainingAmount": 50.25,
  "debitLedgerAccountID": "39b22817-a37f-49b9-adbc-e27971afa39c",
  "creditLedgerAccountID": "c1d8c18a-32a2-4a31-96ec-f4d4f2873a4f"
  }

Responses

  • 201 CREATED: Success. Returns a JSON response containing details of the created OPS events.

Example response body

{
  "status": 200,
  "message": "Success",
  "data": "dbe7a243-196d-45f8-bb6e-317f28fcf227"
}
  • 400 Bad Request: If the request body is not in the correct format or if there are validation errors.

  • 401 Unauthorized: If the user is not authenticated or lacks the necessary permissions to create contracts.

  • 5xx Server Error: If there is a server-side error while processing the request.

Example

  • Invalid creditPaymentChannelID

{
  "status": 400,
  "message": "Invalid creditPaymentChannelID 33ab848d-522b-46ce-8e53-c025ed9caf02",
  "data": null
}
  • Invalid debitPaymentChannelID

{
  "status": 400,
  "message": "Invalid debitPaymentChannelID 3220799ac-c335-4cc7-aa17-d83b997281da",
  "data": null
}
  • Unauthorized access

{
  "status": 401,
  "message": "Unauthorized",
  "data": null
}

7.2.3. Methods

Description

This method is responsible for creating an OPS event. It validates the input data, creates a BusinessEvents object, and saves it to the database.

Parameters

  • createOPSeventDto: The data transfer object containing information for creating an OPS event. Returns

  • Response<UUID>: A response object containing the HTTP status code, a success message, and the event ID of the created OPS event.

Example Usage

public Response<UUID> createOPSevent(CreateOPSeventDto createOPSeventDto) {
		log.info("Create OPS event started by UserId : {}, Request : {}", usersHelper.getUserID(), createOPSeventDto);

		Contracts debitContract = validator.validateOPSdata(createOPSeventDto); (1)

		// Create an OPS event object using the helper method
		BusinessEvents businessEvents = businessEventsHelper.createOpsEvent(createOPSeventDto, debitContract); (2)
		businessEvents = eventsRepo.save(businessEvents); (3)

		log.info("OPS event created by UserId : {}, EventId : {}", usersHelper.getUserID(),
				businessEvents.getEventID());

		return new Response<>(HttpStatus.OK.value(), OPS_EVENT_MESSAGE, businessEvents.getEventID()); (4)
	}

Internal workflow:

1 Validates the data using the Validator service’s validateOPSdata method.
  • Validates the data using the Validator service’s validateOPSdata method.

  • Calls the validateOPSdata method of the Validator service, passing the createOPSeventDto.

  • Validates the CreditPaymentChannelID and DebitPaymentChannelID in the createOPSeventDto.

  • Checks if the CreditPaymentChannelID exists in the paymentRepo.

  • Throws an IllegalArgumentException if the CreditPaymentChannelID is invalid.

  • Retrieves the PaymentChannels object for the DebitPaymentChannelID from the paymentRepo.

  • Throws an IllegalArgumentException if the DebitPaymentChannelID is invalid.

  • Retrieves the Contracts object associated with the DebitPaymentChannelID from the contractsRepo.

  • Throws an IllegalArgumentException if the contract is invalid.

  • Returns the validated Contracts object.

2 Creates a BusinessEvents object using the BusinessEventsHelper service’s createOpsEvent method.
  • Calls the createOpsEvent method of the BusinessEventsHelper service, passing the createOPSeventDto and the validated Contracts object.

  • Creates an initial event body using the createLedgerMap method of the BusinessEventsHelper.

  • Sets various properties of the BusinessEvents object using the values from the createOPSeventDto and the validated Contracts object.

3 Saves the created BusinessEvents object to the database using the eventsRepo.
4 Returns a response containing the HTTP status code, a success message, and the event ID of the created OPS event.

Exceptions

IllegalArgumentException Thrown if the CreditPaymentChannelID or DebitPaymentChannelID is invalid. Thrown if the contract associated with the DebitPaymentChannelID is invalid. Thrown if the contract is invalid.

DataAccessException Thrown if there is an issue accessing the database while saving the BusinessEvents object.

7.2.4. Model classes

Description The CreateOPSeventDto class represents a Data Transfer Object (DTO) for creating an OPS event. It contains various attributes that define the details of the event.

Attributes
  1. value (BigDecimal)

    • Description: The value associated with the OPS event.

    • Constraints: Not null.

    • Example: 100.00

  2. dueTime (LocalDateTime)

    • Description: The due time of the OPS event.

    • Constraints: Not null.

    • Example: 2024-03-07T10:15:30

  3. units (String)

    • Description: The units of the OPS event.

    • Constraints: Not blank, maximum 10 characters.

    • Example: INR

  4. debitPaymentChannelID (UUID)

    • Description: The UUID of the debit payment channel associated with the OPS event.

    • Constraints: Not null.

    • Example: 39b22817-a37f-49b9-adbc-e27971afa39c

  5. creditPaymentChannelID (UUID)

    • Description: The UUID of the credit payment channel associated with the OPS event.

    • Constraints: Not null.

    • Example: c1d8c18a-32a2-4a31-96ec-f4d4f2873a4f

  6. remainingAmount (BigDecimal)

    • Description: The remaining amount after the OPS event.

    • Constraints: None.

    • Example: 50.00

  7. debitLedgerAccountID (UUID)

    • Description: The UUID of the debit ledger account associated with the OPS event.

    • Constraints: Not null.

    • Example: 33ab848d-522b-46ce-8e53-c025ed9caf02

  8. creditLedgerAccountID (UUID)

    • Description: The UUID of the credit ledger account associated with the OPS event.

    • Constraints: Not null.

    • Example: 3220799ac-c335-4cc7-aa17-d83b997281da

  9. Constructors

    • Default constructor.

    • Parameterized constructor with all attributes.

  10. Serialization and Deserialization

    • The class uses Lombok annotations @Getter, @Setter, @NoArgsConstructor, @AllArgsConstructor, and @ToString for serialization and deserialization. These annotations generate getter and setter methods, default and parameterized constructors, and a toString method for the class.

7.2.5. Testing

Description

The createOPSeventTest method evaluates the functionality of the createOPSevent method within the EventsServiceImpl class. This test ensures that the method properly creates an OPS event with the provided DTO and stores it in the repository.

Test methods

Example usage

	@Test
	void createOPSeventTest() { (1)
		Response createOPSevent = eventsServiceImpl.createOPSevent(createOPSeventDto);

		Assertions.assertEquals(200, createOPSevent.getStatus());
		Assertions.assertEquals(eventId, createOPSevent.getData());

		BusinessEvents businessEvents = eventsRepo.findById(eventId).get();
		Map<String, Object> eventBody = (Map<String, Object>) businessEvents.getEventBody();
		BigDecimal value = businessEvents.getValue();
		Map<String, Object> ledgerMap = (Map<String, Object>) eventBody.get("ledgerDetails");

		Assertions.assertEquals(500, value.intValue());
		Assertions.assertEquals(createOPSeventDto.getCreditPaymentChannelID(),
				businessEvents.getCreditPaymentChannelID());
		Assertions.assertEquals(createOPSeventDto.getDebitPaymentChannelID(),
				businessEvents.getDebitPaymentChannelID());
		Assertions.assertEquals(createOPSeventDto.getCreditLedgerAccountID(), ledgerMap.get("creditLedgerAccountID"));
		Assertions.assertEquals(createOPSeventDto.getDebitLedgerAccountID(), ledgerMap.get("debitLedgerAccountID"));

	}
1 createOPSeventTest
  • Purpose : The purpose of this test is to verify that the createOPSevent method behaves correctly by creating an OPS event with the provided DTO, storing it in the repository, and returning the appropriate response.

  • Test steps

    1. Call the createOPSevent method of the EventsServiceImpl class with the createOPSeventDto.

    2. Retrieve the response object returned by the method.

    3. Assert that the status code of the response is equal to 200.

    4. Assert that the event ID returned in the response matches the expected event ID.

    5. Retrieve the newly created business event from the repository using the event ID.

    6. Extract the event body and value from the retrieved business event.

    7. Extract the ledger details from the event body.

  • Assertions

    • Assert that the status code of the response is 200.

    • Assert that the event ID returned in the response matches the expected event ID.

    • Assert that the value of the event matches the expected value.

    • Assert that the credit and debit payment channel IDs of the event match the values provided in the DTO.

    • Assert that the credit and debit ledger account IDs in the ledger details match the values provided in the DTO.

7.3. Delete event

7.3.1. Sequential flow

delete-event.puml
Figure 6. delete events

Delete event process

  • Client: Initiates the request to delete an event by calling the requestDeleteEvent(eventId) method on the controller.

  • BusinessEventsServiceController: Receives the delete event request and activates to handle it. It then calls the deleteEvent(eventId) method on the service layer.

  • BusinessEventsService: Receives the delete event request and activates to handle it. It then calls the deleteEvent(eventId) method on the service implementation.

  • BusinessEventsServiceImpl: Implements the deleteEvent(eventId) method and activates to handle it. It then calls the findById(eventId) method on the repository to retrieve the event to be deleted.

  • BusinessEventsServiceRepo: Receives the find event by ID request and activates to handle it. It retrieves the event based on the provided event ID.

  • BusinessEventsServiceImpl: Receives the event to be deleted from the repository and activates to handle it. It then calls the deleteById(event.getEventID()) method on the repository to delete the event.

  • BusinessEventsServiceRepo: Deletes the event from the repository based on its ID.

  • BusinessEventsService: Receives the response from the repository and activates to handle it. It then returns the response to the controller.

  • BusinessEventsServiceController: Receives the response from the service layer and activates to handle it. It then returns the response to the client, completing the delete event request.

7.3.2. Endpoint

Description

This endpoint allows authorized users to delete a business event based on its eventId by invoking the deleteEvent method in the service layer, which in turn deletes the event from the repository and returns a success response with the deleted event’s eventId.

URL:

/events/{eventId}

Method:

DELETE

Request filter parameters

Parameters

Type

Required

Description

eventId

UUID

Yes

The unique identifier of the event to be deleted.

Responses:

  • 200 OK: Success. Returns a JSON response containing details events.

  • 200 OK: Event deleted successfully. Returns a JSON response containing the deleted event’s UUID.

Example response body

{
    "status": 200,
    "message": "Event deleted successfully",
    "data": "00999de6-fa5e-9999-b8d9-dbf4c9f14b99"
}
  • 400 Bad Request: If the request body is not in the correct format or if there are validation errors.

  • 401 Unauthorized: If the user is not authenticated or lacks the necessary permissions to create contracts.

  • 5xx Server Error: If there is a server-side error while processing the request.

Example:

{
    "status": 400,
    "message": "The request could not be understood by the server due to malformed syntax.",
    "data": null
}

7.3.3. Methods

Description

This method deleteEvent(UUID eventId) in the BusinessEventsServiceImpl class is used to delete a business event from the database based on the provided event ID. It first retrieves the event using the findById method of eventsRepo (an instance of BusinessEventsServiceRepo). If the event is not found, it throws an IllegalArgumentException. If the event is found, it then deletes the event from the database using the deleteById method of eventsRepo.

Parameters

  • UUID eventId: The unique identifier of the event to be deleted.

Returns

  • This method does not return anything (void).

Example usage

	public void deleteEvent(UUID eventId) {

		BusinessEvents event = eventsRepo.findById(eventId) (1)
				.orElseThrow(() -> new IllegalArgumentException("Invalid eventID")); (2)
		eventsRepo.deleteById(event.getEventID()); (3)

	}

Internal workflow

1 Retrieve the event from the database using the findById method of eventsRepo.
2 If the event is not found, throw an IllegalArgumentException.
3 If the event is found, delete the event from the database using the deleteById method of eventsRepo.

Exceptions

  • IllegalArgumentException: Thrown if the event with the specified event ID is not found in the database.

7.3.4. Testing

Description

This test method, deleteEvent, validates the behavior of the deleteEvent function within the EventsServiceImpl class. It specifically tests the scenario where an event with the provided eventID does not exist in the repository.

Test methods

Example usage

	@Test
	 void deleteEvent() throws Exception { (1)

		 when(eventsRepo.findById(ipEventID)).thenReturn(Optional.empty());

		    Throwable exception = assertThrows(IllegalArgumentException.class, () -> eventsServiceImpl.deleteEvent(ipEventID));
		    Assertions.assertEquals("Invalid eventID", exception.getMessage());
	}
1 deleteEvent
  • Purpose : The purpose of this test is to ensure that the deleteEvent method behaves correctly when attempting to delete an event that does not exist in the repository. It verifies that the method appropriately handles the case of an invalid eventID by throwing an IllegalArgumentException with the expected error message.

  • Test steps

    1. Stub the behavior of the eventsRepo mock to return an empty optional when findById is invoked with the specified ipEventID.

    2. Attempt to delete the event by calling the deleteEvent method of the EventsServiceImpl class with the ipEventID.

    3. Capture the thrown exception using assertThrows.

  • Assertions

    • Assert that the thrown exception is an instance of IllegalArgumentException.

    • Assert that the message of the thrown exception matches the expected error message, indicating "Invalid eventID".

7.4. Graph values day wise

7.4.1. Sequential flow

get-events.puml
Figure 7. Graph values day wise

Graph values day wise process

  • The Client initiates the process by calling graphValuesDayWise(fromdate, todate) on the BusinessEventsServiceController.

  • The BusinessEventsServiceController activates and calls getEventsForGraph(fromdate, todate) on the BusinessEventsService.

  • BusinessEventsService activates and calls getEventsForGraph(fromdate, todate) on the BusinessEventsServiceImpl.

  • BusinessEventsServiceImpl activates and calls getEventsForGraph(fromdate, todate) on the BusinessEventsServiceRepo to retrieve a list of events.

  • BusinessEventsServiceRepo provides the list of events (resultList) to BusinessEventsServiceImpl.

  • BusinessEventsServiceImpl aggregates the event values by day and returns eventTimeAndAggregateValue to BusinessEventsService.

  • BusinessEventsService returns the eventTimeAndAggregateValue in a ResponseDto to BusinessEventsServiceController.

  • BusinessEventsServiceController returns the ResponseDto containing the graph values to the Client.

7.4.2. Endpoint

Description

This endpoint is used to fetch graph values for events within a specified date range, which can be useful for generating graphical representations of event data over time. URL

/events/graphValuesDayWise/{fromdate}/{todate}

Method

GET

Request filter parameters

Parameters

Type

Required

Description

fromdate

String

Yes

The start date for the date range.

todate

String

Yes

The end date for the date range.

Responses

  • 200 OK: Success. Returns a JSON response containing graph values for events on a day-by-day basis within the specified date range.

Example Response Body:

{
    "status": 200,
    "message": "Success",
    "data": {
        "2023-09-01": 306343.0,
        "2023-09-02": 5000.0,
        "2023-09-21": 0.0
    }
}
  • 400 Bad Request: If the request body is not in the correct format or if there are validation errors.

  • 401 Unauthorized: If the user is not authenticated or lacks the necessary permissions to create contracts.

  • 5xx Server Error: If there is a server-side error while processing the request.

Example

{
    "status": 400,
    "message": "The request could not be understood by the server due to malformed syntax.",
    "data": null
}

7.4.3. Methods

Description

This method retrieves events for graph plotting within a specified date range and aggregates their values by day.

Parameters

  • fromdate: The start date of the date range.

  • todate: The end date of the date range.

Returns

  • A TreeMap where keys represent event times (dates) and values represent aggregated event values.

Example Usage

	public TreeMap<String, BigDecimal> getEventsForGraph(String fromdate, String todate) {

		// Retrieve a list of event data from the repository based on the specified date
		// range
		(1)
		LocalDateTime fromDate = LocalDateTime.parse(fromdate.split("T")[0].concat("T00:00"));
		LocalDateTime toDate = LocalDateTime.parse(todate.split("T")[0].concat("T00:00")).plusDays(1);
		List<Object[]> resultList = eventsRepo.getEventsForGraph(fromDate, toDate);(2)

		final TreeMap<String, BigDecimal> eventTimeAndAggregateValue = new TreeMap<>();

		// For each event time, retrieve the event values.
		for (final Object[] objects : resultList) { (3)
			final String event_time = objects[0].toString().split("T")[0];
			final double value = Double.parseDouble(objects[1].toString());

			// Aggregate the event value by day in the TreeMap
			eventTimeAndAggregateValue.put(event_time,
					eventTimeAndAggregateValue.containsKey(event_time)
							? eventTimeAndAggregateValue.get(event_time).add(BigDecimal.valueOf(value))
							: BigDecimal.valueOf(value));
		}

		return eventTimeAndAggregateValue;
	}

Internal workflow

1 Parsing Dates: Parses the input fromdate and todate strings into LocalDateTime objects, setting the time to midnight.
2 Repository Call: Calls eventsRepo.getEventsForGraph(fromDate, toDate) to retrieve a list of event data within the specified date range.
  • This method uses a JPQL query to retrieve event times (eventTime) and their corresponding aggregated values (SUM(be.value)) from the BusinessEvents table. It filters the results based on a specified date range (fromDate to toDate), groups them by eventTime, and orders them by eventTime. The method expects fromDate and toDate parameters as LocalDateTime objects and returns a list of object arrays, where each array contains the eventTime and its aggregated value. please give me in point wise

3 Aggregation: Iterates over the result list and aggregates the event values by day, storing them in a TreeMap where each key is a day and the value is the aggregated value for that day.

Exceptions

  • None explicitly thrown by this method. However, exceptions may occur within the validator or worker methods, which are handled internally.

7.4.4. Testing

Description

This test method, getEventsForGraphTest, evaluates the functionality of the getEventsForGraph method within the EventsServiceImpl class. It aims to verify that the method properly retrieves event data within a specified date range and organizes it into a format suitable for graph representation.

Test methods

Example usage

    @Test
	void getEventsForGraphTest() { (1)
		String fromDate = "2023-06-19";
		String toDate = "2023-06-21";

		// Convert String dates to LocalDateTime
		LocalDateTime fromDateTime = LocalDateTime.parse(fromDate.split("T")[0].concat("T00:00"));
		LocalDateTime toDateTime = LocalDateTime.parse(toDate.split("T")[0].concat("T00:00")).plusDays(1);
		// Create a list of sample event data.
		List<Object[]> resultList = new ArrayList<>();
		resultList.add(new Object[] { "2023-06-20", 100.0 });
		resultList.add(new Object[] { "2023-06-21", 200.0 });
		resultList.add(new Object[] { "2023-06-20", 400.0 });

		// Mock the behavior of the repository to return the sample event data.
		when(eventsRepo.getEventsForGraph(fromDateTime, toDateTime)).thenReturn(resultList);
		// Call the service method to retrieve event data for the graph.
		TreeMap<String, BigDecimal> eventsForGraph = eventsServiceImpl.getEventsForGraph(fromDate, toDate);


		Assertions.assertEquals(BigDecimal.valueOf(500.0), eventsForGraph.get("2023-06-20"));
		Assertions.assertEquals(BigDecimal.valueOf(200.0), eventsForGraph.get("2023-06-21"));

	}
1 getEventsForGraphTest
  • Purpose : The purpose of this test is to ensure that the getEventsForGraph method behaves correctly, retrieving event data from the repository within the specified date range and formatting it appropriately for graph plotting.

  • Test steps

    1. Define sample fromDate and toDate strings representing the start and end dates for the query.

    2. Convert the string dates to LocalDateTime objects.

    3. Create a list of object arrays representing sample event data, including event timestamps and corresponding values.

    4. Mock the behavior of the repository to return the sample event data when getEventsForGraph is invoked with the specified date range.

    5. Invoke the getEventsForGraph method of the EventsServiceImpl class with the fromDate and toDate.

    6. Retrieve the resulting TreeMap containing event timestamps as keys and corresponding values.

    7. Extract and store the event values for validation.

  • Assertions

    • Assert that the event value for each timestamp within the specified date range matches the expected value.

    • Ensure that the event values are correctly organized within the TreeMap, with timestamps as keys and corresponding values.

7.5. Liquidity report

7.5.1. Sequential flow

get-liquidity-report.puml
Figure 8. liquidity-report

Liquidity report process

  • The client sends a request to the BusinessEventsServiceController to generate a liquidity report for a specific time.

  • The BusinessEventsServiceController activates and calls the liquidityData method of BusinessEventsService, passing the specified time.

  • Inside BusinessEventsService, the liquidityData method activates and calls the liquidityData method of BusinessEventsServiceImpl, passing the specified time.

  • BusinessEventsServiceImpl activates the UtilityHelper to calculate the fromdate based on the specified time.

  • BusinessEventsServiceImpl then calculates the todate based on the fromdate and regex values.

  • The BusinessEventsServiceImpl iterates 15 times to fetch liquidity events data for each iteration.

  • For each iteration, it activates the BusinessEventsServiceRepo to get the events for the graph for the specified fromdate.

  • The BusinessEventsServiceImpl then activates the BusinessEventsHelper to process the result list and extract the event_time and value from each object array.

  • The BusinessEventsHelper parses the value to a double and adds it to eventTimeAndAggregateValue.

  • After processing all objects, the BusinessEventsHelper returns eventTimeAndAggregateValue to BusinessEventsServiceImpl.

  • BusinessEventsServiceImpl calculates the total value from eventTimeAndAggregateValue.

  • Finally, BusinessEventsServiceImpl returns the finalResult to BusinessEventsServiceController.

  • BusinessEventsServiceController returns a ResponseDto containing the liquidity report to the client.

7.5.2. Endpoint

Description

This endpoint retrieves a liquidity report based on the provided timestamp. It calls a service method to calculate liquidity data for a specified time interval and constructs a response entity containing the report. URL

/events/liquidityReport

Method

GET

Request filter parameters

Parameters

Type

Required

Description

time

String

Yes

The timestamp for which the liquidity report is requested.

Responses

200 OK: Success. Returns a JSON response containing the liquidity report based on the provided timestamp. Example Response Body:

{
"status": 200,
"message": "Success",
"data": {
"2023-09-01": 306343.0,
"2023-09-02": 5000.0,
"2023-09-21": 0.0
}
}
  • 400 Bad Request: If the request body is not in the correct format or if there are validation errors.

  • 401 Unauthorized: If the user is not authenticated or lacks the necessary permissions to create contracts.

  • 5xx Server Error: If there is a server-side error while processing the request.

Example

{
    "status": 400,
    "message": "The request could not be understood by the server due to malformed syntax.",
    "data": null
}

7.5.3. Methods

Description

This method liquidityData(String time) calculates liquidity data for a specified time interval. It iterates over a 15-day period, retrieving event data from a repository, processing it, and aggregating the values.

Parameters

  • time: A string representing the time interval (D for day, W for week, M for month, Q for quarter, H for half-year, A for year).

Returns

  • A TreeMap<String, BigDecimal> where the key is a date and the value is the aggregate value for that date.

Example Usage

   public TreeMap<String, BigDecimal> liquidityData(String time) {

		// Define a mapping of time intervals to their respective day counts
		final HashMap<String, Integer> regexValues = new HashMap<>(); (1)
		regexValues.put("D", 1);
		regexValues.put("W", 7);
		regexValues.put("M", 30);
		regexValues.put("Q", 90);
		regexValues.put("H", 180);
		regexValues.put("A", 360);

		final TreeMap<String, BigDecimal> finalResult = new TreeMap<>(); (2)

		int iterations = 1;

		LocalDateTime fromdate = UtilityHelper.systemLocalDateTime(); (3)
		LocalDateTime todate = fromdate.plusDays(regexValues.get(time));

		// Perform iterations to retrieve liquidity data for the specified time
		// intervals
		while (iterations <= 15) { (4)

			final LocalDateTime queryTodate = todate.plusDays(1);

			List<Object[]> resultList = eventsRepo.getEventsForGraph(fromdate, queryTodate); (5)

			// Process the result list and calculate aggregate value
			TreeMap<String, BigDecimal> eventTimeAndAggregateValue = (TreeMap<String, BigDecimal>) businessEventsHelper
					.processResultList(resultList); (6)

			BigDecimal value = eventTimeAndAggregateValue.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add); (7)

			// Handle cases where the entire date range contains no events
			try {
				finalResult.put(eventTimeAndAggregateValue.lastEntry().getKey(), value);
			} catch (final Exception e) {
				finalResult.put(todate.toString(), value);
			}

			fromdate = todate.plusDays(1);
			todate = fromdate.plusDays(regexValues.get(time));
			iterations++; (8)
		}
		return finalResult; (9)
	}

Internal workflow

1 Initializes a mapping of time intervals to day counts.
2 Initializes an empty TreeMap to store the final result.
3 Sets the start date (fromdate) to the current date and the end date (todate) to the current date plus the day count for the specified time interval.
4 Iterates over a 15-day period:
5 Retrieves event data from the repository for the current date range.
6 Processes the result list to calculate aggregate values for each date.
  • Iterates over each object array in the result list:

  • Extracts the event time and value from the array.

  • Parses the value to a double and adds it to the aggregated value for the event time in the map.

  • If the event time is not present in the map, adds a new entry with the event time and value.

  • Returns the map containing event times and their aggregated values.

7 Adds the aggregate value to the final result map with the date as the key.
8 Updates the start and end dates for the next iteration.
9 Returns the final result map.

Exceptions

  • Handles cases where the entire date range contains no events by adding an entry to the final result map with the end date of the range and a value of zero.

  • Handles cases where the value in the object array cannot be parsed to a double by adding an entry to the map with the event time and a value of zero.

7.5.4. Testing

Description

The liquidityDataTest method evaluates the functionality of the liquidityData method within the EventsServiceImpl class. This test ensures that the method correctly retrieves liquidity data for a specified duration and organizes it into a suitable format.

Test methods

Example usage

	@Test
	void liquidityDataTest() { (1)

		LocalDateTime fromdate = UtilityHelper.systemLocalDateTime();
		LocalDateTime todate = fromdate.plusDays(1);
	    LocalDateTime queryTodate = todate.plusDays(1);

		List<Object[]> resultList = new ArrayList<>();
		resultList.add(new Object[] { fromdate, 1000.0 });
		resultList.add(new Object[] { todate, 5000.0 });

		when(eventsRepo.getEventsForGraph(fromdate, queryTodate)).thenReturn(resultList);

		TreeMap<String, BigDecimal> liquidityData = eventsServiceImpl.liquidityData("D");

		Assertions.assertEquals(BigDecimal.valueOf(6000.0), liquidityData.get(todate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))));

	}
1 liquidityDataTest
  • Purpose : The purpose of this test is to verify that the liquidityData method behaves correctly by retrieving liquidity data from the repository for a given duration and formatting it appropriately for further processing.

  • Test steps

    1. Obtain the current system date and time using UtilityHelper.systemLocalDateTime() as the start date.

    2. Calculate the end date by adding one day to the start date to define the time range for the liquidity data query.

    3. Extend the end date by another day (queryTodate) to encompass the entire duration for liquidity data retrieval.

    4. Prepare a list of object arrays containing sample liquidity data, including timestamps and corresponding liquidity values.

    5. Mock the behavior of the repository to return the sample liquidity data when getEventsForGraph is called with the specified time range.

    6. Invoke the liquidityData method of the EventsServiceImpl class, passing the duration ("D") as a parameter.

    7. Retrieve the resulting TreeMap containing liquidity timestamps as keys and corresponding liquidity values.

    8. Extract and store the liquidity value for validation.

  • Assertions

    • Assert that the liquidity value for the end date matches the expected value.

    • Ensure that the liquidity data is correctly organized within the TreeMap, with timestamps as keys and corresponding liquidity values.

7.6. Contract events

7.6.1. Sequential flow

contract events.puml
Figure 9. Contract Events Retrieval

Contract events retrieval process

  • The client sends a request to the BusinessEventsServiceController to get contract events based on the provided parameters: profileId, eventType, pageNumber, and pageSize.

  • The BusinessEventsServiceController activates and calls the getContractEvents method of BusinessEventsServiceImpl, passing the parameters.

  • Inside BusinessEventsServiceImpl, the findById method of ProfilesRepo is called to retrieve profiles based on the profileId.

  • If no profiles are found, an IllegalArgumentException is thrown, and the method execution stops with the exception propagated to the caller.

  • If profiles are found, the getContractsByCounterpartyID method of ContractsServiceRepo is called to retrieve contracts based on the profiles.

  • Depending on the pagination settings, a Pageable object is created using PageRequest.of(pageNumber, pageSize) if pagination settings are provided.

  • If pagination settings are provided, the findByContractUUIDInAndEventTypeIn method of BusinessEventsServiceRepo is called with contractsList, eventType, and pageable as parameters, and the results are stored in finalEvents.

  • If pagination settings are not provided, the findByContractUUIDInAndEventTypeIn method is called with contractsList and eventType as parameters, and the results are stored in finalEvents.

  • The finalEvents are returned to the BusinessEventsServiceController.

  • The BusinessEventsServiceController returns the eventsList to the client.

7.6.2. Endpoint

Description

This endpoint retrieves a list of business events associated with a specific contract

URL:

/events/contractEvents

Method:

GET

Request filter parameters

Parameters

Type

Required

Description

profileId

UUID

Yes

The identifier of the contract’s profile.

eventType

List

Yes

A list of event types to filter the events.

pageNumber

Integer

No

The page number for pagination.

pageSize

Integer

No

The number of items per page.

Responses

  • 200 OK: Success. Returns a JSON response containing a list of business events associated with the contract.

Example response body

{
    "status": 200,
    "message": "Success",
    "data": [
        {
    "eventID": "123e4567-e89b-12d3-a456-426614174000",
    "eventTime": "2023-09-01T12:00:00",
    "eventType": "IP",
    "eventBody": {},
    "status": "scheduled",
    "executionType": "contractUpdate",
    "value": 100.00,
    "remainingValue": 50.00,
    "creditPaymentChannelID": "54321",
    "debitPaymentChannelID": "67890",
    "userID": "45678",
    "contractUUID": "987e6547-e89b-12d3-a456-426614174000",
    "contractID": "CON123",
    "units": "INR"
   }
    ]
}
  • 400 Bad Request: If the request body is not in the correct format or if there are validation errors.

  • 401 Unauthorized: If the user is not authenticated or lacks the necessary permissions to create contracts.

  • 5xx Server Error: If there is a server-side error while processing the request.

Example

{
    "status": 400,
    "message": "The request could not be understood by the server due to malformed syntax.",
    "data": null
}

7.6.3. Methods

Description

This method retrieves a list of business events associated with a specific contract, filtered by profile ID, event types, and optionally paginated based on page number and page size.

Parameters

  • profileID (UUID): The identifier of the contract’s profile.

  • eventType (List<String>): A list of event types used to filter the events.

  • pageNumber (Integer): The page number for pagination (optional). *` pageSize (Integer):` The number of items per page (optional).

Returns

  • List<BusinessEvents>: A list of business events associated with the contract, filtered and paginated as specified.

Example Usage

	public List<BusinessEvents> getContractEvents(UUID profileID, List<String> eventType, Integer pageNumber,
			Integer pageSize) {

		List<BusinessEvents> finalEvents;

		Profiles profiles = profilesRepo.findById(profileID)
				.orElseThrow(() -> new IllegalArgumentException("profile not found")); (1)

		// Retrieve a list of contracts based on the provided profile ID
		List<Contracts> contractsList = contractsServiceRepo.getContractsByCounterpartyID(profiles); (2)

		// Check if pagination settings are provided
		if (UtilityHelper.isNotNullOrEmpty(pageNumber) && UtilityHelper.isNotNullOrEmpty(pageSize)) { (3)
			Pageable pageable = PageRequest.of(pageNumber, pageSize);
			finalEvents = eventsRepo.findByContractUUIDInAndEventTypeIn(contractsList, eventType, pageable); (4)
		} else {
			finalEvents = eventsRepo.findByContractUUIDInAndEventTypeIn(contractsList, eventType); (5)
		}

		return finalEvents; (6)

	}

Internal workflow

1 Retrieve the Profiles entity using the profileID.
2 Retrieve a list of Contracts associated with the profile using contractsServiceRepo.getContractsByCounterpartyID(profiles).
3 Check if pagination settings are provided.
4 If pagination settings are provided, use eventsRepo.findByContractUUIDInAndEventTypeIn(contractsList, eventType, pageable) to fetch paginated results.
5 If pagination settings are not provided, use eventsRepo.findByContractUUIDInAndEventTypeIn(contractsList, eventType) to fetch all results.
6 Return the list of business events.

Exceptions

  • If the Profiles entity cannot be found for the provided profileID, an IllegalArgumentException is thrown with the message "profile not found".

7.6.4. Testing

Description

This section consists of two test factory methods: getContractEventsWithPagination and getContractEvents. These methods are responsible for dynamically generating test cases to verify the behavior of the getContractEvents method within the EventsServiceImpl class, with and without pagination.

Test methods

Example usage

   @TestFactory
	Stream<DynamicTest> getContractEventsWithPagination() { (1)
		Pageable pageable = PageRequest.of(1, 10);
		when(eventsRepo.findByContractUUIDInAndEventTypeIn(anyList(), anyList(), any())).thenReturn(eventsList);

		List<BusinessEvents> computedEvents = eventsServiceImpl.getContractEvents(userID, eventTypeList, 1, 10);
		List<DynamicTest> dynamicTests = new ArrayList<>();
		for (int i = 0; i < eventsList.size(); i++) {
			BusinessEvents expectedEvent = eventsList.get(i);
			BusinessEvents computedEvent = computedEvents.get(i);

			dynamicTests.add(eventsUtils.createDynamicTest(expectedEvent, computedEvent));
		}
		return dynamicTests.stream();

	}

	@TestFactory
	Stream<DynamicTest> getContractEvents() { (2)
		Pageable pageable = PageRequest.of(1, 10);
		when(eventsRepo.findByContractUUIDInAndEventTypeIn(anyList(), anyList())).thenReturn(eventsList);

		List<BusinessEvents> computedEvents = eventsServiceImpl.getContractEvents(userID, eventTypeList, null, null);
		List<DynamicTest> dynamicTests = new ArrayList<>();
		for (int i = 0; i < eventsList.size(); i++) {
			BusinessEvents expectedEvent = eventsList.get(i);
			BusinessEvents computedEvent = computedEvents.get(i);

			dynamicTests.add(eventsUtils.createDynamicTest(expectedEvent, computedEvent));
		}
		return dynamicTests.stream();

	}
1 getContractEventsWithPagination
  • Purpose : This method dynamically generates test cases to verify the behavior of the getContractEvents method when pagination is applied.

  • Test steps

    1. Create a Pageable object representing the pagination parameters.

    2. Stub the behavior of the eventsRepo mock to return a predefined list of events (eventsList) when invoked with specific parameters.

    3. Invoke the getContractEvents method of the EventsServiceImpl class with the provided user ID, event type list, and pagination parameters.

    4. Compute the events retrieved from the method.

    5. Generate dynamic tests for each event retrieved, comparing the expected event with the computed event using eventsUtils.createDynamicTest().

2 getContractEvents
  • Purpose : This method dynamically generates test cases to verify the behavior of the getContractEvents method when no pagination is applied.

  • Test steps

    1. Create a Pageable object representing default pagination parameters.

    2. Stub the behavior of the eventsRepo mock to return a predefined list of events (eventsList) when invoked with specific parameters.

    3. Invoke the getContractEvents method of the EventsServiceImpl class with the provided user ID, event type list, and no pagination parameters.

    4. Compute the events retrieved from the method.

    5. Generate dynamic tests for each event retrieved, comparing the expected event with the computed event using eventsUtils.createDynamicTest().

7.7. Event values for a specific contract

7.7.1. Sequential flow

get-event values.puml
Figure 10. Get event values

Get events value process:

  • Client initiates the event retrieval process by calling requestEventsValue(contractuuid).

  • BusinessEventsServiceController receives the request and activates the process.

  • BusinessEventsService is activated and calls getEventsValue(contractuuid).

  • BusinessEventsServiceImpl receives the request and calls validateContractUUID(contractuuid) in validator to build a validaton based on the contractuuid.

  • Validator receives the request and calls contractsRepo(contractUUID) in ContractsServiceRepo to retrieve a Contracts.

  • Validator provides the Contracts to BusinessEventsServiceImpl.

  • BusinessEventsServiceImpl calls getEventValues(contracts) in BusinessEventsServiceRepo to retrieve a list of events values based on the contracts.

  • BusinessEventsServiceRepo provides the list of events values (eventsvaluesList) to BusinessEventsServiceImpl.

  • BusinessEventsServiceImpl calls the processResults(eventsvaluesList) in BusinessEventsHelper to retrieve a list of events values based on the eventsvaluesList.

  • BusinessEventsHelper provides the list of events values (eventsvaluesList) to BusinessEventsServiceImpl.

  • BusinessEventsServiceImpl formats the eventsValues and returns them to BusinessEventsService.

  • BusinessEventsService returns the formatted eventsValues to BusinessEventsServiceController.

  • BusinessEventsServiceController returns the formatted eventsValues to the Client.

7.7.2. Endpoint

Description

This endpoint allows users with the appropriate permissions to retrieve events values based on specified criteria for a given contract UUID. URL:

/events/values/{contractuuid}

Method

GET

Request filter parameters

Parameters

Type

Required

Description

contractUUID

UUID

Yes

The UUID of an existing contract to be executed.

Responses

  • 200 OK: Success. Returns a JSON response containing details events.

Example response body

{
    "status": 200,
    "message": "Success",
    "data": [
        {
            "eventID": "7e3f7983-5911-47df-8e67-2d01d46074e2",
            "eventTime": "2022-12-21T06:30:00",
            "eventType": "IP",
            "eventBody": {
                "contractUpdate": {
                    "terms": [
                        {
                            "term": "notionalPrincipal",
                            "value": 50000.0,
                            "operation": "fix",
                            "fixingDays": ""
                        },
                        {
                            "term": "accruedInterest",
                            "value": 0.0,
                            "operation": "fix",
                            "fixingDays": ""
                        },
                        {
                            "term": "feeAccrued",
                            "value": 0.0,
                            "operation": "fix",
                            "fixingDays": ""
                        }
                    ],
                    "contractUUID": "7b1db647-8de5-4c4c-b279-4405c080dc6f"
                }
            },
            "status": "pending",
            "executionType": "contractUpdate",
            "value": 0.0,
            "remainingValue": 0.0,
            "creditPaymentChannelID": "6d484e24-627d-4579-8d61-f6c3107f9eb9",
            "debitPaymentChannelID": "13c3861e-bcc6-48ed-9db1-91cb6825328a",
            "userID": "902375cc-4f72-428f-8db0-95a7baa69b51",
            "contractUUID": "7b1db647-8de5-4c4c-b279-4405c080dc6f",
            "contractID": "a73ebd1f-35e8-4adc-876b-034b92d7098c",
            "units": "CHF"
        }
  ]
}
  • 400 Bad Request: If the request body is not in the correct format or if there are validation errors. Example

{
    "status": 400,
    "message": "The request could not be understood by the server due to malformed syntax.",
    "data": null
}
  • 401 Unauthorized: If the user is not authenticated or lacks the necessary permissions to create contracts.

  • 5xx Server Error: If there is a server-side error while processing the request.

7.7.3. Methods

Description

The getEventsValues method retrieves a list of BusinessEventsValues based on the provided contractuuid.

Returns

  • <List<TreeMap<String, String>>>> : A list of BusinessEventsValues matching with the contractuuid.

Example usage:

public List<TreeMap<String, String>> getEventsValue(UUID contractuuid) {

		Contracts contracts = validator.validateContractUUID(contractuuid);  (1)

		// Call the repository implementation to fetch event values based on the
		// provided contract UUID
		List<Object[]> resultList = eventsRepo.getEventValues(contracts); (2)

		// Delegate the processing of the results to a helper method and return the
		// processed data
		return businessEventsHelper.processResults(resultList); (3)
	}

Internal workflow:

1 Validate the contract UUID using validator.validateContractUUID(contractuuid). If the validation fails, an exception may be thrown.
2 Retrieve event values using eventsRepo.getEventValues(contracts) from the repository. This may involve querying the database for events associated with the specified contract.
3 Delegate the processing of the results to a helper method (businessEventsHelper.processResults(resultList)) and return the processed data.
  • This method processes a list of Object arrays containing event data and organizes it into a list of TreeMap entries.

  • Iterate over each Object array obj in the resultList.

  • Extract eventTime, eventType, remainingAmount, value, and eventId from each obj.

  • Check if eventMap is null or if the current eventTime is different from the one in eventMap.

  • If true, create a new eventMap, add it to eventsList, and set the "eventTime" key.

  • Based on the eventType ("IP" or "PR"), add the corresponding keys and values to eventMap.

  • Repeat steps 4 and 5 for each obj in resultList.

  • Return the eventsList containing TreeMap entries.

Exceptions

If the contract UUID is invalid or does not exist, an IllegalArgumentException is thrown with the message "Invalid contractUUID".

7.7.4. Testing

Description

This test method, getEventsValueTest, verifies the functionality of the getEventsValue method within the EventsServiceImpl class. It ensures that the method correctly retrieves and processes event values associated with a given contract.

Test methods

Example usage

    @Test
	void getEventsValueTest() { (1)
		UUID contractUUID = UUID.randomUUID();
		UUID ipEventId = UUID.randomUUID();
		UUID prEventId = UUID.randomUUID();

		contract = new Contracts();
		contract.setContractUUID(contractUUID);

		List<Object[]> resultList = new ArrayList<>();
		resultList.add(new Object[] { "2023-06-20", "IP", 100.0, 100.0, ipEventId });
		resultList.add(new Object[] { "2023-06-20", "PR", 500.0, 500.0, prEventId });

		when(eventsRepo.getEventValues(contract)).thenReturn(resultList);
		when(contractsRepo.findById(contractUUID)).thenReturn(Optional.of(contract));

		List<TreeMap<String, String>> eventsValue = eventsServiceImpl.getEventsValue(contractUUID);

		TreeMap<String, String> eventMap = eventsValue.get(0);

		Assertions.assertEquals("2023-06-20", eventMap.get("eventTime"));
		Assertions.assertEquals(ipEventId.toString(), eventMap.get("ipEventId"));
		Assertions.assertEquals("IP", eventMap.get("ipEventType"));
		Assertions.assertEquals("100.0", eventMap.get("ipValue"));

		Assertions.assertEquals(prEventId.toString(), eventMap.get("prEventId"));
		Assertions.assertEquals("PR", eventMap.get("prEventType"));
		Assertions.assertEquals("500.0", eventMap.get("prValue"));

	}
1 getEventsValueTest
  • Purpose : The purpose of this test is to validate that the getEventsValue method accurately retrieves event values for a specified contract from the repository and organizes them into a structured format for further processing.

  • Test steps

    1. Generate random UUIDs for the contract, IP event, and PR event.

    2. Create a mock contract object and set its UUID to the generated contract UUID.

    3. Prepare a list of object arrays representing event values including event time, event type, event value, and event IDs.

    4. Stub the behavior of the eventsRepo mock to return the prepared list when getEventValues is invoked with the mock contract.

    5. Stub the behavior of the contractsRepo mock to return the mock contract when findById is invoked with the contract UUID.

    6. Invoke the getEventsValue method of the EventsServiceImpl class with the contract UUID.

    7. Retrieve the resulting list of event values.

    8. Extract and store the event values in a structured format for validation.

  • Assertions

    • Assert that the event values retrieved for the IP event match the expected values, including event time, event type, and event value.

    • Assert that the event values retrieved for the PR event match the expected values, including event time, event type, and event value.

    • Ensure that the event IDs associated with each event are correctly included in the structured format.

Payment channels

1. Introduction

The payment endpoints allows adding new and managing existing payments to each profile.

2. Tables and relations

Establishing relationships

  • In relational databases like PostgreSQL, relationships between tables are crucial for organizing and querying data effectively. These relationships are typically established using foreign key constraints, which define links between tables based on the values of specific columns. Common types of relationships include one-to-one, one-to-many, and many-to-many relationships, each serving different data modeling needs.

payments ERD
Figure 11. Payment channel entity-relationship diagram

Tables

  • Schema:

Payment Channels

  1. Table payment_channels

    Idx Name Data Type

    * πŸ”‘ ⬋

    payment_channelid

    uuid

    contractid

    uuid

    details

    json

    *

    identifier

    varchar(100)

    label

    varchar(100)

    *

    type

    varchar(50)

    * πŸ”Ž

    owner_type

    varchar(10)

    *

    units

    varchar(10)

    *

    system

    varchar(50)

    account_characteristic

    varchar(50)

    * πŸ”Ž

    ownerid

    uuid

    * πŸ”Ž

    userid

    uuid

    • Indexes

      Type Name On

      πŸ”Ž

      payment_channels_idx_owner_type_owner_id

      ON owner_type, ownerid

      πŸ”‘

      payment_channels_pkey

      ON payment_channelid

      πŸ”Ž

      payment_channels_idx_payment_channel_id_owner_id

      ON payment_channelid, ownerid

      πŸ”Ž

      payment_channels_idx_owner_type_user_id

      ON owner_type, userid

    • Constraints

    Name Definition

    payment_channels_owner_type_check

    owner_type::text ~* '^(root/profile)$'::text

  2. Table profile_forms

    Idx Name Data Type

    * πŸ”‘ ⬋

    profile_formid

    bigint GENERATED BY DEFAULT AS IDENTITY

    *

    profile_form_details

    json

    *

    userid

    uuid

    • Indexes

    Type Name On

    πŸ”‘

    profile_forms_pkey

    ON profile_formid

  3. Table profiles

    Idx Name Data Type

    * πŸ”‘ ⬋

    profileid

    uuid

    profile_details

    json

    *

    status

    varchar(10)

    *

    userid

    uuid

    * ⬈

    profile_formid

    bigint

    • Indexes

      Type Name On

      πŸ”‘

      profiles_pkey

      ON profileid

    • Foreign Keys

      Type Name On

      fk_profiles_profile_forms_profile_formid

      profile_formid

    • Constraints

      Name Definition

      profiles_status_check

      status::text ~* '^(active/inactive)$'::text

3. Dependencies and libraries

3.1. Dependencies

Description:

The following dependencies are used in the project to provide various functionalities and features:

  1. spring-kafka

    • Purpose: Spring for Apache Kafka for building Kafka-based messaging systems.

    • Usage: Producing and consuming messages from Kafka topics.

  2. *spring-cloud-starter-openfeign *

    • Purpose: The spring-cloud-starter-openfeign dependency is used in Spring Boot applications to simplify the process of creating REST clients. It integrates the Feign client library into your application, providing a declarative way to define RESTful service clients.

    • Usage: Use spring-cloud-starter-openfeign to define interfaces for RESTful services and easily make HTTP requests to those services. Feign handles the creation of the HTTP request and mapping of the response to Java objects, reducing the boilerplate code typically required for REST client implementations.

  3. *iban4j *

    • Purpose: The iban4j library provides utilities for working with International Bank Account Numbers (IBANs). It offers functionality for validation, generation, and manipulation of IBANs according to the IBAN standard.

    • Usage: Include the iban4j dependency in your project to leverage its features for handling IBANs. You can use it to validate IBANs, generate new IBANs, extract information from IBANs, and perform other operations related to IBANs in your Java applications.

  4. spring-boot-starter-actuator

    • Purpose: The spring-boot-starter-actuator dependency provides monitoring and management capabilities to Spring Boot applications. It includes various built-in endpoints for monitoring application health, metrics, environment details, and more.

    • Usage: Include the spring-boot-starter-actuator dependency in your Spring Boot project to enable monitoring and management features. This allows you to easily monitor the health and performance of your application, gather metrics, and access useful information about the application environment. You can configure and customize these endpoints according to your requirements.

  5. gson

    • Purpose: The gson dependency provides support for JSON serialization and deserialization in Java applications. It allows you to convert Java objects to JSON format and vice versa, making it easy to work with JSON data in your Java applications.

    • Usage: Include the gson dependency in your project to use Gson’s functionality for handling JSON data. You can use Gson’s APIs to parse JSON strings into Java objects, serialize Java objects to JSON strings, and perform various operations on JSON data. This library is commonly used in Java projects to interact with RESTful APIs, process JSON data from web services, and more.

  6. blockcypher

    • Purpose: The blockcypher dependency provides Java bindings for interacting with the BlockCypher API. BlockCypher is a blockchain web services provider that offers APIs for accessing blockchain data, creating transactions, managing wallets, and more. This dependency allows Java applications to integrate with the BlockCypher API and perform various blockchain-related operations.

    • Usage: Include the blockcypher dependency in your project to use the Java bindings provided by BlockCypher. You can use these bindings to make API calls to BlockCypher’s endpoints, such as retrieving blockchain data, creating transactions, and managing wallet addresses. This library is useful for developers building applications that interact with blockchain technology, such as cryptocurrency wallets, blockchain explorers, and decentralized applications (dApps).

  7. Blockcypher_1.0

    • Purpose: The Blockcypher_1.0 dependency provides Java bindings for interacting with the BlockCypher API. BlockCypher is a blockchain web services provider that offers APIs for accessing blockchain data, creating transactions, managing wallets, and more. This dependency enables Java applications to integrate with the BlockCypher API and perform various blockchain-related operations.

    • Usage: Include the Blockcypher_1.0 dependency in your project to utilize the Java bindings provided by BlockCypher. These bindings allow you to make API calls to BlockCypher’s endpoints, such as retrieving blockchain data, creating transactions, and managing wallet addresses. Developers can leverage this library to build applications that interact with blockchain technology, including cryptocurrency wallets, blockchain explorers, and decentralized applications (dApps).

  8. javafaker

    • Purpose: The javafaker dependency provides a Java library for generating fake data. It allows developers to create realistic-looking test data for various purposes, such as testing, prototyping, and generating sample data for demonstrations. javafaker offers a wide range of data types and categories, including names, addresses, phone numbers, internet-related data, dates, and more.

    • Usage: Include the javafaker dependency in your project to access its functionality for generating fake data. You can use the Faker class provided by the library to create instances of fake data objects. Then, you can call methods on these objects to generate specific types of fake data, tailored to your requirements. This library is particularly useful for writing unit tests that require realistic test data or for populating databases with sample data during development.

  9. json

    • Purpose: The json dependency provides a Java library for working with JSON (JavaScript Object Notation) data. It allows developers to parse JSON strings into Java objects, serialize Java objects into JSON strings, manipulate JSON data structures, and perform various operations on JSON data.

    • Usage: Include the json dependency in your project to leverage its functionality for JSON processing. You can use classes like JSONObject and JSONArray provided by the library to create, parse, and manipulate JSON objects and arrays. This library is commonly used in Java applications that interact with APIs, handle JSON-based data exchanges, or store configuration data in JSON format.

  • Dependency versions are specified to ensure compatibility and stability.

  • Additional dependencies may be added or removed based on project requirements and architecture.

3.2. Libraries

Description

The following libraries are used in the project to provide various functionalities and features:

  1. actus-core (version 1.0.1)

    • Purpose: The actus-core library provides core functionality and utilities for working with financial contracts and cash flow projections based on the ACTUS standard.

    • Usage: Use to perform calculations, projections, and analysis of financial contracts and cash flows according to the ACTUS (Algorithmic Contract Types Unified Standards) standard.

4. Exception handling: RestExceptionHandler Class

Description

The RestExceptionHandler class is responsible for handling various exceptions that may occur during the execution of RESTful API endpoints. It provides centralized exception handling to ensure consistent error responses across the application.

Exception handlers

Example usage

@ControllerAdvice
public class RestExceptionHandeler {

	@ExceptionHandler(PaymentChannelException.class)
	public ResponseEntity<Response<String>> exceptionToDoHandler(Exception ex) { (1)
		final Response<String> error = new Response<>();
		error.setStatus(HttpStatus.NOT_FOUND.value());
		error.setMessage(ex.getMessage());

		return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
	}

	@ExceptionHandler(MethodArgumentNotValidException.class)
	public ResponseEntity<Response<List<String>>> handleValidationException(MethodArgumentNotValidException ex) { (2)
		BindingResult bindingResult = ex.getBindingResult();
		List<FieldError> fieldErrors = bindingResult.getFieldErrors();

		List<String> errorMessages = fieldErrors.stream()
				.map(fieldError -> fieldError.getField() + ": " + fieldError.getDefaultMessage()).toList();

		final Response<List<String>> error = new Response<>();
		error.setStatus(HttpStatus.BAD_REQUEST.value());
		error.setMessage(errorMessages.toString());

		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

	@ExceptionHandler(Exception.class)
	public ResponseEntity<Response<String>> exceptionHandler(Exception ex) { (3)
		final Response<String> error = new Response<>();
		error.setStatus(HttpStatus.BAD_REQUEST.value());
		error.setMessage(ex.getMessage());

		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}
1 PaymentChannelException handler
  • Handles exceptions of type PaymentChannelException.

  • Returns a ResponseEntity with a status code of 404 Not Found and an error message derived from the exception’s message.

2 MethodArgumentNotValidException handle
  • Handles exceptions of type MethodArgumentNotValidException.

  • Collects error messages from field errors and constructs a response containing these messages along with a status code of 400 Bad Request.

3 Generic exception handler
  • Handles any other uncaught exceptions that may occur during the execution of API endpoints.

  • Returns a ResponseEntity with a status code of 400 Bad Request and a generic error message derived from the exception’s message.

Customization

  • Additional exception handlers can be added to address specific use cases or domain-specific exceptions.

  • Error messages and status codes can be customized based on application requirements and error scenarios.

6. API

7. PaymentChannelController

7.1. Create new user payment channel

7.1.1. Sequential flow

create new user payment channel.puml
Figure 12. create new user payment channel

Create new user payment channel flow:

  • The client initiates the creation of a payment channel by sending data to the PaymentChannelController.

  • The PaymentChannelController activates and calls the createPaymentChannel method of PaymentChannelService, passing the payment channel data.

  • Inside PaymentChannelService, the createPaymentChannel method activates and calls the createBlockCypherMap method of PaymentWorker, passing the units of the payment channel.

  • PaymentWorker activates and calls the createBlockCypherMap method of PaymentChannelHelper, passing the units.

  • Based on the units, if it’s Ethereum (ETH) or Bitcoin (BTC), the corresponding configurations are used to create the address.

  • If the units are neither Ethereum nor Bitcoin, the IBAN address is created using the IBANService.

  • After creating the address, the PaymentChannelHelper creates a BlockCypher map and returns it to PaymentWorker.

  • PaymentWorker returns the BlockCypher map to PaymentChannelService.

  • PaymentChannelService then validates the payment channel data using the Validator.

  • The Validator checks if the payment channel identifier already exists and if the BlockCypher map is empty in case of an IBAN address.

  • If the validation passes, PaymentChannelService sets the payment channel details using the PaymentChannelHelper.

  • PaymentChannelHelper fetches the user ID and checks if the identifier and label are not empty.

  • If the identifier and label are not empty, a new payment channel is created and saved. Otherwise, an error message is returned.

  • The saved payment channels are returned to the client in a response object.

7.1.2. Endpoint

Description

This endpoint allows users to creates a new user payment channel

URL

/payments/channel/new

Method

POST

Request body

The request body should be a JSON object representing data for creating a new root user payment channel. It should adhere to the structure defined by the UserPaymentChannelDTO class.

Example request body
 {
  "units": "ETH",
  "identifier": "Jeo",
  "label": "Saving A/C",
  "accountCharacteristic": "isBank"
}
Responses
  • 201 CREATED: Success. Returns a JSON response containing details of the created OPS events.

Example response body
{
  "status": 201,
  "message": "Payment channel created successfully",
  "data": {
    "paymentChannelID": "ee3101b0-203d-4421-aacd-77c9e10b5550",
    "contractID": "56edde65-804e-429c-bf89-7141bf431b20",
    "label": "Saving A/C",
    "type": "new",
    "units": "ETH",
    "system": "Ethereum",
    "accountCharacteristic": "isBank",
    "identifier": "Jeo",
    "details": {
      "system": "Ethereum",
      "address": "a65f8d5d18b58fff7b2082c5209c20de28955cb6",
      "accessKey": {
        "private": "304d8c356619cbc9887f305e615359b8f55f0abd9ce7e48e0bebf871f664be88",
        "public": "04cbeb23499afdad2eda545f38cd178e71ddd52f7ec746060a3c2eb88f8628ac7ba1130531dbb9f5f0c1d371c176f375219de3385368cad93643827ed986d355a9"
      }
    },
    "ownerType": "root",
    "ownerID": "fe54273e-c645-49f5-9279-ad6d4067c606",
    "userID": "fe54273e-c645-49f5-9279-ad6d4067c606"
  }
}
  • 400 bad request: If the request body is not in the correct format or if there are validation errors.

{
  "status": 400,
  "message": "Identifier already exists",
  "data": null
}
  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to create contracts.

  • 5xx server error: If there is a server-side error while processing the request.

7.1.3. Methods

Description

This method creates a new payment channel using BlockCypher, validates the data, and saves it, returning a response with the created payment channel’s details

Parameters
  • paymentChannelData: Data representing the payment channel to be created.

Returns
  • Response<PaymentChannels>: A Response object containing the status and the created payment channel.

Example usage
public Response<PaymentChannels> createPaymentChannel(UserPaymentChannelDTO paymentChannelData)
			throws IOException, ParseException, BlockCypherException {
		log.info("userID : {}, request : {}", usersHelper.getUserID(), paymentChannelData);

		final String type = "new"; (1)

		Map<String, Object> blockcyperMap = paymentWorker.createBlockCypherMap(paymentChannelData.getUnits()); (2)

		validator.paymentChannelValidation(paymentChannelData, blockcyperMap); (3)

		PaymentChannels paymentChannels = paymentChannelHelper.setPaymentChannel(paymentChannelData, blockcyperMap,
				type); (4)

		paymentsRepo.save(paymentChannels); (5)

		return new Response<>(HttpStatus.CREATED.value(), "Payment channel created successfully", paymentChannels); (6)
	}
Internal workflow
1 Determining Operation Type
  • It determines the type of operation, which is set as "new".

2 Creating BlockCypher Map
  • The method calls paymentWorker.createBlockCypherMap() to create a BlockCypher map based on the units specified in the payment channel data.

3 Validating Payment Channel Data
  • The payment channel data and the BlockCypher map are validated using the validator.paymentChannelValidation() method.

4 Setting Payment Channel Details
  • If the validation passes, the paymentChannelHelper.setPaymentChannel() method is invoked to set the payment channel details.

5 Saving Payment Channel
  • The newly created payment channel is saved using the paymentsRepo.save() method.

6 Returning Response
  • Finally, a Response object containing the status and the created payment channel is returned.

Exceptions

IOException: If there’s an I/O related issue during the process.

ParseException: If there’s an issue parsing data.

BlockCypherException: If there’s an exception related to BlockCypher operations.

7.1.4. Model classes

Description

The UserPaymentChannelDTO class represents a Data Transfer Object (DTO) containing details for creating a payment channel. It encapsulates information such as units, identifier, label, and accountCharacteristic.

Attributes
  1. units (String)

    • Description: The units associated with the payment channel.

    • Constraints: Not null, not blank, maximum 10 characters.

    • Example: "USD"

  2. identifier (String)

    • Description: The identifier associated with the payment channel.

    • Constraints: Maximum 100 characters.

    • Example: "CHN12345"

  3. label (String)

    • Description: The label associated with the payment channel.

    • Constraints: Maximum 100 characters.

    • Example: "Primary Channel"

  4. accountCharacteristic (String)

    • Description: The account characteristic associated with the payment channel.

    • Constraints: Not null, not blank, maximum 50 characters.

    • Example: "Savings Account"

Constructors
  • Default constructor.

  • Parameterized constructor with all attributes.

Serialization and Deserialization
  • The class uses Lombok annotations @Getter, @Setter, @NoArgsConstructor, @AllArgsConstructor, and @ToString for serialization and deserialization. These annotations generate getter and setter methods, default and parameterized constructors, and a toString method for the class.

7.1.5. Testing

Description

The createNewRootUserPaymentChannel method tests the functionality of creating a new root user payment channel using the createPaymentChannel method in the PaymentChannelServiceImpl class. This test ensures that the payment channel is successfully created with the provided template.

Test methods

Example usage

    @Test
	public void createNewRootUserPaymentChannel() throws IOException, ParseException, BlockCypherException {

		Response<PaymentChannels> createPaymentChannelResponse = paymentChannelServiceImpl
				.createPaymentChannel(rootUserPaymentChannelTemplate);

		PaymentChannels data = createPaymentChannelResponse.getData();
		UUID paymentChannelID = data.getPaymentChannelID();

		Assertions.assertEquals(paymentChannelsTemplate.get(0).getPaymentChannelID(), paymentChannelID);
		Assertions.assertEquals("Payment channel created successfully", createPaymentChannelResponse.getMessage());
		Assertions.assertEquals(201, createPaymentChannelResponse.getStatus());

	}

createNewRootUserPaymentChannel

  • Purpose : The purpose of this test is to verify that the createPaymentChannel method correctly creates a new payment channel for the root user based on the provided template and returns the expected response.

  • Test steps

    1. Call the createPaymentChannel method of the PaymentChannelServiceImpl class with the rootUserPaymentChannelTemplate.

    2. Retrieve the response object returned by the method.

    3. Extract the payment channel data from the response.

    4. Retrieve the payment channel ID from the data.

  • Assertions

    • Assert that the payment channel ID matches the expected payment channel ID.

    • Assert that the message in the response indicates successful creation of the payment channel.

    • Assert that the status code of the response is 201.

7.2. Create serviced and external user payment channel

7.2.1. Sequential flow

Creates serviced and external user payment channel flow.puml
Figure 13. creates serviced and external user payment channel

Creates serviced and external user payment channel flow

Client interaction

  • The client initiates the creation of a payment channel by calling the createserviceMethod(paymentChannelData) method on the PaymentChannelController.

Payment channel controller

  • The request from the client activates the PaymentChannelController.

  • It forwards the request to PaymentChannelServiceImpl by calling the createServicePaymentChannel(paymentChannelData) method.

Payment channel service implementation (ServiceImpl)

  • The PaymentChannelServiceImpl is activated.

  • It begins by validating the identifier with the help of the Validator.

  • The validation includes checking if the identifier is unique by querying the PaymentChannelRepository.

  • If the identifier is not unique, an IllegalArgumentException is thrown back to the client.

  • If validation passes, it continues to the next step.

Validator

  • It performs validation checks on the identifier.

  • If the identifier is unique, validation continues; otherwise, an exception is thrown back to the client.

Payment worker

  • If the payment channel type is 'serviced', the PaymentWorker is activated to check the final balance.

  • Otherwise, it proceeds to the next step without checking the final balance.

Payment channel helper

  • If the payment channel type is 'external', the PaymentChannelHelper is activated.

  • It determines the payment system (e.g., Ethereum, Bitcoin) based on the provided units.

  • Depending on the determined system, it proceeds accordingly.

Setting payment channel attributes

  • The PaymentChannelHelper sets various attributes for the payment channel.

  • It retrieves beneficiary name and address from ServicedAndExternalDTO.

  • It sets attributes in a map and creates a new PaymentChannels instance.

  • Attributes are set based on various data sources including paymentChannelMap, paymentChannelData, and user information obtained via UsersHelper.

Contract creation

  • The PaymentChannelHelper interacts with ContractsFeignClient to create payment contracts.

  • It posts payment information using obtained access token from UsersHelper.

Response generation

  • It generates a response indicating the success of the payment channel creation along with the created payment channel information.

persistence

  • Finally, the created payment channels are saved into the repository via PaymentChannelRepository.

Return response

The response indicating the success of the operation is returned back to the client through the PaymentChannelController.

7.2.2. Endpoint

Description

This endpoint enables the creation of serviced and external user payment channels. Users can provide the necessary data in a POST request, which undergoes validation, processing, and storage in the database.

URL

/payments/channel

Method

POST

Request body

The request body should be a JSON object conforming to the structure defined by the ServicedAndExternalDTO model class.

Example request body
{
  "type": "serviced",
  "identifier": "David007",
  "label": "ser",
  "units": "BTC",
  "accountCharacteristic": "isCash",
  "address": "BvdK6pQghtwMvzfLtZjXT7brAh83JDyi76",
  "beneficiaryName": "danial",
  "beneficiaryAddress": "UK",
  "accessKey": {
    "private": "b44f71aeefbe25b07b4a14ae63a0922aa2d6874906628d7a457f39e4e96c70d8",
    "public": "0270198cf386036bc186f8261045c1f8bc241cffd5858ca977ba62cbeeb6fe5b40",
    "address": "BvdK6pQghtwMvzfLtZjXT7brAh83JDyi76"
  }
}
Responses
  • 201 CREATED: Successful creation of the payment channel. Returns a JSON response with details of the created payment channel.

Example response body
{
  "status": 201,
  "message": "Payment channel created successfully",
  "data": {
    "paymentChannelID": "69684901-a129-49a3-a8b8-12b8697b894f",
    "contractID": "42febae4-4ea4-4e9a-b9ca-e2c2a29d0a63",
    "label": "ser",
    "type": "serviced",
    "units": "BTC",
    "system": "Bitcoin",
    "accountCharacteristic": "isCash",
    "identifier": "David007",
    "details": {
      "accessKey": {
        "private": "b44f71aeefbe25b07b4a14ae63a0922aa2d6874906628d7a457f39e4e96c70d8",
        "address": "BvdK6pQghtwMvzfLtZjXT7brAh83JDyi76",
        "public": "0270198cf386036bc186f8261045c1f8bc241cffd5858ca977ba62cbeeb6fe5b40"
      },
      "address": "BvdK6pQghtwMvzfLtZjXT7brAh83JDyi76",
      "identifier": "David007",
      "label": "ser",
      "type": "serviced",
      "units": "BTC",
      "accountCharacteristic": "isCash",
      "beneficiary": {
        "beneficiaryName": "danial",
        "beneficiaryAddress": "UK"
      },
      "system": "Bitcoin"
    },
    "ownerType": "root",
    "ownerID": "fe54273e-c645-49f5-9279-ad6d4067c606",
    "userID": "fe54273e-c645-49f5-9279-ad6d4067c606"
  }
}
  • 400 bad request: If the request body is not in the correct format or if there are validation errors.

{
  "status": 400,
  "message": "Identifier already exists",
  "data": null
}
  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to create contracts.

  • 5xx server error: If there is a server-side error while processing the request.

7.2.3. Methods

Description

This method creates a payment channel based on the provided data. It handles both serviced and external payment channels.

Parameters
  • paymentChannelData: Data representing the payment channel to be created

Returns
  • Response<PaymentChannels>: A response object indicating the status and the created payment channel.

Example usage
public Response<PaymentChannels> createServicePaymentChannel(ServicedAndExternalDTO paymentChannelData)
			throws ParseException, IOException, BlockCypherException {
		log.info("Service payment channel creation started by userID : {}, request : {}", usersHelper.getUserID(),
				paymentChannelData);

		Map<String, Object> paymentChannelMap = mapper.convertValue(paymentChannelData, Map.class); (1)

		double finalBalance = 0; (2)
		String system;
		String type;

		validator.identifierValidation(usersHelper.getUserID(), paymentChannelMap); (3)

		if (paymentChannelData.getType().equalsIgnoreCase("serviced")) { (4)
			type = "serviced";

			// Extract and parse the access key information
			JSONObject parse2 = paymentChannelData.getAccessKey();
			paymentChannelMap.put("accessKey", parse2);

			// Determine the payment system (e.g., Ethereum or Bitcoin)
			system = paymentChannelData.getUnits().equalsIgnoreCase("ETH") ? "Ethereum" : "Bitcoin";
			finalBalance = paymentWorker.checkFinalBalance(paymentChannelData.getAddress(), system, jsonParser);

		} else {

			type = "external";
			// Determine the payment system based on the provided data
			system = paymentChannelHelper.getSystem(paymentChannelData.getUnits());
		}

		PaymentChannels paymentChannels1 = paymentChannelHelper.setExternalServicePaymentChannel(paymentChannelData,
				paymentChannelMap, system, finalBalance, type); (5)

		paymentChannels1 = paymentsRepo.save(paymentChannels1); (6)

		return new Response<>(HttpStatus.CREATED.value(), "Payment channel created successfully", paymentChannels1); (7)
	}
Internal workflow
1 Data conversion
  • The paymentChannelData object is converted into a Map<String, Object>.

2 Variable initialization
  • Variables such as finalBalance, system, and type are initialized.

  • Identifier validation (identifierValidation)

    1. Retrieves a list of payment channels based on the owner ID and identifier.

    2. Ensures that the identifier is unique by checking if the list is empty.

    3. If the payment channel type is 'Serviced', additional validation is performed by calling the servicedValidation method.

  • Serviced Validation (servicedValidation)

    1. Validates that the 'AccessKey' and 'Address' parameters are not null or empty for a serviced payment channel.

    2. Throws an exception if any of these parameters are missing.

3 Identifier validation
  • The user ID and the payment channel map are validated.

4 Payment channel type determination
  • If the payment channel type is "serviced"

    1. Access key information is extracted and parsed.

    2. The payment system (e.g., Ethereum or Bitcoin) is determined.

    3. The final balance of the payment channel is calculated.

  • If the type is "external"

    • Determine payment system

      1. Checks the units parameter to determine the payment system.

      2. If the units is "eth" (case-insensitive), the payment system is set to "Ethereum".

      3. If the units is "btc" (case-insensitive), the payment system is set to "Bitcoin".

      4. If the units is neither "eth" nor "btc", the payment system is set to "IBAN".

5 Payment channel creation
  • The paymentChannelHelper.setExternalServicePaymentChannel() method is called to set the details of the payment channel.

  • Create JSON object

    1. Create a JSON object (jsonObject2) containing beneficiary name and address.

    2. Put beneficiary details into the paymentChannelMap.

    3. Add the payment system (system) to the paymentChannelMap.

    4. Remove redundant fields from the paymentChannelMap.

  • Create Payment Channels Object

    1. Instantiate a new PaymentChannels object (paymentChannels1).

    2. Set details of the payment channel using the provided data and extracted information:

  • Create payments map

    1. Create a new map (paymentsMap) to hold payment information.

    2. Put currency, notional principal (final balance), and account characteristic into the map.

  • Retrieve contract id

    1. Send a POST request to the contract service (contractFeignClient) with payment information.

    2. Extract the contract ID from the response. ..Set the contract ID in the paymentChannels1 object.

6 Saving payment channel
  • The created payment channel is saved using the repository.

7 Response creation:
  • A response object indicating the success of the operation and the created payment channel is returned.

Exceptions

IllegalArgumentException

  • If the identifier is not unique or if the 'Address' and 'AccessKey' parameters are missing for a serviced payment channel.

ParseException

  • If there’s an issue parsing data.

IOException

  • If there’s an I/O related issue during the process.

BlockCypherException

  • If there’s an exception related to BlockCypher operations.

7.2.4. Model classes

Description:

The ServicedAndExternalDTO class represents a Data Transfer Object (DTO) containing details for a service and an external entity. It includes information such as accessKey, address, beneficiaryAddress, beneficiaryName, identifier, label, type, units, and accountCharacteristic.

Attributes
  1. accessKey (JSONObject)

    • Description: The access key associated with the DTO.

    • Constraints: None.

    • Example:

  "accessKey": {
    "private": "b44f71aeefbe25b07b4a14ae63a0922aa2d6874906628d7a457f39e4e96c70d8",
    "public": "0270198cf386036bc186f8261045c1f8bc241cffd5858ca977ba62cbeeb6fe5b40",
    "address": "BvdK6pQghtwMvzfLtZjXT7brAh83JDyi76"
  }
  1. address (String)

    • Description: The address associated with the DTO.

    • Constraints: None.

    • Example: "123 Main Street"

  2. beneficiaryAddress (String)

    • Description: The beneficiary’s address associated with the DTO.

    • Constraints: Not null, not blank.

    • Example: "UK"

  3. beneficiaryName (String)

    • Description: The beneficiary’s name associated with the DTO.

    • Constraints: Not null, not blank.

    • Example: "John Doe"

  4. identifier (String)

    • Description: The identifier associated with the DTO.

    • Constraints: Not null, not blank, maximum 100 characters.

    • Example: "ABC123"

  5. label (String)

    • Description: The label associated with the DTO.

    • Constraints: Not null, not blank, maximum 100 characters.

    • Example: "External Service"

  6. type (String)

    • Description: The type associated with the DTO.

    • Constraints: Not null, not blank, maximum 50 characters.

    • Example: "Service"

  7. units (String)

    • Description: The units associated with the DTO.

    • Constraints: Not null, not blank, maximum 10 characters.

    • Example: "BTC"

  8. accountCharacteristic (String)

    • Description: The account characteristic associated with the DTO.

    • Constraints: None.

    • Example: "Regular Account"

Constructors
  • Default constructor.

  • Parameterized constructor with all attributes.

Serialization and Deserialization
  • The class uses Lombok annotations @Getter, @Setter, @NoArgsConstructor, @AllArgsConstructor, and @ToString for serialization and deserialization. These annotations generate getter and setter methods, default and parameterized constructors, and a toString method for the class.

7.2.5. Testing

Description

The createServiceExternalRootUserPaymentChannel test method evaluates the functionality of the createServicePaymentChannel method within the PaymentChannelServiceImpl class. This test ensures that the method correctly creates a service payment channel with an external root user.

Test methods

Example usage

 @Test
	public void createServiceExternalRootUserPaymentChannel() throws IOException, ParseException, BlockCypherException {

		when(paymentsRepo.save(any())).thenReturn(paymentChannelsTemplate.get(0));
		Response<PaymentChannels> createServiceExternalPaymentChannelResponse = paymentChannelServiceImpl
				.createServicePaymentChannel(servicedAndExternalTemplate);
		PaymentChannels data = createServiceExternalPaymentChannelResponse.getData();
		UUID paymentChannelID = data.getPaymentChannelID();

		Assertions.assertEquals(paymentChannelsTemplate.get(0).getPaymentChannelID(), paymentChannelID);
		Assertions.assertEquals("Payment channel created successfully",
				createServiceExternalPaymentChannelResponse.getMessage());
		Assertions.assertEquals(201, createServiceExternalPaymentChannelResponse.getStatus());

	}

createServiceExternalRootUserPaymentChannel

  • Purpose : The purpose of this test is to verify that the createServicePaymentChannel method behaves as expected, creating a new payment channel with the specified service and external root user template and returning the appropriate response.

  • Test steps

    1. Stub the behavior of the repository to return the first payment channel template when the save method is called.

    2. Call the createServicePaymentChannel method of the PaymentChannelServiceImpl class with the serviced and external template.

    3. Retrieve the response object returned by the method.

    4. Extract the payment channel data from the response.

    5. Retrieve the payment channel ID from the data.

  • Assertions

    • Assert that the created payment channel ID matches the expected payment channel ID.

    • Assert that the message in the response indicates successful creation of the payment channel.

    • Assert that the status code of the response is 201.

7.3. Create profile payment channel

7.3.1. Sequential flow

create profile payment channel.puml
Figure 14. Creates profile payment channel

Create profile payment channel flow

Client interaction

  • The client initiates a POST request to create a new payment channel for a specific profile ID.

PaymentChannelController activation

  • The PaymentChannelController is activated to handle the incoming request.

Service layer interaction

  • The PaymentChannelController communicates with the PaymentChannelService to process the request.

PaymentChannelService processing

  • The PaymentChannelService, specifically its implementation (PaymentChannelServiceImpl), takes over the processing of creating the payment channel for the specified profile ID.

  • It involves various validations and operations.

Profile validation

  • The service checks if the specified profile ID exists in the database.

  • If the profile exists, it proceeds with further validations; otherwise, it returns an error stating that the profile doesn’t exist.

Identifier validation

  • Checks whether the provided identifier for the payment channel is valid and unique within the scope of the owner’s payment channels.

Additional balidation based on payment channel type

  • Depending on the type of payment channel (e.g., 'serviced'), additional validations are performed.

  • For serviced channels, it checks for the presence of necessary parameters like access key and address.

BlockCypher map creation

  • After validation, the service creates a BlockCypher map based on the type of units (e.g., ETH, BTC, or others). ` PaymentChannelHelper operations`

  • PaymentChannelHelper assists in creating BlockCypher maps and addresses, depending on the units specified.

PaymentWorker interaction

  • The PaymentWorker is involved in creating the BlockCypher map and handling the specifics of each payment unit (ETH, BTC, or others).

Finalization and persistence

  • After creating the BlockCypher map and performing necessary operations, the service sets up the profile payment channel with the obtained information.

  • The profile payment channel data is then saved in the PaymentChannelRepository.

Response preparation

  • Finally, a response is prepared to indicate the success of the operation, including the newly created payment channel information.

Response sending

  • The response is sent back to the PaymentChannelController.

Client Response

  • The PaymentChannelController sends a response entity back to the client, containing the response from the service.

7.3.2. Endpoint

Description

This endpoint facilitates the creation of profile payment channels. Users can provide the required data via a POST request, which is then validated, processed, and stored in the database.

URL

/payments/channel/profiles/{profileID}/new

Method

POST

Request parameters

profileID (Path variable): The unique identifier of the profile for which the payment channel is created.

Request body

paymentChannelData (Request Body): A JSON object containing data for creating a payment channel. It follows the structure defined in the ProfileChannelDto class.

Example request body
{
  "identifier": "David",
  "label": "Saving A/C",
  "units": "INR",
  "type": "new",
  "system": "IBAN"
}
Responses
  • 201 CREATED: Successful creation of the profile payment channel. Returns a JSON response with details of the created payment channel.

Example response body
{
  "status": 201,
  "message": "Payment channel created successfully",
  "data": {
    "paymentChannelID": "a28855a8-6581-4b7e-9096-b47e87e70353",
    "contractID": null,
    "label": "Saving A/C",
    "type": "new",
    "units": "INR",
    "system": "IBAN",
    "accountCharacteristic": null,
    "identifier": "mmmmm",
    "details": {
      "address": "CH7500762QUVXZNF1PP8S",
      "system": "IBAN"
    },
    "ownerType": "profile",
    "ownerID": "d2c87ded-489e-4510-8fe1-95f12c048a5d",
    "userID": "fe54273e-c645-49f5-9279-ad6d4067c606"
  }
}
  • 400 bad request: If the request body is not in the correct format or if there are validation errors.

{
  "status": 400,
  "message": "Identifier already exists",
  "data": null
}
  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to create profile payment channels.

  • 5xx server error: If there is a server-side error while processing the request.

7.3.3. Methods

Description

This method creates a new payment channel associated with a user profile.

Parameters
  • profileID: The unique identifier of the user profile.

  • paymentChannelData: Data representing the profile payment channel.

    • identifier: A unique identifier for the payment channel (maximum 100 characters).

    • label: A label for the payment channel (maximum 100 characters).

    • type: The type of the payment channel.

    • units: The units of currency used in the payment channel (maximum 10 characters).

    • system: The payment system associated with the payment channel (maximum 50 characters).

Returns
  • A response object containing the status and the created payment channel.

Example usage
public Response<PaymentChannels> createProfilePaymentChannel(UUID profileID, ProfileChannelDto paymentChannelData)
			throws IOException, ParseException, BlockCypherException {
		log.info("Profile payment channel creation started by userID : {}, request : {}", usersHelper.getUserID(),
				paymentChannelData);

		final String type = "new"; (1)

		Map<String, Object> paymentChannelMap = mapper.convertValue(paymentChannelData, Map.class); (2)

		validator.profilePaymentChannelValidation(profileID, paymentChannelMap, profileID); (3)

		Map<String, Object> blockcyperMap = paymentWorker.createBlockCypherMap(paymentChannelData.getUnits()); (4)

		PaymentChannels paymentChannels = paymentChannelHelper.setProfilePaymentChannel(paymentChannelData,
				blockcyperMap, type, profileID); (5)

		PaymentChannels paymentAccounts = paymentsRepo.save(paymentChannels); (6)

		return new Response<>(HttpStatus.CREATED.value(), "Profile payment channel created successfully",
				paymentAccounts); (7)

	}
Internal workflow
1 Initialization
  • Initialize the payment channel type (type) as "new".

2 Convert data
  • Convert the paymentChannelData object to a Map using the ObjectMapper.

3 Validation
  • Validate the profile payment channel data using the profilePaymentChannelValidation method from the Validator component.

4 BlockCypher map creation
  • Create a BlockCypher map (blockcyperMap) using the createBlockCypherMap method from the PaymentWorker component, based on the units specified in the payment channel data.

5 Payment channel creation:
  • Set the profile payment channel using the setProfilePaymentChannel method from the PaymentChannelHelper component, providing the payment channel data, BlockCypher map, type, and profile ID.

6 Save payment channel
  • Save the created payment channel using the save method from the PaymentChannelRepository.

7 Response:
  • Create and return a Response object with a status indicating successful creation and the created payment channel.

Exceptions
  • This method may throw IOException, ParseException, or BlockCypherException due to data parsing or BlockCypher operations. Ensure proper error handling mechanisms are implemented.

7.3.4. Model classes

Description:

The ProfileChannelDto class represents a Data Transfer Object (DTO) containing details for a profile channel. It includes information such as identifier, label, type, units, and system.

Attributes
  1. identifier (String)

    • Description: The identifier associated with the profile channel.

    • Constraints: Maximum 100 characters.

    • Example: "David007"

  2. label (String)

    • Description: The label associated with the profile channel.

    • Constraints: Maximum 100 characters.

    • Example: "ser"

  3. type (String)

    • Description: The type associated with the profile channel.

    • Constraints: Not null, not blank, maximum 50 characters.

    • Example: "new"

  4. units (String)

    • Description: The units associated with the profile channel.

    • Constraints: Not null, not blank, maximum 10 characters.

    • Example: "USD"

  5. system (String)

    • Description: The system associated with the profile channel.

    • Constraints: Not null, not blank, maximum 50 characters.

    • Example: "IBAN"

Constructors
  • Default constructor.

  • Parameterized constructor with all attributes.

Serialization and Deserialization
  • The class uses Lombok annotations @Getter, @Setter, @NoArgsConstructor, @AllArgsConstructor, and @ToString for serialization and deserialization. These annotations generate getter and setter methods, default and parameterized constructors, and a toString method for the class.

7.3.5. Testing

Description

The createProfilePaymentChannel test method assesses the functionality of the createProfilePaymentChannel method within the PaymentChannelServiceImpl class. This test ensures that the method correctly creates a payment channel associated with a specific profile ID using the provided template.

Test methods

Example usage

    @Test
	public void createProfilePaymentChannel() throws IOException, ParseException, BlockCypherException {

		when(paymentsRepo.save(any())).thenReturn(paymentChannelsTemplate.get(0));
		String profileID = "f365dfca-2e7a-4b6b-addf-4d64f99142ee";
		Response<PaymentChannels> createProfilePaymentChannel = paymentChannelServiceImpl
				.createProfilePaymentChannel(UUID.fromString(profileID), profilePaymentChannelTemplate);

		System.err.println(createProfilePaymentChannel);

		Assertions.assertEquals(paymentChannelsTemplate.get(0), createProfilePaymentChannel.getData());
		Assertions.assertEquals("Payment channel created successfully",
				createProfilePaymentChannel.getMessage());
		Assertions.assertEquals(201, createProfilePaymentChannel.getStatus());
	}

createProfilePaymentChannel

  • Purpose : The purpose of this test is to verify that the createProfilePaymentChannel method behaves as expected, creating a new payment channel associated with a specific profile ID based on the provided template and returning the appropriate response.

  • Test steps

    1. Stub the behavior of the repository to return the first payment channel template when save method is called.

    2. Define a profile ID string.

    3. Call the createProfilePaymentChannel method of the PaymentChannelServiceImpl class with the provided profile ID converted to a UUID and the profile payment channel template.

    4. Retrieve the response object returned by the method.

  • Assertions

    • Assert that the created payment channel matches the first payment channel template.

    • Assert that the message in the response indicates successful creation of the payment channel.

    • Assert that the status code of the response is 201.

7.4. Create profile serviced and external

7.4.1. Sequential flow

creates profile serviced and external payment channel.puml
Figure 15. Creates profile serviced and external payment channel

Create profile serviced and external payment channel flow

  • Client: Initiates a POST request to create a payment channel for a specific profile.

  • PaymentChannelController: Receives the POST request.

  • PaymentChannelController (activated): Calls the createProfileServicedPaymentChannel method of the PaymentChannelService with the provided parameters.

  • PaymentChannelService (activated): Receives the call to create the payment channel.

  • Validator (activated): Validates the profile and payment channel data.

  • Validator → ProfileRepository: Retrieves the profile from the database by ID.

  • ProfileRepository -→ Validator: Returns the profile.

  • Validator: Checks if the profile exists.

    • UtilityHelper (activated): Checks if the identifier is not null or empty.

    • UtilityHelper -→ Validator: Returns the result.

    • Validator (alt): If the result is true:

      1. Validator: Performs additional validation.

      2. PaymentChannelRepository: Checks for existing payment channels with the same identifier.

      3. Assert: Ensures the uniqueness of the identifier.

      4. Assert (alt): If the identifier is unique, proceeds with further validation.

      5. Validator: Validates the payment channel type.

      6. PaymentChannelHelper: Sets up the payment channel.

    • Validator (else): If the result is false, throws an IllegalArgumentException.

  • Validator (else): If the profile doesn’t exist:

    • Assert: Throws an IllegalArgumentException indicating that the profile doesn’t exist.

  • PaymentChannelService: Saves the created payment channels.

  • PaymentChannelRepository: Persists the payment channels.

  • PaymentChannelRepository -→ PaymentChannelService: Returns the saved payment channels.

  • PaymentChannelService -→ PaymentChannelController: Returns the response.

  • PaymentChannelController: Responds to the client with a ResponseEntity containing the response data.

7.4.2. Endpoint

Description

This endpoint facilitates the creation of profile serviced and external payment channels. Users with appropriate authorization can send a POST request containing the necessary data, which is then processed and stored in the database.

URL

/payments/channel/profiles/{profileID}

Method

POST

Request parameters

profileID (Path variable): The unique identifier of the profile for which the payment channel is created.

Request body

paymentChannelData (Request Body): A JSON object containing data for creating a serviced and external payment channel. It adheres to the structure defined in the ServicedAndExternalDTO class.

Example request body
{
  "type": "serviced",
  "identifier": "David007",
  "label": "ser",
  "units": "BTC",
  "accountCharacteristic": "isCash",
  "address": "BvdK6pQghtwMvzfLtZjXT7brAh83JDyi76",
  "beneficiaryName": "danial",
  "beneficiaryAddress": "UK",
  "accessKey": {
    "private": "b44f71aeefbe25b07b4a14ae63a0922aa2d6874906628d7a457f39e4e96c70d8",
    "public": "0270198cf386036bc186f8261045c1f8bc241cffd5858ca977ba62cbeeb6fe5b40",
    "address": "BvdK6pQghtwMvzfLtZjXT7brAh83JDyi76"
  }
}
Responses
  • 201 CREATED: Successful creation of the profile’s serviced and external payment channel. Returns a JSON response with details of the created payment channel.

Example response body
{
  "status": 201,
  "message": "Payment channel created successfully",
  "data": {
    "paymentChannelID": "a28855a8-6581-4b7e-9096-b47e87e70353",
    "contractID": "ec9d8f46-54e5-4cb0-b94d-e28fb17b88a4",
    "label": "Saving A/C",
    "type": "new",
    "units": "INR",
    "system": "IBAN",
    "accountCharacteristic": "isBank",
    "identifier": "mmmmm",
    "details": {
      "address": "CH7500762QUVXZNF1PP8S",
      "system": "IBAN"
    },
    "ownerType": "profile",
    "ownerID": "d2c87ded-489e-4510-8fe1-95f12c048a5d",
    "userID": "fe54273e-c645-49f5-9279-ad6d4067c606"
  }
}
  • 400 bad request: If the request body is not in the correct format or if there are validation errors.

{
  "status": 400,
  "message": "Identifier already exists",
  "data": null
}
  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to create profile payment channels.

  • 5xx server error: If there is a server-side error while processing the request.

7.4.3. Methods

Description

This method creates a new payment channel for a specific user profile, which can be either serviced or external.

Parameters
  • profileID: The identifier of the user profile for which the payment channel is being created.

  • paymentChannelData: Data representing the payment channel to be created

Returns
  • Response<PaymentChannels>: A response object indicating the status and the created payment channel.

Example usage
     public Response<PaymentChannels> createProfileServicedPaymentChannel(UUID profileID,
			ServicedAndExternalDTO paymentChannelData) throws ParseException {
		log.info("Profile service payment channel creation started by userID : {}, request : {}",
				usersHelper.getUserID(), paymentChannelData);

		final Map<String, Object> paymentChannelMap = mapper.convertValue(paymentChannelData, Map.class); (1)

		String system; (2)
		String type;

		// Validate the payment channel data specific to a user profile
		validator.profileServiceAndExternalPaymentChannelValidation(profileID, paymentChannelMap, profileID); (3)

		if (paymentChannelData.getType().equalsIgnoreCase("serviced")) { (4)
			type = "serviced";

			// Extract and parse the access key information
			final JSONObject parse2 = paymentChannelData.getAccessKey();
			paymentChannelMap.put("accessKey", parse2);

			// Determine the payment system (e.g., Ethereum or Bitcoin)
			system = paymentChannelData.getUnits().equalsIgnoreCase("ETH") ? "Ethereum" : "Bitcoin"; (5)

		} else {
			type = "external";

			// Determine the payment system based on the provided data
			system = paymentChannelHelper.getSystem(paymentChannelData.getUnits());
		}

		PaymentChannels paymentChannels1 = paymentChannelHelper.setExternalServiceProfilePaymentChannel(
				paymentChannelData, paymentChannelMap, system, type, profileID); (6)

		paymentChannels1 = paymentsRepo.save(paymentChannels1); (7)
		return new Response<>(HttpStatus.CREATED.value(), "Payment channel created", paymentChannels1); (8)
	}
Internal workflow
1 Data conversion
  • Convert the paymentChannelData object to a Map using the ObjectMapper.

2 Initialization
  • Initialize variables for the payment channel system (system) and type (type).

3 Validation
  • Validate the payment channel data specific to a user profile using the profileServiceAndExternalPaymentChannelValidation method from the Validator component.

    • This method validates a payment channel associated with a user profile. It ensures that the profile exists, the identifier is not null or empty, and performs additional validation if the payment channel type is "serviced.

4 Type determination
  • Determine the type of the payment channel based on the type field in the paymentChannelData.

5 System determination
  • Determine the payment system (system) based on the type of the payment channel data. If the type is "serviced," use Ethereum or Bitcoin based on the units specified; otherwise, determine the system using the getSystem method from the PaymentChannelHelper.

6 Payment channel creation
  • Set the profile payment channel using the setExternalServiceProfilePaymentChannel method from the PaymentChannelHelper, providing the payment channel data, payment channel map, system, type, and profile ID.

7 Save payment channel
  • Save the created payment channel using the save method from the PaymentChannelRepository.

8 Response
  • Create and return a Response object with a status indicating successful creation and the created payment channel.

Exceptions

This method may throw ParseException if there’s an issue parsing data. Ensure proper error handling mechanisms are implemented.

7.4.4. Model classes

Description:

The ServicedAndExternalDTO class represents a Data Transfer Object (DTO) containing details for a service and an external entity. It includes information such as accessKey, address, beneficiaryAddress, beneficiaryName, identifier, label, type, units, and accountCharacteristic.

Attributes
  1. accessKey (JSONObject)

    • Description: The access key associated with the DTO.

    • Constraints: None.

    • Example:

  "accessKey": {
    "private": "b44f71aeefbe25b07b4a14ae63a0922aa2d6874906628d7a457f39e4e96c70d8",
    "public": "0270198cf386036bc186f8261045c1f8bc241cffd5858ca977ba62cbeeb6fe5b40",
    "address": "BvdK6pQghtwMvzfLtZjXT7brAh83JDyi76"
  }
  1. address (String)

    • Description: The address associated with the DTO.

    • Constraints: None.

    • Example: "123 Main Street"

  2. beneficiaryAddress (String)

    • Description: The beneficiary’s address associated with the DTO.

    • Constraints: Not null, not blank.

    • Example: "UK"

  3. beneficiaryName (String)

    • Description: The beneficiary’s name associated with the DTO.

    • Constraints: Not null, not blank.

    • Example: "John Doe"

  4. identifier (String)

    • Description: The identifier associated with the DTO.

    • Constraints: Not null, not blank, maximum 100 characters.

    • Example: "ABC123"

  5. label (String)

    • Description: The label associated with the DTO.

    • Constraints: Not null, not blank, maximum 100 characters.

    • Example: "External Service"

  6. type (String)

    • Description: The type associated with the DTO.

    • Constraints: Not null, not blank, maximum 50 characters.

    • Example: "Service"

  7. units (String)

    • Description: The units associated with the DTO.

    • Constraints: Not null, not blank, maximum 10 characters.

    • Example: "BTC"

  8. accountCharacteristic (String)

    • Description: The account characteristic associated with the DTO.

    • Constraints: None.

    • Example: "Regular Account"

Constructors
  • Default constructor.

  • Parameterized constructor with all attributes.

Serialization and Deserialization
  • The class uses Lombok annotations @Getter, @Setter, @NoArgsConstructor, @AllArgsConstructor, and @ToString for serialization and deserialization. These annotations generate getter and setter methods, default and parameterized constructors, and a toString method for the class.

7.4.5. Testing

Description

The createProfileServicedPaymentChannel test method evaluates the functionality of the createProfileServicedPaymentChannel method within the PaymentChannelServiceImpl class. This test ensures that the method correctly creates a serviced payment channel associated with a specific profile ID using the provided template.

Test methods

Example usage

	@Test
	public void createProfileServicedPaymentChannel() throws ParseException {

		when(paymentsRepo.save(any())).thenReturn(paymentChannelsTemplate.get(0));
		String profileID = "f365dfca-2e7a-4b6b-addf-4d64f99142ee";
		Response<PaymentChannels> createProfileServicedPaymentChannel = paymentChannelServiceImpl
				.createProfileServicedPaymentChannel(UUID.fromString(profileID), servicedAndExternalTemplate);

		Assertions.assertEquals(paymentChannelsTemplate.get(0), createProfileServicedPaymentChannel.getData());
		Assertions.assertEquals("Payment channel created", createProfileServicedPaymentChannel.getMessage());
		Assertions.assertEquals(201, createProfileServicedPaymentChannel.getStatus());

	}

createProfileServicedPaymentChannel

  • Purpose : The purpose of this test is to verify that the createProfileServicedPaymentChannel method behaves as expected, creating a new serviced payment channel associated with a specific profile ID based on the provided template and returning the appropriate response.

  • Test steps

    1. Stub the behavior of the repository to return the first payment channel template when the save method is called.

    2. Define a profile ID string.

    3. Call the createProfileServicedPaymentChannel method of the PaymentChannelServiceImpl class with the provided profile ID converted to a UUID and the serviced and external template.

    4. Retrieve the response object returned by the method.

  • Assertions

    • Assert that the created payment channel matches the first payment channel template.

    • Assert that the message in the response indicates successful creation of the payment channel.

    • Assert that the status code of the response is 201.

7.5. Delete payment channel

7.5.1. Sequential flow

Deletes payment channel.puml
Figure 16. Deletes payment channel

Deletes payment channel flow

  • The client sends a request to delete a payment channel identified by its ID.

  • The PaymentChannelController is activated to handle the incoming request.

  • The PaymentChannelController forwards the request to the PaymentChannelServiceImpl to execute the deletion operation.

  • The PaymentChannelServiceImpl interacts with the Validator to check if the provided payment channel ID exists.

  • The Validator queries the Repository to find the payment channel by its ID.

  • If the payment channel is found, the Validator confirms its existence and proceeds with the deletion process.

  • The PaymentChannelServiceImpl requests the Repository to delete the payment channel by its ID.

  • After successful deletion, the PaymentChannelServiceImpl prepares a response indicating the success of the operation.

  • The PaymentChannelController sends a response entity back to the client, containing the response from the service.

  • If the payment channel doesn’t exist, an IllegalArgumentException is thrown, and the corresponding error message is returned to the client.

7.5.2. Endpoint

Description

This endpoint facilitates the deletion of a payment channel based on a specific payment channel ID. Users with appropriate authorization can send a DELETE request to delete the specified payment channel.

URL

/payments/channel/{paymentChannelID}

Method

DELETE

Request parameters

paymentChannelID (Path variable): The unique identifier of the payment channel to be deleted.

Responses
  • 200 OK: Successful deletion of the payment channel. Returns a JSON response with the ID of the deleted payment channel.

Example response body
{
  "status": 200,
  "message": "Payment channel deleted successfully",
  "data": "a28855a8-6581-4b7e-9096-b47e87e70353"
}
  • 400 bad request: If the specified payment channel ID does not exist

{
  "status": 400,
  "message": "PaymentChannelID doesn't exist",
  "data": null
}
  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to delete payment channels.

  • 5xx server error: If there is a server-side error while processing the request.

7.5.3. Methods

Description

This method deletes a payment channel based on payment channel id.

Parameters
  • paymentChannelId: The unique identifier of the payment channel to be deleted.

Returns
  • Response<UUID> : Create and return a response object indicating the successful deletion of the payment channel, along with its ID

Example usage
public Response<UUID> deleteByPaymentChannelID(UUID paymentChannelId) {
		log.info("Deleting payment channel by ID by userID : {}, request : {}", usersHelper.getUserID(),
				paymentChannelId);

		validator.checkIdExists(paymentChannelId); (1)

		paymentsRepo.deleteById(paymentChannelId); (2)

		log.info("Deleted payment channel by ID by userID : {}, request : {}", usersHelper.getUserID(),
				paymentChannelId); (3)

		return new Response<>(HttpStatus.OK.value(), "Payment channel deleted successfully", paymentChannelId); (4)
	}
Internal workflow
1 ID existence check
  • Validate whether a payment channel with the provided ID exists in the repository.

2 Deletion
  • If the payment channel exists, delete it from the repository using its ID.

3 Logging (Post deletion)
  • Log the successful deletion of the payment channel, including the user ID and the ID of the deleted payment channel.

4 Response generation
  • Create and return a response object indicating the successful deletion of the payment channel, along with its ID.

Exceptions

IOException: If there’s an I/O related issue during the process.

ParseException: If there’s an issue parsing data.

BlockCypherException: If there’s an exception related to BlockCypher operations.

7.5.4. Testing

Description

The deleteByPaymentChannelID test method evaluates the functionality of the deleteByPaymentChannelID method within the PaymentChannelServiceImpl class. This test ensures that the method correctly deletes a payment channel based on the provided payment channel ID.

Test methods

Example usage

	@Test
	public void deleteByPaymentChannelID() {
		UUID paymentChannelId = paymentChannelsTemplate.get(0).getPaymentChannelID();
		Response<UUID> deleteByPaymentChannelID = paymentChannelServiceImpl.deleteByPaymentChannelID(paymentChannelId);

		Assertions.assertEquals(paymentChannelId, Objects.requireNonNull(deleteByPaymentChannelID).getData());
		Assertions.assertEquals("Payment channel deleted successfully", deleteByPaymentChannelID.getMessage());
		Assertions.assertEquals(200, deleteByPaymentChannelID.getStatus());
	}

deleteByPaymentChannelID

  • Purpose : The purpose of this test is to verify that the deleteByPaymentChannelID method behaves as expected, deleting the payment channel with the specified ID and returning the appropriate response.

  • Test steps

    1. Retrieve the payment channel ID from the payment channel template.

    2. Call the deleteByPaymentChannelID method of the PaymentChannelServiceImpl class with the retrieved payment channel ID.

    3. Retrieve the response object returned by the method.

  • Assertions

    • Assert that the deleted payment channel ID matches the provided payment channel ID.

    • Assert that the message in the response indicates successful deletion of the payment channel.

    • Assert that the status code of the response is 200.

7.6. Update payment channel

7.6.1. Sequential flow

Update profile payment channel.puml
Figure 17. Update profile payment channel

Update profile payment channel flow

  • The client sends a request to update a payment channel, providing the payment channel ID and updated data.

  • The controller forwards the request to the service layer.

  • The service layer calls the validator to check if the payment channel with the provided ID exists.

  • The validator retrieves the payment channel from the repository based on its ID.

  • If the payment channel exists, the validator returns it to the service layer.

  • The service layer invokes the helper method to determine the payment system based on the provided data.

  • The helper method returns the determined payment system to the service layer.

  • Depending on the payment system, the service layer calls the appropriate method in the payment worker.

  • The payment worker performs validation checks specific to the payment system.

  • If validation passes, the validator returns validation success to the payment worker.

  • The payment worker updates the payment channel entity with the provided data.

  • After updating the payment channel, the worker returns control to the service layer.

  • The service layer persists the updated payment channel in the repository.

  • The service layer returns a response to the controller.

  • The controller sends the response back to the client.

  • The diagram includes alternative flows based on whether the payment channel system is "IBAN" or not. It shows different validation and update processes for each case.

  • If mandatory properties are missing during validation, an exception is thrown, indicating the missing properties for the channel ID.

  • If the payment channel does not exist, an exception is thrown indicating that the payment channel ID doesn’t exist.

7.6.2. Endpoint

Description

This endpoint updates an existing payment channel based on the provided payment channel ID and data. Users with appropriate authorization can send a PUT request to update the specified payment channel.

URL

/payments/channel/{paymentChannelId}

Method

PUT

Request parameters
  • paymentChannelId (Path variable): The unique identifier of the payment channel to be updated.

  • paymentChannelData (Request body): Data for updating the payment channel.

Example request body
{
  "type": "serviced",
  "identifier": "David007",
  "label": "ser",
  "units": "BTC",
  "accountCharacteristic": "isCash",
  "address": "BvdK6pQghtwMvzfLtZjXT7brAh83JDyi76",
  "beneficiaryName": "danial",
  "beneficiaryAddress": "UK",
  "accessKey": {
    "private": "b44f71aeefbe25b07b4a14ae63a0922aa2d6874906628d7a457f39e4e96c70d8",
    "public": "0270198cf386036bc186f8261045c1f8bc241cffd5858ca977ba62cbeeb6fe5b40",
    "address": "BvdK6pQghtwMvzfLtZjXT7brAh83JDyi76"
  }
}
Responses
  • 200 OK: Successful update of the payment channel. Returns a JSON response with the updated payment channel.

Example response body
{
  "status": 200,
  "message": "Payment channel updated",
  "data": {
    "paymentChannelID": "13c3861e-bcc6-48ed-9db1-91cb6825328a",
    "contractID": "b02519a2-bed3-4e3b-8169-e94c4f730e64",
    "label": "ser",
    "type": "new",
    "units": "INR",
    "system": "IBAN",
    "accountCharacteristic": "isBank",
    "identifier": "David012",
    "details": {
      "system": "Bitcoin",
      "address": "BvdK6pQghtwMvzfLtZjXT7brAh83JDyi76",
      "accessKey": {
        "private": "b44f71aeefbe25b07b4a14ae63a0922aa2d6874906628d7a457f39e4e96c70d8",
        "address": "BvdK6pQghtwMvzfLtZjXT7brAh83JDyi76",
        "public": "0270198cf386036bc186f8261045c1f8bc241cffd5858ca977ba62cbeeb6fe5b40"
      },
      "beneficiaryAddress": "UK",
      "beneficiaryName": "danial",
      "label": "ser",
      "type": "new",
      "units": "BTC",
      "accountCharacteristic": "isCash"
    },
    "ownerType": "root",
    "ownerID": "902375cc-4f72-428f-8db0-95a7baa69b51",
    "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
  }
}
  • 400 bad request: If the request body is not in the correct format or if there are validation errors.

{
  "status": 400,
  "message": "Mandatory properties are missing for this ChannelID",
  "data": null
}
{
  "status": 400,
  "message": "PaymentChannelID doesn't exist",
  "data": null
}
  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to create contracts.

  • 5xx server error: If there is a server-side error while processing the request.

7.6.3. Methods

Description

This method updates an existing payment channel based on the provided payment channel ID and data

Parameters
  • paymentChannelId: The unique identifier of the payment channel to be updated.

  • paymentChannelData: The data representing the changes to be applied to the payment channel.

Returns
  • Response<PaymentChannels>: A response object indicating the status of the update and the updated payment channel.

Example usage
    public Response<PaymentChannels> updatePaymentChannel(UUID paymentChannelId,
			ServicedAndExternalDTO paymentChannelData) throws ParseException {
		log.info("Updating of payment channel started by userID : {}, request : {}", usersHelper.getUserID(),
				paymentChannelData);

		// Converting payment channel data into key-value pairs.
		Map<String, Object> paymentChannelMap = mapper.convertValue(paymentChannelData, Map.class); (1)

		// Check and retrieve the payment channel based on its unique paymentChannelId
		PaymentChannels paymentChannel = validator.checkIdExists(paymentChannelId); (2)

		// Determine the payment system (e.g., Ethereum or Bitcoin)
		String system = paymentChannelHelper.getSystem(paymentChannelData.getUnits()); (3)

		// Check if the payment channel system is "IBAN" and update accordingly
		if (paymentChannel.getSystem().equalsIgnoreCase("IBAN")) { (4)

			paymentChannel = paymentWorker.updateIBANPaymentChannel(paymentChannelMap, paymentChannelId, paymentChannel,
					system, paymentChannelData);
		}

		// Check if the payment channel system is "Bitcoin" or "Ethereum" and update
		// accordingly
		if (paymentChannel.getSystem().equalsIgnoreCase("Bitcoin")
				|| paymentChannel.getSystem().equalsIgnoreCase("Ethereum")) {

			paymentChannel = paymentWorker.updateETHBTCPaymentChannel(paymentChannelMap, paymentChannelId,
					paymentChannel, system, jsonParser, paymentChannelData);
		}

		paymentsRepo.save(paymentChannel); (5)

		log.info("Updating of payment channel completed by userID : {}, request : {}", usersHelper.getUserID(),
				paymentChannelData);

		return new Response<>(HttpStatus.OK.value(), "Payment channel updated", paymentChannel);
	}
Internal workflow
1 Convert payment channel data into key-value pairs.
2 Retrieve and check existence of payment channel from repository using its ID, then return it if present.
3 Determine the payment system (e.g., Ethereum or Bitcoin).
4 Update the payment channel based on its system:
  • If the payment channel system is "IBAN," call updateIBANPaymentChannel method.

  • If the payment channel system is "Bitcoin" or "Ethereum," call updateETHBTCPaymentChannel method.

5 Save the updated payment channel.
Exceptions

ParseException

  • If there’s an issue parsing data.

IllegalArgumentException

  • If the payment channel with the given ID doesn’t exist.

7.6.4. Model classes

Description:

The ServicedAndExternalDTO class represents a Data Transfer Object (DTO) containing details for a service and an external entity. It includes information such as accessKey, address, beneficiaryAddress, beneficiaryName, identifier, label, type, units, and accountCharacteristic.

Attributes
  1. accessKey (JSONObject)

    • Description: The access key associated with the DTO.

    • Constraints: None.

    • Example:

  "accessKey": {
    "private": "b44f71aeefbe25b07b4a14ae63a0922aa2d6874906628d7a457f39e4e96c70d8",
    "public": "0270198cf386036bc186f8261045c1f8bc241cffd5858ca977ba62cbeeb6fe5b40",
    "address": "BvdK6pQghtwMvzfLtZjXT7brAh83JDyi76"
  }
  1. address (String)

    • Description: The address associated with the DTO.

    • Constraints: None.

    • Example: "123 Main Street"

  2. beneficiaryAddress (String)

    • Description: The beneficiary’s address associated with the DTO.

    • Constraints: Not null, not blank.

    • Example: "UK"

  3. beneficiaryName (String)

    • Description: The beneficiary’s name associated with the DTO.

    • Constraints: Not null, not blank.

    • Example: "John Doe"

  4. identifier (String)

    • Description: The identifier associated with the DTO.

    • Constraints: Not null, not blank, maximum 100 characters.

    • Example: "ABC123"

  5. label (String)

    • Description: The label associated with the DTO.

    • Constraints: Not null, not blank, maximum 100 characters.

    • Example: "External Service"

  6. type (String)

    • Description: The type associated with the DTO.

    • Constraints: Not null, not blank, maximum 50 characters.

    • Example: "Service"

  7. units (String)

    • Description: The units associated with the DTO.

    • Constraints: Not null, not blank, maximum 10 characters.

    • Example: "BTC"

  8. accountCharacteristic (String)

    • Description: The account characteristic associated with the DTO.

    • Constraints: None.

    • Example: "Regular Account"

Constructors
  • Default constructor.

  • Parameterized constructor with all attributes.

Serialization and Deserialization
  • The class uses Lombok annotations @Getter, @Setter, @NoArgsConstructor, @AllArgsConstructor, and @ToString for serialization and deserialization. These annotations generate getter and setter methods, default and parameterized constructors, and a toString method for the class.

7.6.5. Testing

Description

The updatePaymentChannel test method evaluates the functionality of the updatePaymentChannel method within the PaymentChannelServiceImpl class. This test ensures that the method correctly updates an existing payment channel with the provided template.

Test methods

Example usage

	@Test
	public void updatePaymentChannel() throws ParseException {

		UUID paymentChannelId = paymentChannelsTemplate.get(0).getPaymentChannelID();
		Response<PaymentChannels> updatePaymentChannel = paymentChannelServiceImpl
				.updatePaymentChannel(paymentChannelId, servicedAndExternalTemplate);

		Assertions.assertEquals(paymentChannelsTemplate.get(0), updatePaymentChannel.getData());

	}

updatePaymentChannel

  • Purpose : The purpose of this test is to verify that the updatePaymentChannel method behaves as expected, updating an existing payment channel with the specified ID using the provided template and returning the appropriate response.

  • Test steps

    1. Retrieve the payment channel ID from the first payment channel template.

    2. Call the updatePaymentChannel method of the PaymentChannelServiceImpl class with the retrieved payment channel ID and the serviced and external template.

    3. Retrieve the response object returned by the method.

  • Assertions

    • Assert that the updated payment channel data matches the first payment channel template.

7.7. Provide payment channel

7.7.1. Sequential flow

Provide payment channel flow.puml
Figure 18. provide payment channel

Provide payment channel flow

  • The client sends a GET request to retrieve information about a payment channel, specifying the paymentChannelID in the request.

  • The PaymentChannelController is activated to handle the incoming request.

  • The PaymentChannelController forwards the request to the PaymentChannelService to retrieve the payment channel information.

  • The PaymentChannelService, specifically its implementation (PaymentChannelServiceImpl), takes over the processing of retrieving the payment channel information.

  • The PaymentChannelServiceImpl interacts with the Validator to check if the provided payment channel ID exists.

  • The Validator queries the PaymentChannelRepository to find the payment channel by its ID.

  • If the payment channel is found, the Validator confirms its existence.

  • If the payment channel exists, it is returned to the PaymentChannelServiceImpl.

  • The PaymentChannelServiceImpl prepares a response containing the payment channel information.

  • The PaymentChannelService sends the response back to the PaymentChannelController.

  • The PaymentChannelController sends a response containing the payment channel information back to the client.

7.7.2. Endpoint

Description

This endpoint retrieves information about an existing payment channel identified by its unique identifier.

URL

/payments/channel/{paymentChannelID}

Method

GET

Request parameters

paymentChannelID (Path variable): The unique identifier of the payment channel.

Responses
  • 200 OK: Returns a successful response containing details of the specified payment channel.

Example response body
{
  "status": 200,
  "message": "Success",
  "data": {
    "paymentChannelID": "13c3861e-bcc6-48ed-9db1-91cb6825328a",
    "contractID": "b02519a2-bed3-4e3b-8169-e94c4f730e64",
    "label": "Saving A/C",
    "type": "new",
    "units": "INR",
    "system": "IBAN",
    "accountCharacteristic": "isBank",
    "identifier": "David012",
    "details": {
      "system": "IBAN",
      "address": "CH2100762VFQEXKJPTTQE"
    },
    "ownerType": "root",
    "ownerID": "902375cc-4f72-428f-8db0-95a7baa69b51",
    "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
  }
}
  • 400 bad request: If the specified payment channel does not exist.

{
  "status": 400,
  "message": "PaymentChannelID doesn't exist",
  "data": null
}
  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to retrieves payment channels.

  • 5xx server error: If there is a server-side error while processing the request.

7.7.3. Methods

Description

This method retrieves a payment channel based on payment channel id.

Parameters
  • paymentChannelID: The unique identifier of the payment channel to retrieve.

Returns
  • Response<PaymentChannels>: A response object containing the retrieved payment channel.

Example usage
public Response<PaymentChannels> getPaymentChannelsById(UUID paymentChannelID) {
		log.info("Retrieving payment channels by ID by userID : {}, request : {}", usersHelper.getUserID(),
				paymentChannelID);

		PaymentChannels paymentChannels = validator.checkIdExists(paymentChannelID); (1)
		return new Response<>(HttpStatus.OK.value(), "Success", paymentChannels);
	}
Internal workflow
1 Utilize the Validator to check the existence of a payment channel with the given ID in the repository, then retrieve it.
Exceptions

IllegalArgumentException: If the payment channel with the given ID doesn’t exist.

7.7.4. Testing

Description

The getPaymentChannelsById test method evaluates the functionality of the getPaymentChannelsById method within the PaymentChannelServiceImpl class. This test ensures that the method correctly retrieves a payment channel based on the provided payment channel ID.

Test methods

Example usage

   @Test
	public void getPaymentChannelsById() {
		UUID paymentChannelID = paymentChannelsTemplate.get(0).getPaymentChannelID();
		Response<PaymentChannels> paymentChannels = paymentChannelServiceImpl.getPaymentChannelsById(paymentChannelID);

		PaymentChannels data = paymentChannels.getData();

		Assertions.assertEquals(paymentChannelsTemplate.get(0), data);
		Assertions.assertEquals(paymentChannelID, data.getPaymentChannelID());
		Assertions.assertEquals(200, paymentChannels.getStatus());
	}

getPaymentChannelsById

  • Purpose : The purpose of this test is to verify that the getPaymentChannelsById method behaves as expected, retrieving the payment channel with the specified ID and returning the appropriate response.

  • Test steps

    1. Retrieve the payment channel ID from the first payment channel template.

    2. Call the getPaymentChannelsById method of the PaymentChannelServiceImpl class with the retrieved payment channel ID.

    3. Retrieve the response object returned by the method.

    4. Extract the payment channel data from the response.

  • Assertions

    • Assert that the retrieved payment channel matches the first payment channel template.

    • Assert that the retrieved payment channel ID matches the expected payment channel ID.

    • Assert that the status code of the response is 200.

7.8. Provide balance of payment channel

7.8.1. Sequential flow

Provides the balance of payment channel flow.puml
Figure 19. provide payment channel

Provides the balance of payment channel flow

  • The client sends a GET request to retrieve the balance of a payment channel, specifying the paymentChannelID in the request.

  • The PaymentChannelController is activated to handle the incoming request.

  • The PaymentChannelController forwards the request to the PaymentChannelService to retrieve the balance of the payment channel.

  • The PaymentChannelService, specifically its implementation (PaymentChannelServiceImpl), takes over the processing of retrieving the balance of the payment channel.

  • The PaymentChannelServiceImpl interacts with the Validator to check if the provided payment channel ID exists.

  • The Validator queries the PaymentChannelRepository to find the payment channel by its ID.

  • If the payment channel is found, the Validator confirms its existence.

  • Unit-specific Balance Retrieval

    1. Depending on the units of the payment channel (e.g., ETH, BTC, or other units), the PaymentWorker is activated to retrieve the balance.

    2. For ETH units, it interacts with BlockCypherEthereumConfiguration to check the Ethereum balance.

    3. For BTC units, it interacts with BlockCypherBitCoinConfiguration to check the Bitcoin balance.

    4. For other units, it involves fetching the balance using a different method specific to that unit, such as querying contract data through ContractsFeignClient for IBAN payment channels.

  • Contract-based Balance Retrieval (for IBAN payment channels):

    • If the payment channel involves IBAN, it interacts with ContractsFeignClient to fetch contract data.

    • Depending on the availability of contract data, the notional principal is extracted as the balance.

    • If contract data is not available, the balance is set to null.

  • The retrieved balance information is returned to the PaymentChannelServiceImpl.

  • The PaymentChannelService sends the response back to the PaymentChannelController.

  • The PaymentChannelController sends a response containing the balance information back to the client.

7.8.2. Endpoint

Description

This endpoint retrieves the balance of a payment channel identified by its unique identifier.

URL

/payments/channel/{paymentChannelID}/balance

Method

GET

Request parameters

paymentChannelID (Path variable): The unique identifier of the payment channel.

Responses
  • 200 OK: Returns a successful response containing the balance information of the specified payment channel.

Example response body
{
  "status": 200,
  "message": "Success",
  "data": {
    "balance": "50000.0"
  }
}
  • 400 bad request: If the specified payment channel does not exist.

{
  "status": 400,
  "message": "PaymentChannelID doesn't exist",
  "data": null
}
  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to retrieves payment channels.

  • 5xx server error: If there is a server-side error while processing the request.

7.8.3. Methods

Description

This method retrieves the balance of a payment channel identified by its unique paymentChannelID.

Parameters
  • paymentChannelID: The unique identifier of the payment channel for which the balance is to be retrieved.

Returns
  • Response<JSONObject>: A response containing the balance information of the payment channel.

Example usage
/**
	 * Retrieves the balance of a payment channel identified by its unique
	 * paymentChannelID.
	 *
	 * @param paymentChannelID The unique identifier of the payment channel for
	 *                         which the balance is to be retrieved.
	 * @return A response containing the balance information of the payment channel.
	 */

	public Response<JSONObject> getBalanceOfPaymentChannel(UUID paymentChannelID) {
		log.info("Checked payment channel balance by userID : {}, request : {}", usersHelper.getUserID(),
				paymentChannelID);

		PaymentChannels paymentChannel = validator.checkIdExists(paymentChannelID); (1)
		JSONObject balance = paymentWorker.getPaymentChannelBalance(paymentChannel); (2)
		return new Response<>(HttpStatus.OK.value(), "Success", balance);
	}
Internal workflow
1 Check if a payment channel with the given ID exists in the repository using the Validator.
2 Retrieve the balance information of the payment channel using the PaymentWorker.
  • Check the type of payment channel based on the units (e.g., ETH, BTC, or IBAN).

  • Depending on the payment channel type, fetch the balance from the appropriate source: Ethereum, Bitcoin, or IBAN payment channel.

  • Return a JSONObject containing the balance information.

Exceptions

IllegalArgumentException: If the payment channel with the given ID doesn’t exist.

7.8.4. Testing

Description

The getBalanceOfPaymentChannel test method evaluates the functionality of the getBalanceOfPaymentChannel method within the PaymentChannelServiceImpl class. This test verifies that the method correctly retrieves the balance of a specified payment channel.

Test methods

Example usage

	@Test
	public void getBalanceOfPaymentChannel() {
		UUID paymentChannelID = paymentChannelsTemplate.get(0).getPaymentChannelID();
		Response<JSONObject> balance = paymentChannelServiceImpl.getBalanceOfPaymentChannel(paymentChannelID);

		Assertions.assertEquals(balanceTemplate, balance.getData());
		Assertions.assertEquals("Success", balance.getMessage());
		Assertions.assertEquals(200, balance.getStatus());
	}
  • getBalanceOfPaymentChannel

    • Purpose : The purpose of this test is to ensure that the getBalanceOfPaymentChannel method behaves as expected, retrieving the balance of a payment channel and returning the appropriate response.

    • Test steps

      1. Retrieve the payment channel ID from the payment channel template.

      2. Call the getBalanceOfPaymentChannel method of the PaymentChannelServiceImpl class with the retrieved payment channel ID.

      3. Retrieve the response object returned by the method.

      4. Extract the balance data from the response.

    • Assertions

      • Assert that the balance data matches the expected balance template.

      • Assert that the message in the response indicates success.

      • Assert that the status code of the response is 200.

7.9. Provide payment channels based on user

7.9.1. Sequential flow

Provides all payment channels based on specific user  flow.puml
Figure 20. provide payment channels based on user

Provides all payment channels based on specific user flow

  • The client sends a GET request to retrieve payment channels associated with a specific user, specifying the userID in the request.

  • The PaymentChannelController is activated to handle the incoming request.

  • The PaymentChannelController forwards the request to the PaymentChannelService to retrieve the payment channels based on the root user.

  • The PaymentChannelService, specifically its implementation (PaymentChannelServiceImpl), takes over the processing of retrieving payment channels based on the root user.

  • The PaymentChannelServiceImpl interacts with the Validator to check the validity of the provided userID.

  • The Validator queries the PaymentChannelRepository to find payment channels associated with the specified userID.

  • If payment channels are found, the Validator confirms their existence.

  • If payment channels are found, they are returned to the PaymentChannelServiceImpl.

  • The PaymentChannelServiceImpl processes the retrieved payment channels, possibly involving additional processing such as fetching more data or formatting the response.

  • The PaymentChannelServiceImpl prepares a response containing the list of payment channels.

  • The PaymentChannelService sends the response back to the PaymentChannelController.

  • The PaymentChannelController sends a response entity containing the payment channels back to the client.

  • If no payment channels are found or if the provided userID is invalid, an IllegalArgumentException is thrown, and the corresponding error message is returned to the client.

7.9.2. Endpoint

Description

This endpoint retrieves all payment channels associated with a specific user.

URL

/payments/channel/users/{userID}

Method

GET

Request parameters

userID (path): The unique identifier of the root user for whom payment channels are to be retrieved.

Responses
  • 200 OK: Returns a successful response containing a list of payment channels associated with the specified user.

Example response body
{
  "status": 200,
  "message": "Success",
  "data": [
    {
      "paymentChannels": {
        "paymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
        "contractID": null,
        "label": "Saving A/C",
        "type": "new",
        "units": "INR",
        "system": "IBAN",
        "accountCharacteristic": null,
        "identifier": "David",
        "details": {
          "system": "IBAN",
          "address": "CH06007629PZ5UIAH8YFS"
        },
        "ownerType": "profile",
        "ownerID": "d2c87ded-489e-4510-8fe1-95f12c048a5d",
        "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
      },
      "units": "INR"
    },
    {
      "paymentChannels": {
        "paymentChannelID": "a523df29-abdd-4f53-b9c9-1baa9d96f183",
        "contractID": "1d39e542-ead1-4e5b-8a71-4308aadc69ee",
        "label": "CH4900762UQARWN52SP7U",
        "type": "new",
        "units": "CHF",
        "system": "IBAN",
        "accountCharacteristic": null,
        "identifier": "CH4900762UQARWN52SP7U",
        "details": {
          "system": "IBAN",
          "address": "CH4900762UQARWN52SP7U"
        },
        "ownerType": "profile",
        "ownerID": "d2c87ded-489e-4510-8fe1-95f12c048a5d",
        "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
      },
      "units": "CHF"
    }
  }
}
  • 400 bad request: If no payment channels are associated with the specified user.

{
  "status": 400,
  "message": "Invalid userId (or) data not found",
  "data": null
}
  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to retrieves payment channels.

  • 5xx server error: If there is a server-side error while processing the request.

7.9.3. Methods

Description

This method retrieves a list of payment channels associated with a specific root user identified by the provided userID

Parameters
  • userID: The UUID of the root user for whom payment channels are to be retrieved.

Returns
  • Response<List<PaymentChannelResponseEntity>>: A response containing a list of payment channels associated with the specified root user.

Example usage
public Response<List<PaymentChannelResponseEntity>> getPaymentChannelsBasedOnRootUser(UUID userID) {
		log.info("Retrieving payment channels based on  userID : {}, request : {}", usersHelper.getUserID(), userID);

		List<PaymentChannels> list = validator.checkUserData(userID); (1)

		List<PaymentChannelResponseEntity> paymentChannelList = paymentWorker.getpaymentChannelList(userID, list); (2)

		return new Response<>(HttpStatus.OK.value(), "Success", paymentChannelList); (3)
	}
Internal workflow
1 Calls the validator.checkUserData(userID) method to retrieve the list of payment channels associated with the specified user ID.
2 Generates a list of PaymentChannelResponseEntity objects based on the retrieved payment channels using the paymentWorker.getPaymentChannelList(userID, list) method.
3 Returns a response containing the list of payment channels with a success status.
Exceptions

Throws IllegalArgumentException if the userID is invalid or the data is not found.

7.9.4. Testing

Description

The getPaymentChannelsBasedOnRootUser test method evaluates the functionality of the getPaymentChannelsBasedOnRootUser method within the PaymentChannelServiceImpl class. This test ensures that the method correctly retrieves payment channels associated with a specific root user.

Test methods

Example usage

	@Test
	public void getPaymentChannelsBasedOnRootUser() {

		UUID UserID = usersHelper.getUserID();
		when(paymentsRepo.findByUserID(UserID)).thenReturn(paymentChannelsTemplate);
		when(paymentWorker.getpaymentChannelList(UserID, paymentChannelsTemplate)).thenReturn(getRootUserPaymentChannelTemplate);
		Response<List<PaymentChannelResponseEntity>> paymentChannelsBasedOnRootUser = paymentChannelServiceImpl
				.getPaymentChannelsBasedOnRootUser(UserID);

		Assertions.assertEquals(getRootUserPaymentChannelTemplate, paymentChannelsBasedOnRootUser.getData());
		Assertions.assertEquals("Success", paymentChannelsBasedOnRootUser.getMessage());
		Assertions.assertEquals(200, paymentChannelsBasedOnRootUser.getStatus());

	}

getPaymentChannelsBasedOnRootUser

  • Purpose : The purpose of this test is to verify that the getPaymentChannelsBasedOnRootUser method behaves as expected, retrieving payment channels associated with a specific root user and returning the appropriate response.

  • Test steps

    1. Retrieve the user ID of the root user.

    2. Stub the behavior of the repository to return the payment channels template when findByUserID is called with the root user ID.

    3. Stub the behavior of the payment worker to return the root user payment channel template when getpaymentChannelList is called with the root user ID and the payment channels template.

    4. Call the getPaymentChannelsBasedOnRootUser method of the PaymentChannelServiceImpl class with the root user ID.

    5. Retrieve the response object returned by the method.

  • Assertions

    • Assert that the retrieved payment channels match the root user payment channel template.

    • Assert that the message in the response indicates success.

    • Assert that the status code of the response is 200.

7.10. Provide payment channels based on profile

7.10.1. Sequential flow

Provides all payment channels based on specific profile flow.puml
Figure 21. provide payment channels based on profile

Provides all payment channels based on specific profile flow

  • The client sends a GET request to retrieve payment channels associated with a specific profile, specifying the profileID in the request.

  • The PaymentChannelController is activated to handle the incoming request.

  • The PaymentChannelController forwards the request to the PaymentChannelService to retrieve the payment channels based on the profile.

  • The PaymentChannelService, specifically its implementation (PaymentChannelServiceImpl), takes over the processing of retrieving payment channels based on the profile.

  • The PaymentChannelServiceImpl interacts with the Validator to check the validity of the provided profileID.

  • The Validator queries the ProfilesRepository to find profile data associated with the specified profileID.

  • If profile data is found, the Validator confirms its existence.

  • If profile data is found, the PaymentChannelServiceImpl retrieves payment channels associated with the profileID.

  • The PaymentChannelServiceImpl processes the retrieved payment channels, possibly involving additional processing such as formatting the response.

  • The PaymentChannelServiceImpl prepares a response containing the list of payment channels associated with the profile.

  • The PaymentChannelService sends the response back to the PaymentChannelController.

  • The PaymentChannelController sends a response entity containing the payment channels back to the client.

  • If no profile data is found or if the provided profileID is invalid, an IllegalArgumentException is thrown, and the corresponding error message is returned to the client.

7.10.2. Endpoint

Description

This endpoint retrieves all payment channels associated with a specific profile.

URL

/payments/channel/profiles/{profileID}

Method

GET

Request parameters

profileID (path): The unique identifier of the profile for which payment channels are to be retrieved.

Responses
  • 200 OK: Returns a successful response containing a list of payment channels associated with the specified profile.

Example response body
{
  "status": 200,
  "message": "Success",
  "data": [
    {
      "paymentChannels": {
        "paymentChannelID": "fb0fdb85-87ee-4af2-b39a-f3a23227203c",
        "contractID": null,
        "label": "Saving A/C",
        "type": "new",
        "units": "INR",
        "system": "IBAN",
         "accountCharacteristic": "isCash",
        "identifier": "David",
        "details": {
          "system": "IBAN",
          "address": "CH06007629PZ5UIAH8YFS"
        },
        "ownerType": "profile",
        "ownerID": "d2c87ded-489e-4510-8fe1-95f12c048a5d",
        "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
      },
      "units": "INR"
    },
    {
      "paymentChannels": {
        "paymentChannelID": "a523df29-abdd-4f53-b9c9-1baa9d96f183",
        "contractID": "1d39e542-ead1-4e5b-8a71-4308aadc69ee",
        "label": "CH4900762UQARWN52SP7U",
        "type": "new",
        "units": "CHF",
        "system": "IBAN",
        "accountCharacteristic": "isCash",
        "identifier": "CH4900762UQARWN52SP7U",
        "details": {
          "system": "IBAN",
          "address": "CH4900762UQARWN52SP7U"
        },
        "ownerType": "profile",
        "ownerID": "d2c87ded-489e-4510-8fe1-95f12c048a5d",
        "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
      },
    "units": "CHF"
    }
  }
}
  • 400 bad request: If no payment channels are associated with the specified profile.

{
  "status": 400,
  "message": "Invalid profileId (or) data not found",
  "data": null
}
  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to retrieves payment channels.

  • 5xx server error: If there is a server-side error while processing the request.

7.10.3. Methods

Description

This method retrieves payment channels associated with a specific user profile identified by the provided profileID .Parameters

  • profileID: The identifier of the user profile for which payment channels are to be retrieved.

Returns
  • Response<List<PaymentChannelResponseEntity>>: A response containing the payment channels associated with the specified user profile.

Example usage
public Response<List<PaymentChannelResponseEntity>> getPaymentChannelBasedOnProfileID(UUID profileID) {
		log.info("Retrieving payment channels based on profileId, userID : {}, request : {}", usersHelper.getUserID(),
				profileID);

		validator.checkProfileData(profileID); (1)

		return paymentWorker.getProfileList(profileID);(2)
	}}
Internal workflow
1 Calls the validator.checkProfileData(profileID) method to ensure the validity and existence of the user profile identified by profileID.
2 Retrieves the list of payment channels associated with the given profileID using paymentWorker.getProfileList(profileID) and returns a response containing said payment channels.
Exceptions

IllegalArgumentException: Throws an exception with the message "Invalid profileId (or) data not found" if the profile data is invalid or not found.

7.10.4. Testing

Description

The getPaymentChannelBasedOnProfileID test method evaluates the functionality of the getPaymentChannelBasedOnProfileID method within the PaymentChannelServiceImpl class. This test ensures that the method correctly retrieves payment channels associated with a specific profile ID.

Test methods

Example usage

@Test
	public void getPaymentChannelBasedOnProfileID() {

		String profileID = "f365dfca-2e7a-4b6b-addf-4d64f99142ee";
		Response<List<PaymentChannelResponseEntity>> getPaymentChannelBasedOnProfileID = paymentChannelServiceImpl
				.getPaymentChannelBasedOnProfileID(UUID.fromString(profileID));

		List<PaymentChannelResponseEntity> data = getPaymentChannelBasedOnProfileID.getData();
		UUID paymentChannelID = data.get(0).getPaymentChannels().getPaymentChannelID();

		UUID expectedPaymentChannelID = getRootUserPaymentChannelTemplate.get(0).getPaymentChannels()
				.getPaymentChannelID();

		Assertions.assertEquals(getRootUserPaymentChannelTemplate, getPaymentChannelBasedOnProfileID.getData());
		Assertions.assertEquals(expectedPaymentChannelID, paymentChannelID);
		Assertions.assertEquals("Success", getPaymentChannelBasedOnProfileID.getMessage());
		Assertions.assertEquals(200, getPaymentChannelBasedOnProfileID.getStatus());

	}

getPaymentChannelBasedOnProfileID

  • Purpose : The purpose of this test is to verify that the getPaymentChannelBasedOnProfileID method behaves as expected, retrieving payment channels associated with a specific profile ID and returning the appropriate response.

  • Test steps

    1. Define a profile ID string.

    2. Call the getPaymentChannelBasedOnProfileID method of the PaymentChannelServiceImpl class with the provided profile ID converted to a UUID.

    3. Retrieve the response object returned by the method.

    4. Extract the payment channel data from the response.

    5. Retrieve the payment channel ID from the data.

    6. Retrieve the expected payment channel ID from the root user payment channel template.

  • Assertions

    • Assert that the retrieved payment channel data matches the root user payment channel template.

    • Assert that the retrieved payment channel ID matches the expected payment channel ID.

    • Assert that the message in the response indicates success.

    • Assert that the status code of the response is 200.

7.11. Create external profile payment channels

7.11.1. Sequential flow

Create payment channel for external profiles flow.puml
Figure 22. provide payment channels based on user

Create payment channel for external profiles flow

  • The client sends a POST request to create a payment channel for an external profile.

  • The PaymentChannelController is activated to handle the incoming request.

  • The PaymentChannelController forwards the request to the PaymentChannelService to create the external profile payment channel.

  • The PaymentChannelService, specifically its implementation (PaymentChannelServiceImpl), takes over the processing of creating the external profile payment channel.

  • The PaymentChannelServiceImpl interacts with the Validator to check the validity of the provided ownerID and identifier.

  • The Validator queries the ProfilesRepository to find profile data associated with the specified ownerID.

  • If profile data is found, the Validator confirms its existence.

  • If profile data exists, the Validator checks if a payment channel with the provided identifier already exists.

  • If the provided identifier doesn’t exist, the PaymentChannelServiceImpl sets up the external profile payment channel using PaymentChannelHelper.

  • The created payment channel is saved in the PaymentChannelRepository.

  • The PaymentChannelServiceImpl prepares a response containing the created payment channel information.

  • The PaymentChannelService sends the response back to the PaymentChannelController.

  • The PaymentChannelController sends a response entity containing the created payment channel back to the client.

  • If the profile doesn’t exist or if the provided identifier already exists for another payment channel, IllegalArgumentExceptions are thrown with corresponding error messages returned to the client.

7.11.2. Endpoint

Description

This endpoint creates a payment channel for external profiles.

URL

/payments/channel/profiles/external

Method

POST

Request parameters

userID (path): The unique identifier of the root user for whom payment channels are to be retrieved.

Request body

The request body should be a JSON object representing data for creating a new external profile payment channel. It should adhere to the structure defined by the ExternalPaymentChannelDTO

Responses
  • 201 Created: Payment channel created successfully.

Example response body
{
  "status": 201,
  "message": "Payment channel created successfully",
  "data": {
    "paymentChannelID": "08914be0-3e96-4089-88e0-19d955f82b9d",
    "contractID": "12914be0-4e96-4089-44e0-44d955f82b9d,
    "label": "Savings A/C",
    "type": "external",
    "units": "INR",
    "system": "IBAN",
    "accountCharacteristic": "isBank",
    "identifier": "Katheriiiie12",
    "details": {
      "type": "external",
      "identifier": "Katheriiiie12",
      "label": "Savings A/C",
      "ownerID": "d2c87ded-489e-4510-8fe1-95f12c048a5d",
      "units": "INR"
    },
    "ownerType": "profile",
    "ownerID": "d2c87ded-489e-4510-8fe1-95f12c048a5d",
    "userID": "fe54273e-c645-49f5-9279-ad6d4067c606"
  }
}
  • 400 bad request: if the profile with the specified ownerID doesn’t exist or if the identifier is not unique

{
  "status": 400,
  "message": "Profile doesn't exist",
  "data": null
}
  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to create payment channels.

  • 5xx server error: If there is a server-side error while processing the request.

7.11.3. Methods

Description

This method creates an external payment channel associated with a user profile based on the provided paymentChannelData.

Parameters
  • paymentChannelData: The data representing the external payment channel to be created.

Returns
  • A response containing the status of the creation and the created payment channel.

Example usage
public Response<PaymentChannels> createExternalProfilePaymentChannel(ExternalPaymentChannelDTO paymentChannelData) {
		log.info("Creation of external profile payment channel started by userID : {}, request : {}",
				usersHelper.getUserID(), paymentChannelData);

		final Map<String, Object> paymentChannelMap = mapper.convertValue(paymentChannelData, Map.class); (1)

		validator.checkOwnerID(paymentChannelData.getOwnerID(), paymentChannelData.getIdentifier()); (2)

		// Set up an external payment channel for the user profile using the provided
		// data
		PaymentChannels paymentChannel = paymentChannelHelper.setExternalProfilePaymentChannel(paymentChannelMap,
				paymentChannelData); (3)

		paymentsRepo.save(paymentChannel); (4)

		log.info("Creation of external profile payment channel completed by userID : {}, request : {}",
				usersHelper.getUserID(), paymentChannelData);
		return new Response<>(HttpStatus.CREATED.value(), "Payment channel created successfully", paymentChannel);
	}
Internal workflow
1 The paymentChannelData object is converted into a Map<String, Object>.
2 The method checkOwnerID from the Validator class is called to ensure the validity and uniqueness of the owner ID and identifier for the payment channel.
3 The setExternalProfilePaymentChannel method from the PaymentChannelHelper class is called to create the payment channel object.
4 The created payment channel is saved using the paymentsRepo.
Exceptions

IllegalArgumentException: Throws an exception if the profile with the specified owner ID doesn’t exist or if the identifier is not unique.

7.11.4. Model Classes

Description

The ExternalPaymentChannelDTO class serves as a Data Transfer Object (DTO) designed for handling external payment channel data. It encompasses essential details required for creating a payment channel, including units, identifier, label, and ownerID.

Attributes
  1. type (String)

    • Description: Represents the type associated with the payment channel.

    • Constraints: Must not be null, must not be blank.

    • Example: "external"

  2. identifier (String)

    • Description: The identifier associated with the payment channel.

    • Constraints: Maximum 100 characters.

    • Example: "CH7200762Y62RKW1207GW"

  3. label (String)

    • Description: The label associated with the payment channel.

    • Constraints: Maximum 100 characters.

    • Example: "Savings A/C"

  4. ownerID (UUID)

    • Description: Specifies the unique identifier of the owner associated with the payment channel.

    • Constraints: Must not be null.

    • Example: "550e8400-e29b-41d4-a716-446655440000"

  5. units (String )

    • Description: The units associated with the payment channel.

    • Constraints: Not null, not blank, maximum 10 characters.

    • Example: "USD":

Constructors
  • Default constructor.

  • Parameterized constructor with all attributes.

Serialization and Deserialization
  • The class uses Lombok annotations @Getter, @Setter, @NoArgsConstructor, @AllArgsConstructor, and @ToString for serialization and deserialization. These annotations generate getter and setter methods, default and parameterized constructors, and a toString method for the class.

7.11.5. Testing

Description

The createExternalProfilePaymentChannel test method assesses the functionality of the createExternalProfilePaymentChannel method within the PaymentChannelServiceImpl class. This test ensures that the method correctly creates an external profile payment channel using the provided template.

Test methods

Example usage

	@Test
	public void createExternalProfilePaymentChannel() {

		Response<PaymentChannels> createExternalProfilePaymentChannel = paymentChannelServiceImpl
				.createExternalProfilePaymentChannel(externalPaymentChannelTemplate);

		PaymentChannels paymentChannel = createExternalProfilePaymentChannel.getData();
		UUID paymentChannelID = paymentChannel.getPaymentChannelID();
		System.err.println(paymentChannel);

		Assertions.assertEquals(paymentChannelsTemplate.get(0), createExternalProfilePaymentChannel.getData());
		Assertions.assertEquals(paymentChannelsTemplate.get(0).getPaymentChannelID(), paymentChannelID);
		Assertions.assertEquals("Payment channel created successfully",
				createExternalProfilePaymentChannel.getMessage());
		Assertions.assertEquals(201, createExternalProfilePaymentChannel.getStatus());
	}

createExternalProfilePaymentChannel

  • Purpose : The purpose of this test is to verify that the createExternalProfilePaymentChannel method behaves as expected, creating a new external profile payment channel based on the provided template and returning the appropriate response.

  • Test steps

    1. Call the createExternalProfilePaymentChannel method of the PaymentChannelServiceImpl class with the externalPaymentChannelTemplate.

    2. Retrieve the response object returned by the method.

    3. Extract the payment channel data from the response.

    4. Retrieve the payment channel ID from the data.

  • Assertions

    • Assert that the created payment channel matches the provided payment channel template.

    • Assert that the payment channel ID matches the expected payment channel ID.

    • Assert that the message in the response indicates successful creation of the payment channel.

    • Assert that the status code of the response is 201.

7.12. Provide profile payment channels

7.12.1. Sequential flow

Provide profile payment channel flow.puml
Figure 23. provide payment channel

Provide profile payment channel flow

  • The client sends a GET request to retrieve payment channels associated with a user profile.

  • The PaymentChannelController is activated to handle the incoming request.

  • The PaymentChannelController forwards the request to the PaymentChannelService to retrieve the profile payment channels.

  • The PaymentChannelService, specifically its implementation (PaymentChannelServiceImpl), takes over the processing of retrieving the profile payment channels.

  • The PaymentChannelServiceImpl interacts with UsersHelper to retrieve the user ID associated with the request.

  • If units are provided in the request, the PaymentChannelServiceImpl queries the PaymentChannelRepository to find payment channels filtered by units, owner type, and user ID.

  • If no units are provided, it retrieves all payment channels associated with the user profile without filtering by units.

  • The PaymentChannelServiceImpl prepares a response containing the retrieved payment channels.

  • The PaymentChannelService sends the response back to the PaymentChannelController.

  • The PaymentChannelController sends a response entity containing the retrieved payment channels back to the client.

7.12.2. Endpoint

Description

This endpoint retrieves profile payment channels, optionally filtered by units.

URL

/payments/channel/profiles

Method

GET

Request parameters

units (optional): The filter criteria for selecting payment channels.

Responses
  • 200 OK: Returns a successful response containing details of the specified payment channel.

Example response body
{
  "status": 200,
  "message": "Success",
  "data": [
    {
      "paymentChannelID": "08914be0-3e96-4089-88e0-19d955f82b9d",
      "contractID": null,
      "label": "Savings A/C",
      "type": "external",
      "units": "INR",
      "system": "IBAN",
      "accountCharacteristic": isBank,
      "identifier": "Katheriiiie12",
      "details": {
        "type": "external",
        "label": "Savings A/C",
        "units": "INR",
        "ownerID": "d2c87ded-489e-4510-8fe1-95f12c048a5d",
        "identifier": "Katheriiiie12"
      },
      "ownerType": "profile",
      "ownerID": "d2c87ded-489e-4510-8fe1-95f12c048a5d",
      "userID": "fe54273e-c645-49f5-9279-ad6d4067c606"
    },
    {
      "paymentChannelID": "a28855a8-6581-4b7e-9096-b47e87e70353",
      "contractID": null,
      "label": "Saving A/C",
      "type": "new",
      "units": "INR",
      "system": "IBAN",
      "accountCharacteristic": isBank,
      "identifier": "mmmmm",
      "details": {
        "system": "IBAN",
        "address": "CH7500762QUVXZNF1PP8S"
      },
      "ownerType": "profile",
      "ownerID": "d2c87ded-489e-4510-8fe1-95f12c048a5d",
      "userID": "fe54273e-c645-49f5-9279-ad6d4067c606"
    }
  ]
}
  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to retrieves payment channels.

  • 5xx server error: If there is a server-side error while processing the request.

7.12.3. Methods

Description

This method retrieves payment channels associated with a user profile, optionally filtered by units.

Parameters
  • units: The units used for filtering the payment channels. If null or empty, all payment channels associated with the user profile are retrieved.

Returns
  • A response containing a list of payment channels associated with the user profile, filtered by units if provided.

Example usage
	public Response<List<PaymentChannels>> getProfilePaymentChannels(String units) {
		log.info("Retrieving profile payment channels bases on units by userID : {}, request : {}",
				usersHelper.getUserID(), units);

		if (UtilityHelper.isNotNullOrEmpty(units)) { (1)
			// Retrieve a list of payment channels associated with the user profile and
			// filtered by units
			List<PaymentChannels> listOfPayments = paymentsRepo
					.findByOwnerTypeAndUserIDAndUnitsAndContractIDIsNotNull("profile", usersHelper.getUserID(), units);
			return new Response<>(HttpStatus.OK.value(), "Success", listOfPayments);
		}

		// If no units are provided, retrieve all payment channels associated with the
		// user profile
		List<PaymentChannels> listOfPayments = paymentsRepo.getByOwnerTypeAndUserID("profile", usersHelper.getUserID()); (2)

		return new Response<>(HttpStatus.OK.value(), "Success", listOfPayments);
	}
Internal workflow
1 If units are provided, payment channels associated with the user profile are retrieved from the repository based on the specified units.
2 If no units are provided, all payment channels associated with the user profile are retrieved.
Exceptions
  • None explicitly thrown by this method.

7.12.4. Testing

Description

The getProfilePaymentChannels test method evaluates the functionality of the getProfilePaymentChannels method within the PaymentChannelServiceImpl class. This test ensures that the method correctly retrieves payment channels associated with a specific profile, specified by the units parameter.

Test methods

Example usage

 	@Test
	public void getProfilePaymentChannels() {

		String units = "INR";
		Response<List<PaymentChannels>> getProfilePaymentChannels = paymentChannelServiceImpl
				.getProfilePaymentChannels(units);
		List<PaymentChannels> channels = getProfilePaymentChannels.getData();

		Assertions.assertEquals(paymentChannelsTemplate, channels);
		Assertions.assertEquals(paymentChannelsTemplate.get(0).getPaymentChannelID(),
				channels.get(0).getPaymentChannelID());
		Assertions.assertEquals("Success", getProfilePaymentChannels.getMessage());
		Assertions.assertEquals(200, getProfilePaymentChannels.getStatus());
	}

getProfilePaymentChannels

  • Purpose : The purpose of this test is to verify that the getProfilePaymentChannels method behaves as expected, retrieving payment channels associated with a specific profile and returning the appropriate response.

  • Test steps

    1. Define the units parameter as "INR".

    2. Call the getProfilePaymentChannels method of the PaymentChannelServiceImpl class with the specified units parameter.

    3. Retrieve the response object returned by the method.

    4. Extract the payment channels data from the response.

  • Assertions

    • Assert that the retrieved payment channels match the payment channels template.

    • Assert that the payment channel ID of the first payment channel in the response matches the expected payment channel ID.

    • Assert that the message in the response indicates success.

    • Assert that the status code of the response is 200.

7.13. Provides root payment channel

7.13.1. Sequential flow

Provides root payment channel flow.puml
Figure 24. provide root payment channel

Provides root payment channel flow

  • The client sends a GET request to retrieve root user payment channels.

  • The PaymentChannelController is activated to handle the incoming request.

  • The PaymentChannelController forwards the request to the PaymentChannelService to retrieve the root user payment channels.

  • The PaymentChannelService, specifically its implementation (PaymentChannelServiceImpl), takes over the processing of retrieving the root user payment channels.

  • The PaymentChannelServiceImpl interacts with UsersHelper to retrieve the user ID associated with the request.

  • The PaymentChannelServiceImpl queries the PaymentChannelRepository to find payment channels associated with the root user (ownerType: ROOT) and the retrieved user ID.

  • For each payment channel found

    • The PaymentChannelServiceImpl interacts with PaymentWorker to assign a notional value to the payment channel.

    • If a contract exists for the payment channel

      1. It interacts with ContractsFeignClient to fetch contract data.

      2. Parses contract terms and extracts the notional value.

      3. Checks the contract role and notional value sign.

      4. If the contract role is "RPL" (Replenisher) and the notional value is positive, it makes the notional value negative to signify an outgoing payment.

    • If no contract is found, it returns a notional value of 0.0.

This loop continues for each payment channel.

  • If payment channels are found, the PaymentChannelServiceImpl prepares a response containing the retrieved root user payment channels. If no payment channels are found, it returns an empty response.

  • The PaymentChannelService sends the response back to the PaymentChannelController.

  • The PaymentChannelController sends a response entity containing the retrieved root user payment channels back to the client.

7.13.2. Endpoint

Description

This endpoint retrieves the root payment channel.

URL

/payments/channel/root

Method

GET

Parameters
  • This endpoint doesn’t take any parameters.

Responses
  • 200 OK: Returns a successful response containing a list of payment channels associated with the root user.

Example response body
{
  "status": 200,
  "message": "Success",
  "data": [
      {
      "paymentChannels": {
        "paymentChannelID": "72af9abe-d428-41fa-bb19-be5db67e60c8",
        "contractID": "3e1b7893-5b24-45bc-b3f8-238caa59d246",
        "label": "Saving A/C",
        "type": "new",
        "units": "ETHU",
        "system": "IBAN",
        "accountCharacteristic": "isBank",
        "identifier": "Jeoff",
        "details": {
          "system": "IBAN",
          "address": "CH2100762ZH2ZEM01J6AS"
        },
        "ownerType": "root",
        "ownerID": "fe54273e-c645-49f5-9279-ad6d4067c606",
        "userID": "fe54273e-c645-49f5-9279-ad6d4067c606"
      },
      "value": 0
    }
  ]
}
  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to retrieve payment channels.

  • 5xx server error: If there is a server-side error while processing the request.

7.13.3. Methods

Description

This method retrieves payment channels associated with the root user along with their respective notional values. It iterates through the list of payment channels associated with the root user, attempts to assign a notional value to each payment channel, and constructs a response containing the payment channels and their notional values.

Parameters
  • This method doesn’t take any parameters.

Returns
  • Response<List<RootPaymentChannelResponse>>: A response object containing a list of RootPaymentChannelResponse objects representing the payment channels associated with the root user and their respective notional values.

Example usage
public Response<List<RootPaymentChannelResponse>> getRootPaymentChannel() {
		log.info("userID : {}, request : {}", usersHelper.getUserID(), "Retrieving root user payment channels");

		final List<RootPaymentChannelResponse> arrayList = new ArrayList<>(); (1)

		// Retrieve a list of payment channels associated with the root user
		final List<PaymentChannels> listOfPayments = paymentsRepo.getByOwnerTypeAndOwnerID("root",
				usersHelper.getUserID()); (2)

		for (final PaymentChannels paymentChannels : listOfPayments) { (3)

			final RootPaymentChannelResponse rootUserResponse = new RootPaymentChannelResponse();
			rootUserResponse.setPaymentChannels(paymentChannels);

			// Attempt to assign a notional value to the payment channel
			try {
				double notionalValue = paymentWorker.assignNotionalValue(paymentChannels);
				rootUserResponse.setValue(notionalValue);
				arrayList.add(rootUserResponse);
			} catch (Exception e) {

				// If an exception occurs, add the response to the list without a value
				arrayList.add(rootUserResponse);
			}
		}

		return new Response<>(HttpStatus.OK.value(), Constants.SUCCESS, arrayList); (4)
	}
Internal workflow
1 Initializes an empty list to store RootPaymentChannelResponse objects.
2 Retrieves a list of payment channels associated with the root user from the repository (paymentsRepo).
3 For each payment channel in the retrieved list
  • Creates a new RootPaymentChannelResponse object.

  • Sets the payment channel information to the response object.

  • Attempts to assign a notional value to the payment channel using paymentWorker.assignNotionalValue(paymentChannels).

  • If successful, sets the calculated notional value to the response object and adds it to the list.

  • If an exception occurs during the calculation of the notional value, adds the response object to the list without a value.

4 Constructs a response containing the list of RootPaymentChannelResponse objects.
Exceptions

This method handles exceptions by logging them and continuing the process without interrupting the flow.

7.13.4. Testing

Description

The getRootUserPaymentChannel test method evaluates the functionality of the getRootPaymentChannel method within the PaymentChannelServiceImpl class. This test ensures that the method correctly retrieves the root user payment channel.

Test methods

Example usage

 @Test
	public void getRootUserPaymentChannel() {

		Response<List<RootPaymentChannelResponse>> getRootUserPaymentChannel = paymentChannelServiceImpl
				.getRootPaymentChannel();

		List<RootPaymentChannelResponse> data = getRootUserPaymentChannel.getData();
		UUID paymentChannelID = data.get(0).getPaymentChannels().getPaymentChannelID();

		UUID paymentChannelID2 = rootUserPaymentChannelResponseTemplate.get(0).getPaymentChannels()
				.getPaymentChannelID();

		Assertions.assertEquals(paymentChannelID2, paymentChannelID);
		Assertions.assertEquals("Success", getRootUserPaymentChannel.getMessage());
		Assertions.assertEquals(200, getRootUserPaymentChannel.getStatus());
	}

getRootUserPaymentChannel

  • Purpose : The purpose of this test is to verify that the getProfilePaymentChannels method behaves as expected, retrieving payment channels associated with a specific profile and returning the appropriate response.

  • Test steps

    1. Call the getRootPaymentChannel method of the PaymentChannelServiceImpl class.

    2. Retrieve the response object returned by the method.

    3. Extract the data from the response, which should contain a list of root user payment channel responses.

    4. Retrieve the payment channel ID from the data.

    5. Retrieve the expected payment channel ID from the root user payment channel response template.

  • Assertions

    • Assert that the retrieved payment channel ID matches the expected payment channel ID.

    • Assert that the message in the response indicates success.

    • Assert that the status code of the response is 200.

ledger service

1. Introduction

The ledger endpoints allows adding new and managing existing ledgers.Every Transaction details are updated in ledger and states of each contract are stored accordingly.

2. Tables and relations

Establishing Relationships:

  • In relational databases like PostgreSQL, relationships between tables are crucial for organizing and querying data effectively. These relationships are typically established using foreign key constraints, which define links between tables based on the values of specific columns. Common types of relationships include one-to-one, one-to-many, and many-to-many relationships, each serving different data modeling needs.

ledger ERD
Figure 25. Events Entity-Relationship Diagram

Tables

  • Schema:

Ledger service

  1. Table contracts

    Idx Name Data Type

    * πŸ”‘ ⬋

    contractuuid

    uuid

    ⬈

    productid

    bigint

    *

    createdby

    uuid

    executedby

    uuid

    *

    system_time

    timestamp

    selection

    json

    1. Indexes

      Type Name On

      πŸ”‘

      contracts_pkey

      ON contractuuid

    2. Foreign Keys

      Type Name On

      contracts_product_fk

      productid

  2. Table ledger

    Idx Name Data Type

    * πŸ”‘

    ledger_entryid

    uuid

    *

    amount

    numeric

    *

    event_type

    varchar(10)

    *

    credit_ledger_accountid

    uuid

    *

    system_time

    timestamp

    *

    debit_ledger_accountid

    uuid

    *

    eventid

    uuid

    *

    userid

    uuid

    *

    process_time

    timestamp

    *

    units

    varchar(10)

    1. Indexes

      Type Name On

      πŸ”‘

      ledger_pkey

      ON ledger_entryid

    2. Constraints

      Name Definition

      ledger_event_type_check

      event_type::text ~* '^(AD/IED/FP/PR/PD/PRF/PY/PP/IP/IPCI/CE/RRF/RR/DV/PRD/MR/TD/SC/IPCB/MD/XD/STD/PI/IPFX/IPFL/ME/TP/OPS)$'::text

  3. Table ledger_account_states

    Idx Name Data Type

    * πŸ”‘

    ledger_accountid

    uuid

    * πŸ”‘

    status_date

    timestamp

    *

    value

    numeric

    1. Indexes

      Type Name On

      πŸ”‘

      ledger_account_states_pkey

      ON ledger_accountid, status_date

  4. Table ledger_accounts

    Idx Name Data Type

    * πŸ”‘

    ledger_accountid

    uuid

    πŸ”Ž

    associated_with_contractid

    uuid

    *

    ledger_account_label

    varchar(20)

    * πŸ”Ž

    ledger_account_type

    varchar(10)

    * πŸ”Ž

    userid

    uuid

    status_date

    timestamp

    1. Indexes

      Type Name On

      πŸ”‘

      ledger_accounts_pkey

      ON ledger_accountid

      πŸ”Ž

      idx_associated_contract_id_ledger_account_type

      ON associated_with_contractid, ledger_account_type

      πŸ”Ž

      idx_ledger_account_id_user_id

      ON ledger_accountid, userid

  5. Table payment_channels

    Idx Name Data Type

    * πŸ”‘ ⬋

    payment_channelid

    uuid

    contractid

    uuid

    details

    json

    *

    identifier

    varchar(100)

    label

    varchar(100)

    *

    type

    varchar(50)

    * πŸ”Ž

    owner_type

    varchar(10)

    *

    units

    varchar(10)

    *

    system

    varchar(50)

    account_characteristic

    varchar(50)

    * πŸ”Ž

    ownerid

    uuid

    * πŸ”Ž

    userid

    uuid

    1. Indexes

      Type Name On

      πŸ”‘

      payment_channels_pkey

      ON payment_channelid

      πŸ”Ž

      payment_channels_idx_payment_channel_id_owner_id

      ON payment_channelid, ownerid

      πŸ”Ž

      payment_channels_idx_owner_type_user_id

      ON owner_type, userid

      πŸ”Ž

      payment_channels_idx_owner_type_owner_id

      ON owner_type, ownerid

    2. Constraints

      Name Definition

      payment_channels_owner_type_check

      ((owner_type)::text ~* ’^(root

  6. Table payment_details

    Idx Name Data Type

    * πŸ”‘

    id

    bigint GENERATED BY DEFAULT AS IDENTITY

    ⬈

    contract_uuid

    uuid

    ⬈

    record_creator_paymentchannel_id

    uuid

    ⬈

    counterparty_paymentchannel_id

    uuid

    ⬈

    contract_paymentchannel_id

    uuid

    1. Indexes

      Type Name On

      πŸ”‘

      payment_details_pkey

      ON id

    2. Foreign Keys

      Type Name On

      paymentdetails_contractuuid_fk

      contract_uuid

      paymentdetails_contract_payment_fk

      contract_paymentchannel_id

      paymentdetails_counterparty_fk

      counterparty_paymentchannel_id

      paymentdetails_record_creator_fk

      record_creator_paymentchannel_id

  7. Table products

    Idx Name Data Type

    * πŸ”‘ ⬋

    productid

    bigint GENERATED BY DEFAULT AS IDENTITY

    *

    status

    varchar(10)

    *

    template

    json

    * πŸ”Ž

    userid

    uuid

    1. Indexes

      Type Name On

      πŸ”‘

      products_pkey

      ON productid

      πŸ”Ž

      products_idx_userid

      ON userid

    2. Constraints

      Name Definition

      products_status_check

      status::text ~* '^(active/inactive)$'::text

      ===

  8. Table profile_forms

    Idx Name Data Type

    * πŸ”‘ ⬋

    profile_formid

    bigint GENERATED BY DEFAULT AS IDENTITY

    *

    profile_form_details

    json

    *

    userid

    uuid

    1. Indexes

      Type Name On

      πŸ”‘

      profile_forms_pkey

      ON profile_formid

  9. Table profiles

    Idx Name Data Type

    * πŸ”‘ ⬋

    profileid

    uuid

    profile_details

    json

    *

    status

    varchar(10)

    *

    userid

    uuid

    * ⬈

    profile_formid

    bigint

    1. Indexes

      Type Name On

      πŸ”‘

      profiles_pkey

      ON profileid

    2. Foreign Keys

      Type Name On

      fk_profiles_profile_forms_profile_formid

      profile_formid

    3. Constraints

    Name Definition

    profiles_status_check

    status::text ~* '^(active/inactive)$'::text

  10. Table terms

    Idx Name Data Type

    * πŸ”‘

    id

    bigint GENERATED BY DEFAULT AS IDENTITY

    accrued_interest

    numeric

    amortization_date

    timestamp

    array_cycle_anchor_date_of_interest_payment

    varchar(255)

    array_cycle_anchor_date_of_principal_redemption

    varchar(255)

    array_cycle_anchor_date_of_rate_reset

    varchar(255)

    array_cycle_of_interest_payment

    varchar(255)

    array_cycle_of_principal_redemption

    varchar(255)

    array_cycle_of_rate_reset

    varchar(255)

    array_fixed_variable

    varchar(255)

    array_increase_decrease

    varchar(255)

    array_next_principal_redemption_payment

    varchar(255)

    array_rate

    varchar(255)

    business_day_convention

    varchar(5)

    calendar

    varchar(2)

    capitalization_end_date

    timestamp

    contract_deal_date

    timestamp

    contractid

    varchar(255)

    *

    contract_role

    varchar(6)

    contract_performance

    varchar(10)

    *

    contract_type

    varchar(15)

    *

    currency

    varchar(10)

    currency2

    varchar(10)

    cycle_anchor_date_of_dividend_payment

    timestamp

    cycle_anchor_date_of_fee

    timestamp

    cycle_anchor_date_of_interest_calculation_base

    timestamp

    cycle_anchor_date_of_interest_payment

    timestamp

    cycle_anchor_date_of_optionality

    timestamp

    cycle_anchor_date_of_principal_redemption

    timestamp

    cycle_anchor_date_of_rate_reset

    timestamp

    cycle_anchor_date_of_scaling_index

    timestamp

    cycle_of_dividend_payment

    varchar(10)

    cycle_of_fee

    varchar(10)

    cycle_of_interest_calculation_base

    varchar(10)

    cycle_of_interest_payment

    varchar(10)

    cycle_of_optionality

    varchar(10)

    cycle_of_principal_redemption

    varchar(10)

    cycle_of_rate_reset

    varchar(10)

    cycle_of_scaling_index

    varchar(10)

    cycle_point_of_interest_payment

    varchar(1)

    cycle_point_of_rate_reset

    varchar(1)

    *

    day_count_convention

    varchar(10)

    delivery_settlement

    varchar(1)

    end_of_month_convention

    varchar(5)

    fee_accrued

    numeric

    fee_basis

    varchar(1)

    fee_rate

    numeric

    fixing_period

    varchar(255)

    initial_exchange_date

    timestamp

    interest_calculation_base

    varchar(10)

    interest_calculation_base_amount

    numeric

    life_cap

    numeric

    life_floor

    numeric

    market_object_code

    varchar(255)

    market_object_code_of_dividend_rate

    varchar(255)

    market_object_code_of_rate_reset

    varchar(255)

    market_object_code_of_scaling_index

    varchar(255)

    market_value_observed

    numeric

    maturity_date

    timestamp

    maximum_penalty_free_disbursement

    varchar(255)

    next_principal_redemption_payment

    numeric

    next_reset_rate

    numeric

    nominal_interest_rate

    numeric

    nominal_interest_rate2

    numeric

    notional_principal

    numeric

    notional_principal2

    numeric

    object_code_of_prepayment_model

    varchar(255)

    penalty_rate

    numeric

    penalty_type

    varchar(1)

    period_cap

    numeric

    period_floor

    numeric

    premium_discount_atied

    numeric

    price_at_purchase_date

    numeric

    price_at_termination_date

    numeric

    purchase_date

    timestamp

    quantity

    numeric

    rate_spread

    numeric

    rounding_convention

    varchar(255)

    scaling_effect

    varchar(5)

    scaling_index_at_contract_deal_date

    numeric

    settlement_period

    varchar(255)

    status_date

    timestamp

    x_day_notice

    varchar(255)

    termination_date

    timestamp

    delinquency_period

    varchar(255)

    grace_period

    varchar(255)

    market_object_code_of_dividends

    varchar(255)

    rate_multiplier

    numeric

    * ⬈

    contract_uuid

    uuid

    ⬈

    counterparty_id

    uuid

    * πŸ”Ž

    creator_id

    uuid

    1. Indexes

      Type Name On

      πŸ”‘

      terms_pkey

      ON id

      πŸ”Ž

      terms_idx_creator_id

      ON creator_id

    2. Foreign Keys

      Type Name On

      terms_contractuuid_fk

      contract_uuid

      terms_counterparty_id_fk

      counterparty_id

    3. Constraints

    [[width="100%",cols="50%,50%",options="header",]

Name

Definition

terms_business_day_convention_check

business_day_convention::text ~* '^(NOS/SCF/SCMF/CSF/CSMF/SCP/SCMP/CSP/SCMP)$'::text

terms_calendar_check

calendar::text ~* '^(NC/MF)$'::text

terms_fee_basis_check

fee_basis::text ~* '^(A/N)$'::text

terms_delivery_settlement_check

delivery_settlement::text ~* '^(D/S)$'::text

terms_cycle_of_dividend_payment_check

cycle_of_dividend_payment)::text ~ ‘(([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?L(?:([0-1]?)’::text)

terms_cycle_of_interest_calculation_base_check

cycle_of_interest_calculation_base)::text ~ ‘(([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?L(?:([0-1]?)’::text)

terms_cycle_of_interest_payment_check

cycle_of_interest_payment)::text ~ ‘(([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?L(?:([0-1]?)’::text)

terms_cycle_of_principal_redemption_check

cycle_of_principal_redemption)::text ~ ‘(([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?L(?:([0-1]?)’::text)

terms_cycle_of_rate_reset_check

cycle_of_rate_reset)::text ~ ‘(([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?L(?:([0-1]?)’::text)

terms_cycle_of_scaling_index_check

cycle_of_scaling_index)::text ~ ‘(([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?L(?:([0-1]?)’::text)

terms_cycle_point_of_interest_payment_check

cycle_point_of_interest_payment::text ~* '^(B/E)$'::text

terms_contract_performance_check

contract_performance::text ~* '^(PF/DL/DQ/DF/MA/TE/PreDeal)$'::text

terms_penalty_type_check

penalty_type::text ~* '^(N/A/R/I)$'::text

+

  1. Table trail_balance_report

Idx Name Data Type

* πŸ”‘

contractuuid

uuid

* πŸ”‘

date

varchar(255)

*

credit

numeric

*

debit

numeric

payment_channelid

uuid

payment_identifier

uuid

payment_label

varchar(255)

*

userid

uuid

  1. Indexes

    Type Name On

    πŸ”‘

    trail_balance_report_pkey

    ON contractuuid, date

2.1. Libraries

Description:

The following libraries are used in the project to provide various functionalities and features:

  1. actus-core (version 1.0.1):

    • Purpose: The actus-core library provides core functionality and utilities for working with financial contracts and cash flow projections based on the ACTUS standard.

    • Usage: Use to perform calculations, projections, and analysis of financial contracts and cash flows according to the ACTUS (Algorithmic Contract Types Unified Standards) standard.

3. Exception handling

Description

The RestExceptionHandler class provides centralized exception handling for RESTful API endpoints, ensuring consistent error responses throughout the application.

Exception handlers

Example usage

@ControllerAdvice
public class RestExceptionHandler {

	@ExceptionHandler({ LedgerServiceException.class, IllegalArgumentException.class })
	public ResponseEntity<Response<String>> exceptionToDoHandler(Exception ex) { (1)
		final Response<String> error = new Response<>();
		error.setStatus(HttpStatus.BAD_REQUEST.value());
		error.setMessage(ex.getMessage());
		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

	@ExceptionHandler(MethodArgumentNotValidException.class)
	public ResponseEntity<Response<String>> handleValidationException(MethodArgumentNotValidException ex) { (2)
		BindingResult bindingResult = ex.getBindingResult();
		FieldError fieldError = bindingResult.getFieldError();

		final Response<String> error = new Response<>();
		error.setStatus(HttpStatus.BAD_REQUEST.value());
		error.setMessage(fieldError.getDefaultMessage());
		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

	@ExceptionHandler(Exception.class)
	public ResponseEntity<Response<String>> exceptionHandler(Exception ex) { (3)
		final Response<String> error = new Response<>();
		error.setStatus(HttpStatus.BAD_REQUEST.value());
		error.setMessage("The request could not be understood by the server due to malformed syntax.");
		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

}
1 LedgerServiceException and IllegalArgumentException handler
  • Handles exceptions of types LedgerServiceException and IllegalArgumentException.

  • Returns a ResponseEntity with a status code of 400 (BAD_REQUEST) and an error message derived from the exception’s message.

2 MethodArgumentNotValidException handler
  • Handles exceptions of type MethodArgumentNotValidException, typically occurring during input validation.

  • Retrieves the first field error from the binding result and returns it as the error message along with a status code of 400 (BAD_REQUEST).

3 Generic exception handler
  • Handles any other uncaught exceptions that may occur during the execution of API endpoints.

  • Returns a ResponseEntity with a status code of 400 (BAD_REQUEST) and a generic error message indicating malformed syntax.

Customization

  • Additional exception handlers can be added to address specific use cases or domain-specific exceptions.

  • Error messages and status codes can be customized based on application requirements and error scenarios.

5. API

6. LedgerServiceController

6.1. Creates custom ledger accounts

6.1.1. Sequential flow

Create custom ledger accounts.puml
Figure 26. Create custom ledger accounts

Create custom ledger accounts process:

  • Client sends a request with ledger data to create custom ledger accounts.

  • LedgerServiceController handles the incoming request.

  • LedgerServiceController forwards the request to LedgerAccountsService.

  • LedgerAccountsServiceImpl processes creation with LedgerAccountsRepository.

  • Response with saved ledger account IDs sent back to client; in case of failure, appropriate error message returned.

6.1.2. Endpoint

Description

This endpoint creates custom ledger accounts.

URL

/accounting/ledger/accounts

Method

POST

Request body

The request body should be a JSON object representing data for creating a new custom ledger account. It should adhere to the structure defined by the CreateLedgerAccountsDto class.

Example request body
{
  "label": "Saving A/C",
  "type": "new"
}
Responses
  • 200 OK: Success. Returns a JSON response containing details of the created custom ledger account.

Example response body
{
  "status": 200,
  "message": "Custom ledger accounts created successfully",
  "data": "c8f4f920-3b25-4b78-bdfb-f2e3d8a4c3a5"
}
  • 400 bad request: If the request body is not in the correct format or if there are validation errors.

{
  "status": 400,
  "message": "Custom ledger accounts isn't created",
  "data": null
}
  • 401 unauthorized: If there is an issue with the request body, such as missing or invalid parameters.

  • 5xx server error: If there is a server-side error while processing the request.

6.1.3. Methods

Description

This method creates custom ledger accounts based on the provided data.

Parameters
  • ledgerData: The data used to create the custom ledger account. It includes the label and type of the ledger account.

Returns
  • Response<UUID>: A Response object indicating the result of the operation. It contains the UUID of the created ledger account. .Example usage

	public Response<UUID> createCustomLedgerAccounts(CreateLedgerAccountsDto ledgerData) throws LedgerServiceException {
		try {

			log.info("Create custom ledger account started by User : {}, Request : {}", usersHelper.getUserID(),
					ledgerData);

			// Create a new LedgerAccounts object with the provided data and default values.
			LedgerAccounts ledgerAccounts = new LedgerAccounts(ledgerData.getType(), ledgerData.getLabel(), null,
					UtilityHelper.systemLocalDateTime(), usersHelper.getUserID()); (1)

			ledgerAccounts = ledgerAccountsRepository.save(ledgerAccounts); (2)

			log.info("Ledger account created by User : {}, LedgerAccountID : {}", ledgerAccounts.getLedgerAccountID(),
					ledgerData);

			return new Response<>(HttpStatus.OK.value(), "Custom ledger accounts created successfully",
					ledgerAccounts.getLedgerAccountID()); (3)

		} catch (final Exception e) {
			throw new LedgerServiceException("Custom ledger accounts isnΒ΄t created"); (4)
		}
	}
Internal workflow
1 Creates a new LedgerAccounts object with the provided data and default values, including the current timestamp and the user ID retrieved from the UsersHelper.
2 Saves the newly created ledger account using the ledgerAccountsRepository.
3 Constructs and returns a Response object containing the UUID of the created ledger account.
4 Catches any exceptions that occur during the process. If an exception occurs, it throws a LedgerServiceException with an appropriate error message.
Exceptions

LedgerServiceException: If there’s an issue during the ledger account creation.

6.1.4. Model classes

Description:

The CreateLedgerAccountsDto class represents a Data Transfer Object (DTO) containing details for creating ledger accounts. It includes information such as label and type.

Attributes:
  1. label (String)

    • Description: The label associated with the ledger account.

    • Constraints: Not blank.

    • Example: "contract"

  2. type (String)

    • Description: The type associated with the ledger account.

    • Constraints: Not blank.

    • Example: "ipac"

Constructors:
  • Default constructor.

  • Parameterized constructor with all attributes.

Serialization and Deserialization:
  • The class uses Lombok annotations @Getter, @Setter, @NoArgsConstructor, @AllArgsConstructor, and @ToString for serialization and deserialization. These annotations generate getter and setter methods, default and parameterized constructors, and a toString method for the class.

6.1.5. Testing

Description

This test case verifies the creation of custom ledger accounts by the createCustomLedgerAccounts method in the LedgerAccountsServiceImpl class.

Test methods

Example usage

 /**
     * Test case to verify the creation of custom ledger accounts.
     *
     * @throws LedgerServiceException if an error occurs during the test
     */
	@Test
	void createCustomLedgerAccountsTest() throws LedgerServiceException {
		   // Prepare a CreateLedgerAccountsDto with sample data.
		CreateLedgerAccountsDto createLedgerAccountsDto = new CreateLedgerAccountsDto();
		createLedgerAccountsDto.setLabel("contract");
		createLedgerAccountsDto.setType("nv");
		  // Prepare a mock LedgerAccounts object.
		LedgerAccounts ledgerAccounts = new LedgerAccounts(createLedgerAccountsDto.getType(),
				createLedgerAccountsDto.getLabel(), null, LocalDateTime.parse(UtilityHelper.dateTime()),
				usersHelper.getUserID());
		UUID ledgerAccountID = UUID.randomUUID();
		ledgerAccounts.setLedgerAccountID(ledgerAccountID);

		when(ledgerAccountsRepository.save(any())).thenReturn(ledgerAccounts);

		@SuppressWarnings("rawtypes")
		Response response = ledgerAccountsServiceImpl.createCustomLedgerAccounts(createLedgerAccountsDto);
		  // Perform assertions to verify the response data and status.
		Assertions.assertEquals(ledgerAccountID.toString(), response.getData().toString());
		Assertions.assertEquals(200, response.getStatus());
	}

createCustomLedgerAccountsTest

  • Purpose : The purpose of this test is to ensure that the createCustomLedgerAccounts method behaves correctly by creating custom ledger accounts with the provided data and returning the appropriate response.

  • Test steps

    1. Prepare a CreateLedgerAccountsDto object with sample data.

    2. Prepare a mock LedgerAccounts object with the same data.

    3. Set up the behavior of the ledgerAccountsRepository mock to return the mock LedgerAccounts object when save method is called.

    4. Call the createCustomLedgerAccounts method with the prepared CreateLedgerAccountsDto.

    5. Retrieve the response object returned by the method.

  • Assertions

    • Assert that the returned ledger account ID matches the expected value.

    • Assert that the status code of the response is 200.

6.2. Update ledger accounts

6.2.1. Sequential flow

Update ledger account.puml
Figure 27. Update ledger account

Update ledger account process:

  • Client sends a request to update a ledger account with ID and updated label.

  • LedgerServiceController handles the request.

  • LedgerServiceController forwards the request to LedgerAccountsService.

  • LedgerAccountsService updates the account label via LedgerAccountsRepository.

  • Response with updated ledger account ID sent back to client; in case of invalid ID, appropriate error message returned.

6.2.2. Endpoint

Description

This endpoint allows users to update ledger accounts.

URL

/accounting/ledger/accounts/{ledgerAccountID}

Method

PUT

Request parameters

ledgerAccountID (Path variable): The unique identifier of the ledger account to be updated.

Request body

The request body should be a JSON object representing the changes to be applied to the ledger account label. It should adhere to the structure defined by the UpdateLedgerAccountsDto class.

Responses
  • 200 OK: Returns a JSON response indicating that the ledger account label was updated successfully.

Example response body
{
  "status": 200,
  "message": "LedgerAccount label updated successfully",
  "data": "ee3101b0-203d-4421-aacd-77c9e10b5550"
}
  • 400 bad request: If the request body is not in the correct format or if there are validation errors.

{
  "status": 400,
  "message": "Invalid ledgerAccountID",
  "data": null
}
  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to update ledger accounts.

  • 5xx server error: If there is a server-side error while processing the request.

6.2.3. Methods

Description

This method updates the label of a ledger account based on its unique identifier.

Parameters
  • ledgerAccountID: The unique identifier of the ledger account to update.

  • ledgerData: The data containing the new label for the ledger account.

Returns
  • `Response<UUID>: `A Response object indicating the result of the operation. It contains the UUID of the updated ledger account.

Example usage
public Response<UUID> updateLedgerAccounts(UUID ledgerAccountID, UpdateLedgerAccountsDto ledgerData) {

		log.info("Update ledger account started by User : {}, Request : {}", usersHelper.getUserID(), ledgerData);
		// Retrieve the ledger account from the repository using its unique
		// ledgerAccountID.
		LedgerAccounts ledgerAccounts = ledgerAccountsRepository.findById(ledgerAccountID) (1)
				.orElseThrow(() -> new IllegalArgumentException("Invalid ledgerAccountID"));

		// Update the label of the ledger account with the new label provided in
		// ledgerData.
		ledgerAccounts.setLedgerAccountLabel(ledgerData.getLabel()); (2)
		ledgerAccountsRepository.save(ledgerAccounts); (3)

		log.info("Ledger account updated by User : {}, LedgerAccountID : {}", ledgerAccounts.getLedgerAccountID(),
				ledgerData);

		return new Response<>(HttpStatus.OK.value(), "LedgerAccount label updated successfully",
				ledgerAccounts.getLedgerAccountID()); (4)

	}
Internal workflow
1 Retrieves the ledger account from the repository using its unique ID. If the ledger account doesn’t exist, it throws an IllegalArgumentException.
2 Sets the label of the ledger account to the new label provided in ledgerData.
3 Saves the updated ledger account using the ledgerAccountsRepository.
4 Constructs and returns a Response object containing the UUID of the updated ledger account. .Exceptions

IllegalArgumentException: If the provided ledger account ID is invalid, it throws an IllegalArgumentException.

6.2.4. Model classes

Description:

The UpdateLedgerAccountsDto class represents a Data Transfer Object (DTO) containing details for updating ledger accounts. It includes information such as the label of the ledger account to be updated.

Attributes:
  1. label (String)

    • Description: The updated label associated with the ledger account.

    • Constraints: Not blank.

    • Example: "contract"

Constructors:
  • Default constructor.

  • Parameterized constructor with all attributes.

Serialization and Deserialization:
  • The class uses Lombok annotations @Getter, @Setter, @NoArgsConstructor, @AllArgsConstructor, and @ToString for serialization and deserialization. These annotations generate getter and setter methods, default and parameterized constructors, and a toString method for the class.

6.2.5. Testing

Description

This test case verifies the functionality of the updateLedgerAccounts method in the LedgerAccountsServiceImpl class. It ensures that the method correctly updates ledger account information with the provided data and returns the appropriate response.

Test methods

Example usage

 @Test
	void updateLedgerAccountsTest() {
	    // Prepare a mock LedgerAccounts object for testing.
		LedgerAccounts ledgerAccounts = new LedgerAccounts("nv", null, null,
				LocalDateTime.parse(UtilityHelper.dateTime()), usersHelper.getUserID());
		UUID ledgerAccountID = UUID.randomUUID();
		ledgerAccounts.setLedgerAccountID(ledgerAccountID);

		when(ledgerAccountsRepository.findById(ledgerAccountID)).thenReturn(Optional.of(ledgerAccounts));
		when(ledgerAccountsRepository.save(any())).thenReturn(ledgerAccounts);
		 // Prepare an UpdateLedgerAccountsDto with sample data.
		UpdateLedgerAccountsDto updateLedgerAccountsDto = new UpdateLedgerAccountsDto();
		updateLedgerAccountsDto.setLabel("contract");
		 // Call the updateLedgerAccounts method and capture the response.
		@SuppressWarnings("rawtypes")
		Response response = ledgerAccountsServiceImpl.updateLedgerAccounts(ledgerAccountID, updateLedgerAccountsDto);
		  // Perform assertions to verify the response data and status.
		Assertions.assertEquals(ledgerAccountID.toString(), response.getData().toString());
		Assertions.assertEquals(200, response.getStatus());
		 // Retrieve the updated LedgerAccounts object from the repository.
		LedgerAccounts ledgerAccounts2 = ledgerAccountsRepository.findById(ledgerAccountID).get();
		 // Perform assertions to verify the updated attributes of the LedgerAccounts object.
		Assertions.assertEquals(ledgerAccounts.getLedgerAccountID(), ledgerAccounts2.getLedgerAccountID());
		Assertions.assertEquals(ledgerAccounts.getLedgerAccountLabel(), ledgerAccounts2.getLedgerAccountLabel());

	}

createCustomLedgerAccountsTest

  • Purpose : The purpose of this test is to validate that the updateLedgerAccounts method behaves as expected, updating ledger account information with the provided data and returning the appropriate response.

  • Test steps

    1. Prepare a mock LedgerAccounts object with sample data.

    2. Set up the behavior of the ledgerAccountsRepository mock to return the mock LedgerAccounts object when findById method is called with the provided ledger account ID.

    3. Set up the behavior of the ledgerAccountsRepository mock to return the mock LedgerAccounts object when save method is called.

    4. Prepare an UpdateLedgerAccountsDto object with sample data.

    5. Call the updateLedgerAccounts method with the provided ledger account ID and UpdateLedgerAccountsDto.

    6. Retrieve the response object returned by the method.

  • Assertions

    • Assert that the returned ledger account ID matches the expected value.

    • Assert that the status code of the response is 200.

    • Assert that the updated attributes of the LedgerAccounts object match the expected values.

6.3. Provide ledger account information

6.3.1. Sequential flow

Provide ledger account.puml
Figure 28. Provide ledger account

Provide ledger account process:

  • Client sends a request with a ledger account ID.

  • LedgerServiceController delegates to LedgerAccountsServiceImpl.

  • LedgerAccountsServiceImpl interacts with LedgerAccountsRepository.

  • If account is found, its information is retrieved.

  • Response with account information sent back to client; if not found, appropriate error message returned.

6.3.2. Endpoint

Description

This endpoint provides information about a ledger account.

URL

/accounting/ledger/accounts/{ledgerAccountID}

Method

GET

Request parameters

ledgerAccountID (Path variable): The unique identifier of the ledger account to retrieve information for.

Responses
  • 200 OK: Returns a JSON response containing the ledger account information.

Example response body
{
  "status": 200,
  "message": "Success",
  "data": {
    "ledgerAccountID": "005776b4-fa83-4946-9631-ec4d1ae3e730",
    "ledgerAccountType": "feac",
    "ledgerAccountLabel": "contract",
    "associatedWithContractID": "77fb093b-e322-4c0e-9a5b-fd4c38260d42",
    "statusDate": "2024-03-12T15:09:29",
    "userID": "902375cc-4f72-428f-8db0-95a7baa69b51"
  }
}
  • 400 bad request: If the specified ledger account does not exist.

{
  "status": 400,
  "message": "Invalid ledgerAccountID",
  "data": null
}
  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to get ledger accounts.

  • 5xx server error: If there is a server-side error while processing the request.

6.3.3. Methods

Description

This method retrieves a ledger account based on its unique identifier.

Parameters
  • ledgerAccountID: The unique identifier of the ledger account to retrieve.

Returns
  • Response<LedgerAccounts>: A Response object containing the ledger account information if found, or an error message if the ledger account ID is invalid.

Example usage
   public Response<LedgerAccounts> provideLedgerAccounts(UUID ledgerAccountID) {

		// Retrieve the ledger account from the repository using its unique
		// ledgerAccountID.
		LedgerAccounts ledgers = ledgerAccountsRepository.findById(ledgerAccountID)
				.orElseThrow(() -> new IllegalArgumentException("Invalid ledgerAccountID")); (1)

		return new Response<>(HttpStatus.OK.value(), MESSAGE, ledgers);
	}
Internal workflow
1 Retrieve the ledger account from the repository using its unique ledgerAccountID.
Exceptions

IllegalArgumentException: If the provided ledger account ID is invalid, it throws an IllegalArgumentException.

6.3.4. Testing

Description

This test case verifies the functionality of the provideLedgerAccounts method in the LedgerAccountsServiceImpl class. It ensures that the method correctly retrieves and provides ledger account information for the specified ledger account ID.

Test methods

Example usage

   @Test
	void provideLedgerAccountsTest() {
		  // Prepare a mock LedgerAccounts object for testing.
		LedgerAccounts ledgerAccounts = new LedgerAccounts("nv", "contract", null,
				LocalDateTime.parse(UtilityHelper.dateTime()), usersHelper.getUserID());
		UUID ledgerAccountID = UUID.randomUUID();
		ledgerAccounts.setLedgerAccountID(ledgerAccountID);

		when(ledgerAccountsRepository.findById(ledgerAccountID)).thenReturn(Optional.of(ledgerAccounts));

		@SuppressWarnings("rawtypes")
		Response response = ledgerAccountsServiceImpl.provideLedgerAccounts(ledgerAccountID);
	    // Retrieve the provided LedgerAccounts object from the response.
		LedgerAccounts ledgerAccounts2 = (LedgerAccounts) response.getData();
	     // Perform assertions to verify the provided attributes of the LedgerAccounts object.
		Assertions.assertEquals(ledgerAccounts.getLedgerAccountID(), ledgerAccounts2.getLedgerAccountID());
		Assertions.assertEquals(ledgerAccounts.getLedgerAccountLabel(), ledgerAccounts2.getLedgerAccountLabel());
		Assertions.assertEquals(ledgerAccounts.getLedgerAccountType(), ledgerAccounts2.getLedgerAccountType());

	}

provideLedgerAccountsTest

  • Purpose : The purpose of this test is to validate that the provideLedgerAccounts method behaves as expected, retrieving and providing ledger account information for the specified ledger account ID and returning the appropriate response.

  • Test steps

    1. Prepare a mock LedgerAccounts object with sample data.

    2. Set up the behavior of the ledgerAccountsRepository mock to return the mock LedgerAccounts object when findById method is called with the provided ledger account ID.

    3. Call the provideLedgerAccounts method with the provided ledger account ID.

    4. Retrieve the response object returned by the method.

    5. Retrieve the provided LedgerAccounts object from the response.

    6. Perform assertions to verify the provided attributes of the LedgerAccounts object.

  • Assertions

    • Assert that the provided ledger account ID matches the expected value.

    • Assert that the provided ledger account label matches the expected value.

    • Assert that the provided ledger account type matches the expected value.

6.4. Provides list of ledger accounts

6.4.1. Sequential flow

Provides list of ledger accounts.puml
Figure 29. Provide ledger account

Provides list of ledger accounts process:

  • Client request for ledger accounts with pagination and filters is handled by LedgerServiceController.

  • LedgerServiceController delegates request handling to LedgerAccountsService for pagination-based ledger account retrieval.

  • LedgersHelper creates specifications for filtering ledger accounts as per provided criteria.

  • LedgersHelper combines specifications to filter ledger accounts effectively.

  • Retrieved ledger accounts, filtered and paginated, are sent back to the client through LedgerServiceController.

6.4.2. Endpoint

Description

This endpoint provides a list of ledger accounts based on filter parameters and supports pagination. URL

/accounting/ledger/accounts

Method

GET

Request parameters

filterDto (Query parameter): The filter parameters for querying ledger accounts. This parameter is provided as an object with the following fields:

  • ledgerAccountID: The unique identifier of the ledger account.

  • ledgerAccountType: The type of the ledger account.

  • ledgerAccountLabel: The label of the ledger account.

  • associatedWithContractID: The unique identifier of the contract associated with the ledger account.

  • statusDate: The status date of the ledger account.

  • userID: The unique identifier of the user.

pageNumber (Query parameter): The page number for pagination (default is 0).

pageSize (Query parameter): The number of items per page (default is 20).

Responses
  • 200 OK: Returns a JSON response containing a paginated list of ledger accounts based on the filter parameters.

Example response body
{
  "status": 200,
  "message": "Success",
  "data": [
    {
      "ledgerAccountID": "ee3101b0-203d-4421-aacd-77c9e10b5550",
      "ledgerAccountType": "feac",
      "ledgerAccountLabel": "contract",
      "associatedWithContractID": "56edde65-804e-429c-bf89-7141bf431b20",
      "statusDate": "2024-03-27T12:00:00",
      "userID": "fe54273e-c645-49f5-9279-ad6d4067c606"
    },
    {
      "ledgerAccountID": "123e4567-e89b-12d3-a456-426614174000",
      "ledgerAccountType": "dpd",
      "ledgerAccountLabel": "contract",
      "associatedWithContractID": "56edde65-804e-429c-bf89-7141bf431b20",
      "statusDate": "2024-03-27T12:00:00",
      "userID": "fe54273e-c645-49f5-9279-ad6d4067c606"
    }
  ]
}
  • 404 Not Found: If no ledger accounts match the filter criteria.

  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to get ledger accounts.

  • 5xx server error: If there is a server-side error while processing the request.

6.4.3. Methods

Description

This method retrieves a list of ledger accounts based on the provided filter criteria and paging information.

Parameters
  • filterDto: The filter criteria for the ledger accounts.

  • pageable: The paging information, specifying the page size and number.

Returns
  • List<LedgerAccounts>: A list of ledger accounts that match the filter criteria and are paginated.

Example usage
   public List<LedgerAccounts> provideLedgerAccounts(LedgerAccountsFilterDto filterDto, Pageable pageable) {
		Specification<LedgerAccounts> specification = ledgersHelper.getSpecifications(filterDto); (1)
		return ledgerAccountsRepository.findAll(specification, pageable).getContent(); (2)
	}
Internal workflow
1 Retrieve the specifications based on the filter criteria using the LedgersHelper.
2 Retrieve a list of ledger accounts from the repository based on the specifications and paging information.
Exceptions
  • None explicitly thrown by this method.

6.4.4. Testing

Description

This test case verifies the functionality of the provideLedgerAccounts method in the LedgerAccountsServiceImpl class. It aims to ensure that the method correctly provides ledger account information for the specified ledger account ID.

Test methods

Example usage

    @Test
	void provideLedgerAccountsTest() {
		  // Prepare a mock LedgerAccounts object for testing.
		LedgerAccounts ledgerAccounts = new LedgerAccounts("nv", "contract", null,
				LocalDateTime.parse(UtilityHelper.dateTime()), usersHelper.getUserID());
		UUID ledgerAccountID = UUID.randomUUID();
		ledgerAccounts.setLedgerAccountID(ledgerAccountID);

		when(ledgerAccountsRepository.findById(ledgerAccountID)).thenReturn(Optional.of(ledgerAccounts));

		@SuppressWarnings("rawtypes")
		Response response = ledgerAccountsServiceImpl.provideLedgerAccounts(ledgerAccountID);
	    // Retrieve the provided LedgerAccounts object from the response.
		LedgerAccounts ledgerAccounts2 = (LedgerAccounts) response.getData();
	     // Perform assertions to verify the provided attributes of the LedgerAccounts object.
		Assertions.assertEquals(ledgerAccounts.getLedgerAccountID(), ledgerAccounts2.getLedgerAccountID());
		Assertions.assertEquals(ledgerAccounts.getLedgerAccountLabel(), ledgerAccounts2.getLedgerAccountLabel());
		Assertions.assertEquals(ledgerAccounts.getLedgerAccountType(), ledgerAccounts2.getLedgerAccountType());

	}

provideLedgerAccountsTest

  • Purpose : The purpose of this test is to validate that the provideLedgerAccounts method behaves as expected, retrieving and providing ledger account information for the specified ledger account ID and returning the appropriate response.

  • Test steps

    1. Prepare a mock LedgerAccounts object with sample data, including ledger account type, label, creation date, and user ID.

    2. Set up the behavior of the ledgerAccountsRepository mock to return the mock LedgerAccounts object when findById method is called with the provided ledger account ID.

    3. Call the provideLedgerAccounts method with the provided ledger account ID.

    4. Retrieve the response object returned by the method.

    5. Extract the provided LedgerAccounts object from the response.

  • Assertions

    • The provided ledger account ID matches the expected value.

    • The provided ledger account label matches the expected value.

    • The provided ledger account type matches the expected value.

6.5. Provides ledger entry

6.5.1. Sequential flow

Provides ledger entry.puml
Figure 30. Provides ledger entry

Provides ledger entry process:

  • The client initiates ledger entry retrieval.

  • LedgerServiceController is activated upon request reception.

  • LedgerServiceController communicates with LedgerService for ledger entry retrieval.

  • LedgerService manages ledger-related operations.

  • LedgerServiceImpl retrieves ledger entries, interacting with LedgerRepository based on user ID, and sends a ResponseEntity response via LedgerServiceController to the client.

6.5.2. Endpoint

Description

This endpoint provides a list of ledger entries.

URL

/accounting/ledger/entries

Method

GET

Request parameters

This endpoint does not require any request parameters.

Responses
  • 200 OK: Returns a JSON response containing a list of ledger entries.

Example response body
{
  "status": 200,
  "message": "Success",
  "data": [
    {
      "ledgerEntryID": "ee3101b0-203d-4421-aacd-77c9e10b5550",
      "amount": 100.0,
      "eventType": "AD",
      "creditLedgerAccountID": "56edde65-804e-429c-bf89-7141bf431b20",
      "timestamp": "2024-03-27T12:00:00",
      "debitLedgerAccountID": "56edde65-804e-429c-bf89-7141bf431b20",
      "eventID": "56edde65-804e-429c-bf89-7141bf431b20",
      "userID": "fe54273e-c645-49f5-9279-ad6d4067c606",
      "processTime": "2024-03-27T12:00:00",
      "units": "ETH"
    },
    {
      "ledgerEntryID": "123e4567-e89b-12d3-a456-426614174000",
      "amount": 200.0,
      "eventType": "IED",
      "creditLedgerAccountID": "56edde65-804e-429c-bf89-7141bf431b20",
      "timestamp": "2024-03-27T12:00:00",
      "debitLedgerAccountID": "56edde65-804e-429c-bf89-7141bf431b20",
      "eventID": "56edde65-804e-429c-bf89-7141bf431b20",
      "userID": "fe54273e-c645-49f5-9279-ad6d4067c606",
      "processTime": "2024-03-27T12:00:00",
      "units": "ETH"
    }
  ]
}
  • 404 Not Found: If no ledger entries are found.

  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to get ledger entries .

  • 5xx server error: If there is a server-side error while processing the request.

6.5.3. Methods

Description

This method retrieves a list of ledger entries for the currently logged-in user.

Returns
  • List<Ledger>: A list of Ledger objects associated with the logged-in user.

Example usage
   @Override
	public List<Ledger> findAllLedgers() {

	log.info(
			"Retrieving a list of ledger entries for the currently logged-in user started by User : {}, Request : {}",
				usersHelper.getUserID(), "ledger entries list"); (1)
		return ledgerRepository.findByUserID(usersHelper.getUserID()); (2)
	}
Internal workflow
1 Log the start of retrieving ledger entries for the currently logged-in user.
2 Retrieve a list of ledger entries associated with the logged-in user from the repository.
Exceptions

None explicitly thrown by this method.

6.6. Provides state of a ledger account

6.6.1. Sequential flow

Provides state of a ledger account.puml
Figure 31. Provides state of a ledger account

Provides state of a ledger account process:

  • Client requests ledger account state by providing ID.

  • LedgerServiceController is activated upon request.

  • Controller communicates with LedgerAccountStatesService for account state.

  • LedgerAccountStatesService manages account state operations.

  • LedgerAccountStatesServiceImpl fetches account state from LedgerAccountStatesRepository, accessing database.

6.6.2. Endpoint

Description

This endpoint provides the state of a ledger account without specifying a timestamp.

URL

/accounting/ledger/accounts/{ledgerAccountID}/state

Method

GET

Request parameters

ledgerAccountID: The unique identifier of the ledger account for which states are requested.

Responses
  • 200 OK: Returns a JSON response containing a list of ledger account states.

Example response body
{
  "status": 200,
  "message": "Success",
  "data": [
    {
      "keys": {
        "ledgerAccountID": "ee3101b0-203d-4421-aacd-77c9e10b5550",
        "statusDate": "2024-03-27T12:00:00"
      },
      "value": 100.0
    },
    {
      "keys": {
        "ledgerAccountID": "ee3101b0-203d-4421-aacd-77c9e10b5550",
        "statusDate": "2024-03-26T12:00:00"
      },
      "value": 150.0
    }
  ]
}
  • 404 Not Found: If no ledger account states are found for the specified ledger account ID.

  • 401 unauthorized: If the user is not authenticated or lacks the necessary permissions to get the state of a ledger account.

  • 5xx server error: If there is a server-side error while processing the request.

6.6.3. Methods

Description

This method retrieves a list of ledger account states based on the unique identifier of the ledger account.

Parameters
  • ledgerAccountID: The unique identifier of the ledger account for which states are to be retrieved.

Returns
  • List<LedgerAccountStates>: A list of ledger account states associated with the specified ledger account.

Example usage
  public List<LedgerAccountStates> findByLedgerAccountID(UUID ledgerAccountID) {

		return accountStatesRepository.findByLedgerAccountID(ledgerAccountID); (1)
	}
Internal workflow
1 Retrieve a list of ledger account states associated with the specified ledger account from the repository.
Exceptions

None explicitly thrown by this method