feat(main): Add configurable VIES-offline fallback policy
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<module>
|
<module>
|
||||||
<name>ws_vatcheck</name>
|
<name>ws_vatcheck</name>
|
||||||
<displayName><![CDATA[Vat Check]]></displayName>
|
<displayName><![CDATA[Vat Check]]></displayName>
|
||||||
<version><![CDATA[1.0.2]]></version>
|
<version><![CDATA[1.0.3]]></version>
|
||||||
<description><![CDATA[Gecachte vat check]]></description>
|
<description><![CDATA[Gecachte vat check]]></description>
|
||||||
<author><![CDATA[Johan van der Klis | De Websmid BV]]></author>
|
<author><![CDATA[Johan van der Klis | De Websmid BV]]></author>
|
||||||
<tab><![CDATA[]]></tab>
|
<tab><![CDATA[]]></tab>
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<module>
|
<module>
|
||||||
<name>ws_vatcheck</name>
|
<name>ws_vatcheck</name>
|
||||||
<displayName><![CDATA[Vat Check]]></displayName>
|
<displayName><![CDATA[Vat Check]]></displayName>
|
||||||
<version><![CDATA[1.0.1]]></version>
|
<version><![CDATA[1.0.3]]></version>
|
||||||
<description><![CDATA[Gecachte vat check]]></description>
|
<description><![CDATA[Gecachte vat check]]></description>
|
||||||
<author><![CDATA[Johan van der Klis | De Websmid BV]]></author>
|
<author><![CDATA[Johan van der Klis | De Websmid BV]]></author>
|
||||||
<tab><![CDATA[]]></tab>
|
<tab><![CDATA[]]></tab>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use PH7\Eu\Vat\Exception;
|
|||||||
use Websmid\VatCheck\Config\Config;
|
use Websmid\VatCheck\Config\Config;
|
||||||
use Websmid\VatCheck\Model\VatCache;
|
use Websmid\VatCheck\Model\VatCache;
|
||||||
use PrestaShopLogger;
|
use PrestaShopLogger;
|
||||||
|
use Configuration;
|
||||||
|
|
||||||
class EuValidatorAdapter
|
class EuValidatorAdapter
|
||||||
{
|
{
|
||||||
@@ -38,7 +39,7 @@ class EuValidatorAdapter
|
|||||||
3
|
3
|
||||||
);
|
);
|
||||||
|
|
||||||
return false;
|
return $this->resolveOfflineFallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( $euVatValidator instanceof Validator ){
|
if( $euVatValidator instanceof Validator ){
|
||||||
@@ -52,4 +53,50 @@ class EuValidatorAdapter
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decide what to do when VIES itself can't be reached, per the configured
|
||||||
|
* Config::OFFLINE_MODE_CONFIG_KEY policy. Returning true here tells
|
||||||
|
* CacheTaxManager to go ahead and read VatCache::checkVatIsValid() next, so
|
||||||
|
* the "reuse last known" modes just need to confirm a prior record exists
|
||||||
|
* (checkVatIsValid() will then return whatever it already holds); the
|
||||||
|
* "always valid" modes without a prior record need us to actually write one.
|
||||||
|
*/
|
||||||
|
private function resolveOfflineFallback(): bool
|
||||||
|
{
|
||||||
|
$mode = Configuration::get(Config::OFFLINE_MODE_CONFIG_KEY) ?: Config::OFFLINE_MODE_DEFAULT;
|
||||||
|
$fullVat = $this->isoCode.$this->vatNr;
|
||||||
|
|
||||||
|
switch ($mode) {
|
||||||
|
case Config::OFFLINE_MODE_VALID:
|
||||||
|
$this->storeOfflineResult($fullVat, true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Config::OFFLINE_MODE_LAST_KNOWN_OR_INVALID:
|
||||||
|
return VatCache::hasEverBeenChecked($fullVat);
|
||||||
|
|
||||||
|
case Config::OFFLINE_MODE_LAST_KNOWN_OR_VALID:
|
||||||
|
if (VatCache::hasEverBeenChecked($fullVat)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->storeOfflineResult($fullVat, true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Config::OFFLINE_MODE_INVALID:
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function storeOfflineResult(string $fullVat, bool $valid): void
|
||||||
|
{
|
||||||
|
$vatCache = VatCache::getOrCreateByVat($fullVat);
|
||||||
|
$vatCache->vat_nr = $fullVat;
|
||||||
|
$vatCache->valid = $valid;
|
||||||
|
|
||||||
|
$vatCache->save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,24 @@ class Config
|
|||||||
|
|
||||||
CONST CACHE_VALIDITY = 1;
|
CONST CACHE_VALIDITY = 1;
|
||||||
|
|
||||||
|
// Configuration key holding the chosen offline-fallback mode.
|
||||||
|
CONST OFFLINE_MODE_CONFIG_KEY = 'WS_VATCHECK_OFFLINE_MODE';
|
||||||
|
|
||||||
|
// What to decide when the VIES service can't be reached.
|
||||||
|
CONST OFFLINE_MODE_INVALID = 'invalid';
|
||||||
|
CONST OFFLINE_MODE_VALID = 'valid';
|
||||||
|
CONST OFFLINE_MODE_LAST_KNOWN_OR_INVALID = 'last_known_or_invalid';
|
||||||
|
CONST OFFLINE_MODE_LAST_KNOWN_OR_VALID = 'last_known_or_valid';
|
||||||
|
|
||||||
|
CONST OFFLINE_MODE_DEFAULT = self::OFFLINE_MODE_INVALID;
|
||||||
|
|
||||||
|
CONST OFFLINE_MODE_LABELS = [
|
||||||
|
self::OFFLINE_MODE_INVALID => 'Always mark VAT as invalid',
|
||||||
|
self::OFFLINE_MODE_VALID => 'Always mark VAT as valid',
|
||||||
|
self::OFFLINE_MODE_LAST_KNOWN_OR_INVALID => 'Reuse the last known result, otherwise mark invalid',
|
||||||
|
self::OFFLINE_MODE_LAST_KNOWN_OR_VALID => 'Reuse the last known result, otherwise mark valid',
|
||||||
|
];
|
||||||
|
|
||||||
// Article 39bis W.BTW intra-community exemption notice, per invoice language.
|
// Article 39bis W.BTW intra-community exemption notice, per invoice language.
|
||||||
CONST INTRACOMMUNITY_EXEMPTION_TEXTS = [
|
CONST INTRACOMMUNITY_EXEMPTION_TEXTS = [
|
||||||
'nl' => 'Vrijgestelde intracommunautaire levering – artikel 39bis W.BTW',
|
'nl' => 'Vrijgestelde intracommunautaire levering – artikel 39bis W.BTW',
|
||||||
|
|||||||
@@ -45,6 +45,16 @@ class VatCache extends ObjectModel
|
|||||||
return (bool)Db::getInstance()->getValue('SELECT `valid` FROM `'._DB_PREFIX_.'vat_cache` WHERE `vat_nr` = "'.pSQL($vatNr).'" ORDER BY `id_vat` DESC');
|
return (bool)Db::getInstance()->getValue('SELECT `valid` FROM `'._DB_PREFIX_.'vat_cache` WHERE `vat_nr` = "'.pSQL($vatNr).'" ORDER BY `id_vat` DESC');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlike checkVatIsCached(), this ignores Config::CACHE_VALIDITY entirely —
|
||||||
|
* used by the offline-fallback "reuse last known result" modes, which want
|
||||||
|
* whatever was last recorded regardless of how stale it is.
|
||||||
|
*/
|
||||||
|
public static function hasEverBeenChecked(string $vatNr)
|
||||||
|
{
|
||||||
|
return (bool)Db::getInstance()->getValue('SELECT `id_vat` FROM `'._DB_PREFIX_.'vat_cache` WHERE `vat_nr` = "'.pSQL($vatNr).'" ORDER BY `id_vat` DESC');
|
||||||
|
}
|
||||||
|
|
||||||
public static function getOrCreateByVat(string $vatNr)
|
public static function getOrCreateByVat(string $vatNr)
|
||||||
{
|
{
|
||||||
$className = get_called_class();
|
$className = get_called_class();
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Websmid\VatCheck\Module\Admin;
|
||||||
|
|
||||||
|
use Websmid\VatCheck\Config\Config;
|
||||||
|
use Configuration;
|
||||||
|
use Tools;
|
||||||
|
use HelperForm;
|
||||||
|
use Context;
|
||||||
|
|
||||||
|
trait SettingsForm
|
||||||
|
{
|
||||||
|
public function getContent()
|
||||||
|
{
|
||||||
|
if ((bool) Tools::isSubmit('submitWsVatCheckSettings')) {
|
||||||
|
$this->postProcessSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->renderSettingsForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function postProcessSettings()
|
||||||
|
{
|
||||||
|
$mode = Tools::getValue(Config::OFFLINE_MODE_CONFIG_KEY);
|
||||||
|
|
||||||
|
if (!array_key_exists($mode, Config::OFFLINE_MODE_LABELS)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Configuration::updateValue(Config::OFFLINE_MODE_CONFIG_KEY, $mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function renderSettingsForm()
|
||||||
|
{
|
||||||
|
$helper = new HelperForm();
|
||||||
|
|
||||||
|
$helper->show_toolbar = false;
|
||||||
|
$helper->table = $this->table;
|
||||||
|
$helper->module = $this;
|
||||||
|
$helper->default_form_language = Context::getContext()->language->id;
|
||||||
|
$helper->allow_employee_form_lang = (int) Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG', 0);
|
||||||
|
|
||||||
|
$helper->identifier = $this->identifier;
|
||||||
|
$helper->submit_action = 'submitWsVatCheckSettings';
|
||||||
|
$helper->currentIndex = Context::getContext()->link->getAdminLink('AdminModules', false)
|
||||||
|
. '&configure=' . $this->name
|
||||||
|
. '&tab_module=' . $this->tab
|
||||||
|
. '&module_name=' . $this->name;
|
||||||
|
$helper->token = Tools::getAdminTokenLite('AdminModules');
|
||||||
|
|
||||||
|
$helper->tpl_vars = [
|
||||||
|
'fields_value' => $this->getSettingsFormValues(),
|
||||||
|
'languages' => Context::getContext()->controller->getLanguages(),
|
||||||
|
'id_language' => Context::getContext()->language->id,
|
||||||
|
];
|
||||||
|
|
||||||
|
return $helper->generateForm([$this->getSettingsFormStructure()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSettingsFormValues()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Config::OFFLINE_MODE_CONFIG_KEY => Configuration::get(
|
||||||
|
Config::OFFLINE_MODE_CONFIG_KEY,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
Config::OFFLINE_MODE_DEFAULT
|
||||||
|
),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSettingsFormStructure()
|
||||||
|
{
|
||||||
|
$choices = [];
|
||||||
|
foreach (Config::OFFLINE_MODE_LABELS as $value => $label) {
|
||||||
|
$choices[] = [
|
||||||
|
'id' => $value,
|
||||||
|
'value' => $value,
|
||||||
|
'label' => $this->trans($label, [], 'Modules.Ws_VatCheck.Admin'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'form' => [
|
||||||
|
'legend' => [
|
||||||
|
'title' => $this->trans('VAT Check settings', [], 'Modules.Ws_VatCheck.Admin'),
|
||||||
|
'icon' => 'icon-cogs',
|
||||||
|
],
|
||||||
|
'input' => [
|
||||||
|
[
|
||||||
|
'type' => 'radio',
|
||||||
|
'label' => $this->trans('When VIES is unreachable', [], 'Modules.Ws_VatCheck.Admin'),
|
||||||
|
'name' => Config::OFFLINE_MODE_CONFIG_KEY,
|
||||||
|
'desc' => $this->trans(
|
||||||
|
'What to decide about a VAT number when the EU VIES service can\'t be reached to check it.',
|
||||||
|
[],
|
||||||
|
'Modules.Ws_VatCheck.Admin'
|
||||||
|
),
|
||||||
|
'values' => $choices,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'submit' => [
|
||||||
|
'title' => $this->trans('Save', [], 'Admin.Actions'),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ namespace Websmid\VatCheck\Module;
|
|||||||
|
|
||||||
use Websmid\VatCheck\Config\Config;
|
use Websmid\VatCheck\Config\Config;
|
||||||
use Db;
|
use Db;
|
||||||
|
use Configuration;
|
||||||
|
|
||||||
trait Install
|
trait Install
|
||||||
{
|
{
|
||||||
@@ -21,9 +22,18 @@ trait Install
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$this->registerConfiguration()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function registerConfiguration()
|
||||||
|
{
|
||||||
|
return Configuration::updateValue(Config::OFFLINE_MODE_CONFIG_KEY, Config::OFFLINE_MODE_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
private function registerHooks()
|
private function registerHooks()
|
||||||
{
|
{
|
||||||
foreach (Config::HOOKS as $hook) {
|
foreach (Config::HOOKS as $hook) {
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Websmid\VatCheck\Config\Config;
|
||||||
|
|
||||||
|
if (!defined('_PS_VERSION_')) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
function upgrade_module_1_0_3($module)
|
||||||
|
{
|
||||||
|
return Configuration::updateValue(Config::OFFLINE_MODE_CONFIG_KEY, Config::OFFLINE_MODE_DEFAULT);
|
||||||
|
}
|
||||||
+3
-1
@@ -23,6 +23,7 @@
|
|||||||
use Websmid\VatCheck\Module\Install;
|
use Websmid\VatCheck\Module\Install;
|
||||||
use Websmid\VatCheck\Module\Front\FrontHooks;
|
use Websmid\VatCheck\Module\Front\FrontHooks;
|
||||||
use Websmid\VatCheck\Module\Admin\AdminHooks;
|
use Websmid\VatCheck\Module\Admin\AdminHooks;
|
||||||
|
use Websmid\VatCheck\Module\Admin\SettingsForm;
|
||||||
|
|
||||||
if (file_exists(__DIR__ . '/vendor/autoload.php')) {
|
if (file_exists(__DIR__ . '/vendor/autoload.php')) {
|
||||||
require_once __DIR__ . '/vendor/autoload.php';
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
@@ -35,12 +36,13 @@ class Ws_VatCheck extends \Module
|
|||||||
{
|
{
|
||||||
use Install;
|
use Install;
|
||||||
use AdminHooks;
|
use AdminHooks;
|
||||||
|
use SettingsForm;
|
||||||
use FrontHooks;
|
use FrontHooks;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->name = 'ws_vatcheck';
|
$this->name = 'ws_vatcheck';
|
||||||
$this->version = '1.0.2';
|
$this->version = '1.0.3';
|
||||||
$this->author = 'Johan van der Klis | De Websmid BV';
|
$this->author = 'Johan van der Klis | De Websmid BV';
|
||||||
$this->need_instance = 0;
|
$this->need_instance = 0;
|
||||||
$this->bootstrap = true;
|
$this->bootstrap = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user