For multi-currency projects, there's no single solution. In this tutorial, we'll take a look at different approaches to this problem: DB schema, currency rate calculation, and more.
We will compare three models for PHP/Laravel projects:
- Converting Currencies in Real-Time
- Store Prices per Currency: Prestashop Example
- Mixed Approach: Building a Multi-Currency System
Let's go!
Converting Currencies in Real-Time
When attempting to find a solution for this - you might encounter a suggestion to use real-time currency exchange API. This approach looks into converting your base currency (like USD
or EUR
) to another currency based on a real-time exchange rate.
General Workflow Would Look Something Like this:
- You have a base currency (like
USD
orEUR
) - You have a currency that you want to convert to (like
GBP
) - You call the API to get the exchange rate for the currency you want to convert to (or in some cases already converted amount)
- You show the price in the currency that the user requested (either by multiplying the price by the exchange rate, or by using the already converted amount)
- You store the price in the currency that the user requested
- You store the exchange rate that you used to convert the price (to be able to convert it back to the base currency)
Of course, there are many things that you need to save/modify in your database:
- Have allowed currencies list (like
USD
,EUR
,GBP
, etc.) - Save the currency that the user requested (like
GBP
) in the database - Two simple columns should do itcharged_currency
andcharged_amount
. - Save the exchange rate that you used to convert the price (like
0.8
) - Two simple columns should do itexchange_rate
andexchange_rate_date
. - Save the original currency (like
USD
) - Two simple columns should do itoriginal_currency
andoriginal_amount
.
How Does It Look in the Database?
Your migration might look something like this:
Schema::create('products', function (Blueprint $table) { $table->id(); $table->string('name'); $table->integer('price'); $table->timestamps();}); Schema::create('orders', function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->constrained(); $table->integer('original_price'); $table->string('original_currency'); $table->integer('charged_price'); $table->string('charged_currency'); $table->float('exchange_rate')->nullable(); $table->timestamps();}); Schema::create('order_products', function (Blueprint $table) { $table->id(); $table->foreignId('order_id')->constrained(); $table->foreignId('product_id')->constrained(); $table->integer('original_price'); $table->string('original_currency'); $table->integer('charged_price'); $table->string('charged_currency'); $table->float('exchange_rate')->nullable(); $table->integer('quantity')->default(1); $table->timestamps();});
Which would result in a database schema like this:
Pay attention to the saving of original currency and...