Initial commit: ws_vatcheck at v1.0.3
Includes the fix for the GR/EL VAT prefix bug that broke exemption for every Greek VAT number (in_array-on-values vs array_key_exists in CacheTaxManager/VatNumber, plus the missing use import in EuValidatorAdapter). Adds IMPROVEMENTS.txt with a checklist of features adopted from comparing against the vatchecker module (offline-fallback policy, failure logging, company-name check, configurable EU country list, per-product exclusion, GB/XI mapping, AJAX live validation, address-priority strategy). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
vendor/
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
ws_vatcheck — planned improvements
|
||||||
|
adapted from a comparison against the "vatchecker" module (Inform-All & Keraweb), 2026-09-11
|
||||||
|
cache TTL (1 year) explicitly kept as-is, not on this list.
|
||||||
|
|
||||||
|
[ ] 1. Configurable VIES-offline fallback policy
|
||||||
|
- Add a setting (e.g. VATCHECK_OFFLINE_MODE) with explicit modes instead of an
|
||||||
|
implicit fail-closed default:
|
||||||
|
- always mark invalid (current implicit behavior)
|
||||||
|
- always mark valid
|
||||||
|
- reuse last cached result, fall back to invalid if none
|
||||||
|
- reuse last cached result, fall back to valid if none
|
||||||
|
- Directly related to the GR/EL bug fixed this session: the fallback behavior
|
||||||
|
should be an explicit, chosen policy, not an accidental side effect of
|
||||||
|
whether an exception happens to get caught.
|
||||||
|
|
||||||
|
[ ] 2. Log every VIES check failure
|
||||||
|
- Currently EuValidatorAdapter::checkAndStore() has no logging at all on
|
||||||
|
failure (this silence was a big part of why the GR/EL bug took so long to
|
||||||
|
diagnose). Add PrestaShopLogger::addLog(...) (or equivalent) whenever the
|
||||||
|
Europa/Validator call throws, including the VAT number, country code, and
|
||||||
|
the fault message.
|
||||||
|
|
||||||
|
[ ] 3. Company-name cross-check against VIES response
|
||||||
|
- When VIES returns a company name for a validated VAT number, optionally
|
||||||
|
compare it (normalized: lowercase, strip punctuation/legal-entity suffixes
|
||||||
|
like bv/gmbh/ltd/nv/sa) against the address's company field. Make this
|
||||||
|
togglable, since not all member states return a name.
|
||||||
|
|
||||||
|
[ ] 4. Configurable EU country allow-list
|
||||||
|
- Replace hardcoded VatNumber::$euIso-driven behavior with an admin-configurable
|
||||||
|
list of which EU countries are allowed to order VAT-free, similar to
|
||||||
|
vatchecker's VATCHECKER_EU_COUNTRIES setting.
|
||||||
|
|
||||||
|
[ ] 5. Per-product VAT exclusion
|
||||||
|
- Some products (e.g. certain digital services) may need to always charge VAT
|
||||||
|
regardless of customer VAT-exempt status. Add a product-level flag/table
|
||||||
|
(mirroring vatchecker_excluded_products) and consult it before applying the
|
||||||
|
0% tax manager for a given product line.
|
||||||
|
|
||||||
|
[ ] 6. GB -> XI (Northern Ireland) mapping
|
||||||
|
- VatNumber::$euIso has no entry at all for the UK/Northern Ireland. If this
|
||||||
|
shop (or any future ws_vatcheck deployment) ships to Northern Ireland with an
|
||||||
|
XI-prefixed VAT number, it will hit the same class of key/value bug already
|
||||||
|
fixed for Greece. Add the mapping and cover it with the same key-based checks.
|
||||||
|
|
||||||
|
[ ] 7. Front-end AJAX live VAT validation
|
||||||
|
- Add an AJAX front controller + JS so the address form validates the VAT
|
||||||
|
number as the customer types, instead of only on form submit
|
||||||
|
(hookActionValidateCustomerAddressForm). Mirrors vatchecker's ajax.php +
|
||||||
|
front.js/front.css pattern. Improves UX and surfaces bad VAT numbers earlier.
|
||||||
|
|
||||||
|
[ ] 8. Configurable address-priority strategy
|
||||||
|
- Add a setting for which address's VAT number is authoritative when invoice
|
||||||
|
and delivery addresses differ (shipping only / invoice only / prioritize
|
||||||
|
invoice / prioritize shipping), instead of relying on implicit PS tax-address
|
||||||
|
resolution. Mirrors vatchecker's VATCHECKER_ADDRESS_SELECT.
|
||||||
|
|
||||||
|
Explicitly deferred / not adopting:
|
||||||
|
- Shortening the 1-year cache TTL (Config::CACHE_VALIDITY) — decided to leave as-is.
|
||||||
|
- Class overrides (Carrier/Product) as used by vatchecker — do not port this pattern;
|
||||||
|
it conflicts with other modules that override the same core classes and is fragile
|
||||||
|
across PS core upgrades. If shipping/product tax rule assignment ever needs
|
||||||
|
behavior beyond what the taxManager hook covers, investigate a hook-based solution
|
||||||
|
first before reaching for an override.
|
||||||
|
- Legacy $this->l() / translations/{iso}.php system — ws_vatcheck already uses
|
||||||
|
$this->trans() correctly per house convention for PS >= 1.7.6.0.
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "websmid/vatcheck",
|
||||||
|
"description": "Maakt het vrijstellen van BTW mogelijk via een gecachte vat check",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Johan van der Klis - De Websmid BV",
|
||||||
|
"email": "johan@dewebsmid.nl"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"ph-7/eu-vat-validator": "3.1"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Websmid\\VatCheck\\": "src/"
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"ws_vatcheck.php"
|
||||||
|
],
|
||||||
|
"exclude-from-classmap": []
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"preferred-install": "dist",
|
||||||
|
"prepend-autoloader": false
|
||||||
|
},
|
||||||
|
"type": "prestashop-module",
|
||||||
|
"author": "Johan van der Klis - De Websmid BV",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
Generated
+91
@@ -0,0 +1,91 @@
|
|||||||
|
{
|
||||||
|
"_readme": [
|
||||||
|
"This file locks the dependencies of your project to a known state",
|
||||||
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
|
"This file is @generated automatically"
|
||||||
|
],
|
||||||
|
"content-hash": "ccb92e4629eb4c104b85c939daa54a7c",
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "ph-7/eu-vat-validator",
|
||||||
|
"version": "3.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/pH-7/eu-vat-validator.git",
|
||||||
|
"reference": "03dc5305984ad71a71c363ab4cb1f691a5d9408b"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/pH-7/eu-vat-validator/zipball/03dc5305984ad71a71c363ab4cb1f691a5d9408b",
|
||||||
|
"reference": "03dc5305984ad71a71c363ab4cb1f691a5d9408b",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-soap": "*",
|
||||||
|
"php": ">=7.1.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phake/phake": "^3.1",
|
||||||
|
"phpunit/phpunit": "^7.5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"PH7\\Eu\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"GPL-3.0-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Pierre-Henry Soria",
|
||||||
|
"email": "hi@ph7.me",
|
||||||
|
"homepage": "https://github.com/pH-7/eu-vat-validator",
|
||||||
|
"role": "Software Engineer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A simple and clean PHP class that validates EU VAT numbers against the central ec.europa.eu database (using the official europa API).",
|
||||||
|
"homepage": "https://pierrehenry.be",
|
||||||
|
"keywords": [
|
||||||
|
"TVA",
|
||||||
|
"eu vat",
|
||||||
|
"tva number",
|
||||||
|
"validate eu vat",
|
||||||
|
"validate vat number",
|
||||||
|
"validation",
|
||||||
|
"validator",
|
||||||
|
"vat",
|
||||||
|
"vat number",
|
||||||
|
"vat number validator",
|
||||||
|
"vat validator",
|
||||||
|
"vies"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/pH-7/eu-vat-validator/issues",
|
||||||
|
"source": "https://github.com/pH-7/eu-vat-validator/tree/3.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://github.com/pH-7",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://ko-fi.com/phenry",
|
||||||
|
"type": "ko_fi"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2023-01-04T11:50:01+00:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"packages-dev": [],
|
||||||
|
"aliases": [],
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"stability-flags": [],
|
||||||
|
"prefer-stable": false,
|
||||||
|
"prefer-lowest": false,
|
||||||
|
"platform": [],
|
||||||
|
"platform-dev": [],
|
||||||
|
"plugin-api-version": "2.3.0"
|
||||||
|
}
|
||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<module>
|
||||||
|
<name>ws_vatcheck</name>
|
||||||
|
<displayName><![CDATA[Vat Check]]></displayName>
|
||||||
|
<version><![CDATA[1.0.3]]></version>
|
||||||
|
<description><![CDATA[Gecachte vat check]]></description>
|
||||||
|
<author><![CDATA[Johan van der Klis | De Websmid BV]]></author>
|
||||||
|
<tab><![CDATA[]]></tab>
|
||||||
|
<is_configurable>0</is_configurable>
|
||||||
|
<need_instance>0</need_instance>
|
||||||
|
</module>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
services:
|
||||||
|
Websmid\VatCheck\Command\CleanCommand:
|
||||||
|
class: Websmid\VatCheck\Command\CleanCommand
|
||||||
|
tags: ['console.command']
|
||||||
|
|
||||||
|
Websmid\VatCheck\Command\BulkCheckCommand:
|
||||||
|
class: Websmid\VatCheck\Command\BulkCheckCommand
|
||||||
|
tags: ['console.command']
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<module>
|
||||||
|
<name>ws_vatcheck</name>
|
||||||
|
<displayName><![CDATA[Vat Check]]></displayName>
|
||||||
|
<version><![CDATA[1.0.3]]></version>
|
||||||
|
<description><![CDATA[Gecachte vat check]]></description>
|
||||||
|
<author><![CDATA[Johan van der Klis | De Websmid BV]]></author>
|
||||||
|
<tab><![CDATA[]]></tab>
|
||||||
|
<is_configurable>0</is_configurable>
|
||||||
|
<need_instance>0</need_instance>
|
||||||
|
</module>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright since 2007 PrestaShop SA and Contributors
|
||||||
|
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
||||||
|
*
|
||||||
|
* NOTICE OF LICENSE
|
||||||
|
*
|
||||||
|
* This source file is subject to the Academic Free License 3.0 (AFL-3.0)
|
||||||
|
* that is bundled with this package in the file LICENSE.md.
|
||||||
|
* It is also available through the world-wide-web at this URL:
|
||||||
|
* https://opensource.org/licenses/AFL-3.0
|
||||||
|
* If you did not receive a copy of the license and are unable to
|
||||||
|
* obtain it through the world-wide-web, please send an email
|
||||||
|
* to license@prestashop.com so we can send you a copy immediately.
|
||||||
|
*
|
||||||
|
* DISCLAIMER
|
||||||
|
*
|
||||||
|
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||||
|
* versions in the future. If you wish to customize PrestaShop for your
|
||||||
|
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
||||||
|
*
|
||||||
|
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
||||||
|
* @copyright Since 2007 PrestaShop SA and Contributors
|
||||||
|
* @license https://opensource.org/licenses/AFL-3.0 Academic Free License 3.0 (AFL-3.0)
|
||||||
|
*/
|
||||||
|
|
||||||
|
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
|
||||||
|
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
|
||||||
|
|
||||||
|
header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||||
|
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||||
|
header("Pragma: no-cache");
|
||||||
|
|
||||||
|
header("Location: ../");
|
||||||
|
exit;
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\VatCheck\Adapter;
|
||||||
|
|
||||||
|
use PH7\Eu\Vat\Validator;
|
||||||
|
use PH7\Eu\Vat\Provider\Europa;
|
||||||
|
use PH7\Eu\Vat\Exception;
|
||||||
|
use Websmid\VatCheck\Config\Config;
|
||||||
|
use Websmid\VatCheck\Model\VatCache;
|
||||||
|
|
||||||
|
class EuValidatorAdapter
|
||||||
|
{
|
||||||
|
protected $vatNr = '';
|
||||||
|
|
||||||
|
protected $isoCode = '';
|
||||||
|
|
||||||
|
private $checkStatus;
|
||||||
|
|
||||||
|
public function __construct(string $vatNr, string $isoCode)
|
||||||
|
{
|
||||||
|
$this->vatNr = str_replace($isoCode, '', $vatNr);
|
||||||
|
$this->isoCode = $isoCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkAndStore()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$euVatValidator = new Validator(new Europa, $this->vatNr, $this->isoCode);
|
||||||
|
} catch(Exception $e){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( $euVatValidator instanceof Validator ){
|
||||||
|
$fullVat = $this->isoCode.$this->vatNr;
|
||||||
|
$vatCache = VatCache::getOrCreateByVat($fullVat);
|
||||||
|
$vatCache->vat_nr = $fullVat;
|
||||||
|
$vatCache->valid = $euVatValidator->check();
|
||||||
|
|
||||||
|
$vatCache->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\VatCheck\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputDefinition;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Websmid\VatCheck\Service\LoggingService;
|
||||||
|
|
||||||
|
abstract class BaseCommand extends Command
|
||||||
|
{
|
||||||
|
public $output;
|
||||||
|
public $input;
|
||||||
|
|
||||||
|
public $logger;
|
||||||
|
|
||||||
|
public function __construct(string $name = null)
|
||||||
|
{
|
||||||
|
parent::__construct($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function log($message, $object = null, $id = null)
|
||||||
|
{
|
||||||
|
if (!is_null($this->logger)) {
|
||||||
|
$this->logger->log($message, $object, $id);
|
||||||
|
} else {
|
||||||
|
$now = (new \DateTime())->format('Y-m-d H:i:s');
|
||||||
|
$line = $now . ' --> ' . $message . PHP_EOL;
|
||||||
|
$this->logs[] = $line;
|
||||||
|
$this->output->write($line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$this->output = $output;
|
||||||
|
$this->input = $input;
|
||||||
|
|
||||||
|
set_time_limit(0);
|
||||||
|
ini_set('memory_limit', '-1');
|
||||||
|
|
||||||
|
$this->executeCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract function executeCommand();
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\VatCheck\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Websmid\VatCheck\Service\LoggingService;
|
||||||
|
use Db;
|
||||||
|
use Country;
|
||||||
|
use Websmid\VatCheck\Adapter\EuValidatorAdapter;
|
||||||
|
use Websmid\VatCheck\Model\VatNumber;
|
||||||
|
|
||||||
|
class BulkCheckCommand extends BaseCommand
|
||||||
|
{
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('vatcheck:bulkcheck');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function executeCommand()
|
||||||
|
{
|
||||||
|
$this->log('Start process');
|
||||||
|
$this->logger = new LoggingService();
|
||||||
|
$this->logger->setConsole($this->output);
|
||||||
|
//$this->logger->enablePrestaLog();
|
||||||
|
|
||||||
|
$vatInfosToCheck = Db::getInstance()->executeS('
|
||||||
|
SELECT
|
||||||
|
`vat_number`, `id_country`
|
||||||
|
FROM
|
||||||
|
`'._DB_PREFIX_.'address`
|
||||||
|
WHERE
|
||||||
|
`vat_number` NOT IN(
|
||||||
|
SELECT
|
||||||
|
`vat_nr`
|
||||||
|
FROM
|
||||||
|
`'._DB_PREFIX_.'vat_cache`
|
||||||
|
) AND `vat_number` != ""
|
||||||
|
');
|
||||||
|
|
||||||
|
foreach($vatInfosToCheck as $vatInfo){
|
||||||
|
|
||||||
|
$isoCode = Country::getIsoById((int)$vatInfo['id_country']);
|
||||||
|
$vatNumber = new VatNumber($vatInfo['vat_number'], $isoCode);
|
||||||
|
|
||||||
|
if( $vatNumber->hasErrors() || $vatNumber->isNotEuIso() ){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$euValidator = new EuValidatorAdapter($vatNumber->getFormattedVat(), $isoCode);
|
||||||
|
$euValidator->checkAndStore();
|
||||||
|
|
||||||
|
$this->log('Iteration end, now ging to sleep 3s');
|
||||||
|
sleep(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->log('Stored VATS checked!');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\VatCheck\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Websmid\VatCheck\Service\LoggingService;
|
||||||
|
use Websmid\VatCheck\Model\VatCache;
|
||||||
|
|
||||||
|
class CleanCommand extends BaseCommand
|
||||||
|
{
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('vatcheck:cleanrecords');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function executeCommand()
|
||||||
|
{
|
||||||
|
$this->log('Start process');
|
||||||
|
$this->logger = new LoggingService();
|
||||||
|
$this->logger->setConsole($this->output);
|
||||||
|
//$this->logger->enablePrestaLog();
|
||||||
|
|
||||||
|
VatCache::cleanOldRecords();
|
||||||
|
|
||||||
|
return $this->log('Records cleaned!');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\VatCheck\Config;
|
||||||
|
|
||||||
|
class Config
|
||||||
|
{
|
||||||
|
// Hooks
|
||||||
|
CONST HOOKS = [
|
||||||
|
'actionTaxManager',
|
||||||
|
'taxManager',
|
||||||
|
'actionValidateCustomerAddressForm',
|
||||||
|
'displayInvoiceLegalFreeText'
|
||||||
|
];
|
||||||
|
|
||||||
|
CONST CACHE_VALIDITY = 1;
|
||||||
|
|
||||||
|
// Article 39bis W.BTW intra-community exemption notice, per invoice language.
|
||||||
|
CONST INTRACOMMUNITY_EXEMPTION_TEXTS = [
|
||||||
|
'nl' => 'Vrijgestelde intracommunautaire levering – artikel 39bis W.BTW',
|
||||||
|
'fr' => 'Livraison intracommunautaire exonérée de TVA – article 39bis du Code TVA',
|
||||||
|
'en' => 'Intra-Community supply exempt from VAT according to Article 39bis of the Belgian VAT Code.',
|
||||||
|
'de' => 'Von der Mehrwertsteuer befreite innergemeinschaftliche Lieferung – Artikel 39bis des belgischen Mehrwertsteuergesetzbuches',
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\VatCheck\Console;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Input\InputDefinition;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
|
||||||
|
class WebInput implements InputInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
public function getFirstArgument()
|
||||||
|
{
|
||||||
|
// TODO: Implement getFirstArgument() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasParameterOption($values, $onlyParams = false)
|
||||||
|
{
|
||||||
|
// TODO: Implement hasParameterOption() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParameterOption($values, $default = false, $onlyParams = false)
|
||||||
|
{
|
||||||
|
// TODO: Implement getParameterOption() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bind(InputDefinition $definition)
|
||||||
|
{
|
||||||
|
// TODO: Implement bind() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function validate()
|
||||||
|
{
|
||||||
|
// TODO: Implement validate() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getArguments()
|
||||||
|
{
|
||||||
|
// TODO: Implement getArguments() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getArgument($name)
|
||||||
|
{
|
||||||
|
// TODO: Implement getArgument() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setArgument($name, $value)
|
||||||
|
{
|
||||||
|
// TODO: Implement setArgument() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasArgument($name)
|
||||||
|
{
|
||||||
|
// TODO: Implement hasArgument() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOptions()
|
||||||
|
{
|
||||||
|
// TODO: Implement getOptions() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOption($name)
|
||||||
|
{
|
||||||
|
if (isset($_GET[$name])) {
|
||||||
|
return $_GET[$name];
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setOption($name, $value)
|
||||||
|
{
|
||||||
|
// TODO: Implement setOption() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasOption($name)
|
||||||
|
{
|
||||||
|
// TODO: Implement hasOption() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isInteractive()
|
||||||
|
{
|
||||||
|
// TODO: Implement isInteractive() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setInteractive($interactive)
|
||||||
|
{
|
||||||
|
// TODO: Implement setInteractive() method.
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\VatCheck\Console;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
class WebOutput implements OutputInterface
|
||||||
|
{
|
||||||
|
public $cleaned = false;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
ini_set('output_buffering', 'Off');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write($messages, $newline = false, $options = 0)
|
||||||
|
{
|
||||||
|
if (!$this->cleaned) {
|
||||||
|
//ob_end_flush();
|
||||||
|
$this->cleaned = true;
|
||||||
|
}
|
||||||
|
echo $messages . '<br/>';
|
||||||
|
$this->flush_buffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flush_buffers()
|
||||||
|
{
|
||||||
|
//$result = ob_get_contents();
|
||||||
|
//echo $result;
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function writeln($messages, $options = 0)
|
||||||
|
{
|
||||||
|
// TODO: Implement writeln() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setVerbosity($level)
|
||||||
|
{
|
||||||
|
// TODO: Implement setVerbosity() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVerbosity()
|
||||||
|
{
|
||||||
|
// TODO: Implement getVerbosity() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isQuiet()
|
||||||
|
{
|
||||||
|
// TODO: Implement isQuiet() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isVerbose()
|
||||||
|
{
|
||||||
|
// TODO: Implement isVerbose() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isVeryVerbose()
|
||||||
|
{
|
||||||
|
// TODO: Implement isVeryVerbose() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isDebug()
|
||||||
|
{
|
||||||
|
// TODO: Implement isDebug() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDecorated($decorated)
|
||||||
|
{
|
||||||
|
// TODO: Implement setDecorated() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isDecorated()
|
||||||
|
{
|
||||||
|
// TODO: Implement isDecorated() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFormatter(OutputFormatterInterface $formatter)
|
||||||
|
{
|
||||||
|
// TODO: Implement setFormatter() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFormatter()
|
||||||
|
{
|
||||||
|
// TODO: Implement getFormatter() method.
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\VatCheck\Model;
|
||||||
|
|
||||||
|
use Websmid\VatCheck\Config\Config;
|
||||||
|
use ObjectModel;
|
||||||
|
use Db;
|
||||||
|
|
||||||
|
class VatCache extends ObjectModel
|
||||||
|
{
|
||||||
|
/** @var int|null */
|
||||||
|
public $id;
|
||||||
|
|
||||||
|
public $vat_nr = '';
|
||||||
|
|
||||||
|
public $valid;
|
||||||
|
|
||||||
|
public $date_add;
|
||||||
|
|
||||||
|
public $date_upd;
|
||||||
|
|
||||||
|
public static $definition = [
|
||||||
|
'table' => 'vat_cache',
|
||||||
|
'primary' => 'id_vat',
|
||||||
|
'fields' => [
|
||||||
|
'vat_nr' => ['type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => true],
|
||||||
|
'valid' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool', 'required' => true],
|
||||||
|
'date_add' => ['type' => self::TYPE_DATE, 'validate' => 'isDate'],
|
||||||
|
'date_upd' => ['type' => self::TYPE_DATE, 'validate' => 'isDate'],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
public static function getIdByVat(string $vatNr)
|
||||||
|
{
|
||||||
|
return Db::getInstance()->getValue('SELECT `id_vat` FROM `'._DB_PREFIX_.'vat_cache` WHERE `vat_nr` = "'.pSQL($vatNr).'" AND `date_add` > DATE_SUB(NOW(), INTERVAL '.(int)Config::CACHE_VALIDITY.' YEAR)');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function checkVatIsCached(string $vatNr)
|
||||||
|
{
|
||||||
|
return (bool)self::getIdByVat($vatNr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function checkVatIsValid(string $vatNr)
|
||||||
|
{
|
||||||
|
return (bool)Db::getInstance()->getValue('SELECT `valid` FROM `'._DB_PREFIX_.'vat_cache` WHERE `vat_nr` = "'.pSQL($vatNr).'" ORDER BY `id_vat` DESC');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getOrCreateByVat(string $vatNr)
|
||||||
|
{
|
||||||
|
$className = get_called_class();
|
||||||
|
$idVat = $className::getIdByVat($vatNr);
|
||||||
|
|
||||||
|
return ( empty($idVat) ) ? new $className() : new $className($idVat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function cleanOldRecords()
|
||||||
|
{
|
||||||
|
return Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'vat_cache` WHERE `date_add` < DATE_SUB(NOW(), INTERVAL '.(int)Config::CACHE_VALIDITY.' YEAR)');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\VatCheck\Model;
|
||||||
|
|
||||||
|
use Websmid\VatCheck\Config\Config;
|
||||||
|
use Context;
|
||||||
|
|
||||||
|
class VatNumber
|
||||||
|
{
|
||||||
|
private $vatNumber;
|
||||||
|
|
||||||
|
private $isoCode;
|
||||||
|
|
||||||
|
private $errorMessage = '';
|
||||||
|
|
||||||
|
public static $euIso = [
|
||||||
|
'AT' => 'AT',
|
||||||
|
'BE' => 'BE',
|
||||||
|
'DK' => 'DK',
|
||||||
|
'FI' => 'FI',
|
||||||
|
'FR' => 'FR',
|
||||||
|
'FX' => 'FR',
|
||||||
|
'DE' => 'DE',
|
||||||
|
'GR' => 'EL',
|
||||||
|
'IE' => 'IE',
|
||||||
|
'IT' => 'IT',
|
||||||
|
'LU' => 'LU',
|
||||||
|
'NL' => 'NL',
|
||||||
|
'PT' => 'PT',
|
||||||
|
'ES' => 'ES',
|
||||||
|
'SE' => 'SE',
|
||||||
|
'CY' => 'CY',
|
||||||
|
'EE' => 'EE',
|
||||||
|
'HU' => 'HU',
|
||||||
|
'LV' => 'LV',
|
||||||
|
'LT' => 'LT',
|
||||||
|
'MT' => 'MT',
|
||||||
|
'PL' => 'PL',
|
||||||
|
'SK' => 'SK',
|
||||||
|
'CZ' => 'CZ',
|
||||||
|
'SI' => 'SI',
|
||||||
|
'RO' => 'RO',
|
||||||
|
'BG' => 'BG',
|
||||||
|
'HR' => 'HR',
|
||||||
|
];
|
||||||
|
|
||||||
|
private $isoPattern = [
|
||||||
|
'AT' => 'U[A-Z\d]{8}',
|
||||||
|
'BE' => '[0|1]{1}\d{9}',
|
||||||
|
'BG' => '\d{9,10}',
|
||||||
|
'CY' => '\d{8}[A-Z]',
|
||||||
|
'CZ' => '\d{8,10}',
|
||||||
|
'DE' => '\d{9}',
|
||||||
|
'DK' => '(\d{2} ?){3}\d{2}',
|
||||||
|
'EE' => '\d{9}',
|
||||||
|
'GR' => '\d{9}',
|
||||||
|
'ES' => '[A-Z]\d{7}[A-Z]|\d{8}[A-Z]|[A-Z]\d{8}',
|
||||||
|
'FI' => '\d{8}',
|
||||||
|
'FR' => '([A-Z0-9]{2})\d{9}',
|
||||||
|
'FX' => '([A-Z0-9]{2})\d{9}',
|
||||||
|
'HR' => '\d{11}',
|
||||||
|
'HU' => '\d{8}',
|
||||||
|
'IE' => '[A-Z\d]{8}|[A-Z\d]{9}',
|
||||||
|
'IT' => '\d{11}',
|
||||||
|
'LT' => '(\d{9}|\d{12})',
|
||||||
|
'LU' => '\d{8}',
|
||||||
|
'LV' => '\d{11}',
|
||||||
|
'MT' => '\d{8}',
|
||||||
|
'NL' => '\d{9}B\d{2}',
|
||||||
|
'PL' => '\d{10}',
|
||||||
|
'PT' => '\d{9}',
|
||||||
|
'RO' => '\d{2,10}',
|
||||||
|
'SE' => '\d{12}',
|
||||||
|
'SI' => '\d{8}',
|
||||||
|
'SK' => '\d{10}',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
string $rawVatNumber,
|
||||||
|
string $rawIsoCode
|
||||||
|
) {
|
||||||
|
$this->vatNumber = $this->commonFormatVatNumber($rawVatNumber);
|
||||||
|
|
||||||
|
$this->isoCode = strtoupper($rawIsoCode);
|
||||||
|
|
||||||
|
$this->validateVatNr();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function validateVatNr()
|
||||||
|
{
|
||||||
|
$vatPrefix = self::$euIso[$this->isoCode] ?? $this->isoCode;
|
||||||
|
|
||||||
|
if( substr($this->vatNumber, 0, 2) != $vatPrefix ){
|
||||||
|
$this->errorMessage = Context::getContext()->getTranslator()->trans('ISO in VAT number doesn\'t seem to match selected country', [], 'Modules.Ws_VatCheck.Front');
|
||||||
|
}
|
||||||
|
|
||||||
|
$trimmedVat = str_replace($vatPrefix, '', $this->vatNumber);
|
||||||
|
$isoPattern = $this->isoPattern[$this->isoCode];
|
||||||
|
|
||||||
|
if( !preg_match('/^(?:'.$isoPattern.')$/', $trimmedVat) ){
|
||||||
|
$this->errorMessage = Context::getContext()->getTranslator()->trans('VAT number doesn\'t seem to be valid', [], 'Modules.Ws_VatCheck.Front');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFormattedVat()
|
||||||
|
{
|
||||||
|
return $this->vatNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasErrors()
|
||||||
|
{
|
||||||
|
return !empty($this->errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isNotEuIso()
|
||||||
|
{
|
||||||
|
return !array_key_exists($this->isoCode, self::$euIso);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function commonFormatVatNumber(string $rawVatNumber)
|
||||||
|
{
|
||||||
|
return strtoupper(preg_replace('/[ .]/', '', $rawVatNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getErrorMessage()
|
||||||
|
{
|
||||||
|
return $this->errorMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\VatCheck\Module\Admin;
|
||||||
|
|
||||||
|
use Websmid\VatCheck\Config\Config;
|
||||||
|
|
||||||
|
trait AdminHooks
|
||||||
|
{
|
||||||
|
public function isUsingNewTranslationSystem()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\VatCheck\Module\Front;
|
||||||
|
|
||||||
|
use Websmid\VatCheck\TaxManager\CacheTaxManager;
|
||||||
|
use Websmid\VatCheck\Model\VatNumber;
|
||||||
|
use Websmid\VatCheck\Config\Config;
|
||||||
|
use Address;
|
||||||
|
use Configuration;
|
||||||
|
use Country;
|
||||||
|
use Language;
|
||||||
|
use Product;
|
||||||
|
use Tools;
|
||||||
|
|
||||||
|
trait FrontHooks
|
||||||
|
{
|
||||||
|
public function hookActionValidateCustomerAddressForm(&$params)
|
||||||
|
{
|
||||||
|
$form = $params['form'];
|
||||||
|
$vatNumber = (string)$form->getValue('vat_number');
|
||||||
|
$vatNumber = str_replace(' ', '', $vatNumber);
|
||||||
|
|
||||||
|
if (empty($vatNumber)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$countryIso = (string)Country::getIsoById((string)$form->getValue('id_country'));
|
||||||
|
$vatNumber = new VatNumber($vatNumber, $countryIso);
|
||||||
|
|
||||||
|
if( $vatNumber->isNotEuIso() ){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$form->setValue('vat_number', $vatNumber->getFormattedVat());
|
||||||
|
if( $vatNumber->hasErrors() ){
|
||||||
|
$form->getField('vat_number')->addError($vatNumber->getErrorMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $vatNumber->hasErrors();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hookTaxManager($args)
|
||||||
|
{
|
||||||
|
if (call_user_func(['Websmid\VatCheck\TaxManager\CacheTaxManager', 'isAvailableForThisAddress'], $args['address'])) {
|
||||||
|
return new CacheTaxManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hookDisplayInvoiceLegalFreeText(array $params)
|
||||||
|
{
|
||||||
|
$order = $params['order'];
|
||||||
|
$address = new Address((int) $order->{Configuration::get('PS_TAX_ADDRESS_TYPE')});
|
||||||
|
|
||||||
|
if (!CacheTaxManager::isAvailableForThisAddress($address)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$existingText = Configuration::get('PS_INVOICE_LEGAL_FREE_TEXT', (int) $order->id_lang, null, (int) $order->id_shop);
|
||||||
|
|
||||||
|
return trim($existingText . "\n\n" . $this->getIntraCommunityExemptionText((int) $order->id_lang));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getIntraCommunityExemptionText(int $idLang)
|
||||||
|
{
|
||||||
|
$isoCode = strtolower(Language::getIsoById($idLang));
|
||||||
|
|
||||||
|
return Config::INTRACOMMUNITY_EXEMPTION_TEXTS[$isoCode] ?? Config::INTRACOMMUNITY_EXEMPTION_TEXTS['en'];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\VatCheck\Module;
|
||||||
|
|
||||||
|
use Websmid\VatCheck\Config\Config;
|
||||||
|
use Db;
|
||||||
|
|
||||||
|
trait Install
|
||||||
|
{
|
||||||
|
public function install()
|
||||||
|
{
|
||||||
|
if (!parent::install()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->createTables()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->registerHooks()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function registerHooks()
|
||||||
|
{
|
||||||
|
foreach (Config::HOOKS as $hook) {
|
||||||
|
if (!$this->registerHook($hook)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createTables()
|
||||||
|
{
|
||||||
|
$sqlToExec = [];
|
||||||
|
$sqlToExec[] = '
|
||||||
|
CREATE TABLE IF NOT EXISTS '._DB_PREFIX_.'vat_cache (
|
||||||
|
`id_vat` INTEGER(12) PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
`vat_nr` VARCHAR(256),
|
||||||
|
`valid` TINYINT(1),
|
||||||
|
`date_add` DATE NOT NULL,
|
||||||
|
`date_upd` DATE NOT NULL
|
||||||
|
);';
|
||||||
|
|
||||||
|
foreach($sqlToExec as $sqlBlock){
|
||||||
|
Db::getInstance()->execute($sqlBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\VatCheck\Service;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
class LoggingService
|
||||||
|
{
|
||||||
|
private $output;
|
||||||
|
private $logs = [];
|
||||||
|
/**
|
||||||
|
* @var true
|
||||||
|
*/
|
||||||
|
private $echo = false;
|
||||||
|
private $presta = false;
|
||||||
|
|
||||||
|
public function setConsole(OutputInterface $output) : self
|
||||||
|
{
|
||||||
|
$this->output = $output;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enableEcho() : self
|
||||||
|
{
|
||||||
|
$this->echo = true;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function enablePrestaLog() : self
|
||||||
|
{
|
||||||
|
$this->presta = true;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function log($message, $object = null, $object_id = null)
|
||||||
|
{
|
||||||
|
$now = (new \DateTime())->format('Y-m-d H:i:s');
|
||||||
|
$line = $now . ' --> '.$message . PHP_EOL;
|
||||||
|
$this->logs[] = $line;
|
||||||
|
if (!is_null($this->output)) {
|
||||||
|
$this->output->write($line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->echo) {
|
||||||
|
echo $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->presta) {
|
||||||
|
\PrestaShopLogger::addLog($message, 1, null, $object, $object_id, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\VatCheck\TaxManager;
|
||||||
|
|
||||||
|
use Websmid\VatCheck\Config\Config;
|
||||||
|
use TaxManagerInterface;
|
||||||
|
use Address;
|
||||||
|
use Country;
|
||||||
|
use Tax;
|
||||||
|
use TaxCalculator;
|
||||||
|
use Configuration;
|
||||||
|
use Context;
|
||||||
|
use Websmid\VatCheck\Model\VatCache;
|
||||||
|
use Websmid\VatCheck\Model\VatNumber;
|
||||||
|
use Websmid\VatCheck\Adapter\EuValidatorAdapter;
|
||||||
|
|
||||||
|
class CacheTaxManager implements TaxManagerInterface
|
||||||
|
{
|
||||||
|
public static function isAvailableForThisAddress(Address $address)
|
||||||
|
{
|
||||||
|
if( empty($address->vat_number) ){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( (int)$address->id_country == (int)Configuration::get('PS_COUNTRY_DEFAULT') ){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$isoCode = Country::getIsoById((int)$address->id_country);
|
||||||
|
if( !array_key_exists($isoCode, VatNumber::$euIso) ){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( VatCache::checkVatIsCached($address->vat_number) ){
|
||||||
|
return VatCache::checkVatIsValid($address->vat_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
$vatPrefix = VatNumber::$euIso[$isoCode];
|
||||||
|
$euValidator = new EuValidatorAdapter($address->vat_number, $vatPrefix);
|
||||||
|
if( !$euValidator->checkAndStore() ){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return VatCache::checkVatIsValid($address->vat_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTaxCalculator()
|
||||||
|
{
|
||||||
|
$tax = new Tax();
|
||||||
|
$tax->rate = 0;
|
||||||
|
|
||||||
|
return new TaxCalculator([$tax]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
if (!defined('_PS_VERSION_')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
function upgrade_module_1_0_2($module)
|
||||||
|
{
|
||||||
|
return $module->registerHook('displayInvoiceLegalFreeText');
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* 2007-2023 De Websmid BV
|
||||||
|
*
|
||||||
|
* NOTICE OF LICENSE
|
||||||
|
*
|
||||||
|
* This file is not open source! Each license that you purchased is only available for 1 wesite only.
|
||||||
|
* If you want to use this file on more websites (or projects), you need to purchase additional licenses.
|
||||||
|
* You are not allowed to redistribute, resell, lease, license, sub-license or offer our resources to any third party.
|
||||||
|
*
|
||||||
|
* DISCLAIMER
|
||||||
|
*
|
||||||
|
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||||
|
* versions in the future. If you wish to customize PrestaShop for your
|
||||||
|
* needs please contact us for extra customization service at an affordable price
|
||||||
|
*
|
||||||
|
* @author De Websmid BV <info@dewebsmid.nl>
|
||||||
|
* @copyright 2007-2024 De Websmid BV
|
||||||
|
* @license Valid for 1 website (or project) for each purchase of license
|
||||||
|
* International Registered Trademark & Property of De Websmid BV
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Websmid\VatCheck\Module\Install;
|
||||||
|
use Websmid\VatCheck\Module\Front\FrontHooks;
|
||||||
|
use Websmid\VatCheck\Module\Admin\AdminHooks;
|
||||||
|
|
||||||
|
if (file_exists(__DIR__ . '/vendor/autoload.php')) {
|
||||||
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined('_PS_VERSION_')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
class Ws_VatCheck extends \Module
|
||||||
|
{
|
||||||
|
use Install;
|
||||||
|
use AdminHooks;
|
||||||
|
use FrontHooks;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->name = 'ws_vatcheck';
|
||||||
|
$this->version = '1.0.3';
|
||||||
|
$this->author = 'Johan van der Klis | De Websmid BV';
|
||||||
|
$this->need_instance = 0;
|
||||||
|
$this->bootstrap = true;
|
||||||
|
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->displayName = $this->trans('Vat Check', [], 'Modules.Ws_VatCheck.Admin');
|
||||||
|
$this->description = $this->trans('Gecachte vat check', [], 'Modules.Ws_VatCheck.Description');
|
||||||
|
$this->ps_versions_compliancy = ['min' => '1.7.0.0', 'max' => _PS_VERSION_];
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user