yolk / valvat

Validates european vat numbers. Standalone or as a ActiveModel validator.
MIT License
321 stars 80 forks source link

Periodic Savon::UnknownOperationError when validating VAT #100

Closed lvonk closed 2 years ago

lvonk commented 3 years ago

Hi, we use Valvat::Lookup.validate(vat) (1.1.0) to validate VAT numbers. Approximately once per month for a short time period (<15 mins) we see a Savon::UnknownOperationError being raised with the following details:

Unable to find SOAP operation: :check_vat
Operations provided by your service: []

Could this be maintenance or something? I read in the docs then nil is returned, perhaps something changed on the VIES side?

yolk commented 3 years ago

This could be maintenance, but more likely the VIES-server is in an unstable state when returning this answer. Do you get this response for all kinds of VAT numbers, or only for numbers from specific states?

Any data to narrow down the issue would be helpful! Thanks!

lvonk commented 3 years ago

We are mostly targetting the dutch market, the last two occurrences were with VAT numbers from NL (Netherlands) and BE (belgium)

The last occurrences were:

Screenshot 2021-03-22 at 22 20 45 Screenshot 2021-03-22 at 22 21 03
aiomaster commented 3 years ago

We've seen this exception at the same time for different countries (NL and AT, occurred at 17th May between 19h and 20h), so I think it is independend of the country. Backtrace looks like:

/GEM_ROOT/gems/savon-2.12.1/lib/savon/operation.rb:23:in ensure_exists!
/GEM_ROOT/gems/savon-2.12.1/lib/savon/operation.rb:15:in create
/GEM_ROOT/gems/savon-2.12.1/lib/savon/client.rb:32:in operation
/GEM_ROOT/gems/savon-2.12.1/lib/savon/client.rb:36:in call
/GEM_ROOT/gems/valvat-1.1.0/lib/valvat/lookup/request.rb:18:in perform
/GEM_ROOT/gems/valvat-1.1.0/lib/valvat/lookup.rb:31:in response
/GEM_ROOT/gems/valvat-1.1.0/lib/valvat/lookup.rb:13:in validate
/GEM_ROOT/gems/valvat-1.1.0/lib/valvat/lookup.rb:20:in validate

If it is just another possibility how the VIES-service can be down, this gem should handle this case and throw some kind of ViesError maybe something like ServiceUnavailable instead.

ArturT commented 3 years ago

I see the same error:

 Savon::UnknownOperationError:
       Unable to find SOAP operation: :check_vat
       Operations provided by your service: []

Maybe we could do what is suggested here https://github.com/yolk/valvat/issues/103 and rescue Savon::UnknownOperationError here? https://github.com/yolk/valvat/blob/c72f011ffd4453468fef96f4ae874923897b9695/lib/valvat/lookup/request.rb#L20

Would this handle the error gracefully?

I have raise_error: false option in my model validation so I would expect when Savon::UnknownOperationError happens then vat_id field is considered as valid:

  validates :vat_id,
    valvat: {
      lookup: {
        raise_error: false, # this should gracefully handle the error. We prefer to accept VAT ID when VIES is down
        savon: {
          log: false
        }
      }
    }

---EDITED:

I monkey patched valvat gem to rescue Savon::SOAPFault but it did not help. There was some other error so I decided to do a different workaround.

ArturT commented 3 years ago

Here is my workaround (updated 26 Jan 2022):

  # add to model
  validate :validate_vat_id_in_vies

  def validate_vat_id_in_vies
    # suppress all known error cases
    # https://github.com/yolk/valvat#handling-of-other-vies-errors
    result = Valvat.new(vat_id).exists?(raise_error: false)

    # When response is `nil` then VIES system is down. Let's assume VAT ID is valid then.
    # That is why we check `result == false` and only then add validation error when we are sure VAT ID is missing in VIES system.
    if result == false
      errors.add(:vat_id, message: 'must be a valid VAT ID that is present in VIES database (please consult https://ec.europa.eu/taxation_customs/vies/vatRequest.html)')
    end
  rescue Savon::UnknownOperationError, Savon::HTTPError, Valvat::UnknownViesError => e
    # let's assume VAT ID is valid when VIES is down and don't raise the error
    Rails.logger.warn("Valvat gem failed due to: #{e.inspect}")
  end

I dont' use anymore:

  validates :vat_id,
    valvat: {
      lookup: {
        raise_error: false, # this should gracefully handle the error. We prefer to accept VAT ID when VIES is down
        savon: {
          log: false
        }
      }
    }
yolk commented 2 years ago

Is this still a problem? v1.1.2 fixed a similar error.

ArturT commented 2 years ago

I was using v1.1.2 and I had a different error Valvat::UnknownViesError. I updated my workaround code above.

yolk commented 2 years ago

Fixed in v1.1.3