Drupal 8 commerce (2.x) - multi currency how to

For multi-currency in drupal 7 commerce we had it all running out of the box with drupal multicurrency modul. You had price fields per currency and rules that would solve that. There is no out of the box solution like that yet, but this module is pretty close to it.

If you want to know how to do it programmatically and understand how it works under the hood, follow along.
As we adopted OOP approach it is now all about Resolvers, specifically implementing PriceResolverInterface in your custom class that must be in specific service. So lets make a module for it and then add a service like this in module root.

    class: Drupal\custom_price\Resolvers\CustomPriceResolver
    arguments: ['@request_stack']
      - { name: commerce_price.price_resolver, priority: 666 }

crucial thing here are tags, this is a way to hook your new class into commerce system, particularly commerce_price.chain_price_resolver service which accepts tags, it is a service collector, look up more about it here https://www.drupal.org/docs/8/api/services-and-dependency-injection/ser….

So when we did that, we can define our new class in my_module/src/Resolvers directory


namespace Drupal\custom_price\Resolvers;

use Drupal\commerce\Context;
use Drupal\commerce\PurchasableEntityInterface;
use Drupal\commerce_price\Resolver\PriceResolverInterface;
use Drupal\commerce_price\Price;
use \Drupal\user\Entity\User;

 * Returns the price based on the current user being a VIP user.
class CustomPriceResolver implements PriceResolverInterface {

   * {@inheritdoc}
  public function resolve(PurchasableEntityInterface $entity, $quantity, Context $context) {

    $geo_locator = \Drupal::service('geoip.geolocation');
    $ip_address = \Drupal::request()->getClientIp();
    $country = $geo_locator->geolocate($ip_address);

    if ($country == "Germany") {
      $eu_price = $entity->get('field_price_eu');
      return new Price($eu_price->number, $eu_price->currency_code);
    else {
      return $entity->getPrice();

What we did here is simple. We first implemented proper interface, then we used GeoIP to obtain country information (install GeoIP module or SmartIP module to have such service), if it is a match we change currency output to different one, in this case in Euros. If it doesn't match we supply the default one.

To finalize this I need to mention that we needed to make 2 more adjustments in UI before adding this code. First we needed to add another price field to product variation type (field_price_eu) and second is display of that field. We need to go to product variation type, switch to manage display and change format of a price field, from "default" change it to "combined" that way you will get proper result (otherwise it will not display change) and also hide other price fields so you only have one displayed.