FX Remittance Back Office for Refah Bank's Exchange House

In 2020 and 2021 I worked freelance as a full-stack developer for the currency-exchange house of Refah Bank. Its foreign-currency remittances were accounted for in a spreadsheet. I built the back-office system that replaced it: remittances, commissions, central-bank and NIMA allocations and the balance with every counterparty were recorded in one SQL Server database and calculated in one place.

Context

An exchange house sends and receives foreign currency on behalf of its customers. A single remittance can involve several parties: the customer, other exchange houses and brokers that take a commission or a deduction, and, for allocated currency, the central bank and the NIMA foreign-exchange system. At the end, each party owes or is owed an amount in a particular currency.

Before this project, that work lived in a spreadsheet with one row per remittance. Formula columns produced the converted amount, the final remittance amount, the deductions taken by each exchange house and broker, and the figures behind each counterparty's balance.

The engineering problem

A spreadsheet is a good tool for one person and a weak one for a shared financial record. In general terms, moving this work into a system meant dealing with four things:

  • The formulas were the business rules. Every amount came from a spreadsheet column. The system had to produce the same numbers, or nobody could check it against what they already knew.
  • Commissions vary. Different remittance types and currency pairs carry different commissions, charged on the exchange-house side or the broker side, and applied per thousand units, per currency unit or as a coefficient.
  • Balances are derived data. What each counterparty owes or is owed follows from the remittances. If a remittance changes and its balance entries do not, the reports go wrong without any visible error.
  • The history already existed. Past remittances were in the spreadsheet and had to come across with the same calculations, not be typed in again.

What I built

I built the system as an ASP.NET Core MVC application on SQL Server. It started on .NET Core 3.1, and I moved it to .NET 5 in December 2020. Its main parts:

  • Remittance records. Each remittance stores its origin and destination currency, bank and country, rate, rial equivalent, customer, account and counterparty, with file attachments and dated milestones entered and shown in the Jalali calendar.
  • Remittance types as a configurable tree. Currency transfers, central-bank allocations, NIMA purchases and returns, and fund management are categories in a tree, each marked as a deposit, a withdrawal or a commission. A type carries default commissions and milestones that pre-fill new entries.
  • One calculation service. On the server it calculates the converted amount, the final remittance amount, the deductions by exchange houses and brokers, and the debtor and creditor entries for each counterparty. These calculations reproduce the spreadsheet columns they replace.
  • A CSV importer for the legacy spreadsheet. It reads the old export, creates any missing customers, customer groups and remittance types, and runs each past remittance through the same calculation service before saving it.
  • Reports. Balances by customer, by broker, and by broker and customer, per currency, split into debtor and creditor and shown with the exchange-house and broker commissions, plus a detailed statement. Tables are paged and searched on the server and can be exported to CSV.
  • An admin panel with access control. Users have roles and belong to user groups. Once a remittance's completion date is recorded, only an admin can edit it.

Design notes

These notes explain the reasoning behind the design. They describe the application, not the bank's wider systems.

The spreadsheet as the specification

Each figure in the calculation service is documented with the spreadsheet column it replaces, and the calculated values are stored with the remittance. That made it possible to check any number in the system against the original sheet, and it kept the rules in one service instead of spreading them across screens.

Balances are sums, not stored values

No customer or counterparty has a stored balance that gets updated over time. Each remittance carries its own debtor and creditor entries, and the reports add them up. A balance therefore cannot disagree with the remittances behind it, and correcting a remittance corrects every report that includes it.

A remittance and its figures are saved together

A new remittance is built as one object graph with its commissions, milestones, calculated figures and balance entries, and written in a single EF Core save. An edit does not patch figures in place: it removes the old record and inserts a recalculated copy in the same save. EF Core runs each save in one database transaction, so the stored figures always come from the current version of the remittance.

Commission rules as data

Default commissions are rows, not code. Each one belongs to a remittance type and currency pair, holds an exchange-house value and a broker value, and says how it applies: per thousand units, per currency unit or as a coefficient. New remittances start from these defaults and can be adjusted case by case.

Stack

  • ASP.NET Core MVC: .NET Core 3.1, moved to .NET 5 in December 2020
  • EF Core and SQL Server
  • ASP.NET Core Identity
  • Autofac and AutoMapper
  • Serilog, with errors logged to a SQL Server table
  • CsvHelper
  • jQuery and DataTables, with server-side paging

Outcome

  • Remittance accounting moved from a spreadsheet into one SQL Server database, with one calculation service shared by data entry, editing and the import of past records.
  • Balance reports by customer, broker and currency, built from the same per-remittance entries and exportable to CSV.

Related

Another piece of financial software on this site is the financial indicator dashboard. For backend work on financial or internal business systems, see Work with me.

Frequently asked questions

What did Mahdi Molavi build for Refah Bank's exchange house?

Working freelance as a full-stack developer in 2020 and 2021, he built a back-office system that replaced spreadsheet-based accounting for foreign-currency remittances at Refah Bank's currency-exchange house.

What does the system record?

Remittances with their origin and destination currency, bank, country, rate and rial equivalent; commissions and deductions by exchange houses and brokers; central-bank allocations and NIMA purchases and returns; and the debtor and creditor balance of each counterparty.

What happened to the data already in the spreadsheet?

A CSV importer read the legacy spreadsheet export, created any missing customers and remittance types, and ran every past remittance through the same calculation service as new entries before saving it.

Which technologies did the project use?

ASP.NET Core MVC, started on .NET Core 3.1 and moved to .NET 5 in December 2020, with EF Core and SQL Server, ASP.NET Core Identity, Autofac, AutoMapper, Serilog and CsvHelper.

More in this section

Projects