Presented by David Kitchen / @dwkitchen
Technical Lead for Commerce Guys UK
Tax specialist and Commerce Contributor
Bojan Zivanovic (bojanz)
and Ryan Szrama (rszrama)
Our vision is for Drupal Commerce to be the number one
open source e-commerce platform in the world...
Powering truly flexible e-commerce.
A brief history.
*Led by Bojan Zivanovic.
$ ¢ £ p ¥ ₤ ₧ € ₹ ₩ ₴ ₯ ₮ ₲ ₳ ₵ ₭ ₪ ₫
€12,345.99
12 345,99 €
12.345,99 €
د.إ. ٩٩٩٫٩٩
A price is a value object. Each operation (add, subtract, multiply, divide, round) produces a new price instance. All amounts are passed as strings, and manipulated using bcmath.
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);
// Every operation produces a new Price instance.
$total = $firstPrice
->add($secondPrice)
->subtract($thirdPrice)
->multiply('4')
->divide('2');
echo $total; // 359.366 EUR
echo $total->round(); // 359.37 EUR
echo $total->round(Price::ROUND_HALF_UP, 1); // 359.4 EUR
echo $total->greaterThan($firstPrice); // true
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;
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('en-US');
$currencyFormatter = new NumberFormatter($numberFormat, NumberFormatter::CURRENCY);
echo $currencyFormatter->formatCurrency($price->getAmount(), $price->getCurrency());
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();
}
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');
Zones are territorial groupings mostly used for shipping or tax purposes. For example, a set of shipping rates associated with 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.
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);
{
"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": "1991-03-19",
"end_date": "2008-11-30"
},
Validated the architecture with members of SensioLabs, Smile, Publicis Modem, OSInet, i-KOS, Adyax, Ekino, and others.
<?php
namespace Drupal\commerce\Entity
Create a "mini" ledger for payments with double entry like accounting features.
Office hours: Wednesdays at 1PM GMT
Find us in #drupal-commerce.