3

Short Version: What do you think is the best option for a Value Object that needs to access currency conversion rates in the database? ex:

Invoice.Amount = Invoice.Amount.toCurrency('CAD')

Long Version: I have a Value Object called InvoiceAmount and it has a method, toCurrency, that will convert the invoice amount to a specified currency. I'd like to reuse this currency conversion logic because I know I'm going to need it in other bounded contexts(e.g. SalesOrderAmount, FreightCost, etc.). My first thought was to create a Money object in a SharedKernel and then have SalesOrderAmount, FreightCost and InvoiceAmount inherit from Money. The toCurrencywould be implemented in the Money class so it is only in one place. This sounds ok to me but maybe there is a better way. Now the problem I have is that in my system the currency conversion rates are stored in the database so I need a repository to access conversion rates in order for Money to implement toCurrency. I'm pretty sure DDD says not to call Repositories in Entities or Value Objects so I'm struggling to figure out how to achieve this. I was thinking of using a Domain Service to actually do the currency conversion and Money would just call the Domain Service, however, I'm not sure if DDD considers this a good option either. Maybe I need to inject the Domain Service into each Aggregate Root (SalesOrder, Invoice and Shipment) so I can inject that into each Money value object so it can in turn do the currency conversion. What do you think? Thank you in advance.

Jan Muncinsky
  • 4,282
  • 4
  • 22
  • 40
Tony Raimo
  • 187
  • 2
  • 9

1 Answers1

4

 I'm pretty sure DDD says not to call Repositories in Entities or Value Objects

Keep on that, it's a good rule. It will keep your model clean and pure.

I  was thinking of using a Domain Service to actually do the currency conversion

I think this is the way to go. However, you should try to design your model according to the real world. Who is responsible in the financial world with money conversions? A Bank or an Exchange point (I don't know how exactly are they called in your country).

So, my suggestion is to define a Domain interface implemented in the Infrastructure (i.e. MoneyExchangeService) that has a single method: convertAmount. You call it in the Application layer and pass the result to your Account aggregate method as arguments. This will keep the responsibilities to where they belong.

Constantin Galbenu
  • 16,951
  • 3
  • 38
  • 54
  • Thanks for the suggestion. I guess I'm still stuck on my Money Value object having a toCurrency method. If I take your approach, I could not have a toCurrency method and I would have to move the currency conversion to the UseCase/Application layer. I was hoping to come up with a solution that could keep the currency conversion in the Money.toCurrency method. – Tony Raimo Jan 07 '18 at 20:48
  • I have a similar problem with converting Units of Measure (e.g. LB to KG, IN to CM) in which the conversion factors are stored in the database. I have a Value Object for FreightUnits and I have a method FreightUnits.convertUOM that will convert from pounds to kilograms for example. I feel like this simple conversion logic is too low level for the UseCase/Application layer. Am I incorrect in thinking this way? – Tony Raimo Jan 07 '18 at 20:48
  • 1
    @TonyRaimo I'm suggesting that the service would be a Domain service with the implementation in the Infrastructure only if a persistence is used, otherwise the implementation is also in the Domain layer, i.e. a units converter service – Constantin Galbenu Jan 07 '18 at 22:02