Storing and Reading Payment Information
Payment information (Initiation, Instruction and Transaction details) is initially stored by a processing flow.
Any subsequent cancellations/changes of payment details won’t update the original entry. Instead, new entries will be inserted. This adjustment Payment Entries can be created in two different ways, either:
-
holding only the specific adjustment detail being updated, or
-
holding a complete up-to-date Payment Message, including the adjustments being applied
Choosing one of the options above affects which Payment Warehouse Datasource implementation is suitable for your use case. Analogous to the options above, there are 2 appropriate Payment Warehouse Datasource implementations at your disposal:
-
Aggregate Entries Warehouse Datasource
-
Latest Entry Warehouse Datasource
Aggregate Entries Warehouse Datasource
Storing only adjustment details means storage doesn’t hold a singular version of an up-to-date payment information entry, with all the adjustments applied. Merging of related information is performed on the read side when fetching the stored payment information.
| Aggregate Entries Warehouse Datasource implementation is responsible for applying any additional adjustments made to the initially stored payment information. |
Information aggregation
Aggregate Entries Payment Warehouse Datasource implementation reads the data from the Payment Warehouse and aggregates it. To observe how the merging works, we can use an Instruction Payment Entry example.
When a processing flow initially stores details about a Payment Instruction, it creates a PaymentEntry object and stores it in the Warehouse.
{
"_id": "BatchInitiation|6e6cf57a-7201-43db-b9db-a8c33e3a0b19|0",
"unitOfWorkId": "f4c5d646-fe8e-4586-bf32-496ce8814344",
"relatedUnitOfWork": "63051ca7-3592-40b1-a5d2-b7e69e602b8d",
"clientRequestId": "ac541cde-00fc-427f-be5f-23c2f091718e-filehappy",
"associationId": "BatchInitiation|6e6cf57a-7201-43db-b9db-a8c33e3a0b19",
"processingEntity": "BANK_ENTITY_1",
"sequence": 0,
"globalState": "PENDING",
"type": "BULK",
"data": [
{
"objectId": "5945909f-0cfc-43f8-a28d-b92d1823e6a9",
"parentObjectId": "2c235f35-b6b2-414a-a298-caf86f1e4e45",
"name": "Pain001Instruction",
"category": "MDS",
"contentType": "com.iconsolutions.iso20022.message.components.payment_instruction.payment_instruction30.PaymentInstruction30",
"content": "{.......}"
}
],
"_class": "com.iconsolutions.ipf.warehouse.port.mongo.repository.MongoPaymentEntry"
}
Any subsequent change (data adjustment or cancellation) results in storing an additional PaymentEntry object entry. The new entry is created with an identical unitOfWorkId value as the initial PaymentEntry object and its sequence value increased by one.
{
"_id" : "BatchInitiation|6e6cf57a-7201-43db-b9db-a8c33e3a0b19|1",
"unitOfWorkId" : "f4c5d646-fe8e-4586-bf32-496ce8814344",
........
"sequence" : 1,
"globalState" : "CANCELLED"
}
AggregateEntriesWarehouseDataSource encapsulates the logic for applying additional Instruction PaymentEntry adjustments in a functional interface defined as:
Function<List<PaymentEntry>, MyPaymentWarehouseInstruction> instructionAggregatorFunction
In a similar fashion, there are also functional interfaces for Initiation and Transaction information aggregation:
-
Function<List<PaymentEntry>, <Optional<MyPaymentWarehouseInitiation>> initationAggregatorFunction, and -
Function<List<PaymentEntry>, MyPaymentWarehouseTransaction> transactionAggregatorFunction
Providing initationAggregatorFunction is optional. It can be omitted if you are not storing Initiation level information in the first place.
|
Latest Entry Warehouse Datasource
When you apply each adjustment over the previous adjustments (and the initially stored payment information), then the most recent Payment Entry will have complete up-to-date information.
Using a similar example as above, the initial PaymentEntry object created by the Processing flow and stored in the Warehouse will be identical in this case as well.
{
"_id": "BatchInitiation|6e6cf57a-7201-43db-b9db-a8c33e3a0b19|0",
"unitOfWorkId": "f4c5d646-fe8e-4586-bf32-496ce8814344",
"relatedUnitOfWork": "63051ca7-3592-40b1-a5d2-b7e69e602b8d",
"clientRequestId": "ac541cde-00fc-427f-be5f-23c2f091718e-filehappy",
"associationId": "BatchInitiation|6e6cf57a-7201-43db-b9db-a8c33e3a0b19",
"processingEntity": "BANK_ENTITY_1",
"sequence": 0,
"globalState": "PENDING",
"type": "BULK",
"data": [
{
"objectId": "5945909f-0cfc-43f8-a28d-b92d1823e6a9",
"parentObjectId": "2c235f35-b6b2-414a-a298-caf86f1e4e45",
"name": "Pain001Instruction",
"category": "MDS",
"contentType": "com.iconsolutions.iso20022.message.components.payment_instruction.payment_instruction30.PaymentInstruction30",
"content": "{.......}"
}
],
"_class": "com.iconsolutions.ipf.warehouse.port.mongo.repository.MongoPaymentEntry"
}
Again, any subsequent change (data adjustment or cancellation) will result in storing an additional PaymentEntry object, having the identical unitOfWorkId value as the initial PaymentEntry object, and having its sequence value increased by one.
Only this time, `Payment Entry' will contain a complete initial entry and have the adjustments applied to it.
{
"_id": "BatchInitiation|6e6cf57a-7201-43db-b9db-a8c33e3a0b19|0",
"unitOfWorkId": "f4c5d646-fe8e-4586-bf32-496ce8814344", (1)
"relatedUnitOfWork": "63051ca7-3592-40b1-a5d2-b7e69e602b8d",
"clientRequestId": "ac541cde-00fc-427f-be5f-23c2f091718e-filehappy",
"associationId": "BatchInitiation|6e6cf57a-7201-43db-b9db-a8c33e3a0b19",
"processingEntity": "BANK_ENTITY_1",
"sequence": 1, (2)
"globalState": "CANCELLED", (3)
"type": "BULK",
"data": [
{
"objectId": "5945909f-0cfc-43f8-a28d-b92d1823e6a9",
"parentObjectId": "2c235f35-b6b2-414a-a298-caf86f1e4e45",
"name": "Pain001Instruction",
"category": "MDS",
"contentType": "com.iconsolutions.iso20022.message.components.payment_instruction.payment_instruction30.PaymentInstruction30",
"content": "{.......}"
}
],
"_class": "com.iconsolutions.ipf.warehouse.port.mongo.repository.MongoPaymentEntry"
}
| 1 | unitOfWorkId identical to the one from the initial Payment Entry |
| 2 | sequence value increased by one |
| 3 | CANCELLED state change applied to the initial data |
In this case, data merging on the read side is not necessary. Only the Payment Entry being read needs to be mapped to the appropriate Initiation/Instruction/Transaction payment message. Fetching and mapping is handled by the Datasource itself, you only need to implement and wire in the following functional interfaces:
-
Function<PaymentEntry, MyPaymentWarehouseInstruction> instructionMapper
-
Function<PaymentEntry, MyPaymentWarehouseTransaction> transactionMapper
-
Function<PaymentEntry, MyPaymentWarehouseInitiation> initiationMapper (optional)
Providing initiationMapper is optional. It can be omitted if you are not storing Initiation level information in the first place.
|