abstract class LocalTaxTypeBase in Commerce Core 8.2
Provides the base class for local tax types.
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements DerivativeInspectionInterface, PluginInspectionInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
- class \Drupal\commerce_tax\Plugin\Commerce\TaxType\TaxTypeBase implements TaxTypeInterface, ContainerFactoryPluginInterface
- class \Drupal\commerce_tax\Plugin\Commerce\TaxType\LocalTaxTypeBase implements LocalTaxTypeInterface
- class \Drupal\commerce_tax\Plugin\Commerce\TaxType\TaxTypeBase implements TaxTypeInterface, ContainerFactoryPluginInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
Expanded class hierarchy of LocalTaxTypeBase
File
- modules/
tax/ src/ Plugin/ Commerce/ TaxType/ LocalTaxTypeBase.php, line 24
Namespace
Drupal\commerce_tax\Plugin\Commerce\TaxTypeView source
abstract class LocalTaxTypeBase extends TaxTypeBase implements LocalTaxTypeInterface {
/**
* The rounder.
*
* @var \Drupal\commerce_price\RounderInterface
*/
protected $rounder;
/**
* The chain tax rate resolver.
*
* @var \Drupal\commerce_tax\Resolver\ChainTaxRateResolverInterface
*/
protected $chainRateResolver;
/**
* The zones.
*
* @var \Drupal\commerce_tax\TaxZone[]
*/
protected $zones;
/**
* The matched zones.
*
* @var array
*/
protected $matchedZones;
/**
* Constructs a new LocalTaxTypeBase object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
* The event dispatcher.
* @param \Drupal\commerce_price\RounderInterface $rounder
* The rounder.
* @param \Drupal\commerce_tax\Resolver\ChainTaxRateResolverInterface $chain_rate_resolver
* The chain tax rate resolver.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EventDispatcherInterface $event_dispatcher, RounderInterface $rounder, ChainTaxRateResolverInterface $chain_rate_resolver) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $event_dispatcher);
$this->rounder = $rounder;
$this->chainRateResolver = $chain_rate_resolver;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('entity_type.manager'), $container
->get('event_dispatcher'), $container
->get('commerce_price.rounder'), $container
->get('commerce_tax.chain_tax_rate_resolver'));
}
/**
* {@inheritdoc}
*/
public function shouldRound() {
return TRUE;
}
/**
* {@inheritdoc}
*/
public function applies(OrderInterface $order) {
$store = $order
->getStore();
return $this
->matchesAddress($store) || $this
->matchesRegistrations($store);
}
/**
* {@inheritdoc}
*/
public function apply(OrderInterface $order) {
$calculation_date = $order
->getCalculationDate();
$store = $order
->getStore();
$prices_include_tax = $store
->get('prices_include_tax')->value;
$zones = $this
->getZones();
foreach ($order
->getItems() as $order_item) {
$customer_profile = $this
->resolveCustomerProfile($order_item);
if (!$customer_profile) {
continue;
}
$rates = $this
->resolveRates($order_item, $customer_profile);
foreach ($rates as $zone_id => $rate) {
$zone = $zones[$zone_id];
$percentage = $rate
->getPercentage($calculation_date);
// Stores are allowed to enter prices without tax even if they're
// going to be displayed with tax, and vice-versa.
// Now that the rates are known, use them to determine the final
// unit price (which will in turn finalize the order item total).
if ($prices_include_tax != $this
->isDisplayInclusive()) {
$unit_price = $order_item
->getUnitPrice();
$tax_amount = $percentage
->calculateTaxAmount($unit_price, $prices_include_tax);
$tax_amount = $this->rounder
->round($tax_amount);
if ($prices_include_tax && !$this
->isDisplayInclusive()) {
$unit_price = $unit_price
->subtract($tax_amount);
}
elseif (!$prices_include_tax && $this
->isDisplayInclusive()) {
$unit_price = $unit_price
->add($tax_amount);
}
$order_item
->setUnitPrice($unit_price);
}
// Now determine the tax amount, taking into account other adjustments.
$adjusted_total_price = $order_item
->getAdjustedTotalPrice([
'promotion',
'fee',
]);
$tax_amount = $percentage
->calculateTaxAmount($adjusted_total_price, $this
->isDisplayInclusive());
if ($this
->shouldRound()) {
$tax_amount = $this->rounder
->round($tax_amount);
}
$order_item
->addAdjustment(new Adjustment([
'type' => 'tax',
'label' => $zone
->getDisplayLabel(),
'amount' => $tax_amount,
'percentage' => $percentage
->getNumber(),
'source_id' => $this->parentEntity
->id() . '|' . $zone
->getId() . '|' . $rate
->getId(),
'included' => $this
->isDisplayInclusive(),
]));
}
}
}
/**
* Checks whether the tax type matches the store's billing address.
*
* @param \Drupal\commerce_store\Entity\StoreInterface $store
* The store.
*
* @return bool
* TRUE if the tax type matches the billing address, FALSE otherwise.
*/
protected function matchesAddress(StoreInterface $store) {
$zones = $this
->getMatchingZones($store
->getAddress());
return !empty($zones);
}
/**
* Checks whether the tax type matches the store's tax registrations.
*
* Countries have a yearly transaction threshold (such as $30k) which
* when breached requires companies to register for tax collection.
* This also often applies to foreign companies selling to that
* country's residents. Furthermore, many countries are now trying to
* make foreign companies collect their tax when selling digital products
* to their residents, regardless of any threshold.
* The $store->tax_registrations field allows merchants to precisely specify
* for which countries they are collecting tax.
*
* @param \Drupal\commerce_store\Entity\StoreInterface $store
* The store.
*
* @return bool
* TRUE if the tax type matches the tax registrations, FALSE otherwise.
*/
protected function matchesRegistrations(StoreInterface $store) {
foreach ($this
->getZones() as $zone) {
if ($this
->checkRegistrations($store, $zone)) {
return TRUE;
}
}
return FALSE;
}
/**
* Checks whether the store is registered to collect taxes in the given zone.
*
* @param \Drupal\commerce_store\Entity\StoreInterface $store
* The store.
* @param \Drupal\commerce_tax\TaxZone $zone
* The tax zone.
*
* @return bool
* TRUE if the store is registered in the given zone, FALSE otherwise.
*/
protected function checkRegistrations(StoreInterface $store, TaxZone $zone) {
foreach ($store
->get('tax_registrations') as $field_item) {
if ($zone
->match(new Address($field_item->value))) {
return TRUE;
}
}
return FALSE;
}
/**
* Resolves the tax rates for the given order item and customer profile.
*
* @param \Drupal\commerce_order\Entity\OrderItemInterface $order_item
* The order item.
* @param \Drupal\profile\Entity\ProfileInterface $customer_profile
* The customer profile. Contains the address and tax number.
*
* @return \Drupal\commerce_tax\TaxRate[]
* The tax rates, keyed by tax zone ID.
*/
protected function resolveRates(OrderItemInterface $order_item, ProfileInterface $customer_profile) {
$zones = $this
->resolveZones($order_item, $customer_profile);
if (!$zones) {
return [];
}
// Provide the tax type entity to the resolvers.
$this->chainRateResolver
->setTaxType($this->parentEntity);
$rates = [];
foreach ($zones as $zone) {
$rate = $this->chainRateResolver
->resolve($zone, $order_item, $customer_profile);
if (is_object($rate)) {
$rates[$zone
->getId()] = $rate;
}
}
return $rates;
}
/**
* Resolves the tax zones for the given order item and customer profile.
*
* @param \Drupal\commerce_order\Entity\OrderItemInterface $order_item
* The order item.
* @param \Drupal\profile\Entity\ProfileInterface $customer_profile
* The customer profile. Contains the address and tax number.
*
* @return \Drupal\commerce_tax\TaxZone[]
* The tax zones.
*/
protected function resolveZones(OrderItemInterface $order_item, ProfileInterface $customer_profile) {
$customer_address = $customer_profile
->get('address')
->first();
$resolved_zones = $this
->getMatchingZones($customer_address);
return $resolved_zones;
}
/**
* Builds the summary of all available tax rates.
*
* @return array
* The summary form element.
*/
protected function buildRateSummary() {
$zones = $this
->getZones();
usort($zones, function ($a, $b) {
/** @var \Drupal\commerce_tax\TaxZone $a */
/** @var \Drupal\commerce_tax\TaxZone $b */
return strcmp($a
->getLabel(), $b
->getLabel());
});
$element = [
'#type' => 'details',
'#title' => $this
->t('Tax rates'),
'#markup' => $this
->t('The following tax rates are provided:'),
'#open' => TRUE,
];
$element['table'] = [
'#type' => 'table',
'#header' => [
$this
->t('Tax rate'),
[
'data' => $this
->t('Percentage'),
'colspan' => 2,
],
],
'#input' => FALSE,
];
foreach ($zones as $zone) {
if (count($zones) > 1) {
$element['table'][$zone
->getId()] = [
'#attributes' => [
'class' => [
'region-title',
],
'no_striping' => TRUE,
],
'label' => [
'#markup' => $zone
->getLabel(),
'#wrapper_attributes' => [
'colspan' => 3,
],
],
];
}
foreach ($zone
->getRates() as $rate) {
$formatted_percentages = array_map(function ($percentage) {
/** @var \Drupal\commerce_tax\TaxRatePercentage $percentage */
return $percentage
->toString();
}, $rate
->getPercentages());
$element['table'][$zone
->getId() . '|' . $rate
->getId()] = [
'rate' => [
'#markup' => $rate
->getLabel(),
],
'percentages' => [
'#markup' => implode('<br>', $formatted_percentages),
],
];
}
}
return $element;
}
/**
* {@inheritdoc}
*/
public function getZones() {
if (empty($this->zones)) {
$zones = $this
->buildZones();
// Dispatch an event to allow altering the tax zones.
$event = new BuildZonesEvent($zones, $this);
$this->eventDispatcher
->dispatch(TaxEvents::BUILD_ZONES, $event);
$this->zones = $event
->getZones();
}
return $this->zones;
}
/**
* {@inheritdoc}
*/
public function getMatchingZones(AddressInterface $address) {
$address_hash = spl_object_hash($address);
if (!isset($this->matchedZones[$address_hash])) {
$this->matchedZones[$address_hash] = [];
foreach ($this
->getZones() as $zone) {
if ($zone
->match($address)) {
$this->matchedZones[$address_hash][] = $zone;
}
}
}
return $this->matchedZones[$address_hash];
}
/**
* Builds the tax zones.
*
* @return \Drupal\commerce_tax\TaxZone[]
* The tax zones, keyed by ID.
*/
protected abstract function buildZones();
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
DependencySerializationTrait:: |
protected | property | An array of entity type IDs keyed by the property name of their storages. | |
DependencySerializationTrait:: |
protected | property | An array of service IDs keyed by property name used for serialization. | |
LocalTaxTypeBase:: |
protected | property | The chain tax rate resolver. | |
LocalTaxTypeBase:: |
protected | property | The matched zones. | |
LocalTaxTypeBase:: |
protected | property | The rounder. | |
LocalTaxTypeBase:: |
protected | property | The zones. | |
LocalTaxTypeBase:: |
public | function |
Checks whether the tax type applies to the given order. Overrides TaxTypeBase:: |
|
LocalTaxTypeBase:: |
public | function |
Applies the tax type to the given order. Overrides TaxTypeInterface:: |
|
LocalTaxTypeBase:: |
protected | function | Builds the summary of all available tax rates. | |
LocalTaxTypeBase:: |
abstract protected | function | Builds the tax zones. | 6 |
LocalTaxTypeBase:: |
protected | function | Checks whether the store is registered to collect taxes in the given zone. | |
LocalTaxTypeBase:: |
public static | function |
Creates an instance of the plugin. Overrides TaxTypeBase:: |
1 |
LocalTaxTypeBase:: |
public | function |
Gets the tax zones which match the given address. Overrides LocalTaxTypeInterface:: |
|
LocalTaxTypeBase:: |
public | function |
Gets the tax zones. Overrides LocalTaxTypeInterface:: |
|
LocalTaxTypeBase:: |
protected | function | Checks whether the tax type matches the store's billing address. | 1 |
LocalTaxTypeBase:: |
protected | function | Checks whether the tax type matches the store's tax registrations. | 1 |
LocalTaxTypeBase:: |
protected | function | Resolves the tax rates for the given order item and customer profile. | |
LocalTaxTypeBase:: |
protected | function | Resolves the tax zones for the given order item and customer profile. | 2 |
LocalTaxTypeBase:: |
public | function |
Gets whether tax should be rounded at the order item level. Overrides LocalTaxTypeInterface:: |
1 |
LocalTaxTypeBase:: |
public | function |
Constructs a new LocalTaxTypeBase object. Overrides TaxTypeBase:: |
1 |
MessengerTrait:: |
protected | property | The messenger. | 29 |
MessengerTrait:: |
public | function | Gets the messenger. | 29 |
MessengerTrait:: |
public | function | Sets the messenger. | |
PluginBase:: |
protected | property | Configuration information passed into the plugin. | 1 |
PluginBase:: |
protected | property | The plugin implementation definition. | 1 |
PluginBase:: |
protected | property | The plugin_id. | |
PluginBase:: |
constant | A string which is used to separate base plugin IDs from the derivative ID. | ||
PluginBase:: |
public | function |
Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the definition of the plugin implementation. Overrides PluginInspectionInterface:: |
3 |
PluginBase:: |
public | function |
Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface:: |
|
PluginBase:: |
public | function | Determines if the plugin is configurable. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. | |
TaxTypeBase:: |
protected | property | The ID of the parent config entity. | |
TaxTypeBase:: |
protected | property | The entity type manager. | |
TaxTypeBase:: |
protected | property | The event dispatcher. | |
TaxTypeBase:: |
protected | property | The parent config entity. | |
TaxTypeBase:: |
protected | property | A cache of prepared customer profiles, keyed by order ID. | |
TaxTypeBase:: |
public | function |
Form constructor. Overrides PluginFormInterface:: |
6 |
TaxTypeBase:: |
protected | function | Builds a customer profile for the given order. | |
TaxTypeBase:: |
public | function |
Calculates dependencies for the configured plugin. Overrides DependentPluginInterface:: |
|
TaxTypeBase:: |
public | function |
Gets default configuration for this plugin. Overrides ConfigurableInterface:: |
1 |
TaxTypeBase:: |
public | function |
Gets this plugin's configuration. Overrides ConfigurableInterface:: |
|
TaxTypeBase:: |
public | function |
Gets the tax type label. Overrides TaxTypeInterface:: |
|
TaxTypeBase:: |
protected | function | Gets the taxable type for the given order item. | |
TaxTypeBase:: |
public | function |
Gets the tax type weight. Overrides TaxTypeInterface:: |
|
TaxTypeBase:: |
public | function |
Gets whether the tax type is display inclusive. Overrides TaxTypeInterface:: |
|
TaxTypeBase:: |
protected | function | Resolves the customer profile for the given order item. | |
TaxTypeBase:: |
public | function |
Sets the configuration for this plugin instance. Overrides ConfigurableInterface:: |
1 |
TaxTypeBase:: |
public | function |
Form submission handler. Overrides PluginFormInterface:: |
1 |
TaxTypeBase:: |
public | function |
Form validation handler. Overrides PluginFormInterface:: |
1 |
TaxTypeBase:: |
public | function |
Overrides DependencySerializationTrait:: |
|
TaxTypeBase:: |
public | function |
Overrides DependencySerializationTrait:: |