DRUPAL COMMERCE 2.X DRUPAL CAMP LONDON 2015 Presented by David Kitchen / @dwkitchen
Jul 16, 2015
DRUPAL COMMERCE 2.XDRUPAL CAMP LONDON 2015
Presented by David Kitchen / @dwkitchen
INTRODUCTIONS
DAVID KITCHEN
Technical Lead for Commerce Guys UKTax specialist and Commerce Contributor
DRUPAL COMMERCE 2.X CO-MAINTAINERS
Bojan Zivanovic (bojanz) and Ryan Szrama (rszrama)
Our vision is for Drupal Commerce to be the number oneopen source e-commerce platform in the world...
Powering truly flexible e-commerce.
DRUPAL COMMERCE 1.XA brief history.
BUILT FROM SCRATCH ON DRUPAL 7
MINIMALISTIC AND FLEXIBLE
USES VIEWS FOR ALL LISTINGS
USES RULES FOR BUSINESS LOGIC
RELIES ON "ESSENTIAL CONTRIBS" AND DISTRIBUTIONS TOCOMPLETE THE EXPERIENCE
WE'RE DOING SOMETHING RIGHT...
SYMFONY PHP LIBRARIES
WE* STARTED WITH RESEARCH*Led by Bojan Zivanovic.
Define the deficiencies in our own softwareExisting */money librariesSonata / Sylius e-commerce bundlesNon-Symfony PHP applicationsNon-PHP applications
IDENTIFYING OUR WEAKNESSESAge old tax management issuesIncomplete price management APIIncomplete currency formatting rulesAddress implementation stretched to the limitLimited ability to collaborate outside of Drupal
PROPOSING STANDALONE SOLUTIONSInternationalization (esp. currency formatting)Address formatting / validationTerritory grouping (to support taxing)Tax rate management (at least for VAT)Price calculation and manipulation
Not just interfaces / classes but unprecedented data.also
Minimal dependencies.
Simple APIs with clear documentation and examples.
Full test coverage.
Reusable by any PHP based e-commerce application.
INTLNumber Formatter, inspired by intl.CurrenciesCountriesLanguages
COMING SOON
Date Formatting
Drupal Commerce blog.
CURRENCY HANDLING
$ ¢ £ p ¥ ₤ ₧ € ₹ ₩ ₴ ₯ ₮ ₲ ₳ ₵ ₭ ₪ ₫
CURRENCY FORMATTING
€12,345.99
12 345,99 €
12.345,99 €
د.إ. ۹۹۹٫۹۹
PRICINGA price is a value object. Each operation (add, subtract,
multiply, divide, round) produces a new price instance. Allamounts are passed as strings, and manipulated using
bcmath.
CREATING PRICES
use CommerceGuys\Intl\Currency\CurrencyRepository;use CommerceGuys\Pricing\Price;
$currencyRepository = new CurrencyRepository;$currency = $currencyRepository>get('EUR');
$firstPrice = new Price('99.99', $currency);$secondPrice = new Price('100', $currency);$thirdPrice = new Price('20.307', $currency);
PRICE OPERATIONS
// Every operation produces a new Price instance.$total = $firstPrice>add($secondPrice)>subtract($thirdPrice)>multiply('4')>divide('2');echo $total; // 359.366 EURecho $total>round(); // 359.37 EURecho $total>round(Price::ROUND_HALF_UP, 1); // 359.4 EURecho $total>greaterThan($firstPrice); // true
CURRENCY CONVERSION
use CommerceGuys\Intl\Currency\CurrencyRepository;use CommerceGuys\Pricing\Price;
$currencyRepository = new CurrencyRepository;$eur = $currencyRepository>get('EUR');$usd = $currencyRepository>get('USD');
// Use an external library to get an actual exchange rate.$rate = 1;$eurPrice = new Price('100', $eur);$usdPrice = $eurPrice>convert($usd, $rate);echo $usdPrice;
CURRENCY FORMATTING
use CommerceGuys\Intl\Currency\CurrencyRepository;use CommerceGuys\Intl\NumberFormat\NumberFormatRepository;use CommerceGuys\Intl\Formatter\NumberFormatter;use CommerceGuys\Pricing\Price;
$currencyRepository = new CurrencyRepository;$currency = $currencyRepository>get('USD');$price = new Price('99.99', $currency);
$numberFormatRepository = new NumberFormatRepository;$numberFormat = $numberFormatRepository>get('enUS');
$currencyFormatter = new NumberFormatter($numberFormat, NumberFormatter::CURRENCY);echo $currencyFormatter>formatCurrency($price>getAmount(), $price>getCurrency());
ADDRESSINGAddress formats for 200 countriesSubdivisions (administrative areas, localities, dependentlocalities) for 40 countriesSubdivision translations for all of the parent country's (i.eCanada, Switzerland) official languages.Validation (via Symfony Validator)Form generation (via Symfony Form)Postal formatting
Featured on the Drupal Commerce blog.
ADDRESS DATA
use CommerceGuys\Addressing\Repository\AddressFormatRepository;use CommerceGuys\Addressing\Repository\SubdivisionRepository;
$addressFormatRepository = new AddressFormatRepository();$subdivisionRepository = new SubdivisionRepository();
// Get the address format for Canada.$addressFormat = $addressFormatRepository>get('CA');
// Get the subdivisions for Canada, in French.$states = $subdivisionRepository>getAll('CA', 0, 'fr');foreach ($states as $state) echo $state>getName();
WHAT FIELDS?
SOMEWHERE ELSE
ADDRESS FORMAT
Which fields are used, and in which orderWhich fields are requiredWhich fields need to be uppercasedField labelsRegular expression for validating postal codes
ADDRESS FORMATTING
use CommerceGuys\Addressing\Formatter\PostalFormatter;use CommerceGuys\Addressing\Provider\DataProvider;
$dataProvider = new DataProvider();$formatter = new PostalFormatter($dataProvider);
// Format an address for sending from Switzerland, in French.// If the address destination is not Switzerland, the country name will be// appended in French, uppercase.echo $formatter>format($address, 'CH', 'fr');
ZONEZones are territorial groupings mostly used for shipping or
tax purposes. For example, a set of shipping rates associatedwith a zone where the rates become available only if the
customer's address matches the zone.
A zone can match other zones, countries, subdivisions(states/provinces/municipalities), postal codes. Postal codes
can also be expressed using ranges or regular expressions.
Create the German VAT zone
use CommerceGuys\Addressing\Model\Address;use CommerceGuys\Zone\Model\Zone;use CommerceGuys\Zone\Model\ZoneMemberCountry;
$zone = new Zone();$zone>setId('german_vat');$zone>setName('German VAT');$zone>setScope('tax');
Add Germany to the zone,
$germanyZoneMember = new ZoneMemberCountry();$germanyZoneMember>setCountryCode('DE');$zone>addMember($germanyZoneMember);
add the 4 Austrian postal codes that are in Germany for VAT.
$austriaZoneMember = new ZoneMemberCountry();$austriaZoneMember>setCountryCode('AT');$austriaZoneMember>setIncludedPostalCodes('6691, 6991:6993');$zone>addMember($austriaZoneMember);
Initialising a zone matcher.
use CommerceGuys\Addressing\Model\Address;use CommerceGuys\Zone\Matcher\ZoneMatcher;use CommerceGuys\Zone\Repository\ZoneRepository;
$repository = new ZoneRepository('resources/zone');$matcher = new ZoneMatcher($repository);
Create an address.
$austrianAddress = new Address();$austrianAddress>setCountryCode('AT');$austrianAddress>setPostalCode('6692');
Get the matching tax zones.
$zones = $matcher>matchAll($austrianAddress, 'tax');
Is in Germany for VAT.
TAXSmart data model designed for fluctuating tax rateamounts ("19% -> 21% on January 1st").Predefined tax rates and zones for EU countries, Iceland,Norway, South Africa and Switzerland. More to come.Tax resolvers with logic for all major use cases.
EU TAX RESOLVER
use CommerceGuys\Tax\Repository\TaxTypeRepository;use CommerceGuys\Tax\Resolver\Engine\TaxTypeResolverEngine;use CommerceGuys\Tax\Resolver\Engine\TaxRateResolverEngine;use CommerceGuys\Tax\Resolver\TaxType\EuTaxTypeResolver;use CommerceGuys\Tax\Resolver\TaxRate\DefaultTaxRateResolver;use CommerceGuys\Tax\Resolver\TaxResolver;
$taxTypeRepository = new TaxTypeRepository();$taxTypeResolverEngine = new TaxTypeResolverEngine();$taxTypeResolverEngine>add(new EuTaxTypeResolver($taxTypeRepository));$taxRateResolverEngine = new TaxRateResolverEngine();$taxRateResolverEngine>add(new DefaultTaxRateResolver());$resolver = new TaxResolver($taxTypeResolverEngine, $taxRateResolverEngine);
CALCULATES THE VAT RATE BASED ON
Goods or ServicesType of service, digital, educationB2C or B2BSupplier locationCustomer Location
FULL DATA INC. HISTORIC RATES
"name": "British VAT","zone": "gb_vat","tag": "EU","rates": [ "id": "gb_vat_standard", "name": "Standard", "display_name": "% VAT", "default": true, "amounts": [ "id": "gb_vat_standard_1991", "amount": 0.175, "start_date": "19910319", "end_date": "20081130" ,
WE'RE DOING SOMETHING RIGHT...
DRUPAL COMMERCE 2.X
DRUPAL COMMERCE 2.X SPRINT
Validated the architecture with members of SensioLabs,Smile, Publicis Modem, OSInet, i-KOS, Adyax, Ekino, and
others.
ONCE AGAIN, WE START FROM SCRATCH<?php
namespace Drupal\commerce\Entity
2.X ENTITY RELATIONSHIP MODEL
MULTI-STORE / MULTI-VENDOR
HIERARCHICAL PRODUCT MODEL
IMPROVED ORDER WORKFLOWS
IMPROVED PAYMENT PROCESSINGCreate a "mini" ledger for payments with double entry like
accounting features.
TRY IT OUT
CONTRIBUTE ON GITHUB
QUESTIONS?Office hours: Wednesdays at 1PM GMT
Find us in #drupal-commerce.