savonrb / savon

Heavy metal SOAP client
https://www.savonrb.com
MIT License
2.07k stars 616 forks source link

Possible wrong XML generation #708

Closed coding-bunny closed 6 years ago

coding-bunny commented 9 years ago

Okay,

I'll be careful with this issue, as I do not know yet if this is a problem with Savon generating wrong XML for my Soap request or the remote API acting weird.

Description

Let me describe the issue first. I need to make 3 requests to a remote SOAP api.

  1. Authenticate
  2. Get Token
  3. Get Data

The first two calls are being generated properly, and I'm getting the information back from the API without issue. The last call however fails.

Details

The WSDL for the SOAP API can be found here: https://orbis.bvdinfo.com/orbisneo/scripts/webservices/remoteaccess.asmx?WSDL

The method I'm trying to call is GetData

The error the Savon client receives is: Savon::SOAPFault: (soap:Receiver) Server was unable to process request. ---> selectionToken must be provided

Browser Request

When using my chrome plugin, the following request is being generated:

<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope">
    <Body>
        <GetData xmlns="http://bvdep.com/webservices/">
            <sessionHandle>1FGQAY7UWCXHEMX</sessionHandle>
            <!-- Optional -->
            <selection>
                <Token>0</Token>
                <SelectionCount>1</SelectionCount>
            </selection>
            <query>DEFINE P1 AS [Parameters.DimensionSelName=NrOfYears;NrOfYears.Index=0;],
            P2 AS [Parameters.Currency=RECORD;Parameters.Units=0;Parameters.DimensionSelName=NrOfYears;NrOfYears.Index=0;],
            P3 AS [Parameters.Currency=RECORD;Parameters.Units=0;Parameters.DimensionSelName=NrOfYears;NrOfYears.Index=1;],
            P4 AS [Parameters.Currency=SESSION;Parameters.Units=0;Parameters.DimensionSelName=NrOfYears;NrOfYears.Index=0;];

            SELECT LINE GENERAL_INFO.NAME AS NAME,
            LINE ACCOUNTS_HEADER.ORIG_CURRENCY USING P1 AS CURRENCY,
            LINE STATUS_ACC_INFO.LASTYEAR AS CURRENTYEAR,
            MODEL [Unified]LINE REPORT_PROFILE.OPREV USING P2 AS CURRENTREVENUE,
            MODEL [Unified]LINE REPORT_PROFILE.OPREV USING P3 AS PREVIOUSREVENUE,
            LINE UDV00002 USING P4 AS PROFITMARGIN,
            LINE UDV00003 USING P4 AS CURRENTRATIO,
            MODEL [C]LINE RATIOS.514 USING P4 AS CREDITORDAYS,                                                                                                                                                                                                                                                                                                                MODEL [C]LINE RATIOS.513 USING P4 AS COLLECTIONDAYS
            FROM RemoteAccess.A</query>
        <fromRecord>0</fromRecord>
        <nrRecords>1</nrRecords>
        <resultFormat>XML</resultFormat>
    </GetData>
</Body>

However, when I try to call the same logic with Savon, it generates the following request instead:

<?xml version="1.0" encoding="UTF-8"?>
    <env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://bvdep.com/webservices/" xmlns:env="http://www.w3.org/2003/05/soap-envelope">
         <env:Body>
             <tns:GetData>
                 <SessionHandle>3F3VAY7UWLHTFZJ</SessionHandle>
                 <Selection>
                     <Token>0</Token>
                     <SelectionCount>1</SelectionCount>
                 </Selection>
                 <Query>DEFINE P1 AS [Parameters.DimensionSelName=NrOfYears;NrOfYears.Index=0;],
            P2 AS [Parameters.Currency=RECORD;Parameters.Units=0;Parameters.DimensionSelName=NrOfYears;NrOfYears.Index=0;],
            P3 AS [Parameters.Currency=RECORD;Parameters.Units=0;Parameters.DimensionSelName=NrOfYears;NrOfYears.Index=1;],
            P4 AS [Parameters.Currency=SESSION;Parameters.Units=0;Parameters.DimensionSelName=NrOfYears;NrOfYears.Index=0;];

            SELECT LINE GENERAL_INFO.NAME AS NAME,
            LINE ACCOUNTS_HEADER.ORIG_CURRENCY USING P1 AS CURRENCY,
            LINE STATUS_ACC_INFO.LASTYEAR AS CURRENTYEAR,
            MODEL [Unified]LINE REPORT_PROFILE.OPREV USING P2 AS CURRENTREVENUE,
            MODEL [Unified]LINE REPORT_PROFILE.OPREV USING P3 AS PREVIOUSREVENUE,
            LINE UDV00002 USING P4 AS PROFITMARGIN,
            LINE UDV00003 USING P4 AS CURRENTRATIO,
            MODEL [C]LINE RATIOS.514 USING P4 AS CREDITORDAYS,                                                                                                                                                                                                                                                                                                                MODEL [C]LINE RATIOS.513 USING P4 AS COLLECTIONDAYS
            FROM RemoteAccess.A
                   </Query>
                  <FromRecord>0</FromRecord>
                  <NrRecords>1</NrRecords>
                  <ResultFormat>XML</ResultFormat>
             </tns:GetData>
       </env:Body>
  </env:Envelope>

