Vies VAT Validator checkout WooCommerce - wordpress

does anyone know this plugin for VAT validation? https://wordpress.org/plugins/vies-validator/
Here is the explanation of the library used: https://github.com/pH-7/eu-vat-validator
It works very well, also because in my case I already have the VAT number as a field, and therefore, since it allows you to assign the ID to the panel of your existing field, it validates it.
However, I would like to exclude Italy from validation, inside the plugin I see the 3 functions that validate the VAT number, but I can't understand how to exclude the country I want.
/**
* Validate the VAT Number
*
* #since 1.0.0
*/
public function vies_validator_validate_vat() {
$enable_vat = get_option($this->option_name . '_add_vat_field');
if ($enable_vat && $enable_vat == 1) {
$vat_id = 'vies_billing_vat';
}
else {
$vat_id = get_option($this->option_name . '_vat_id');
}
if ($vat_id && !empty(trim($vat_id))) {
$this->vies_validator_validate_vat_field($vat_id);
}
}
/**
* Check a VAT Number via API
*
* #since 1.0.0
*/
protected function vatCheck($vat_number) {
$country = substr($vat_number, 0, 2);
try {
$oVatValidator = new Validator(new Europa, $vat_number, $country);
return $oVatValidator->check();
}
catch (Exception $e) {
return false;
}
}
/**
* Validates vat number
*
* #since 1.0.0
*/
protected function vies_validator_validate_vat_field($vat_id) {
if(isset($_POST[$vat_id]) && !empty($_POST[$vat_id])) {
$vat_number = $_POST[$vat_id];
if (! $this->vatCheck($vat_number)) {
wc_add_notice(__(get_option('vies_validator_message'), 'vies-validator'), 'error');
}
}
}
}
Only the functions are protected and public and I don't understand how to call a hook to make the function run in WordPress functions.php.
Here, I see the hooks being logged and there is the WooCommerce checkout hook.
/**
* Register all of the hooks related to the public-facing
functionality
* of the plugin.
*
* #since 1.0.0
* #access private
*/
private function define_public_hooks() {
$plugin_public = new Vies_Validator_Public( $this->get_plugin_name(), $this->get_version() );
$this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_styles' );
$this->loader->add_action( 'wp_enqueue_scripts', $plugin_public, 'enqueue_scripts' );
if (get_option('vies_validator_add_vat_field') == '1') {
$this->loader->add_filter('woocommerce_billing_fields', $plugin_public, 'vies_validator_add_vat_field', 10, 1);
$this->loader->add_filter( 'woocommerce_my_account_my_address_formatted_address', $plugin_public, 'vies_my_account_my_address_formatted_address', 10, 3 );
$this->loader->add_filter( 'woocommerce_order_formatted_billing_address', $plugin_public, 'vies_add_vat_formatted_billing_address', 10, 2 );
$this->loader->add_filter( 'woocommerce_formatted_address_replacements', $plugin_public, 'vies_formatted_address_replacements', 10, 2 );
$this->loader->add_filter( 'woocommerce_customer_meta_fields', $plugin_public, 'vies_customer_meta_fields' );
$this->loader->add_filter( 'woocommerce_admin_billing_fields', $plugin_public, 'vies_admin_billing_fields' );
$this->loader->add_filter( 'woocommerce_found_customer_details', $plugin_public, 'vies_found_customer_details' );
}
$this->loader->add_action('woocommerce_checkout_process', $plugin_public, 'vies_validator_validate_vat');
}
Thanks

If you just want the code to accept all Italian VAT numbers then you can just make a small modification to the vat check function:
protected function vatCheck($vat_number) {
$country = substr($vat_number, 0, 2);
if ($country == 'IT' || $country == 'it') {
return true;
} else {
try {
$oVatValidator = new Validator(new Europa, $vat_number, $country);
return $oVatValidator->check();
}
catch (Exception $e) {
return false;
}
}
}
If you want the code to reject all Italian numbers then use this version:
protected function vatCheck($vat_number) {
$country = substr($vat_number, 0, 2);
if ($country == 'IT' || $country == 'it') {
return false;
} else {
try {
$oVatValidator = new Validator(new Europa, $vat_number, $country);
return $oVatValidator->check();
}
catch (Exception $e) {
return false;
}
}
}
Good luck. I hope it will work for you. If not then you might find this VAT Validation Add-in that works with directly within Excel and can do bulk VAT validation: https://www.sanocast.dk/vat-validation/
It is fantastic! (I might be a little biased - it is my own creation)

Related

Woocommerce custom product_type seems not to be saved correctly

