#!/usr/bin/ruby

=begin
Purpose: To check EU VAT ID
Description:
  This is a script that uses VIES WSDL/SOAP interface to check
  validity of a given European VAT ID.
Author: Michal Safranek <wejn at box dot cz>
TS: 20080417163500
Example:

$ ./checkvat.rb CZ26058774
Name:    Web4U s.r.o.
Address: 
Country: CZ
VAT ID:  26058774
R.Date:  2008-04-17T00:00:00Z

$ ./checkvat.rb CZ26058773
Error: Invalid VAT ID

$ ./checkvat.rb CZ27806138
Name:    OVX.cz 2003 s.r.o.
Address: 
Country: CZ
VAT ID:  27806138
R.Date:  2008-04-17T00:00:00Z

=end

require 'rubygems'
gem 'soap4r'

unless ARGV.size == 1 && ARGV.first =~ /^[A-Z]{2}\d+$/i
    $stderr.puts "Usage: #{File.basename($0)} <vatID>"
    $stderr.puts "Example: CZ26257645"
    exit 1
end

###### require 'defaultDriver.rb' # {{{

###### require 'default.rb' # {{{

require 'xsd/qname'

# {urn:ec.europa.eu:taxud:vies:services:checkVat:types}checkVat
#   countryCode - SOAP::SOAPString
#   vatNumber - SOAP::SOAPString
class CheckVat
  attr_accessor :countryCode
  attr_accessor :vatNumber

  def initialize(countryCode = nil, vatNumber = nil)
    @countryCode = countryCode
    @vatNumber = vatNumber
  end
end

# {urn:ec.europa.eu:taxud:vies:services:checkVat:types}checkVatResponse
#   countryCode - SOAP::SOAPString
#   vatNumber - SOAP::SOAPString
#   requestDate - SOAP::SOAPDate
#   valid - SOAP::SOAPBoolean
#   name - SOAP::SOAPString
#   address - SOAP::SOAPString
class CheckVatResponse
  attr_accessor :countryCode
  attr_accessor :vatNumber
  attr_accessor :requestDate
  attr_accessor :valid
  attr_accessor :name
  attr_accessor :address

  def initialize(countryCode = nil, vatNumber = nil, requestDate = nil, valid = nil, name = nil, address = nil)
    @countryCode = countryCode
    @vatNumber = vatNumber
    @requestDate = requestDate
    @valid = valid
    @name = name
    @address = address
  end
end

###### end of require 'default.rb' # }}}

###### require 'defaultMappingRegistry.rb' # {{{

require 'soap/mapping'

module DefaultMappingRegistry
  EncodedRegistry = ::SOAP::Mapping::EncodedRegistry.new
  LiteralRegistry = ::SOAP::Mapping::LiteralRegistry.new
  NsTypes = "urn:ec.europa.eu:taxud:vies:services:checkVat:types"

  LiteralRegistry.register(
    :class => CheckVat,
    :schema_name => XSD::QName.new(NsTypes, "checkVat"),
    :schema_element => [
      ["countryCode", ["SOAP::SOAPString", XSD::QName.new(nil, "countryCode")]],
      ["vatNumber", ["SOAP::SOAPString", XSD::QName.new(nil, "vatNumber")]]
    ]
  )

  LiteralRegistry.register(
    :class => CheckVatResponse,
    :schema_name => XSD::QName.new(NsTypes, "checkVatResponse"),
    :schema_element => [
      ["countryCode", ["SOAP::SOAPString", XSD::QName.new(nil, "countryCode")]],
      ["vatNumber", ["SOAP::SOAPString", XSD::QName.new(nil, "vatNumber")]],
      ["requestDate", ["SOAP::SOAPDate", XSD::QName.new(nil, "requestDate")]],
      ["valid", ["SOAP::SOAPBoolean", XSD::QName.new(nil, "valid")]],
      ["name", ["SOAP::SOAPString", XSD::QName.new(nil, "name")]],
      ["address", ["SOAP::SOAPString", XSD::QName.new(nil, "address")]]
    ]
  )
end

###### end of require 'defaultMappingRegistry.rb' # }}}

require 'soap/rpc/driver'

class CheckVatPortType < ::SOAP::RPC::Driver
  DefaultEndpointUrl = "http://ec.europa.eu/taxation_customs/vies/api/checkVatPort"

  Methods = [
    [ "",
      "checkVat",
      [ ["in", "parameters", ["::SOAP::SOAPElement", "urn:ec.europa.eu:taxud:vies:services:checkVat:types", "checkVat"]],
        ["out", "parameters", ["::SOAP::SOAPElement", "urn:ec.europa.eu:taxud:vies:services:checkVat:types", "checkVatResponse"]] ],
      { :request_style =>  :document, :request_use =>  :literal,
        :response_style => :document, :response_use => :literal,
        :faults => {} }
    ]
  ]

  def initialize(endpoint_url = nil)
    endpoint_url ||= DefaultEndpointUrl
    super(endpoint_url, nil)
    self.mapping_registry = DefaultMappingRegistry::EncodedRegistry
    self.literal_mapping_registry = DefaultMappingRegistry::LiteralRegistry
    init_methods
  end

private

  def init_methods
    Methods.each do |definitions|
      opt = definitions.last
      if opt[:request_style] == :document
        add_document_operation(*definitions)
      else
        add_rpc_operation(*definitions)
        qname = definitions[0]
        name = definitions[2]
        if qname.name != name and qname.name.capitalize == name.capitalize
          ::SOAP::Mapping.define_singleton_method(self, qname.name) do |*arg|
            __send__(name, *arg)
          end
        end
      end
    end
  end
end

###### end of require 'defaultDriver.rb' # }}}

cv = CheckVatPortType.new

ctry = ARGV.first[0,2].upcase
id = ARGV.first[2..-1]

resp = nil
begin
    resp = cv.checkVat(CheckVat.new(ctry, id))

    if resp.valid
        puts <<-EOF
Name:    #{resp.name}
Address: #{resp.address}
Country: #{resp.countryCode}
VAT ID:  #{resp.vatNumber}
R.Date:  #{resp.requestDate}
        EOF
        exit 0
    else
        $stderr.puts "Error: Invalid VAT ID"
        exit 1
    end
rescue
    $stderr.puts "Exception -- input is somehow wrong (wrong country?):"
    $stderr.puts $!.to_s
    exit 1
end