Amartha manages multiple bank accounts and requires a service to reconcile transactions occurring within their system against corresponding transactions reflected in bank statements. This process helps identify errors, discrepancies, and missing transactions.
- Internal Transactions:
trxID: Unique identifier for the transaction (string)amount: Transaction amount (decimal)type: Transaction type (enum: DEBIT, CREDIT)transactionTime: Date and time of the transaction (datetime)
- Bank Statement:
unique_identifier: Unique identifier for the transaction in the bank statement (string) (varies by bank, not necessarily equivalent to trxID )amount: Transaction amount (decimal) (can be negative for debits)date: Date of the transaction (date)
-
Total number of transactions processed
-
Total number of matched transactions
-
Total number of unmatched transactions
3.1. Details of unmatched transactions:
a. System transaction details if missing in bank statement(s) b. Bank statement details if missing in system transactions (grouped by bank) -
Total discrepancies (sum of absolute differences in amount between matched transactions)
-
Date format used in argument is
YYYYMMDD -
Allow multiple files for bank statements with format
bankName_YYYYMMDD.csv -
Allow processing large dataset (>10000 records)
-
Dockerize to allow environment consistency
go run . financial_statement.csv bankName_YYYYMMDD.csv,bankName_YYYYMMDD.csv,... YYYYMMDD YYYYMMDD
e.g:
go run . csv/st_small.csv csv/bankA_20250605.csv,csv/bankB_20250605.csv 20250604 20250610
docker build -t reconciliation-service .
docker run --rm \
-v $(pwd)/csv:/app/csv \
reconciliation-service \
csv/system_transactions.csv \
csv/bankA_20250605_large.csv,csv/bankB_20250605_large.csv \
20250604 \
20250610
-
make build: to build docker image -
make run: to run docker image using predefined args -
make run-custom: to run docker image using custom args
make run-custom ARGS="csv/system_transactions.csv csv/bankA.csv,csv/bankB.csv 20250604 20250610"
-
Financial statement: must be in csv -
Bank statements:- must be in csv
- can be multiple, separated by comma
- format is bankName_YYYYMMDD.csv (eg: BCA_20250612.csv)
-
Start date: format is YYYYMMDD -
End date: format is YYYYMMDD
There is a variable in .env which is used to determine reconcilliation strategy. Set it to simple will make the program using conventional looping to reconcile the data, while set to concurrent or simply remove its value will automatically make the program using concurrency which implements go worker.
-
Allow system to receive arguments with following structure:
<internal_transaction_file_path> <external_transaction_file_path_1>, <external_transaction_file_path_2>, ... <external_transaction_file_path_n> <start_date> <end_date> -
Check availability and validity of each file
-
Store each file to objects based on file structure and add flag as an indicator for matched, validate format for each record as well:
- Internal Transactions
- Bank Statements
-
Create object to store discrepancy data
-
Loop through each record in internal transactions and compare with bank statements (using go routine), set flag match if the amount is match
- Comparison logic:
if record amount and date is equal to bank statements
then set flag as match and increase matched amount
if no record is equal to bank statements then
set flag as unmatched and
increase unmatched amount
add discrepancy data
-
Once all of the records in internal transactions have been checked, then check on bank statement for any unmatched flag as it is considered as missing data
-
Print out discrepancies data, invalid data, and processing time
-
If arguments not have transaction file path then terminate and return error -
If arguments not have bank statement file path then terminate and return error -
If arguments not have start date or end date then terminate and return error
-
If file path and extension is correct then proceed -
If file path is incorrect then terminate and return error -
If file extension is not csv then terminate and return error
-
If first line row is not equal to expected header then terminate and return error -
if record has incorrect data type then skip and store the error data -
if record has correct data type then add to object and set its flag to false -
if record has been stored successfully in object then compare between transaction statements with bank statements -
if record comparison is matched then set record matched flag to true and increase number of matched transaction
-
if reaches end of record then count total number of matched transactions -
if reaches end of record then list of records with record matched flag false and treat as unmatched transactions -
if reaches end of record then count total number of unmatched transactions -
if reaches end of record then sum total discrepancies