I am creating my own plugin for woocommerce and realized, that my custom product_type is not saved when the product has been created or updated. I am sure that the problem is coming from my plugin, but I am not sure where to look at.
Function to add the product_type (according to a post)
function extend_woocommerce()
{
Class WC_Product_Connected_To_General_Product extends WC_Product_Simple
{
public function __construct($product)
{
$this->product_type = 'connected_to_general_product';
$this->manage_stock = 'yes';
parent::__construct($product);
}
}
}
Class which is called in the plugin
Class general_stock {
/**
* general_stock constructor.
*/
function __construct()
{
if($this->check_if_woocommerce_is_active()){
add_action('init',[$this, 'add_woocommerce_product_type'])
add_filter('product_type_selector', [$this,'add_woocommerce_product_type_general_connected_product']);
...
}
/**
* add_woocommerce_product_type
*/
function add_woocommerce_product_type(){
extend_woocommerce();
}
/**
* add_woocommerce_product_type_general_connected_product
* #param $types
* #return mixed
*/
function add_woocommerce_product_type_general_connected_product($types){
$types[$this->product_type_name] = __('Connected to general Product','ln-general-stock');
return $types;
}
However "everything" works so far: I am able to select the new product type in backend and saving it aswell. (It is selected when I edit the product).
But when I query the Product in frontend and dump it, the value of product_type equals simple which I think should be connected_to_general_product or is this information stored in another value?
Thank you in advance for your help!
Remember the extends of product class name has to start with WP_Product_ followed with the producto type. Eg.:
class WC_Product_Moto extends WC_Product {
protected $product_type = 'moto';
public function get_type(){
return 'moto';
}
}
I would probably re-arrange the structure of your plugin a bit. I like to load the plugin on the woocommerce_loaded plugin, then you don't even need a conditional check to see if WooCommerce is active. But I think the problem is the array key/value pair that you are adding to the product_type_selector filter.
Class general_stock {
/**
* pseudo constructor.
*/
public static function init()
{
include_once( 'path-to/class-wc-product-connected-to-general-product.php' );
add_filter('product_type_selector', array( __CLASS__, 'add_woocommerce_product_type_general_connected_product' ) );
}
...
/**
* add_woocommerce_product_type_general_connected_product
* #param $types
* #return mixed
*/
public static function add_woocommerce_product_type_general_connected_product($types){
$types['general-product'] = __('Connected to general Product','ln-general-stock');
return $types;
}
}
add_action( 'woocommerce_loaded', 'general_stock::init');
Class WC_Product_Connected_To_General_Product extends WC_Product_Simple
{
public function __construct($product)
{
$this->product_type = 'connected_to_general_product';
$this->manage_stock = 'yes';
parent::__construct($product);
}
}
Also, add this code if doesn't work.
add_filter( 'woocommerce_product_class', array($this,'load_custom_product_type_class'), 10, 2 );
public function load_custom_product_type_class( $classname, $product_type ){
if ( $product_type == 'your_custom_product_type_here' ) {
$classname = 'YOUR_PRODUCT_TYPE_CLASS_NAME';
}
return $classname;
}
I had the same problem and found that I had to define a missing function in my case
if (class_exists('WC_Product_Simple')) {
class WC_Product_Ebook_Store extends WC_Product_Simple {
public function __construct( $product ) {
$this->product_type = 'ebook_store';
parent::__construct( $product );
}
public function get_type() {
return 'ebook_store';
}
}
}

Can't Change property value through a method in a WordPress plugin

I'm trying to check if WooCommerce is active or not, I created a property with with a default value of false, then I created a method to check if WooCommerce is active using is_plugin_active() and admin_init hook, if active the value of the property must be updated to true: here is the code:
class MyClass{
public $woo_active = false;
public function __construct(){
add_action( 'admin_init', array( $this, 'check_if_woo_active' ) );
}
// check if WooCommerce is active
public function check_if_woo_active(){
if( is_plugin_active( 'woocommerce/woocommerce.php' ) ){
$this->woo_active = true;
}
}
// is_woo_active()
public function is_woo_active(){
return $this->woo_active;
}
}
$var = new MyClass();
var_dump( $var->is_woo_active() );
the issue is that var_dump returns false even if WooCommerce is active, BUT, if I use var_dump inside the function check_if_woo_active(), it returns true.
Why the property value is not updated? thanks
Updated:
The Second Solution as #helgatheviking sugested works fine, also this works very well and short
class MyClass{
// check if WooCommerce is active
public function is_woo_active(){
include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
if( is_plugin_active( 'woocommerce/woocommerce.php' ) ){
return true;
}else{
return false;
}
}
}
$var = new MyClass();
var_dump( $var->is_woo_active() );
If I had to guess, then $var = new MyClass(); is run before admin_init so the check_if_woo_active() isn't run.
Couple things you could do. First, I will usually launch my plugin on the woocommerce_loaded hook. That way I am 100% sure WooCommerce is running.
class MyClass{
protected static $instance = null;
/**
* Main MyClass Instance
*
* Ensures only one instance of MyClass is loaded or can be loaded.
*
* #static
* #see MyClass()
* #return MyClass - Main instance
* #since 0.1.0
*/
public static function instance() {
if ( ! isset( self::$instance ) && ! ( self::$instance instanceof MyClass ) ) {
self::$instance = new MyClass();
}
return self::$instance;
}
public function __construct(){
// Do what you want, WC is definitely active
}
}
/**
* Returns the main instance of class.
*
* #return MyClass
*/
function MyClass() {
return MyClass::instance();
}
// Launch the class if WooCommerce is loaded:
add_action( 'woocommerce_loaded', 'MyClass' );
You could also mimic what WooCommerce does with their premium plugins and check the option that stores the active plugins:
class MyClass{
private static $active_plugins;
public static function get_active_plugins() {
self::$active_plugins = (array) get_option( 'active_plugins', array() );
if ( is_multisite() ){
self::$active_plugins = array_merge( self::$active_plugins, get_site_option( 'active_sitewide_plugins', array() ) );
}
}
// check if WooCommerce is active
public static function check_if_woo_active() {
if ( ! self::$active_plugins ) self::get_active_plugins();
return in_array( 'woocommerce/woocommerce.php', self::$active_plugins ) || array_key_exists( 'woocommerce/woocommerce.php', self::$active_plugins );
}
}
var_dump( MyClass::check_if_woo_active() );

Property is not flushed

I call a service in a controller:
$this->getContainer()->get('pro_convocation')->sendDelegationEmails();
Here it is the method executed with the service:
function sendDelegationEmails()
{
foreach ($this->getRepository()->findWithPendingDelegationsEmail(1) as $convocation) {
if (! $convocation->delegationsEmailCanBeSent()) continue;
$this->sendDelegationsEmails($convocation);
$convocation->_setDelegationsEmailIsSent(); //<--- it is not saved
$this->save($convocation);
}
}
and the other used methods in the same class:
/**
* #return \Pro\ConvocationBundle\Entity\ConvocationRepository
*/
private function getRepository()
{
return $this->get('doctrine')->getRepository('ProConvocationBundle:Convocation');
}
function save(ConvocationEntity $convocation)
{
$this->getEntityManager()->persist($convocation);
$this->getEntityManager()->flush();
}
function sendDefinitiveMinute(ConvocationEntity $convocation)
{
foreach ($convocation->getCommunity()->getMembers() as $user) {
$this->get('pro.notifications')->send(Notification::create()
...
->setBody($this->get('templating')->render(
'ProConvocationBundle:Convocation:definitive-minute.html.twig',
array(
'convocation' => $convocation,
'convocationIsOrdinary' => $this->get('pro_convocation.ordinariness')->isOrdinary($convocation),
'user' => $user
)
))
);
}
}
EDIT: The send method:
function send(Notification $notification)
{
if (! $notification->getRecipient()) throw new \Exception("Recipient not set");
if (! $notification->getRecipient()->getEmail()) {
$this->logger->info(sprintf(
"Notification \"%s\" ignored as recipient %s has no email",
$notification->getSubject(), $notification->getRecipient()));
return;
}
// Ignore notifications to the own author
if ($notification->getAuthor() === $notification->getRecipient()) {
$this->logger->info(sprintf(
"Notification ignored as recipient is the author (%s)",
$notification->getRecipient()));
return;
}
$em = $this->doctrine->getManager();
$em->persist($notification);
$em->flush();
if ($this->notificationHasToBeMailed($notification)) {
$this->mail($notification);
$this->logger->info("Notification mailed to {$notification->getRecipient()}");
}
}
END EDIT
The _setDelegationsEmailIsSent method and delegationsEmailIsSent property in the Convocation entity:
/**
* #ORM\Column(type="boolean", name="delegations_email_is_sent")
* #Constraints\NotNull
*/
private $delegationsEmailIsSent = false;
/**
* #internal
* #see \Pro\ConvocationBundle\Convocation::sendDelegationsEmails()
*/
function _setDelegationsEmailIsSent()
{
$this->delegationsEmailIsSent = true;
}
The problem is that delegations_email_is_sent in the database is not changing to true when executing the sendDelegationEmails method in a controller. I've tried several changes without success. It seems to be related to flush method, but I don't find the issue.

Finding out what changed via postUpdate listener in Symfony 2.1

I have a postUpdate listener and I'd like to know what the values were prior to the update and what the values for the DB entry were after the update. Is there a way to do this in Symfony 2.1? I've looked at what's stored in getUnitOfWork() but it's empty since the update has already taken place.
You can use this ansfer Symfony2 - Doctrine - no changeset in post update
/**
* #param LifecycleEventArgs $args
*/
public function postUpdate(LifecycleEventArgs $args)
{
$changeArray = $args->getEntityManager()->getUnitOfWork()->getEntityChangeSet($args->getObject());
}
Found the solution here. What I needed was actually part of preUpdate(). I needed to call getEntityChangeSet() on the LifecycleEventArgs.
My code:
public function preUpdate(Event\LifecycleEventArgs $eventArgs)
{
$changeArray = $eventArgs->getEntityChangeSet();
//do stuff with the change array
}
Your Entitiy:
/**
* Order
*
* #ORM\Table(name="order")
* #ORM\Entity()
* #ORM\EntityListeners(
* {"\EventListeners\OrderListener"}
* )
*/
class Order
{
...
Your listener:
class OrderListener
{
protected $needsFlush = false;
protected $fields = false;
public function preUpdate($entity, LifecycleEventArgs $eventArgs)
{
if (!$this->isCorrectObject($entity)) {
return null;
}
return $this->setFields($entity, $eventArgs);
}
public function postUpdate($entity, LifecycleEventArgs $eventArgs)
{
if (!$this->isCorrectObject($entity)) {
return null;
}
foreach ($this->fields as $field => $detail) {
echo $field. ' was ' . $detail[0]
. ' and is now ' . $detail[1];
//this is where you would save something
}
$eventArgs->getEntityManager()->flush();
return true;
}
public function setFields($entity, LifecycleEventArgs $eventArgs)
{
$this->fields = array_diff_key(
$eventArgs->getEntityChangeSet(),
[ 'modified'=>0 ]
);
return true;
}
public function isCorrectObject($entity)
{
return $entity instanceof Order;
}
}
You can find example in doctrine documentation.
class NeverAliceOnlyBobListener
{
public function preUpdate(PreUpdateEventArgs $eventArgs)
{
if ($eventArgs->getEntity() instanceof User) {
if ($eventArgs->hasChangedField('name') && $eventArgs->getNewValue('name') == 'Alice') {
$eventArgs->setNewValue('name', 'Bob');
}
}
}
}

Propel - merge collection

Working with Propel ORM 1.5, I'm missing a method to merge two PropelCollections.
A short proposal may be :
public function mergeCollection($collection){
foreach($collection as $i => $item){
if( ! $this->contains($item)){
// append item
$this->append($item);
}
}
}
So I'm new to Propel I would like to ask you, if there are better ways to do it ?
Or is this functionality already included in Propel, but i didn't yet discovered it ?
It seems to have been discuted twice in the mailing list, but I can't find the ticket.
At least, you can try this code and/or open a ticket on Github.
/**
* Add a collection of elements, preventing duplicates
*
* #param array $collection The collection
*
* #return int the number of new element in the collection
*/
public function addCollection($collection)
{
$i = 0;
foreach($collection as $ref) {
if ($this->add($ref)) {
$i = $i + 1;
}
}
return $i;
}
/**
* Add a an element to the collection, preventing duplicates
*
* #param $element The element
*
* #return bool if the element was added or not
*/
public function add($element)
{
if ($element != NULL) {
if ($this->isEmpty()) {
$this->append($element);
return true;
} else if (!$this->contains($element)) {
set_error_handler("error_2_exception");
try {
if (!method_exists($element, 'getPrimaryKey')) {
restore_error_handler();
$this->append($element);
return true;
}
if ($this->get($element->getPrimaryKey()) != null) {
restore_error_handler();
return false;
} else {
$this->append($element);
restore_error_handler();
return true;
}
} catch (Exception $x) {
//il semble que l'element ne soit pas dans la collection
restore_error_handler(); //restore the old handler
$this->append($element);
return true;
}
restore_error_handler(); //restore the old handler
}
}
return false;
}
}
function error_2_exception($errno, $errstr, $errfile, $errline,$context) {
throw new Exception('',$errno);
return true;
}

Resources