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.
Tables
-
Schema
-
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)
-
Foreign keys
Type Name On fk_business_events_contracts_contractuuid
contractuuid
-
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)
-
-
Table contracts
Index Name Data type * π β¬
contractuuid
uuid
β¬
productid
bigint
*
createdby
uuid
executedby
uuid
*
system_time
timestamp
selection
json
-
Foreign keys
Type Name On contracts_product_fk
productid
-
-
Table contracts_history
Index Name Data type * π β¬
contractuuid
uuid
* π β¬
status_date
timestamp
productid
bigint
selection
json
*
system_time
timestamp
-
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
-
Constraints
Name Definition payment_channels_owner_type_check
((owner_type)::text ~* β^(root/profile)$'::text)
-
-
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
-
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
-
-
Table products
Idx Name Data Type * π β¬
productid
bigint GENERATED BY DEFAULT AS IDENTITY
*
status
varchar(10)
*
template
json
* π
userid
uuid
-
Constraints
Name Definition products_status_check
((status)::text ~* β^(active/inactive)$'::text)
-
-
Table profile_forms
Idx Name Data Type * π β¬
profile_formid
bigint GENERATED BY DEFAULT AS IDENTITY
*
profile_form_details
json
*
userid
uuid
-
Table profiles
Index Name Data type * π β¬
profileid
uuid
profile_details
json
*
status
varchar(10)
*
userid
uuid
* β¬
profile_formid
bigint
-
Foreign keys
Type Name On fk_profiles_profile_forms_profile_formid
profile_formid
-
Constraints
Name Definition profiles_status_check
((status)::text ~* β^(active/inactive)$'::text)
-
-
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
-
Foreign keys
Type Name On terms_contractuuid_fk
contract_uuid
terms_counterparty_id_fk
counterparty_id
-
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)
-
-
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
-
Foreign keys
Type Name On fk-contracts_history-terms_history
contractuuid, status_date
-
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:
-
spring-kafka
-
Purpose: Spring for Apache Kafka for building Kafka-based messaging systems.
-
Usage: Producing and consuming messages from Kafka topics.
-
-
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.
-
-
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.
-
-
modelmapper (version 0.7.5)
-
Purpose: The
modelmapperdependency 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
modelmapperto 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.
-
3.2. Libraries
Description
The following libraries are used in the project to provide various functionalities and features:
-
actus-core (version 1.0.1)
-
Purpose: The
actus-corelibrary 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.
-
-
ariadne-contracts (version 0.0.2)
-
Purpose: The
ariadne-contractslibrary offers functionality and utilities for working with contract data and management within financial applications. -
Usage: Use
ariadne-contractsto handle contract data, perform contract management tasks, and integrate contract-related functionalities into financial applications.
-
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.
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
|
| 2 | AccessDeniedException handler
|
| 3 | Generic exception handler
|
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
Contract creation process
The below business process / method βcreateContractβ enables creation of a Loan account / Checking account. Here below are process steps -
-
To fetch the product form (Product Template) with ProductID as specified in the contract object.
-
Product template this is fetched is validated with request payload (Contract terms)
-
Counterparty and PaymentDetails are validated.
The validation that are performed at this stage are
-
If counterpartyIDs (Profile IDs) and Counterparty payment channel exists
-
If creator ID (user ID) and creator payment channel ID exist
-
If contract terms are compliant with ACTUS data dictionary
-
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)
}
| 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.
-
productId-
Type: Long
-
Description:Identifier of the product associated with the contract.
-
Constraints: Required field.
-
Example: 1
-
-
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 } ] } -
-
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" } } -
-
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
CreateContractsDtoobject. -
All-args Constructor: Initializes a
CreateContractsDtoobject 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
CreateContractsDtoclass 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);
}
| 1 | Product validation
|
| 2 | Contract and product template size validation
|
| 3 | Contract selection validation
|
| 4 | Terms validation
|
| 5 | Error handling
|
6.1.6. Testing
Description
This section provides an overview of the testing strategy and objectives for the create contract method.
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
|
| 2 | createContractTest
|
Test environment
-
Framework : JUnit 5 (https://junit.org/junit5/docs/current/user-guide/)
-
Mocking framework : Mockito (if applicable) (https://site.mockito.org/)
-
How to run test cases : (https://www.baeldung.com/spring-boot-testing)
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
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
contractUUIDis 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
contractUUIDis 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.
-
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 getContractSchedulemethod to compute the contract schedule.3 Throws a ContractsExceptionif any error occurs during computation. -
-
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 generateSchedulemethod to generate the contract schedule. -
-
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
IllegalArgumentExceptionif 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)
}
| 1 | Validating contract UUID
|
| 2 | Retrieving contract
|
| 3 | Validating contract status
|
|
|
6.2.5. Testing
Description
This section provides an overview of the testing strategy and objectives for the get computed contract schedule method.
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()
|
| 2 | computeContractScheduleTest()
|
6.3. Execute contracts
6.3.1. Sequential flow
Contract execution process
-
This method executes a contract identified by the given contract UUID.
-
It validates the contract, sets its performance to "PF" (Performant).
-
Saves the contract schedule.
-
Creates a Metaco account for the contract, only if the contract’s selection contains a "Ledger ID" key.
-
Updates contract payment channels, and sends a Kafka event signaling the contract execution.
-
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
contractUUIDis 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
contractUUIDis 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 ofBusinessEventsrepresenting 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;
}
| 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. |
|
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
IllegalArgumentExceptionif 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)
}
| 1 | Validating contract UUID
|
| 2 | Retrieving contract
|
| 3 | Validating contract status
|
|
|
6.3.5. Testing
Description
This section provides an overview of the testing strategy and objectives for the execute contract method.
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()
|
| 2 | executeContractAfterTest()
|
6.4. Get contracts
6.4.1. Sequential flow
Contract retrieval process
-
Retrieve contracts entities : The
getContractsmethod starts by fetching a list of Contracts entities from the data source based on the provided filtering criteria and pagination parameters. -
Iterate through contracts list
-
For each contract in the retrieved list
-
-
Retrieve contract terms : The terms associated with each contract are retrieved to provide additional details.
-
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.
-
-
Map terms to DTO
-
The terms associated with each contract are mapped to a list of TermsDto objects using a mapping function.
-
-
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
-
-
-
Add ContractsDto to list : The created ContractsDto object is added to the list of ContractsDto objects representing the retrieved contracts.
-
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 |
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.
-
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. -
-
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. -
-
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.
-
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
-
-
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
-
-
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
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 ofUpdateContractDtoobjects containing contract update information.
Returns
-
List<ContractsResponseDto> :List ofContractsResponseDtoobjects 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)
}
| 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.
-
contractUUID-
Type: UUID
-
Description: Represents the universally unique identifier (UUID) of the contract to be updated.
-
Example: 3539ebf7-e93f-4e38-90d5-8c4729ed493c
-
-
productID-
Type: Long
-
Description: Represents the identifier of the product associated with the contract.
-
Example: 1
-
-
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 theUpdateContractDtoclass 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);
}
}
| 1 | Contract UUID validation
|
| 2 | Contract terms validation
|
| 3 | Error handling
|
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.
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
|
| 2 | updateContractAfterTest
|
6.6. Update executed contract
6.6.1. Sequential flow
Executed contract updation process
-
The User triggers the "updateExecutedContract" operation by providing updation data and the contract UUID.
-
The Controller receives the request and activates.
-
The Controller forwards the request to the ContractService.
-
The ContractService activates to process the update.
-
The ContractService delegates validation of the executed contract data to the UpdateContractValidator.
-
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.
-
-
-
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.
|
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);
}
| 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.
-
contractPerformance
-
Type: String
-
Description: Indicates the performance status of the contract.
-
Example: "PreDeal"
-
-
calendar
-
Type: String
-
Description: Specifies the calendar system used for scheduling events related to the contract.
-
Example: "Monday to Friday"
-
-
businessDayConvention
-
Type: String
-
Description: Defines the method for adjusting dates that fall on non-business days.
-
Example: "SCF"
-
-
endOfMonthConvention
-
Type: String
-
Description: Specifies how end-of-month dates are handled in calculations.
-
Example: "EOM"
-
-
contractType
-
Type: String
-
Description: Identifies the type or category of the contract.
-
Example: "PAM"
-
-
statusDate
-
Type: LocalDateTime
-
Description: Represents the date at which the status of the contract was last updated.
-
Example: "2022-12-31 00:00:00"
-
-
contractRole
-
Type: String
-
Description: Specifies the role of the contract in a transaction or relationship.
-
Example: "RPA"
-
-
creatorID
-
Type: String
-
Description: Identifier of the user or system that created the contract.
-
Example: "902375cc-4f72-428f-8db0-95a7baa69b51"
-
-
counterpartyID
-
Type: String
-
Description: Identifier of the counterparty involved in the contract.
-
Example: "d2c87ded-489e-4510-8fe1-95f12c048a5d"
-
-
contractID
-
Type: String
-
Description: Unique identifier for the contract.
-
Example: "9ec8997e-70b5-4fa1-82fe-56cbc0fc8149"
-
click to see more….
-
marketObjectCodeOfDividends
-
Type: String
-
Description: Code or identifier for the market object related to dividends.
-
Example: "DIV"
-
-
cycleAnchorDateOfFee
-
Type: LocalDateTime
-
Description: Date used as a reference point for fee calculation cycles.
-
Example: "2023-01-01T00:00:00"
-
-
cycleOfFee
-
Type: String
-
Description: Specifies the frequency or pattern of fee payments.
-
Example: "1M"
-
-
feeBasis
-
Type: String
-
Description: Basis or method used for calculating fees.
-
Example: "A"
-
-
feeRate
-
Type: BigDecimal
-
Description: Rate at which fees are applied, usually expressed as a percentage.
-
Example: 2500.00
-
-
feeAccrued
-
Type: BigDecimal
-
Description: Total amount of fees accrued up to the present time.
-
Example: 1000.0
-
-
cycleAnchorDateOfInterestPayment
-
Type: LocalDateTime
-
Description: Date serving as a reference point for interest payment cycles.
-
Example: "2023-01-21T06:30:00"
-
-
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"]
-
-
cycleOfInterestPayment
-
Type: String
-
Description: Frequency or pattern of interest payments.
-
Example: "P1ML1"
-
-
arrayCycleOfInterestPayment
-
Type: String
-
Description: An array containing multiple cycles of interest payments.
-
Example: ["1M", "6M"]
-
-
nominalInterestRate
-
Type: BigDecimal
-
Description: Nominal interest rate applied to the principal.
-
Example: 0.01
-
-
nominalInterestRate2
-
Type: BigDecimal
-
Description: Additional nominal interest rate, if applicable.
-
Example: 0.03
-
-
dayCountConvention
-
Type: String
-
Description: Method used for calculating the number of days between two dates.
-
Example: "30E360"
-
-
accruedInterest
-
Type: BigDecimal
-
Description: Total amount of interest accrued up to the present time.
-
Example: 500.0
-
-
capitalizationEndDate
-
Type: LocalDateTime
-
Description: Date when interest capitalization ends.
-
Example: "2024-12-31T23:59:59"
-
-
cycleAnchorDateOfInterestCalculationBase
-
Type: LocalDateTime
-
Description: Date used as a reference point for interest calculation.
-
Example: "2024-03-01T00:00:00"
-
-
cycleOfInterestCalculationBase
-
Type: String
-
Description: Frequency or pattern of interest calculation.
-
Example: "P1ML1"
-
-
interestCalculationBase
-
Type: String
-
Description: Specifies the base amount or balance used for interest calculation.
-
Example: "NT"
-
-
interestCalculationBaseAmount
-
Type: BigDecimal
-
Description: Amount used as the base for interest calculation.
-
Example: 10000.0
-
-
cyclePointOfInterestPayment
-
Type: String
-
Description: Specifies the point within each interest period when interest payments are made.
-
Example: "E"
-
-
currency
-
Type: String
-
Description: The currency in which monetary values are expressed.
-
Example: "USD"
-
-
currency2
-
Type: String
-
Description: Another currency, if applicable.
-
Example: "EUR"
-
-
amortizationDate
-
Type: LocalDateTime
-
Description: Date when the principal is scheduled to be repaid.
-
Example: "2024-12-31T23:59:59"
-
-
contractDealDate
-
Type: LocalDateTime
-
Description: Date when the contract was executed or agreed upon.
-
Example: "2024-03-01T00:00:00"
-
-
initialExchangeDate
-
Type: LocalDateTime
-
Description: Date of the initial exchange or transaction related to the contract.
-
Example: "2024-03-01T00:00:00"
-
-
maturityDate
-
Type: LocalDateTime
-
Description: Date when the contract reaches maturity or expires.
-
Example: "2024-12-31T23:59:59"
-
-
notionalPrincipal
-
Type: BigDecimal
-
Description: The principal amount on which interest is calculated.
-
Example: 100000.0
-
-
notionalPrincipal2
-
Type: BigDecimal
-
Description: Another principal amount, if applicable.
-
Example: 50000.0
-
-
quantity
-
Type: String
-
Description: Quantity or amount associated with the contract.
-
Example: "3"
-
-
cycleAnchorDateOfPrincipalRedemption
-
Type: LocalDateTime
-
Description: Date used as a reference point for principal redemption cycles.
-
Example: "2024-03-01T00:00:00"
-
-
arrayCycleAnchorDateOfPrincipalRedemption
-
Type: String
-
Description: An array containing multiple cycle anchor dates of principal redemption.
-
Example: ["2024-01-01", "2024-04-01", "2024-07-01"]
-
-
cycleOfPrincipalRedemption
-
Type: String
-
Description: Frequency or pattern of principal redemption.
-
Example: "P1ML1"
-
-
arrayCycleOfPrincipalRedemption
-
Type: String
-
Description: An array containing multiple cycles of principal redemption.
-
Example: ["1M", "6M"]
-
-
nextPrincipalRedemptionPayment
-
Type: BigDecimal
-
Description: Next scheduled payment for principal redemption.
-
Example: 1000.0
-
-
arrayNextPrincipalRedemptionPayment
-
Type: String
-
Description: An array containing multiple next principal redemption payments.
-
Example: ["1000.0", "500.50", "750.25"]
-
-
arrayIncreaseDecrease
-
Type: String
-
Description: An array containing information about increases or decreases in certain aspects of the contract.
-
Example: "INC"
-
-
purchaseDate
-
Type: LocalDateTime
-
Description: Date when the contract was purchased or acquired.
-
Example: "2024-03-01T00:00:00"
-
-
priceAtPurchaseDate
-
Type: BigDecimal
-
Description: Price of the contract at the time of purchase.
-
Example: 100.0
-
-
terminationDate
-
Type: LocalDateTime
-
Description: Date when the contract is terminated or ends.
-
Example: "2024-12-31T23:59:59"
-
-
priceAtTerminationDate
-
Type: BigDecimal
-
Description: Price of the contract at the time of termination.
-
Example: 90.0
-
-
marketObjectCodeOfScalingIndex
-
Type: String
-
Description: Code or identifier for the market object related to scaling index.
-
Example: "SCAL-001"
-
-
scalingIndexAtContractDealDate
-
Type: BigDecimal
-
Description: Scaling index value at the contract deal date.
-
Example: 120.0
-
-
cycleAnchorDateOfScalingIndex
-
Type: LocalDateTime
-
Description: Date used as a reference point for scaling index cycles.
-
Example: "2024-03-01T00:00:00"
-
-
cycleOfScalingIndex
-
Type: String
-
Description: Frequency or pattern of scaling index adjustments.
-
Example: "3M"
-
-
scalingEffect
-
Type: String
-
Description: Effect or impact of scaling on the contract.
-
Example: "0N0"
-
-
cycleAnchorDateOfRateReset
-
Type: LocalDateTime
-
Description: Date used as a reference point for rate reset cycles.
-
Example: "2024-03-01T00:00:00"
-
-
arrayCycleAnchorDateOfRateReset
-
Type: String
-
Description: An array containing multiple cycle anchor dates of rate reset.
-
Example: ["2024-01-01", "2024-04-01", "2024-07-01"]
-
-
cycleOfRateReset
-
Type: String
-
Description: Frequency or pattern of rate resets.
-
Example: "Monthly", "Quarterly", "Annually"
-
-
arrayCycleOfRateReset
-
Type: String
-
Description: An array containing multiple cycles of rate resets.
-
Example: ["1M","1Y"]
-
-
rateSpread
-
Type: BigDecimal
-
Description: Additional interest rate spread applied to a benchmark rate.
-
Example: 0.02
-
-
arrayRate
-
Type: String
-
Description: An array containing multiple interest rates.
-
Example: ["0.05", "0.06", "0.04"]
-
-
arrayFixedVariable
-
Type: String
-
Description: An array indicating whether interest rates are fixed or variable.
-
Example: "F"
-
-
marketObjectCodeOfRateReset
-
Type: String
-
Description: Code or identifier for the market object related to rate reset.
-
Example: "e4d7d42c-f11a-4ff3-886f-5bf36db3bac9"
-
-
cyclePointOfRateReset
-
Type: String
-
Description: Specifies the point within each interest period when rate resets occur.
-
Example: "B"
-
-
fixingPeriod
-
Type: String
-
Description: Period during which interest rates are fixed.
-
Example: "3M"
-
-
nextResetRate
-
Type: BigDecimal
-
Description: Next scheduled rate after a reset.
-
Example: 0.07
-
-
rateMultiplier
-
Type: BigDecimal
-
Description: Multiplier applied to a reference rate to determine the interest rate.
-
Example: 1.5
-
-
settlementPeriod
-
Type: LocalDateTime
-
Description: Period during which settlement occurs.
-
Example: "2024-03-01T00:00:00"
-
-
deliverySettlement
-
Type: String
-
Description: Method or process used for delivery settlement.
-
Example: "S"
-
-
marketValueObserved
-
Type: BigDecimal
-
Description: Observed market value of the contract.
-
Example: 10000.0
-
-
premiumDiscountAtIED
-
Type: BigDecimal
-
Description: Premium or discount applied at the initial exchange date (IED).
-
Example: 500.0
-
-
cycleAnchorDateOfOptionality
-
Type: LocalDateTime
-
Description: Date used as a reference point for optionality cycles.
-
Example: "2024-03-01T00:00:00"
-
-
cycleOfOptionality
-
Type: String
-
Description: Frequency or pattern of optionality.
-
Example: "P1ML1"
-
-
lifeCap
-
Type: BigDecimal
-
Description: Maximum cap on interest rates over the life of the contract.
-
Example: 0.08
-
-
lifeFloor
-
Type: BigDecimal
-
Description: Minimum floor on interest rates over the life of the contract.
-
Example: 0.03
-
-
penaltyType
-
Type: String
-
Description: Type or category of penalty associated with the contract.
-
Example: "N"
-
-
penaltyRate
-
Type: BigDecimal
-
Description: Rate at which penalties are applied, usually expressed as a percentage.
-
Example: 0.05
-
-
objectCodeOfPrepaymentModel
-
Type: String
-
Description: Code or identifier for the prepayment model object.
-
Example: "PREPAY-MODEL"
-
-
periodCap
-
Type: BigDecimal
-
Description: Maximum cap on interest rates for a specific period.
-
Example: 0.08
-
-
periodFloor
-
Type: BigDecimal
-
Description: Minimum floor on interest rates for a specific period.
-
Example: 0.03
-
-
marketObjectCode
-
Type: String
-
Description: Code or identifier for the market object associated with the contract.
-
Example: "YC.USA.TREASURY"
-
-
cycleAnchorDateOfDividendPayment
-
Type: LocalDateTime
-
Description: Date used as a reference point for dividend payment cycles.
-
Example: "2024-03-01T00:00:00"
-
-
cycleOfDividendPayment
-
Type: String
-
Description: Frequency or pattern of dividend payments.
-
Example: "1Q"
-
-
tenure
-
Type: String
-
Description: Duration or term of the contract.
-
Example: "5Y"
-
-
roundingConvention
-
Type: String
-
Description: Method used for rounding numerical values in calculations.
-
Example: "Half Up"
-
-
xDayNotice
-
Type: String
-
Description: Notice period required for certain actions or events.
-
Example: "30D"
-
-
maximumPenaltyFreeDisbursement
-
Type: String
-
Description: Maximum amount that can be disbursed without incurring penalties.
-
Example: "10000"
-
-
delinquencyPeriod
-
Type: String
-
Description: Period during which a payment is considered delinquent.
-
Example: "30D"
-
-
gracePeriod
-
Type: String
-
Description: Period of time after a payment is due before penalties are applied.
-
Example: "7D"
-
|
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
|
| 2 | Updated contract terms validation
|
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.
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
|
| 2 | updatePFContractAfterTest
|
6.7. Create dynamic event
6.7.1. Sequential flow
Steps to create dynamic event
-
Receive request
-
The system receives a request from the user to create a dynamic event.
-
-
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.
-
-
-
Create dynamic event
-
If the data is valid, the system creates a dynamic event based on the provided data.
-
-
Save event
-
The system saves the created dynamic event.
-
-
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.
|
6.7.3. Methods
Description
This method is responsible for creating a dynamic event associated with a contract.
-
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 validateContractUUIDmethod 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. -
-
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 createDynamicEventmethod 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.
-
time
-
Type: LocalDateTime
-
Description: Represents the time of the dynamic event.
-
Constraints: Cannot be null.
-
Example: "2024-02-23T06:30"
-
-
type
-
Type: String
-
Description: Represents the type of the dynamic event.
-
Constraints: Cannot be null.
-
Example: "TP"
-
-
value
-
Type: BigDecimal
-
Description: Represents the value associated with the dynamic event.
-
Constraints: Cannot be null.
-
Example: 5000
-
-
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
DynamicEventDtoclass 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
Contractsobject 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;
}
| 1 | Contract UUID validation
|
| 2 | Event date validation
|
| 3 | Future processed events check
|
6.7.6. Testing
Description
This section provides an overview of the testing strategy and objectives for the create dynamic event method.
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()
|
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.
Tables
-
Schema
-
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)
-
Foreign keys
Type Name On fk_business_events_contracts_contractuuid
contractuuid
-
Constraints
Name Definition business_events_event_type_check
((event_type)::text ~* β^(AD
business_events_status_check
((status)::text ~* β^(scheduled
-
-
Table contracts
Index Name Data type * π β¬
contractuuid
uuid
β¬
productid
bigint
*
createdby
uuid
executedby
uuid
*
system_time
timestamp
selection
json
-
Foreign keys
Type Name On contracts_product_fk
productid
-
-
Table contracts_history
Index Name Data type * π β¬
contractuuid
uuid
* π β¬
status_date
timestamp
productid
bigint
selection
json
*
system_time
timestamp
-
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
-
Constraints
Name Definition payment_channels_owner_type_check
((owner_type)::text ~* β^(root
-
-
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
-
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
-
-
Table products
Index Name Data type * π β¬
productid
bigint GENERATED BY DEFAULT AS IDENTITY
*
status
varchar(10)
*
template
json
* π
userid
uuid
-
Constraints
Name Definition products_status_check
((status)::text ~* β^(active
-
-
Table profile_forms
Index Name Data type * π β¬
profile_formid
bigint GENERATED BY DEFAULT AS IDENTITY
*
profile_form_details
json
*
userid
uuid
-
Table profiles
Index Name Data type * π β¬
profileid
uuid
profile_details
json
*
status
varchar(10)
*
userid
uuid
* β¬
profile_formid
bigint
-
Foreign keys
Type Name On fk_profiles_profile_forms_profile_formid
profile_formid
-
Constraints
Name Definition profiles_status_check
((status)::text ~* β^(active
-
-
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
-
Foreign keys
Type Name On terms_contractuuid_fk
contract_uuid
terms_counterparty_id_fk
counterparty_id
-
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
-
-
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
-
Foreign keys
Type Name On fk-contracts_history-terms_history
contractuuid, status_date
-
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
-
-
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
-
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:
-
spring-kafka
-
Purpose: Spring for Apache Kafka for building Kafka-based messaging systems.
-
Usage: Producing and consuming messages from Kafka topics.
-
-
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.
-
-
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.
-
-
modelmapper (version 0.7.5)
-
Purpose: The
modelmapperdependency 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
modelmapperto 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.
-
-
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)
-
-
-
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.
-
-
3.2. Libraries
Description
The following libraries are used in the project to provide various functionalities and features:
-
actus-core (version 1.0.1)
-
Purpose: The
actus-corelibrary 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.
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
|
| 2 | handleValidationException handler
|
| 3 | AccessDeniedException handler
|
| 4 | Generic exception handler
|
| 5 | handleConstraintViolationException handler
|
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. TransactionServiceController
6.1. Transfer
6.1.1. Sequential flow
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
-
The system checks if the transfer data is valid.
-
It ensures that the transfer amount is greater than zero.
-
It verifies the existence of sender and receiver contracts and payment channels.
Transfer process
-
If data is valid, the system proceeds with the transfer process.
-
It saves transaction details, initializes business events, and updates contract balances.
-
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)
}
| 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.
-
value-
Type: BigDecimal
-
Description: Represents the amount of funds to be transferred.
-
Constraints: Not null.
-
Example: 1000
-
-
contractUUID-
Type: UUID
-
Description: Represents the UUID of the contract initiating the transfer.
-
Constraints: Not null.
-
Example: a1933b07-a12c-4666-9669-8a1bda511086
-
-
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;
}
| 1 | Transfer amount validation
|
| 2 | Sender details validation
|
| 3 | Receiver details validation
|
| 4 | Currency validation
|
| 5 | Sender account balance validation
|
6.1.6. Testing
Description
This section provides an overview of the testing strategy and objectives for the transfer method.
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()
|
6.2. Transaction
6.2.1. Sequential flow
Transaction process
This process includes transactions of different event types based on the provided TransactionDto. Here below are process steps -
Data validation
-
Incoming requests are handled at "/transaction" endpoint.
-
Transaction data is validated using the @Valid annotation.
-
Event IDs are retrieved from the transaction data.
-
Each transaction is individually validated for correctness.
Transaction process
-
Valid transactions proceed to the processing phase.
-
Processing involves updating contract information and performing associated event processes.
-
Transaction details are saved alongside the associated business event.
-
Responses are generated based on transaction success or failure.
-
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
-
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 workflow1 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.
-
-
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 workflow1 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
-
TransactionDto
Description
The
TransactionDtoclass represents a data transfer object (DTO) for a transaction. It encapsulates information about a transaction including its event ID, value, and process time.Attributes-
eventID-
Type: UUID
-
Description: Represents the unique identifier of the event associated with the transaction.
-
Constraints: Not null.
-
Example: 4e3723af-ece4-4934-963b-bfbabb510212
-
-
value-
Type: BigDecimal
-
Description: Represents the value of the transaction.
-
Constraints: Not null.
-
Example: 3320.8481981622112
-
-
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()); -
-
-
TransactionResponseDto
Description
The
TransactionResponseDtoclass 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-
eventID-
Type: UUID
-
Description: Represents the unique identifier of the event associated with the transaction.
-
Constraints: Not null.
-
Example: 4e3723af-ece4-4934-963b-bfbabb510212
-
-
valid-
Type: String
-
Description: Indicates whether the transaction is valid or not.
-
Constraints: Can take values "TRUE" or "FALSE".
-
Example: TRUE
-
-
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;
}
| 1 | EventID validation
|
| 2 | Event status validation
|
| 3 | Non-OPS events validation
|
| 4 | Setting response data
|
|
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.
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()
|
6.3. Get transactions
6.3.1. Sequential flow
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
-
Upon receiving a GET request to the
/txsendpoint, the server validates the query parameters includingfilterDto,page, andsize.
Get transactions process
-
The server parses the query parameters and sets up pagination based on the provided
pageandsize. -
It generates a JPA specification from the
TransactionFilterDtoto filter transactions. -
The server executes a database query using the generated specification and pagination settings.
-
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 |
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)
}
| 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.
-
transactionId-
Type: UUID
-
Description: Represents the unique identifier of the transaction.
-
Example: 18d57dd4-5898-40af-aa06-52eb7cd28ebb
-
-
userID-
Type: UUID
-
Description: Represents the unique identifier of the user associated with the transaction.
-
Example: 902375cc-4f72-428f-8db0-95a7baa69b51
-
-
eventID-
Type: UUID
-
Description: Represents the unique identifier of the event associated with the transaction.
-
Example: f771b128-c948-4dea-8359-6a43e1f4ef3f
-
-
processTime-
Type: String
-
Description: Represents the timestamp indicating the processing time of the transaction.
-
Example: 2023-01-01T00:00:00
-
-
debitPaymentChannelID-
Type: UUID
-
Description:Represents the unique identifier of the debit payment channel used in the transaction.
-
Example: 13c3861e-bcc6-48ed-9db1-91cb6825328a
-
-
creditPaymentChannelID-
Type: UUID
-
Description: Represents the unique identifier of the credit payment channel used in the transaction.
-
Example: fb0fdb85-87ee-4af2-b39a-f3a23227203c
-
-
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.
Tables
-
Schema:
BussinessEvents
-
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)
-
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
-
Foreign Keys
Type Name On fk_business_events_contracts_contractuuid
( contractuuid ) ref public.contracts (contractuuid)
-
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
-
-
Table contracts
Idx Name Data Type * π β¬
contractuuid
uuid
β¬
productid
bigint
*
createdby
uuid
executedby
uuid
*
system_time
timestamp
selection
json
-
Indexes
Type Name On π
contracts_pkey
ON contractuuid
-
Foreign Keys
Type Name On contracts_product_fk
( productid ) ref public.products (productid)
-
-
-
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
-
-
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
-
Indexes
Type Name On π
payment_details_pkey
ON id
-
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)
-
-
Table products
Idx Name Data Type * π β¬
productid
bigint GENERATED BY DEFAULT AS IDENTITY
*
status
varchar(10)
*
template
json
* π
userid
uuid
-
Indexes
Type Name On π
products_pkey
ON productid
π
products_idx_userid
ON userid
-
Constraints
Name Definition products_status_check
status::text ~* '^(active/inactive)$'::text
-
-
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
-
-
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 ) ref public.profile_forms (profile_formid)
-
Constraints
Name Definition profiles_status_check
status::text ~* '^(active/inactive)$'::text
-
-
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
-
Indexes
Type Name On π
terms_pkey
ON id
π
terms_idx_creator_id
ON creator_id
-
Foreign Keys
Type Name On terms_contractuuid_fk
( contract_uuid ) ref public.contracts (contractuuid)
terms_counterparty_id_fk
( counterparty_id ) ref public.profiles (profileid)
-
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:
-
spring-kafka
-
Purpose: Spring for Apache Kafka for building Kafka-based messaging systems.
-
Usage: Producing and consuming messages from Kafka topics.
-
-
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.
-
-
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.
-
3.2. Libraries
Description
The following libraries are used in the project to provide various functionalities and features:
-
actus-core (version 1.0.1)
-
Purpose: The
actus-corelibrary 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.
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
|
| 2 | MethodArgumentNotValidException handler
|
| 3 | AccessDeniedException handler
|
| 4 | Generic exception handler
|
| 5 | ConstraintViolationException handler
|
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.
7. BusinessEventsServiceController
7.1. Get events
7.1.1. Sequential flow
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 |
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).
|
| 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.
-
eventID (UUID)
-
Description: The unique identifier of the event. -
Constraints: None. -
Example: 123e4567-e89b-12d3-a456-426614174000.
-
-
eventTime (LocalDateTime)
-
Description: The timestamp of the event. -
Constraints: None. -
Example: "2024-02-29T12:34:56".
-
-
eventType (String)
-
Description: The type of the event. -
Constraints: None. -
Example: "AD".
-
-
status (String)
-
Description: The status of the event. -
Constraints: None. -
Example: "scheduled".
-
-
contractUUID (UUID)
-
Description: The UUID of the contract associated with the event. -
Constraints: None. -
Example: 123e4567-e89b-12d3-a456-426614174000.
-
-
Constructors
-
All Args Constructor:Initializes all attributes of the DTO. -
No Args Constructor:Initializes the DTO with default values.
-
-
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.
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
|
7.2. Register OPS events
7.2.1. Sequential flow
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.
|
| 2 | Creates a BusinessEvents object using the BusinessEventsHelper service’s createOpsEvent method.
|
| 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.
-
value (BigDecimal)
-
Description: The value associated with the OPS event. -
Constraints: Not null. -
Example: 100.00
-
-
dueTime (LocalDateTime)
-
Description: The due time of the OPS event. -
Constraints: Not null. -
Example: 2024-03-07T10:15:30
-
-
units (String)
-
Description: The units of the OPS event. -
Constraints: Not blank, maximum 10 characters. -
Example: INR
-
-
debitPaymentChannelID (UUID)
-
Description: The UUID of the debit payment channel associated with the OPS event. -
Constraints: Not null. -
Example: 39b22817-a37f-49b9-adbc-e27971afa39c
-
-
creditPaymentChannelID (UUID)
-
Description: The UUID of the credit payment channel associated with the OPS event. -
Constraints: Not null. -
Example: c1d8c18a-32a2-4a31-96ec-f4d4f2873a4f
-
-
remainingAmount (BigDecimal)
-
Description: The remaining amount after the OPS event. -
Constraints: None. -
Example: 50.00
-
-
debitLedgerAccountID (UUID)
-
Description: The UUID of the debit ledger account associated with the OPS event. -
Constraints: Not null. -
Example: 33ab848d-522b-46ce-8e53-c025ed9caf02
-
-
creditLedgerAccountID (UUID)
-
Description: The UUID of the credit ledger account associated with the OPS event. -
Constraints: Not null. -
Example: 3220799ac-c335-4cc7-aa17-d83b997281da
-
-
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 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.
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
|
7.3. Delete event
7.3.1. Sequential flow
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.
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
|
7.4. Graph values day wise
7.4.1. Sequential flow
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
TreeMapwhere 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.
|
| 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.
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
|
7.5. Liquidity report
7.5.1. Sequential flow
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.
|
| 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.
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
|
7.6. Contract events
7.6.1. Sequential flow
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.
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
|
| 2 | getContractEvents
|
7.7. Event values for a specific contract
7.7.1. Sequential flow
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.
|
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.
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
|
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.
Tables
-
Schema:
Payment Channels
-
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
-
-
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
-
-
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:
-
spring-kafka
-
Purpose: Spring for Apache Kafka for building Kafka-based messaging systems.
-
Usage: Producing and consuming messages from Kafka topics.
-
-
*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.
-
-
*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.
-
-
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.
-
-
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.
-
-
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).
-
-
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).
-
-
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.
-
-
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.
-
3.2. Libraries
Description
The following libraries are used in the project to provide various functionalities and features:
-
actus-core (version 1.0.1)
-
Purpose: The
actus-corelibrary 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.
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
|
| 2 | MethodArgumentNotValidException handle
|
| 3 | Generic exception handler
|
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.
7. PaymentChannelController
7.1. Create new user payment channel
7.1.1. Sequential flow
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) orBitcoin(BTC), the corresponding configurations are used to create the address. -
If the units are neither
EthereumnorBitcoin, theIBANaddress 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
DescriptionThis endpoint allows users to creates a new user payment channel
URL
/payments/channel/new
Method
POST
Request bodyThe 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
DescriptionThis 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 usagepublic 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
|
| 2 | Creating BlockCypher Map
|
| 3 | Validating Payment Channel Data
|
| 4 | Setting Payment Channel Details
|
| 5 | Saving Payment Channel
|
| 6 | Returning Response
|
ExceptionsIOException: 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.
-
units (String)
-
Description: The units associated with the payment channel. -
Constraints: Not null, not blank, maximum 10 characters. -
Example: "USD"
-
-
identifier (String)
-
Description: The identifier associated with the payment channel. -
Constraints: Maximum 100 characters. -
Example: "CHN12345"
-
-
label (String)
-
Description: The label associated with the payment channel. -
Constraints: Maximum 100 characters. -
Example: "Primary Channel"
-
-
accountCharacteristic (String)
-
Description: The account characteristic associated with the payment channel. -
Constraints: Not null, not blank, maximum 50 characters. -
Example: "Savings Account"
-
-
Default constructor.
-
Parameterized constructor with all attributes.
-
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.
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
-
Call the createPaymentChannel method of the PaymentChannelServiceImpl class with the rootUserPaymentChannelTemplate.
-
Retrieve the response object returned by the method.
-
Extract the payment channel data from the response.
-
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
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
DescriptionThis 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 bodyThe 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
DescriptionThis 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 usagepublic 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
|
| 2 | Variable initialization
|
| 3 | Identifier validation
|
| 4 | Payment channel type determination
|
| 5 | Payment channel creation
|
| 6 | Saving payment channel
|
| 7 | Response creation:
|
ExceptionsIllegalArgumentException
-
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.
-
accessKey (JSONObject)
-
Description: The access key associated with the DTO. -
Constraints: None. -
Example:
-
"accessKey": {
"private": "b44f71aeefbe25b07b4a14ae63a0922aa2d6874906628d7a457f39e4e96c70d8",
"public": "0270198cf386036bc186f8261045c1f8bc241cffd5858ca977ba62cbeeb6fe5b40",
"address": "BvdK6pQghtwMvzfLtZjXT7brAh83JDyi76"
}
-
address (String)
-
Description: The address associated with the DTO. -
Constraints: None. -
Example: "123 Main Street"
-
-
beneficiaryAddress (String)
-
Description: The beneficiary’s address associated with the DTO. -
Constraints: Not null, not blank. -
Example: "UK"
-
-
beneficiaryName (String)
-
Description: The beneficiary’s name associated with the DTO. -
Constraints: Not null, not blank. -
Example: "John Doe"
-
-
identifier (String)
-
Description: The identifier associated with the DTO. -
Constraints: Not null, not blank, maximum 100 characters. -
Example: "ABC123"
-
-
label (String)
-
Description: The label associated with the DTO. -
Constraints: Not null, not blank, maximum 100 characters. -
Example: "External Service"
-
-
type (String)
-
Description: The type associated with the DTO. -
Constraints: Not null, not blank, maximum 50 characters. -
Example: "Service"
-
-
units (String)
-
Description: The units associated with the DTO. -
Constraints: Not null, not blank, maximum 10 characters. -
Example: "BTC"
-
-
accountCharacteristic (String)
-
Description: The account characteristic associated with the DTO. -
Constraints: None. -
Example: "Regular Account"
-
-
Default constructor.
-
Parameterized constructor with all attributes.
-
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.
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
-
Stub the behavior of the repository to return the first payment channel template when the save method is called.
-
Call the createServicePaymentChannel method of the PaymentChannelServiceImpl class with the serviced and external template.
-
Retrieve the response object returned by the method.
-
Extract the payment channel data from the response.
-
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 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
DescriptionThis 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 parametersprofileID (Path variable): The unique identifier of the profile for which the payment channel is created.
Request bodypaymentChannelData (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
DescriptionThis 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 usagepublic 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
|
| 2 | Convert data
|
| 3 | Validation
|
| 4 | BlockCypher map creation
|
| 5 | Payment channel creation:
|
| 6 | Save payment channel
|
| 7 | Response:
|
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.
-
identifier (String)
-
Description: The identifier associated with the profile channel. -
Constraints: Maximum 100 characters. -
Example: "David007"
-
-
label (String)
-
Description: The label associated with the profile channel. -
Constraints: Maximum 100 characters. -
Example: "ser"
-
-
type (String)
-
Description: The type associated with the profile channel. -
Constraints: Not null, not blank, maximum 50 characters. -
Example: "new"
-
-
units (String)
-
Description: The units associated with the profile channel. -
Constraints: Not null, not blank, maximum 10 characters. -
Example: "USD"
-
-
system (String)
-
Description: The system associated with the profile channel. -
Constraints: Not null, not blank, maximum 50 characters. -
Example: "IBAN"
-
-
Default constructor.
-
Parameterized constructor with all attributes.
-
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.
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
-
Stub the behavior of the repository to return the first payment channel template when save method is called.
-
Define a profile ID string.
-
Call the createProfilePaymentChannel method of the PaymentChannelServiceImpl class with the provided profile ID converted to a UUID and the profile payment channel template.
-
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
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:
-
Validator: Performs additional validation.
-
PaymentChannelRepository: Checks for existing payment channels with the same identifier.
-
Assert: Ensures the uniqueness of the identifier.
-
Assert (alt): If the identifier is unique, proceeds with further validation.
-
Validator: Validates the payment channel type.
-
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
DescriptionThis 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 parametersprofileID (Path variable): The unique identifier of the profile for which the payment channel is created.
Request bodypaymentChannelData (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
DescriptionThis 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
|
| 2 | Initialization
|
| 3 | Validation
|
| 4 | Type determination
|
| 5 | System determination
|
| 6 | Payment channel creation
|
| 7 | Save payment channel
|
| 8 | Response
|
ExceptionsThis 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.
-
accessKey (JSONObject)
-
Description: The access key associated with the DTO. -
Constraints: None. -
Example:
-
"accessKey": {
"private": "b44f71aeefbe25b07b4a14ae63a0922aa2d6874906628d7a457f39e4e96c70d8",
"public": "0270198cf386036bc186f8261045c1f8bc241cffd5858ca977ba62cbeeb6fe5b40",
"address": "BvdK6pQghtwMvzfLtZjXT7brAh83JDyi76"
}
-
address (String)
-
Description: The address associated with the DTO. -
Constraints: None. -
Example: "123 Main Street"
-
-
beneficiaryAddress (String)
-
Description: The beneficiary’s address associated with the DTO. -
Constraints: Not null, not blank. -
Example: "UK"
-
-
beneficiaryName (String)
-
Description: The beneficiary’s name associated with the DTO. -
Constraints: Not null, not blank. -
Example: "John Doe"
-
-
identifier (String)
-
Description: The identifier associated with the DTO. -
Constraints: Not null, not blank, maximum 100 characters. -
Example: "ABC123"
-
-
label (String)
-
Description: The label associated with the DTO. -
Constraints: Not null, not blank, maximum 100 characters. -
Example: "External Service"
-
-
type (String)
-
Description: The type associated with the DTO. -
Constraints: Not null, not blank, maximum 50 characters. -
Example: "Service"
-
-
units (String)
-
Description: The units associated with the DTO. -
Constraints: Not null, not blank, maximum 10 characters. -
Example: "BTC"
-
-
accountCharacteristic (String)
-
Description: The account characteristic associated with the DTO. -
Constraints: None. -
Example: "Regular Account"
-
-
Default constructor.
-
Parameterized constructor with all attributes.
-
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.
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
-
Stub the behavior of the repository to return the first payment channel template when the save method is called.
-
Define a profile ID string.
-
Call the createProfileServicedPaymentChannel method of the PaymentChannelServiceImpl class with the provided profile ID converted to a UUID and the serviced and external template.
-
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 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
DescriptionThis 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 parameterspaymentChannelID (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
DescriptionThis 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 usagepublic 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
|
| 2 | Deletion
|
| 3 | Logging (Post deletion)
|
| 4 | Response generation
|
ExceptionsIOException: 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.
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
-
Retrieve the payment channel ID from the payment channel template.
-
Call the deleteByPaymentChannelID method of the PaymentChannelServiceImpl class with the retrieved payment channel ID.
-
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 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
DescriptionThis 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
DescriptionThis 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:
|
| 5 | Save the updated payment channel. |
ExceptionsParseException
-
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.
-
accessKey (JSONObject)
-
Description: The access key associated with the DTO. -
Constraints: None. -
Example:
-
"accessKey": {
"private": "b44f71aeefbe25b07b4a14ae63a0922aa2d6874906628d7a457f39e4e96c70d8",
"public": "0270198cf386036bc186f8261045c1f8bc241cffd5858ca977ba62cbeeb6fe5b40",
"address": "BvdK6pQghtwMvzfLtZjXT7brAh83JDyi76"
}
-
address (String)
-
Description: The address associated with the DTO. -
Constraints: None. -
Example: "123 Main Street"
-
-
beneficiaryAddress (String)
-
Description: The beneficiary’s address associated with the DTO. -
Constraints: Not null, not blank. -
Example: "UK"
-
-
beneficiaryName (String)
-
Description: The beneficiary’s name associated with the DTO. -
Constraints: Not null, not blank. -
Example: "John Doe"
-
-
identifier (String)
-
Description: The identifier associated with the DTO. -
Constraints: Not null, not blank, maximum 100 characters. -
Example: "ABC123"
-
-
label (String)
-
Description: The label associated with the DTO. -
Constraints: Not null, not blank, maximum 100 characters. -
Example: "External Service"
-
-
type (String)
-
Description: The type associated with the DTO. -
Constraints: Not null, not blank, maximum 50 characters. -
Example: "Service"
-
-
units (String)
-
Description: The units associated with the DTO. -
Constraints: Not null, not blank, maximum 10 characters. -
Example: "BTC"
-
-
accountCharacteristic (String)
-
Description: The account characteristic associated with the DTO. -
Constraints: None. -
Example: "Regular Account"
-
-
Default constructor.
-
Parameterized constructor with all attributes.
-
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.
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
-
Retrieve the payment channel ID from the first payment channel template.
-
Call the updatePaymentChannel method of the PaymentChannelServiceImpl class with the retrieved payment channel ID and the serviced and external template.
-
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
-
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
DescriptionThis endpoint retrieves information about an existing payment channel identified by its unique identifier.
URL
/payments/channel/{paymentChannelID}
Method
GET
Request parameterspaymentChannelID (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
DescriptionThis 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 usagepublic 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. |
ExceptionsIllegalArgumentException: 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.
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
-
Retrieve the payment channel ID from the first payment channel template.
-
Call the getPaymentChannelsById method of the PaymentChannelServiceImpl class with the retrieved payment channel ID.
-
Retrieve the response object returned by the method.
-
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
-
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
-
Depending on the units of the payment channel (e.g., ETH, BTC, or other units), the PaymentWorker is activated to retrieve the balance.
-
For ETH units, it interacts with BlockCypherEthereumConfiguration to check the Ethereum balance.
-
For BTC units, it interacts with BlockCypherBitCoinConfiguration to check the Bitcoin balance.
-
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
DescriptionThis endpoint retrieves the balance of a payment channel identified by its unique identifier.
URL
/payments/channel/{paymentChannelID}/balance
Method
GET
Request parameterspaymentChannelID (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
DescriptionThis 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.
|
ExceptionsIllegalArgumentException: 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.
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
-
Retrieve the payment channel ID from the payment channel template.
-
Call the getBalanceOfPaymentChannel method of the PaymentChannelServiceImpl class with the retrieved payment channel ID.
-
Retrieve the response object returned by the method.
-
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
-
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
DescriptionThis endpoint retrieves all payment channels associated with a specific user.
URL
/payments/channel/users/{userID}
Method
GET
Request parametersuserID (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
DescriptionThis 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 usagepublic 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. |
ExceptionsThrows 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.
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
-
Retrieve the user ID of the root user.
-
Stub the behavior of the repository to return the payment channels template when findByUserID is called with the root user ID.
-
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.
-
Call the getPaymentChannelsBasedOnRootUser method of the PaymentChannelServiceImpl class with the root user ID.
-
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
-
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
DescriptionThis endpoint retrieves all payment channels associated with a specific profile.
URL
/payments/channel/profiles/{profileID}
Method
GET
Request parametersprofileID (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
DescriptionThis 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 usagepublic 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. |
ExceptionsIllegalArgumentException: 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.
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
-
Define a profile ID string.
-
Call the getPaymentChannelBasedOnProfileID method of the PaymentChannelServiceImpl class with the provided profile ID converted to a UUID.
-
Retrieve the response object returned by the method.
-
Extract the payment channel data from the response.
-
Retrieve the payment channel ID from the data.
-
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
-
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
DescriptionThis endpoint creates a payment channel for external profiles.
URL
/payments/channel/profiles/external
Method
POST
Request parametersuserID (path): The unique identifier of the root user for whom payment channels are to be retrieved.
Request bodyThe 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
DescriptionThis 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 usagepublic 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. |
ExceptionsIllegalArgumentException: 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.
-
type (String)
-
Description: Represents the type associated with the payment channel. -
Constraints: Must not be null, must not be blank. -
Example: "external"
-
-
identifier (String)
-
Description: The identifier associated with the payment channel. -
Constraints: Maximum 100 characters. -
Example: "CH7200762Y62RKW1207GW"
-
-
label (String)
-
Description: The label associated with the payment channel. -
Constraints: Maximum 100 characters. -
Example: "Savings A/C"
-
-
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"
-
-
units (String )
-
Description: The units associated with the payment channel. -
Constraints: Not null, not blank, maximum 10 characters. -
Example: "USD":
-
-
Default constructor.
-
Parameterized constructor with all attributes.
-
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.
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
-
Call the createExternalProfilePaymentChannel method of the PaymentChannelServiceImpl class with the externalPaymentChannelTemplate.
-
Retrieve the response object returned by the method.
-
Extract the payment channel data from the response.
-
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
-
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
DescriptionThis endpoint retrieves profile payment channels, optionally filtered by units.
URL
/payments/channel/profiles
Method
GET
Request parametersunits (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
DescriptionThis 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.
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
-
Define the units parameter as "INR".
-
Call the getProfilePaymentChannels method of the PaymentChannelServiceImpl class with the specified units parameter.
-
Retrieve the response object returned by the method.
-
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
-
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
-
It interacts with ContractsFeignClient to fetch contract data.
-
Parses contract terms and extracts the notional value.
-
Checks the contract role and notional value sign.
-
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
DescriptionThis 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
DescriptionThis 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 usagepublic 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
|
| 4 | Constructs a response containing the list of RootPaymentChannelResponse objects. |
ExceptionsThis 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.
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
-
Call the getRootPaymentChannel method of the PaymentChannelServiceImpl class.
-
Retrieve the response object returned by the method.
-
Extract the data from the response, which should contain a list of root user payment channel responses.
-
Retrieve the payment channel ID from the data.
-
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.
Tables
-
Schema:
Ledger service
-
Table contracts
Idx Name Data Type * π β¬
contractuuid
uuid
β¬
productid
bigint
*
createdby
uuid
executedby
uuid
*
system_time
timestamp
selection
json
-
Indexes
Type Name On π
contracts_pkey
ON contractuuid
-
Foreign Keys
Type Name On contracts_product_fk
productid
-
-
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)
-
Indexes
Type Name On π
ledger_pkey
ON ledger_entryid
-
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
-
-
Table ledger_account_states
Idx Name Data Type * π
ledger_accountid
uuid
* π
status_date
timestamp
*
value
numeric
-
Indexes
Type Name On π
ledger_account_states_pkey
ON ledger_accountid, status_date
-
-
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
-
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
-
-
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_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
-
Constraints
Name Definition payment_channels_owner_type_check
((owner_type)::text ~* β^(root
-
-
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
-
Indexes
Type Name On π
payment_details_pkey
ON id
-
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
-
-
Table products
Idx Name Data Type * π β¬
productid
bigint GENERATED BY DEFAULT AS IDENTITY
*
status
varchar(10)
*
template
json
* π
userid
uuid
-
Indexes
Type Name On π
products_pkey
ON productid
π
products_idx_userid
ON userid
-
Constraints
Name Definition products_status_check
status::text ~* '^(active/inactive)$'::text
===
-
-
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
-
-
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
-
-
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
-
Indexes
Type Name On π
terms_pkey
ON id
π
terms_idx_creator_id
ON creator_id
-
Foreign Keys
Type Name On terms_contractuuid_fk
contract_uuid
terms_counterparty_id_fk
counterparty_id
-
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 |
+
-
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 |
-
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:
-
actus-core (version 1.0.1):
-
Purpose: The
actus-corelibrary 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.
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
|
| 2 | MethodArgumentNotValidException handler
|
| 3 | Generic exception handler
|
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. LedgerServiceController
6.1. Creates custom ledger accounts
6.1.1. Sequential flow
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
DescriptionThis endpoint creates custom ledger accounts.
URL
/accounting/ledger/accounts
Method
POST
Request bodyThe 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
DescriptionThis 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. |
ExceptionsLedgerServiceException: 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.
-
label (String)
-
Description: The label associated with the ledger account. -
Constraints: Not blank. -
Example: "contract"
-
-
type (String)
-
Description: The type associated with the ledger account. -
Constraints: Not blank. -
Example: "ipac"
-
-
Default constructor.
-
Parameterized constructor with all attributes.
-
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.
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
-
Prepare a CreateLedgerAccountsDto object with sample data.
-
Prepare a mock LedgerAccounts object with the same data.
-
Set up the behavior of the ledgerAccountsRepository mock to return the mock LedgerAccounts object when save method is called.
-
Call the createCustomLedgerAccounts method with the prepared CreateLedgerAccountsDto.
-
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 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
DescriptionThis endpoint allows users to update ledger accounts.
URL
/accounting/ledger/accounts/{ledgerAccountID}
Method
PUT
Request parametersledgerAccountID (Path variable): The unique identifier of the ledger account to be updated.
Request bodyThe 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
DescriptionThis 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 usagepublic 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.
-
label (String)
-
Description: The updated label associated with the ledger account. -
Constraints: Not blank. -
Example: "contract"
-
-
Default constructor.
-
Parameterized constructor with all attributes.
-
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.
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
-
Prepare a mock LedgerAccounts object with sample data.
-
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.
-
Set up the behavior of the ledgerAccountsRepository mock to return the mock LedgerAccounts object when save method is called.
-
Prepare an UpdateLedgerAccountsDto object with sample data.
-
Call the updateLedgerAccounts method with the provided ledger account ID and UpdateLedgerAccountsDto.
-
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 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
DescriptionThis endpoint provides information about a ledger account.
URL
/accounting/ledger/accounts/{ledgerAccountID}
Method
GET
Request parametersledgerAccountID (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
DescriptionThis 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. |
ExceptionsIllegalArgumentException: 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.
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
-
Prepare a mock LedgerAccounts object with sample data.
-
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.
-
Call the provideLedgerAccounts method with the provided ledger account ID.
-
Retrieve the response object returned by the method.
-
Retrieve the provided LedgerAccounts object from the response.
-
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 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
DescriptionThis endpoint provides a list of ledger accounts based on filter parameters and supports pagination. URL
/accounting/ledger/accounts
Method
GET
Request parametersfilterDto (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
DescriptionThis 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.
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
-
Prepare a mock LedgerAccounts object with sample data, including ledger account type, label, creation date, and user ID.
-
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.
-
Call the provideLedgerAccounts method with the provided ledger account ID.
-
Retrieve the response object returned by the method.
-
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 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
DescriptionThis endpoint provides a list of ledger entries.
URL
/accounting/ledger/entries
Method
GET
Request parametersThis 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
DescriptionThis 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. |
ExceptionsNone explicitly thrown by this method.
6.6. Provides state of a ledger account
6.6.1. Sequential flow
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
DescriptionThis endpoint provides the state of a ledger account without specifying a timestamp.
URL
/accounting/ledger/accounts/{ledgerAccountID}/state
Method
GET
Request parametersledgerAccountID: 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
DescriptionThis 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. |
ExceptionsNone explicitly thrown by this method