<?php declare(strict_types=1);
namespace Acris\Tax\Core\Checkout\Cart\Tax;
use Acris\Tax\Components\Service\TaxService;
use Acris\Tax\Components\Service\VatIdValidationService;
use Acris\Tax\Core\Checkout\Cart\TaxRuleLoader;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\System\Country\CountryEntity;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\Checkout\Cart\Tax\TaxDetector as ParentTaxDetector;
class TaxDetector extends ParentTaxDetector
{
/**
* @var ParentTaxDetector
*/
private $parentTaxDetector;
/**
* @var EntityRepositoryInterface
*/
private $customerGroupRulesRepository;
/**
* @var EntityRepositoryInterface
*/
private $countryRulesRepository;
/**
* @var null|array
*/
private $savedCustomerGroupRuleIds;
/**
* @var null|array
*/
private $savedCountryRuleIds;
/**
* @var TaxRuleLoader
*/
private $taxRuleLoader;
/**
* @var array|null
*/
private $ruleIdsForContext;
/**
* @var TaxService
*/
private $taxService;
public function __construct(
ParentTaxDetector $parentTaxDetector,
EntityRepositoryInterface $customerGroupRulesRepository,
EntityRepositoryInterface $countryRulesRepository,
TaxRuleLoader $taxRuleLoader,
TaxService $taxService
)
{
$this->parentTaxDetector = $parentTaxDetector;
$this->customerGroupRulesRepository = $customerGroupRulesRepository;
$this->countryRulesRepository = $countryRulesRepository;
$this->savedCustomerGroupRuleIds = null;
$this->savedCountryRuleIds = null;
$this->taxRuleLoader = $taxRuleLoader;
$this->taxService = $taxService;
}
public function useGross(SalesChannelContext $context): bool
{
return $this->parentTaxDetector->useGross($context);
}
public function isNetDelivery(SalesChannelContext $context): bool
{
if ($this->taxService->isExcludedCountry($context->getShippingLocation()->getCountry()->getId(), $context->getSalesChannel()->getId()))
return false;
$ruleIdsFromSalesChannelContext = $this->getRuleIdsFromSalesChannelContext($context);
$checkDefaultAdvancedTaxRules = $this->checkDefaultAdvancedTaxRules($context, $ruleIdsFromSalesChannelContext);
if (is_bool($checkDefaultAdvancedTaxRules)) return $checkDefaultAdvancedTaxRules;
$countryRuleIds = $this->getCountryRuleIds($context);
if(empty($countryRuleIds)) {
return $this->parentTaxDetector->isNetDelivery($context);
}
foreach ($countryRuleIds as $countryRuleId) {
if(array_key_exists('rule_id', $countryRuleId) === false) {
continue;
}
if(in_array($countryRuleId['rule_id'], $ruleIdsFromSalesChannelContext)) {
return true;
}
}
return false;
}
public function isCompanyTaxFree(SalesChannelContext $context, CountryEntity $shippingLocationCountry): bool
{
if ($this->taxService->isExcludedCountry($shippingLocationCountry->getId(), $context->getSalesChannel()->getId()))
return false;
$ruleIdsFromSalesChannelContext = $this->getRuleIdsFromSalesChannelContext($context);
$checkDefaultAdvancedTaxRules = $this->checkDefaultAdvancedTaxRules($context, $ruleIdsFromSalesChannelContext);
if (is_bool($checkDefaultAdvancedTaxRules)) return $checkDefaultAdvancedTaxRules;
$countryRuleIds = $this->getCountryRuleIds($context);
if(empty($countryRuleIds)) {
return $this->parentTaxDetector->isCompanyTaxFree($context, $shippingLocationCountry);
}
foreach ($countryRuleIds as $countryRuleId) {
if(array_key_exists('rule_id', $countryRuleId) === false) {
continue;
}
if(in_array($countryRuleId['rule_id'], $ruleIdsFromSalesChannelContext)) {
return true;
}
}
return false;
}
private function getRuleIdsFromSalesChannelContext(SalesChannelContext $context): array
{
if(empty($context->getRuleIds())) {
if(is_array($this->ruleIdsForContext) === true) {
return $this->ruleIdsForContext;
}
$ruleIds = $this->taxRuleLoader->loadRulesIdsForContext($context);
return $this->ruleIdsForContext = $ruleIds;
}
return $context->getRuleIds();
}
private function getCustomerGroupRuleIds(SalesChannelContext $context)
{
if($this->savedCustomerGroupRuleIds === null) {
$customerGroupRuleIds = $this->customerGroupRulesRepository->searchIds((new Criteria())->addFilter(new EqualsFilter('customerGroupId', $context->getCurrentCustomerGroup()->getId())), $context->getContext());
$this->savedCustomerGroupRuleIds = $customerGroupRuleIds->getIds();
}
return $this->savedCustomerGroupRuleIds;
}
private function getCountryRuleIds(SalesChannelContext $context)
{
if($this->savedCountryRuleIds === null) {
$countryRuleIds = $this->countryRulesRepository->searchIds((new Criteria())->addFilter(new EqualsFilter('countryId', $context->getShippingLocation()->getCountry()->getId())), $context->getContext());
$this->savedCountryRuleIds = $countryRuleIds->getIds();
}
return $this->savedCountryRuleIds;
}
private function checkDefaultAdvancedTaxRules(SalesChannelContext $context, ?array $ruleIdsFromSalesChannelContext): ?bool
{
if (empty($ruleIdsFromSalesChannelContext) || !is_array($ruleIdsFromSalesChannelContext)) {
return null;
}
if (!$this->checkEuCountries($context->getShippingLocation()->getCountry())) return null;
$companyTax = $context->getShippingLocation()->getCountry()->getCompanyTax();
if (list($rules, $useAndRule) = $this->taxService->getDefaultAdvancedTaxRules($context->getSalesChannel()->getId())) {
if (!empty($rules) && is_bool($useAndRule)) {
if ($useAndRule) {
foreach ($rules as $rule) {
if(!in_array($rule, $ruleIdsFromSalesChannelContext)) {
return false;
}
}
$companyTax->setEnabled(true);
return true;
} else {
foreach ($rules as $rule) {
if(in_array($rule, $ruleIdsFromSalesChannelContext)) {
$companyTax->setEnabled(true);
return true;
}
}
return false;
}
}
}
return null;
}
private function checkEuCountries(CountryEntity $country): bool
{
return in_array($country->getIso(), VatIdValidationService::DEFAULT_SPECIFIC_COUNTRIES);
}
}