Aim

  • Identify solidus workflow (version 2.10!)
  • Identify some shop and customization needs from a German Shop perspective
  • Get used to write jekyll blog posts

Requirements

  • Linux System able to run “modern” (as of 2020) Rails tech stack
  • tolerance: I write down as I learn
  • capacity to forget: solidus will further emancipate from spree and the installation process will change

As this is my first contact with solidus, I can guarantee that next time I would do things different. Nonetheless, I want to keep some notes for me along the way.

Pretext: What I understand about solidus so far

Solidus is an e-commerce (“online shop”) system that you can integrate with your Ruby on Rails web-application.

It is a fork of Spree, which was acquired - I’d call it a “protective fork” but do not know the details.

While it seems possible to “install solidus” as engines and gems into an empty Rails application and have a basic shop running, it is also possible to extend the solidus business logic, or just use some parts in the light of your bigger application. It looks like a pretty big thing.

Step one: Bring up the framework

For playing around we want a solidus shop with the whole shebang, thus instead of requiring only the frontend, backend or other parts, we grab the solidus dependency, which will pull in all the other stuff.

We will basically follow the solidus README.

# Create a new Rails app (time of writing: Rails6)
rails new soshop
cd soshop

# Add dependencies (will modify Gemfile and run bundler)
bundle add solidus
bundle add solidus_auth_devise

# Hook it all up - including migrations, sample data etc.
# This step is interactive (will ask for email and password)
rails g spree:install

That’s it, we can now fire up the server.

rails s

and visit localhost:3000 to see the frontend or localhost:3000/admin to log into the backend with the credentials given in the install step (admin@example.com and test123 by default).

Step Two: Don’t pay

We want to make the default currency Euros and look at a checkout process.

As the scenario is a German shop I want to change the Default currency from $ to € (admin -> Settings -> Store -> Default Currency). While we are there, we can also set the default tax country (“Tax Country for Empty Carts”).

Just under that the frontend language can be changed, but we leave that for now.

It is already time for a test-dive and put we can something in our shopping cart and see that the price is listed in €. However, when we continue to checkout the Billing Adress Form

  • requires users to enter a phone number,
  • doesnt require users to enter a last name and
  • the default address country is the US

– we would like to change all of that.

Billing-Address: Switch off your phone

We want to make the phone number field in addresses optional.

The solidus documentation points us directly to the NoPhone monkey-patch .

However, I had to figure out how to apply this monkey patch. After some professional help I figured that the file needs to end on _decorator.rb (rtfm) to be auto-required.

So, add a file:

# app/models/spree/address/optional_phone_decorator.rb
module Spree::Address::OptionalPhoneDecorator                                    
  def require_phone?                                                             
    false                                                                        
  end                                                                            
                                                                                 
  Spree::Address.prepend self                                                    
end 

In this case the “required” markers in the frontend are already aware that the requiredness is optional (the red asterix next to the form input will disappear on server restart).

Billing-Address: Hi Bill … ?

We want to make the last name field in addresses mandatory.

Apparently, in version 3.0, solidus will replace firstname and lastname of addresses by a single name field, but the current (2.10) backend and frontend still use both attributes.

For whatever reason, only firstname is a required attribute - in order to identify users/addresses and make a valid “contract” (bill) with them we need both, though. At least I believe that it works like that in the EU.

Therefore, we will add a validation in the Backend and adjust the frontend address form (in contrast to the phone number case above, this is not pre-arranged).

Backend: Address validation for lastname

# app/models/spree/address/mandatory_last_name_decorator.rb
module Spree::Address::MandatoryLastNameDecorator
  def self.prepended(base)
    base.validates :lastname, presence: true
  end

  Spree::Address.prepend self
end

Frontend: Address validation for lastname

# Copy the address form
mkdir -p app/views/spree/address/
cp $(bundle show solidus_frontend)/app/views/spree/address/_form.html.erb \
  app/views/spree/address

# solidus also has a generator to copy views, something like this:
# bundle exec rails generate solidus:views:override --only \
#  address/something

# In that file, add `class: 'required' and `, required: true` to the lastname
# field (around line 10, as an example see the firstname field at line 5)
# Also, add the `field-required` class to the containing div (again, see above.)

This basically reverts this Pull Request: https://github.com/solidusio/solidus/pull/2393

Billing-Address: Adjust default customer location

We want that the default customers billing and shipping address is within Germany.

The form will default to Spree::Country.default, which we can influence by modifying config/initializers/spree.rb

# config/initializers/spree.rb add

  # ...
  config.default_country_iso = 'DE'
  # ...

In case you need a different iso code, refer to the docs or look what is already seeded: rails r 'p Spree::Country.all.to_a'.

Exclude customers

It’s sad and not fair and we love all our “neighbours” (that includes humans on other continents), but right now we cannot spend resources on intensive regulation, tax and shipping company research.

We want have to restrict billing and shipping addresses to a predefined list of countries.

Thus we will exclude countries from the list of countries to chose from as shipping and billing address.

Therefore, in the backend navigate to Settings -> Zones and delete “North America”. Reflect.

Now, either create a new zone that includes just the countries that are fitting your business needs and possibilities, or modify the example one (“EU_VAT”).

Afterwards, set the checkout_zone in config/initializers/spree.rb:

# config/initializers/spree.rb

  #...
  config.checkout_zone = 'EU_VAT' # referenced by zone name
  #...

Taxes

We need to define the German default tax rates.

In Germany, you’ll probably need two tax items. Specify in Backend -> Settings -> Taxes . As this is vanilla solidus, I do not dive into details here.

Wrapup

So far, most things went relatively smooth - few hours including writing this post. Of course to be compliant we would need a lot more customizations (base prices, gdpr and other legal stuff). Maybe I will look into that later.

If you want to cherry-pick commits or see how the whole codebase looks, I set up a github-repository with relatively clean commits for that.

Having a better idea?

Awesome! Get in contact with me!