How to Consume SOAP with Savon in Rails app

1.2k views Asked by At

I need to communicate to a service called ifthenpay via Soap using Savon on a Rails app that i'm working on.

The service generates payment references so users could pay on home banking or in cash machines.

The app needs to communicate to the service to see if the payment was made or not.

I'm using Savon and this is what i have so far in the checkout model(don't know if this is the right place to put the above code):

def self.check_status!
    client = Savon.client(
      wsdl: "http://www.ifthensoftware.com/IfmbWS/IfmbWS.asmx?WSDL",
      endpoint: "http://localhost:3000",
      namespaces: {"xmlns:ift"=>"https://www.ifthensoftware.com/"}
      )

    begin
      response = client.call(:get_payments, message: check_status_hash)
    rescue Savon::SOAPFault => error
      #...
    end
  end

  def self.check_status_hash
    {
      "ift:get_payments" => {
        "ift:chavebackoffice" => { "ift:chavebackoffice" => "0000-0000-0000-0000" },
        "ift:entidade" => {"ift:entidade" => "11202"},
        "ift:subidentidade" => {"ift:subidentidade" => "202"},
        "ift:dtHrInicio" => {"ift:dtHrInicio" => ""},
        "ift:dtHrFim" => {"ift:dtHrFim" => ""},
        "ift:referencia" => {"ift:referencia" => ""},
        "ift:valor" => {"ift:valor" => ""}
        }
      }
  end

I've an admin page where i need to list all the payments that have been made, so i can manage what was selled.

You can see the service operations here

What do i need to put in the controller and in the view for this to work?

I really appreciate your help, because i'm struggling with this for a long time.

1

There are 1 answers

1
Ruby Racer On BEST ANSWER

From my point of view, and pardon me because I'm not very experienced with the use of savon, you are slightly overkilling this.

To start with, you are providing the client with a WSDL url, so what is the use of attaching a doubtfully necessary endpoint?

A namespace is, to my understanding, necessary, once again, in case there is no standard WSDl interface.

I would go, to start off, I would simply go for:

@client = Savon.client(wsdl: "http://www.ifthensoftware.com/IfmbWS/IfmbWS.asmx?WSDL")

Watch the @client instead of client. We need to assign the client to a variable that will be reachable throughout the entire process (request, process, response).

Next, you will need to prepare your request. Parsing the above url, there is a banch of methods. You are providing in your example getPayments request.

I will not use this space to tell you how to construct the hash, but the hash should look something like this:

request_hash = {
    chavebackoffice: "0000-0000-0000-0000",
    entidade: "11202",
    subidentidade: "202",
    dtHrInicio: "",
    dtHrFim: "",
    referencia: "",
    valor: ""
}

To make the call to the api, you should simply do this:

@response = @client.call(:get_payments) do
    message request_hash
end

And then, parse the @response. You will probably need to turn it to a hash first. Maybe something like this:

@data = @response.to_hash[:get_payments_response][:get_payments_result][:ifmb]

I hope this will help you enough. It should be more than enough.

Putting all up: Controller code, adapt to your need

before_action :set_client, only: [:get_payments, :other_actions_perhaps]

def get_payments
    # params[:whatever] in case you post to @whatever object
    # params without [:whatever] if you are using "GET" method
    request_hash = {
        chavebackoffice: params[:whatever][:chavebackoffice],
        entidade: params[:whatever][:entidade],
        subidentidade: params[:whatever][:subidentidade],
        dtHrInicio: params[:whatever][:dtHrInicio],
        dtHrFim: params[:whatever][:dtHrFim],
        referencia: params[:whatever][:referencia],
        valor: params[:whatever][:valor]
    }
    response = @client.call(:get_payments) do
        message request_hash
    end
    # use this @data in your view
    @data = response.to_hash[:get_payments_response][:get_payments_result][:ifmb]
end

def set_client
     @client = Savon.client(wsdl: "http://www.ifthensoftware.com/IfmbWS/IfmbWS.asmx?WSDL")
end