So the difference for me is the namespace. I've tried playing around with the settings hash when creating my client, but I cannot get the generated response to actually look like what I am using in my browser.

Would it be possible to do this? Or am I looking in the wrong direction to get this problem resolved?

Source Code

   def token(force: false)
      Rails.cache.fetch('bureau_van_dijk_token', force: force, expires_in: 15.minutes) do
        message = { username: username, password: password }
        response = transport_layer.call(:open, message: message)
        response.body[:open_response][:open_result]
      end
    end

    protected

    def find_by_bvd_id
      message = { session_handle: token, id: @supplier.bureau_van_dijk_id }
      response = transport_layer.call(:find_by_bvd_id, message: message)
      response.body[:find_by_bvd_id_response][:find_by_bvd_id_result] rescue nil
    end

    def get_data
      selection = find_by_bvd_id

      if selection && selection[:selection_count].to_i > 0
        message = {
          session_handle: token,
          selection: { token: selection[:token], selection_count: selection[:selection_count] },
          query:
            'DEFINE P1 AS [Parameters.DimensionSelName=NrOfYears;NrOfYears.Index=0;],
            P2 AS [Parameters.Currency=RECORD;Parameters.Units=0;Parameters.DimensionSelName=NrOfYears;NrOfYears.Index=0;],
            P3 AS [Parameters.Currency=RECORD;Parameters.Units=0;Parameters.DimensionSelName=NrOfYears;NrOfYears.Index=1;],
            P4 AS [Parameters.Currency=SESSION;Parameters.Units=0;Parameters.DimensionSelName=NrOfYears;NrOfYears.Index=0;];

            SELECT LINE GENERAL_INFO.NAME AS NAME,
            LINE ACCOUNTS_HEADER.ORIG_CURRENCY USING P1 AS CURRENCY,
            LINE STATUS_ACC_INFO.LASTYEAR AS CURRENTYEAR,
            MODEL [Unified]LINE REPORT_PROFILE.OPREV USING P2 AS CURRENTREVENUE,
            MODEL [Unified]LINE REPORT_PROFILE.OPREV USING P3 AS PREVIOUSREVENUE,
            LINE UDV00002 USING P4 AS PROFITMARGIN,
            LINE UDV00003 USING P4 AS CURRENTRATIO,
            MODEL [C]LINE RATIOS.514 USING P4 AS CREDITORDAYS,                                                                                                                                                                                                                                                                                                                MODEL [C]LINE RATIOS.513 USING P4 AS COLLECTIONDAYS
            FROM RemoteAccess.A',
          from_record: selection[:token],
          nr_records: 1,
          result_format: 'XML'
        }
        response = transport_layer.call(:get_data, message: message)
        response.body[:get_data_response][:get_data_result]
      else
        []
      end
    end

    private

    def settings
      Settings.interfaces.bureau_van_dijk
    end

    def transport_layer
      Savon.client(soap_options)
    end

    def soap_options
      settings.slice(:wsdl).merge(
        open_timeout: 300,
        read_timeout: 300,
        logger: Rails.logger,
        log: true,
        soap_version: 2,
        convert_request_keys_to: :camelcase,
        element_form_default: :unqualified
      )
    end

    def username
      settings.username
    end

    def password
      settings.password
    end
stale[bot] commented 6 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] commented 6 years ago

This issue is now closed due to inactivity. If you believe this needs further action, please re-open to discuss.