Skip to content

Commit 5257977

Browse files
committed
[FEATURE] #22 Added dynamic shipping tax class calculation
1 parent 0f94788 commit 5257977

File tree

5 files changed

+228
-0
lines changed

5 files changed

+228
-0
lines changed

Model/Config.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
*/
1616
class Config implements ConfigInterface
1717
{
18+
const DYNAMIC_TYPE_DEFAULT = 0;
19+
const DYNAMIC_TYPE_HIGHEST_PRODUCT_TAX = 1;
20+
1821
/**
1922
* Configuration reader
2023
*
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 FireGento e.V.
4+
* See LICENSE.md bundled with this module for license details.
5+
*/
6+
namespace FireGento\MageSetup\Model\System\Config\Source\Tax;
7+
8+
use FireGento\MageSetup\Model\Config;
9+
10+
/**
11+
* Class Dynamic
12+
*
13+
* @package FireGento\MageSetup\Model\System\Config\Source\Tax
14+
*/
15+
class Dynamic implements \Magento\Framework\Option\ArrayInterface
16+
{
17+
/**
18+
* @var array
19+
*/
20+
protected $options = null;
21+
22+
/**
23+
* To option array
24+
*
25+
* @return array
26+
*/
27+
public function toOptionArray()
28+
{
29+
if (null === $this->options) {
30+
$options = [
31+
[
32+
'value' => Config::DYNAMIC_TYPE_DEFAULT,
33+
'label' => __('No dynamic shipping tax caluclation')
34+
],
35+
[
36+
'value' => Config::DYNAMIC_TYPE_HIGHEST_PRODUCT_TAX,
37+
'label' => __('Use the highest product tax')
38+
]
39+
];
40+
41+
$this->options = $options;
42+
}
43+
44+
return $this->options;
45+
}
46+
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<?php
2+
/**
3+
* Copyright © 2016 FireGento e.V.
4+
* See LICENSE.md bundled with this module for license details.
5+
*/
6+
namespace FireGento\MageSetup\Plugin\Tax\Config;
7+
8+
use Magento\Store\Model\Store;
9+
use FireGento\MageSetup\Model\Config;
10+
11+
/**
12+
* Class AroundGetShippingTaxClassPlugin
13+
*
14+
* @package FireGento\MageSetup\Plugin\Tax\Config
15+
*/
16+
class AroundGetShippingTaxClassPlugin
17+
{
18+
const CONFIG_PATH_DYNAMIC_SHIPPING_TAX_CLASS = 'tax/classes/dynamic_shipping_tax_class';
19+
20+
/**
21+
* @var \Magento\Framework\App\Config\ScopeConfigInterface
22+
*/
23+
private $scopeConfig;
24+
25+
/**
26+
* @var \Magento\Checkout\Model\Cart
27+
*/
28+
private $cart;
29+
/**
30+
* @var \Magento\Customer\Model\Session
31+
*/
32+
private $customerSession;
33+
/**
34+
* @var \Magento\Customer\Model\ResourceModel\GroupRepository
35+
*/
36+
private $groupRepository;
37+
/**
38+
* @var \Magento\Tax\Model\Calculation\Proxy
39+
*/
40+
private $taxCalculation;
41+
42+
/**
43+
* AroundGetShippingTaxClassPlugin constructor.
44+
*
45+
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
46+
* @param \Magento\Checkout\Model\Cart $cart
47+
* @param \Magento\Customer\Model\Session $customerSession
48+
* @param \Magento\Customer\Model\ResourceModel\GroupRepository $groupRepository
49+
* @param \Magento\Tax\Model\Calculation\Proxy $taxCalculation
50+
*/
51+
public function __construct(
52+
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
53+
\Magento\Checkout\Model\Cart $cart,
54+
\Magento\Customer\Model\Session $customerSession,
55+
\Magento\Customer\Model\ResourceModel\GroupRepository $groupRepository,
56+
\Magento\Tax\Model\Calculation\Proxy $taxCalculation
57+
)
58+
{
59+
$this->scopeConfig = $scopeConfig;
60+
$this->cart = $cart;
61+
$this->customerSession = $customerSession;
62+
$this->groupRepository = $groupRepository;
63+
$this->taxCalculation = $taxCalculation;
64+
}
65+
66+
/**
67+
* @param \Magento\Tax\Model\Config $subject
68+
* @param \Closure $proceed
69+
* @param null|string|bool|int|Store $store
70+
* @return mixed
71+
*/
72+
public function aroundGetShippingTaxClass(\Magento\Tax\Model\Config $subject, \Closure $proceed, $store)
73+
{
74+
$handle = \fopen('abc.log', 'w+');
75+
76+
$dynamicType = (int)$this->scopeConfig->getValue(
77+
self::CONFIG_PATH_DYNAMIC_SHIPPING_TAX_CLASS,
78+
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
79+
$store
80+
);
81+
82+
// TODO: Check for admin quote
83+
84+
$quoteItems = $this->cart->getItems();
85+
86+
// If the default behaviour was configured or there are no products in cart, use default tax class id
87+
if ($dynamicType == Config::DYNAMIC_TYPE_DEFAULT || count($quoteItems) == 0) {
88+
return $proceed($store);
89+
}
90+
91+
$taxClassId = false;
92+
93+
// Retrieve the highest product tax class
94+
if ($dynamicType == Config::DYNAMIC_TYPE_HIGHEST_PRODUCT_TAX) {
95+
$taxClassId = $this->getHighestProductTaxClassId($quoteItems, $store);
96+
}
97+
98+
// If no tax class id was found, use default one
99+
if (!$taxClassId) {
100+
$taxClassId = $proceed($store);
101+
}
102+
103+
return $taxClassId;
104+
}
105+
106+
/**
107+
* @param array $quoteItems
108+
* @param null|string|bool|int|Store $store
109+
* @return bool|mixed|null
110+
*/
111+
private function getHighestProductTaxClassId($quoteItems, $store)
112+
{
113+
$taxClassIds = [];
114+
$highestTaxRate = null;
115+
116+
foreach ($quoteItems as $quoteItem) {
117+
/** @var $quoteItem \Magento\Quote\Model\Quote\Item */
118+
if ($quoteItem->getParentItem()) {
119+
continue;
120+
}
121+
122+
// Retrieve the tax percent
123+
$taxPercent = $quoteItem->getTaxPercent();
124+
if (!$taxPercent) {
125+
$taxPercent = $this->getTaxPercent($quoteItem->getTaxClassId(), $store);
126+
}
127+
128+
// Add the tax class
129+
if (is_float($taxPercent) && !in_array($taxPercent, $taxClassIds)) {
130+
$taxClassIds[$taxPercent] = $quoteItem->getTaxClassId();
131+
}
132+
}
133+
134+
// Fetch the highest tax rate
135+
ksort($taxClassIds);
136+
if (count($taxClassIds) > 0) {
137+
$highestTaxRate = array_pop($taxClassIds);
138+
}
139+
if (!$highestTaxRate || is_null($highestTaxRate)) {
140+
return false;
141+
}
142+
143+
return $highestTaxRate;
144+
}
145+
146+
/**
147+
* @param int $productTaxClassId
148+
* @param null|string|bool|int|Store $store
149+
* @return float|int
150+
*/
151+
private function getTaxPercent($productTaxClassId, $store)
152+
{
153+
$groupId = $this->customerSession->getCustomerGroupId();
154+
$group = $this->groupRepository->getById($groupId);
155+
$customerTaxClassId = $group->getTaxClassId();
156+
157+
$request = $this->taxCalculation->getRateRequest(null, null, $customerTaxClassId, $store);
158+
$request->setData('product_class_id', $productTaxClassId);
159+
160+
$taxPercent = $this->taxCalculation->getRate($request);
161+
if (!$taxPercent) {
162+
$taxPercent = 0;
163+
}
164+
165+
return $taxPercent;
166+
}
167+
}

etc/adminhtml/system.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,5 +136,13 @@
136136
</field>
137137
</group>
138138
</section>
139+
<section id="tax">
140+
<group id="classes">
141+
<field id="dynamic_shipping_tax_class" translate="label" type="select" sortOrder="11" showInDefault="1" showInWebsite="1" showInStore="0">
142+
<label>Dynamic Shipping Tax Class</label>
143+
<source_model>FireGento\MageSetup\Model\System\Config\Source\Tax\Dynamic</source_model>
144+
</field>
145+
</group>
146+
</section>
139147
</system>
140148
</config>

etc/di.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,8 @@
4343
<type name="Magento\CheckoutAgreements\Model\Agreement">
4444
<plugin name="mageSetupFilterAgreementContent" type="FireGento\MageSetup\Plugin\Agreements\AfterGetContent" sortOrder="1"/>
4545
</type>
46+
47+
<type name="Magento\Tax\Model\Config">
48+
<plugin name="mageSetupDynamicShippingTaxClass" type="FireGento\MageSetup\Plugin\Tax\Config\AroundGetShippingTaxClassPlugin" sortOrder="1"/>
49+
</type>
4650
</config>

0 commit comments

Comments
 (0)