Viewing File: /home/maglabs/it/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SetupUtil.php
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Tax\Model\Sales\Total\Quote;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Quote\Model\Quote;
use Magento\Tax\Model\Config;
use Magento\Tax\Model\Calculation;
use Magento\Quote\Model\Quote\Item\Updater;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Framework\Api\Filter;
use Magento\Framework\Api\Search\FilterGroup;
use Magento\Framework\Api\SearchCriteriaInterface;
/**
* Setup utility for quote
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class SetupUtil
{
/**
* Default tax related configurations
*
* @var array
*/
protected $defaultConfig = [
Config::CONFIG_XML_PATH_SHIPPING_TAX_CLASS => '0',
Config::CONFIG_XML_PATH_PRICE_INCLUDES_TAX => 0, //Excluding tax
Config::CONFIG_XML_PATH_SHIPPING_INCLUDES_TAX => 0, //Excluding tax
Config::CONFIG_XML_PATH_BASED_ON => 'shipping', // or 'billing'
Config::CONFIG_XML_PATH_APPLY_ON => '0',
Config::CONFIG_XML_PATH_APPLY_AFTER_DISCOUNT => '0',
Config::CONFIG_XML_PATH_DISCOUNT_TAX => '0',
Config::XML_PATH_ALGORITHM => Calculation::CALC_TOTAL_BASE,
//@TODO: add config for cross border trade
];
const TAX_RATE_TX = 'tax_rate_tx';
const TAX_RATE_AUSTIN = 'tax_rate_austin';
const TAX_RATE_SHIPPING = 'tax_rate_shipping';
const TAX_STORE_RATE = 'tax_store_rate';
const REGION_TX = '57';
const REGION_CA = '12';
const COUNTRY_US = 'US';
const AUSTIN_POST_CODE = '79729';
/**
* Tax rates
*
* @var array
*/
protected $taxRates = [
self::TAX_RATE_TX => [
'data' => [
'tax_country_id' => self::COUNTRY_US,
'tax_region_id' => self::REGION_TX,
'tax_postcode' => '*',
'code' => self::TAX_RATE_TX,
'rate' => '20',
],
'id' => null,
],
self::TAX_RATE_AUSTIN => [
'data' => [
'tax_country_id' => self::COUNTRY_US,
'tax_region_id' => self::REGION_TX,
'tax_postcode' => self::AUSTIN_POST_CODE,
'code' => self::TAX_RATE_AUSTIN,
'rate' => '5',
],
'id' => null,
],
self::TAX_RATE_SHIPPING => [
'data' => [
'tax_country_id' => self::COUNTRY_US,
'tax_region_id' => '*',
'tax_postcode' => '*',
'code' => self::TAX_RATE_SHIPPING,
'rate' => '7.5',
],
'id' => null,
],
self::TAX_STORE_RATE => [
'data' => [
'tax_country_id' => self::COUNTRY_US,
'tax_region_id' => self::REGION_CA,
'tax_postcode' => '*',
'code' => self::TAX_STORE_RATE,
'rate' => '8.25',
],
'id' => null,
],
];
const PRODUCT_TAX_CLASS_1 = 'product_tax_class_1';
const PRODUCT_TAX_CLASS_2 = 'product_tax_class_2';
const SHIPPING_TAX_CLASS = 'shipping_tax_class';
/**
* List of product tax class that will be created
*
* @var array
*/
protected $productTaxClasses = [
self::PRODUCT_TAX_CLASS_1 => null,
self::PRODUCT_TAX_CLASS_2 => null,
self::SHIPPING_TAX_CLASS => null,
];
const CUSTOMER_TAX_CLASS_1 = 'customer_tax_class_1';
const CUSTOMER_PASSWORD = 'password';
/**
* List of customer tax class to be created
*
* @var array
*/
protected $customerTaxClasses = [
self::CUSTOMER_TAX_CLASS_1 => null,
];
/**
* List of tax rules
*
* @var array
*/
protected $taxRules = [];
const CONFIG_OVERRIDES = 'config_overrides';
const TAX_RATE_OVERRIDES = 'tax_rate_overrides';
const TAX_RULE_OVERRIDES = 'tax_rule_overrides';
/**
* Default data for shopping cart rule
*
* @var array
*/
protected $defaultShoppingCartPriceRule = [
'name' => 'Shopping Cart Rule',
'is_active' => 1,
'customer_group_ids' => [\Magento\Customer\Model\GroupManagement::CUST_GROUP_ALL],
'coupon_type' => \Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON,
'simple_action' => 'by_percent',
'discount_amount' => 40,
'discount_step' => 0,
'stop_rules_processing' => 1,
'apply_to_shipping' => 0,
'website_ids' => [1],
];
/**
* Object manager
*
* @var \Magento\Framework\ObjectManagerInterface
*/
public $objectManager;
/**
* @var \Magento\Customer\Api\CustomerRepositoryInterface
*/
protected $customerRepository;
/**
* @var \Magento\Customer\Api\AccountManagementInterface
*/
protected $accountManagement;
/**
* @param \Magento\Framework\ObjectManagerInterface $objectManager
*/
public function __construct($objectManager)
{
$this->objectManager = $objectManager;
$this->customerRepository = $this->objectManager->create(
\Magento\Customer\Api\CustomerRepositoryInterface::class
);
$this->accountManagement = $this->objectManager->create(
\Magento\Customer\Api\AccountManagementInterface::class
);
}
/**
* Create customer tax classes
*
* @return $this
*/
protected function createCustomerTaxClass()
{
foreach (array_keys($this->customerTaxClasses) as $className) {
$this->customerTaxClasses[$className] = $this->objectManager->create(\Magento\Tax\Model\ClassModel::class)
->setClassName($className)
->setClassType(\Magento\Tax\Model\ClassModel::TAX_CLASS_TYPE_CUSTOMER)
->save()
->getId();
}
return $this;
}
/**
* Create product tax classes
*
* @return $this
*/
protected function createProductTaxClass()
{
foreach (array_keys($this->productTaxClasses) as $className) {
$this->productTaxClasses[$className] = $this->objectManager->create(\Magento\Tax\Model\ClassModel::class)
->setClassName($className)
->setClassType(\Magento\Tax\Model\ClassModel::TAX_CLASS_TYPE_PRODUCT)
->save()
->getId();
}
return $this;
}
/**
* Set the configuration.
*
* @param array $configData
* @return $this
*/
protected function setConfig($configData)
{
/** @var \Magento\Config\Model\ResourceModel\Config $config */
$config = $this->objectManager->get(\Magento\Config\Model\ResourceModel\Config::class);
foreach ($configData as $path => $value) {
if ($path == Config::CONFIG_XML_PATH_SHIPPING_TAX_CLASS) {
$value = $this->productTaxClasses[$value];
}
$config->saveConfig(
$path,
$value,
ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
0
);
}
/** @var \Magento\Framework\App\Config\ReinitableConfigInterface $config */
$config = $this->objectManager->get(\Magento\Framework\App\Config\ReinitableConfigInterface::class);
$config->reinit();
return $this;
}
/**
* Create tax rates
*
* @param array $overrides
* @return $this
*/
protected function createTaxRates($overrides)
{
$taxRateOverrides = empty($overrides[self::TAX_RATE_OVERRIDES]) ? [] : $overrides[self::TAX_RATE_OVERRIDES];
foreach (array_keys($this->taxRates) as $taxRateCode) {
if (isset($taxRateOverrides[$taxRateCode])) {
$this->taxRates[$taxRateCode]['data']['rate'] = $taxRateOverrides[$taxRateCode];
}
$this->taxRates[$taxRateCode]['id'] = $this->objectManager->create(
\Magento\Tax\Model\Calculation\Rate::class
)
->setData($this->taxRates[$taxRateCode]['data'])
->save()
->getId();
}
return $this;
}
/**
* Convert the code to id for productTaxClass, customerTaxClass and taxRate in taxRuleOverrideData
*
* @param array $taxRuleOverrideData
* @param array $taxRateIds
* @return array
*/
protected function processTaxRuleOverrides($taxRuleOverrideData, $taxRateIds)
{
if (!empty($taxRuleOverrideData['customer_tax_class_ids'])) {
$customerTaxClassIds = [];
foreach ($taxRuleOverrideData['customer_tax_class_ids'] as $customerClassCode) {
$customerTaxClassIds[] = $this->customerTaxClasses[$customerClassCode];
}
$taxRuleOverrideData['customer_tax_class_ids'] = $customerTaxClassIds;
}
if (!empty($taxRuleOverrideData['product_tax_class_ids'])) {
$productTaxClassIds = [];
foreach ($taxRuleOverrideData['product_tax_class_ids'] as $productClassCode) {
$productTaxClassIds[] = $this->productTaxClasses[$productClassCode];
}
$taxRuleOverrideData['product_tax_class_ids'] = $productTaxClassIds;
}
if (!empty($taxRuleOverrideData['tax_rate_ids'])) {
$taxRateIdsForRule = [];
foreach ($taxRuleOverrideData['tax_rate_ids'] as $taxRateCode) {
$taxRateIdsForRule[] = $taxRateIds[$taxRateCode];
}
$taxRuleOverrideData['tax_rate_ids'] = $taxRateIdsForRule;
}
return $taxRuleOverrideData;
}
/**
* Return a list of product tax class ids NOT including shipping product tax class
*
* @return array
*/
protected function getProductTaxClassIds()
{
$productTaxClassIds = [];
foreach ($this->productTaxClasses as $productTaxClassName => $productTaxClassId) {
if ($productTaxClassName != self::SHIPPING_TAX_CLASS) {
$productTaxClassIds[] = $productTaxClassId;
}
}
return $productTaxClassIds;
}
/**
* Return a list of tax rate ids NOT including shipping tax rate
*
* @return array
*/
protected function getDefaultTaxRateIds()
{
$taxRateIds = [
$this->taxRates[self::TAX_RATE_TX]['id'],
$this->taxRates[self::TAX_STORE_RATE]['id'],
];
return $taxRateIds;
}
/**
* Return the default customer group tax class id
*
* @return int
*/
public function getDefaultCustomerTaxClassId()
{
/** @var \Magento\Customer\Api\GroupManagementInterface $groupManagement */
$groupManagement = $this->objectManager->get(\Magento\Customer\Api\GroupManagementInterface::class);
$defaultGroup = $groupManagement->getDefaultGroup();
return $defaultGroup->getTaxClassId();
}
/**
* Create tax rules
*
* @param array $overrides
* @return $this
*/
protected function createTaxRules($overrides)
{
$taxRateIds = [];
foreach ($this->taxRates as $taxRateCode => $taxRate) {
$taxRateIds[$taxRateCode] = $taxRate['id'];
}
//The default customer tax class id is used to calculate store tax rate
$customerClassIds = [
$this->customerTaxClasses[self::CUSTOMER_TAX_CLASS_1],
$this->getDefaultCustomerTaxClassId()
];
//By default create tax rule that covers all product tax classes except SHIPPING_TAX_CLASS
//The tax rule will cover all tax rates except TAX_RATE_SHIPPING
$taxRuleDefaultData = [
'code' => 'Test Rule',
'priority' => '0',
'position' => '0',
'customer_tax_class_ids' => $customerClassIds,
'product_tax_class_ids' => $this->getProductTaxClassIds(),
'tax_rate_ids' => $this->getDefaultTaxRateIds(),
];
//Create tax rules
if (empty($overrides[self::TAX_RULE_OVERRIDES])) {
//Create separate shipping tax rule
$shippingTaxRuleData = [
'code' => 'Shipping Tax Rule',
'priority' => '0',
'position' => '0',
'customer_tax_class_ids' => $customerClassIds,
'product_tax_class_ids' => [$this->productTaxClasses[self::SHIPPING_TAX_CLASS]],
'tax_rate_ids' => [$this->taxRates[self::TAX_RATE_SHIPPING]['id']],
];
$this->taxRules[$shippingTaxRuleData['code']] = $this->objectManager
->create(\Magento\Tax\Model\Calculation\Rule::class)
->setData($shippingTaxRuleData)
->save()
->getId();
//Create a default tax rule
$this->taxRules[$taxRuleDefaultData['code']] = $this->objectManager
->create(\Magento\Tax\Model\Calculation\Rule::class)
->setData($taxRuleDefaultData)
->save()
->getId();
} else {
foreach ($overrides[self::TAX_RULE_OVERRIDES] as $taxRuleOverrideData) {
//convert code to id for productTaxClass, customerTaxClass and taxRate
$taxRuleOverrideData = $this->processTaxRuleOverrides($taxRuleOverrideData, $taxRateIds);
$mergedTaxRuleData = array_merge($taxRuleDefaultData, $taxRuleOverrideData);
$this->taxRules[$mergedTaxRuleData['code']] = $this->objectManager
->create(\Magento\Tax\Model\Calculation\Rule::class)
->setData($mergedTaxRuleData)
->save()
->getId();
}
}
return $this;
}
/**
* Set up tax classes, tax rates and tax rules
* The override structure:
* override['self::CONFIG_OVERRIDES']
* [
* [config_path => config_value]
* ]
* override['self::TAX_RATE_OVERRIDES']
* [
* ['tax_rate_code' => tax_rate]
* ]
* override['self::TAX_RULE_OVERRIDES']
* [
* [
* 'code' => code //Required, has to be unique
* 'priority' => 0
* 'position' => 0
* 'tax_customer_class' => array of customer tax class names as defined in this class
* 'tax_product_class' => array of product tax class names as defined in this class
* 'tax_rate' => array of tax rate codes as defined in this class
* ]
* ]
*
* @param array $overrides
* @return void
*/
public function setupTax($overrides)
{
//Create product tax classes
$this->createProductTaxClass();
//Create customer tax classes
$this->createCustomerTaxClass();
//Create tax rates
$this->createTaxRates($overrides);
//Create tax rules
$this->createTaxRules($overrides);
//Tax calculation configuration
if (!empty($overrides[self::CONFIG_OVERRIDES])) {
$this->setConfig($overrides[self::CONFIG_OVERRIDES]);
}
}
/**
* Create a simple product with given sku, price and tax class
*
* @param string $sku
* @param float $price
* @param int $taxClassId
* @return \Magento\Catalog\Model\Product
*/
public function createSimpleProduct($sku, $price, $taxClassId)
{
/** @var \Magento\Catalog\Model\Product $product */
$product = $this->objectManager->create(\Magento\Catalog\Model\Product::class);
$product->isObjectNew(true);
$product->setTypeId('simple')
->setAttributeSetId(4)
->setName('Simple Product' . $sku)
->setSku($sku)
->setPrice($price)
->setTaxClassId($taxClassId)
->setStockData(
[
'use_config_manage_stock' => 1,
'qty' => 100,
'is_qty_decimal' => 0,
'is_in_stock' => 1
]
)->setMetaTitle('meta title')
->setMetaKeyword('meta keyword')
->setMetaDescription('meta description')
->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
->save();
$product = $product->load($product->getId());
return $product;
}
/**
* Create a customer group and associated it with given customer tax class
*
* @param int $customerTaxClassId
* @return int
*/
protected function createCustomerGroup($customerTaxClassId)
{
/** @var \Magento\Customer\Api\GroupRepositoryInterface $groupRepository */
$groupRepository = $this->objectManager->create(\Magento\Customer\Api\GroupRepositoryInterface::class);
$customerGroupFactory = $this->objectManager->create(\Magento\Customer\Api\Data\GroupInterfaceFactory::class);
$customerGroup = $customerGroupFactory->create()
->setCode('custom_group')
->setTaxClassId($customerTaxClassId);
$customerGroupId = $groupRepository->save($customerGroup)->getId();
return $customerGroupId;
}
/**
* Create a customer
*
* @return \Magento\Customer\Api\Data\CustomerInterface
*/
protected function createCustomer()
{
$customerGroupId = $this->createCustomerGroup($this->customerTaxClasses[self::CUSTOMER_TAX_CLASS_1]);
/** @var \Magento\Customer\Model\Customer $customer */
$customer = $this->objectManager->create(\Magento\Customer\Model\Customer::class);
$customer->isObjectNew(true);
$customer->setWebsiteId(1)
->setEntityTypeId(1)
->setAttributeSetId(1)
->setEmail('customer@example.com')
->setPassword('password')
->setGroupId($customerGroupId)
->setStoreId(1)
->setIsActive(1)
->setFirstname('Firstname')
->setLastname('Lastname')
->save();
return $this->customerRepository->getById($customer->getId());
}
/**
* Create customer address
*
* @param array $addressOverride
* @param int $customerId
* @return \Magento\Customer\Model\Address
*/
protected function createCustomerAddress($addressOverride, $customerId)
{
$defaultAddressData = [
'attribute_set_id' => 2,
'telephone' => 3468676,
'postcode' => self::AUSTIN_POST_CODE,
'country_id' => self::COUNTRY_US,
'city' => 'CityM',
'company' => 'CompanyName',
'street' => ['Green str, 67'],
'lastname' => 'Smith',
'firstname' => 'John',
'parent_id' => 1,
'region_id' => self::REGION_TX,
];
$addressData = array_merge($defaultAddressData, $addressOverride);
/** @var \Magento\Customer\Model\Address $customerAddress */
$customerAddress = $this->objectManager->create(\Magento\Customer\Model\Address::class);
$customerAddress->setData($addressData)
->setCustomerId($customerId)
->save();
return $customerAddress;
}
/**
* Create shopping cart rule
*
* @param array $ruleDataOverride
* @return $this
*/
protected function createCartRule($ruleDataOverride)
{
/** @var \Magento\SalesRule\Model\Rule $salesRule */
$salesRule = $this->objectManager->create(\Magento\SalesRule\Model\Rule::class);
$ruleData = array_merge($this->defaultShoppingCartPriceRule, $ruleDataOverride);
$salesRule->setData($ruleData);
$salesRule->save();
return $this;
}
/**
* Create a quote object with customer
*
* @param array $quoteData
* @param \Magento\Customer\Api\Data\CustomerInterface $customer
* @return Quote
*/
protected function createQuote($quoteData, $customer)
{
/** @var \Magento\Customer\Api\AddressRepositoryInterface $addressService */
$addressService = $this->objectManager->create(\Magento\Customer\Api\AddressRepositoryInterface::class);
/** @var array $shippingAddressOverride */
$shippingAddressOverride = empty($quoteData['shipping_address']) ? [] : $quoteData['shipping_address'];
/** @var \Magento\Customer\Model\Address $shippingAddress */
$shippingAddress = $this->createCustomerAddress($shippingAddressOverride, $customer->getId());
/** @var \Magento\Quote\Model\Quote\Address $quoteShippingAddress */
$quoteShippingAddress = $this->objectManager->create(\Magento\Quote\Model\Quote\Address::class);
$quoteShippingAddress->importCustomerAddressData($addressService->getById($shippingAddress->getId()));
/** @var array $billingAddressOverride */
$billingAddressOverride = empty($quoteData['billing_address']) ? [] : $quoteData['billing_address'];
/** @var \Magento\Customer\Model\Address $billingAddress */
$billingAddress = $this->createCustomerAddress($billingAddressOverride, $customer->getId());
/** @var \Magento\Quote\Model\Quote\Address $quoteBillingAddress */
$quoteBillingAddress = $this->objectManager->create(\Magento\Quote\Model\Quote\Address::class);
$quoteBillingAddress->importCustomerAddressData($addressService->getById($billingAddress->getId()));
/** @var Quote $quote */
$quote = $this->objectManager->create(Quote::class);
$quote->setStoreId(1)
->setIsActive(true)
->setIsMultiShipping(false)
->assignCustomerWithAddressChange($customer, $quoteBillingAddress, $quoteShippingAddress)
->setCheckoutMethod('register')
->setPasswordHash($this->accountManagement->getPasswordHash(static::CUSTOMER_PASSWORD));
return $quote;
}
/**
* Add products to quote
*
* @param Quote $quote
* @param array $itemsData
* @return $this
*/
protected function addProductToQuote($quote, $itemsData)
{
foreach ($itemsData as $itemData) {
$sku = $itemData['sku'];
$price = $itemData['price'];
$qty = isset($itemData['qty']) ? $itemData['qty'] : 1;
$taxClassName =
isset($itemData['tax_class_name']) ? $itemData['tax_class_name'] : self::PRODUCT_TAX_CLASS_1;
$taxClassId = $this->productTaxClasses[$taxClassName];
$product = $this->createSimpleProduct($sku, $price, $taxClassId);
$quote->addProduct($product, $qty);
}
return $this;
}
/**
* Create a quote based on given data
*
* @param array $quoteData
*
* @return Quote
*/
public function setupQuote($quoteData)
{
$customer = $this->createCustomer();
$quote = $this->createQuote($quoteData, $customer);
$this->addProductToQuote($quote, $quoteData['items']);
if (isset($quoteData['update_items'])) {
$this->updateItems($quote, $quoteData['update_items']);
}
//Set shipping amount
if (isset($quoteData['shipping_method'])) {
$quote->getShippingAddress()->setShippingMethod($quoteData['shipping_method']);
$quote->getShippingAddress()->setCollectShippingRates(true);
}
//create shopping cart rules if necessary
if (!empty($quoteData['shopping_cart_rules'])) {
foreach ($quoteData['shopping_cart_rules'] as $ruleData) {
$ruleData['customer_group_ids'] = [$customer->getGroupId()];
$this->createCartRule($ruleData);
}
}
return $quote;
}
/**
* Update quote items
*
* @param Quote $quote
* @param array $items
*
* @return void
*/
private function updateItems(Quote $quote, array $items): void
{
$updater = $this->objectManager->get(Updater::class);
$productRepository = $this->objectManager->get(ProductRepositoryInterface::class);
$filter = $this->objectManager->create(Filter::class);
$filter->setField('sku')->setValue(array_keys($items));
$filterGroup = $this->objectManager->create(FilterGroup::class);
$filterGroup->setFilters([$filter]);
$searchCriteria = $this->objectManager->create(SearchCriteriaInterface::class);
$searchCriteria->setFilterGroups([$filterGroup]);
$products = $productRepository->getList($searchCriteria)->getItems();
/** @var ProductInterface $product */
foreach ($products as $product) {
$quoteItem = $quote->getItemByProduct($product);
$updater->update(
$quoteItem,
$items[$product->getSku()]
);
}
}
}
Back to Directory
File Manager