Class: Docdata::Response

Inherits:
Object
  • Object
show all
Defined in:
lib/docdata/response.rb

Overview

Object representing a "response" with attributes provided by Docdata

Examples:

:create_success=>{
  :success=>"Operation successful.", 
  :key=>"A7B623A3A7DB5949316F82049450C3F3"
}

Constant Summary collapse

@@success =
false

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(args = nil) ⇒ Response

Initializer to transform a +Hash+ into an Response object

Parameters:

  • args (Hash) (defaults to: nil)


53
54
55
56
57
58
59
# File 'lib/docdata/response.rb', line 53

def initialize(args=nil)
  @report = {}
  return if args.nil?
  args.each do |k,v|
    instance_variable_set("@#{k}", v) unless v.nil?
  end
end

Instance Attribute Details

#amountInteger

Returns the captured amount in cents.

Returns:

  • (Integer)

    the captured amount in cents



35
36
37
# File 'lib/docdata/response.rb', line 35

def amount
  @amount
end

#currencyString

Returns Currency ("EUR", "GBP", "USD", etc.).

Returns:

  • (String)

    Currency ("EUR", "GBP", "USD", etc.)



41
42
43
# File 'lib/docdata/response.rb', line 41

def currency
  @currency
end

#keyString

Returns Payment key for future correspondence about this transaction.

Returns:

  • (String)

    Payment key for future correspondence about this transaction



14
15
16
# File 'lib/docdata/response.rb', line 14

def key
  @key
end

#messageString

Returns Response message from DocData.

Returns:

  • (String)

    Response message from DocData



23
24
25
# File 'lib/docdata/response.rb', line 23

def message
  @message
end

Returns:

  • (Boolean)


32
33
34
# File 'lib/docdata/response.rb', line 32

def paid
  @paid
end

#paymentDocdata::Payment

Returns object.

Returns:



44
45
46
# File 'lib/docdata/response.rb', line 44

def payment
  @payment
end

#reportHash

Returns The parsed report node of the reponse-xml.

Returns:

  • (Hash)

    The parsed report node of the reponse-xml



26
27
28
# File 'lib/docdata/response.rb', line 26

def report
  @report
end

#statusString

Returns the status of this response (capture response).

Returns:

  • (String)

    the status of this response (capture response)



38
39
40
# File 'lib/docdata/response.rb', line 38

def status
  @status
end

#successBoolean Also known as: success?

Returns true/false, depending of the API response.

Returns:

  • (Boolean)

    true/false, depending of the API response



16
17
18
# File 'lib/docdata/response.rb', line 16

def success
  @success
end

#urlString

Returns the return URL.

Returns:

  • (String)

    the return URL



47
48
49
# File 'lib/docdata/response.rb', line 47

def url
  @url
end

#xmlString

Returns The raw XML returned by the API.

Returns:

  • (String)

    The raw XML returned by the API



29
30
31
# File 'lib/docdata/response.rb', line 29

def xml
  @xml
end

Class Method Details

.parse(method_name, response) ⇒ Object

Parses the returned response hash and turns it into a new Docdata::Response object

Parameters:

  • method_name (String)

    (name of the method: create, start, cancel, etc.)

  • response (Hash)


90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/docdata/response.rb', line 90

def self.parse(method_name, response)
  body, xml = self.response_body(response)
  if body["#{method_name}_response".to_sym] && body["#{method_name}_response".to_sym]["#{method_name}_error".to_sym]
    raise DocdataError.new(response), body["#{method_name}_response".to_sym]["#{method_name}_error".to_sym][:error]
  else
    m = body["#{method_name}_response".to_sym]["#{method_name}_success".to_sym]
    r = self.new(key: m[:key], message: m[:success], success: true)
    r.xml    = xml #save the raw xml
    # puts m[:report]
    if m[:report]
      r.report = m[:report]
    end
    r.set_attributes
    return r
  end
end

.response_body(response) ⇒ Hash

plain XML files, in normal use, it uses a Savon::Response

Returns:

  • (Hash)

    the body of the response. In the test environment, this uses



109
110
111
112
113
114
115
116
117
118
119
# File 'lib/docdata/response.rb', line 109

def self.response_body(response)
  if response.is_a?(File)
    parser = Nori.new(:convert_tags_to => lambda { |tag| tag.snakecase.to_sym })
    xml = response.read 
    body = parser.parse(xml).first.last.first.last
  else
    body = response.body.to_hash
    xml = response.xml
  end
  return body, xml
end

Instance Method Details

#amount_to_setObject

[Integer] the amount to set, calculated from the multiple payment nodes



63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/docdata/response.rb', line 63

def amount_to_set
  #  if (report && Response.payment_node(report) && Response.payment_node(report)[:authorization] && Response.payment_node(report)[:authorization][:amount].present?)
  if (report && Response.payment_node(report) && Response.payment_node(report)[:authorization] && Response.payment_node(report)[:authorization][:amount].present?)
    if canceled
      return Response.payment_node(report)[:authorization][:amount].to_i
    else
      return total_acquirer_pending + total_acquirer_approved
    end
  else
    return false
  end
end

#authorizedBoolean Also known as: authorized?

Returns:

  • (Boolean)


213
214
215
# File 'lib/docdata/response.rb', line 213

def authorized
  payment_status == "AUTHORIZED"
end

#canceledBoolean Also known as: canceled?

Returns:

  • (Boolean)


219
220
221
222
# File 'lib/docdata/response.rb', line 219

def canceled
  (payment_status && payment_status == "CANCELED") || 
    (capture_status && capture_status == "CANCELED")
end

#capture_statusString

Returns the status of the capture, if exists.

Returns:

  • (String)

    the status of the capture, if exists



226
227
228
229
230
231
232
# File 'lib/docdata/response.rb', line 226

def capture_status
  if report && Response.payment_node(report) && Response.payment_node(report)[:authorization] && Response.payment_node(report)[:authorization][:capture]
    Response.payment_node(report)[:authorization][:capture][:status]
  else
    nil
  end
end

#currency_to_setString

Returns the currency if this transaction.

Returns:

  • (String)

    the currency if this transaction



236
237
238
239
240
241
242
# File 'lib/docdata/response.rb', line 236

def currency_to_set
  if status_xml &&  status_xml.xpath("//amount").any?
    status_xml.xpath("//amount").first.attributes["currency"].value
  else
    nil
  end
end

#docNokogiri::XML::Document

Returns object.

Returns:

  • (Nokogiri::XML::Document)

    object



245
246
247
248
249
250
# File 'lib/docdata/response.rb', line 245

def doc
  # remove returns and whitespaces between tags
  xml_string = xml.gsub("\n", "").gsub(/>\s+</, "><")
  # return Nokogiri::XML::Document
  @doc ||= Nokogiri.XML(xml_string)
end

#is_paid?Boolean

Note:

Docdata doesn't explicitly say 'paid' or 'not paid', this is a little bit a gray area.

Note:

This method is never 100% reliable. If you need to finetune this, please implement your own method, using

There are several approaches to determine if a payment is paid, some slow and safe, other quick and unreliable. The reason for this is that some payment methods have a much longer processing time. For each payment method a different 'paid'. the available data (total_captured, total_registered, etc.) from the Docs: Safe route: The safest route to check whether all payments were made is for the merchants to refer to the “Total captured” amount to see whether this equals the “Total registered amount”. While this may be the safest indicator, the downside is that it can sometimes take a long time for acquirers or shoppers to actually have the money transferred and it can be captured. Quick route: Another option is to see whether the sum of “total shopper pending”, “total acquirer pending” and “total acquirer authorized” matches the “total registered sum”. This implies that everyone responsible has indicated that they are going to make the payment and that the merchant is trusting that everyone will indeed make this. While this route will be faster, it does also have the risk that some payments will actually not have been made. Balanced route: Depending on the merchant's situation, it can be a good option to only refer to certain totals. For instance, if the merchant only makes use of credit card payments it could be a good route to only look at “Total acquirer approved”, since this will be rather safe but quicker than looking at the captures.

Returns:

  • (Boolean)

    true/false, depending wether this payment is considered paid.



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/docdata/response.rb', line 185

def is_paid?

  if payment_method
    case payment_method
    # ideal (dutch)
    when "IDEAL" 
      (total_registered == total_captured) ## && (capture_status == "CAPTURED")
    # creditcard
    when "MASTERCARD", "VISA", "AMEX"
      (total_registered == total_acquirer_approved)
    # sofort überweisung (german)
    when "SOFORT_UEBERWEISUNG"
      (total_registered == total_acquirer_approved)
    # podium giftcard (dutch)
    when "PODIUM_GIFTCARD"
      (total_registered == total_captured)
    # fallback: if total_registered equals total_caputured,
    # we can assume that this order is paid. No 100% guarantee.
    else
      total_registered == total_acquirer_approved
    end
  else
    false
  end
end

#payment_methodString

Returns the payment method of this transaction.

Returns:

  • (String)

    the payment method of this transaction



129
130
131
132
133
134
135
136
137
138
139
# File 'lib/docdata/response.rb', line 129

def payment_method
  begin
    if report && Response.payment_node(report).present? && Response.payment_node(report)[:payment_method].present?
      Response.payment_node(report)[:payment_method].to_s
    else
      nil
    end
  rescue
    nil
  end
end

#payment_statusString

Returns the status string provided by the API. One of [AUTHORIZED, CANCELED].

Returns:

  • (String)

    the status string provided by the API. One of [AUTHORIZED, CANCELED]



143
144
145
146
147
148
149
# File 'lib/docdata/response.rb', line 143

def payment_status
  if report && Response.payment_node(report) && Response.payment_node(report)[:authorization]
    Response.payment_node(report)[:authorization][:status]
  else
    nil
  end
end

#pidString

Returns the PID of the transaction.

Returns:

  • (String)

    the PID of the transaction



152
153
154
155
156
157
158
# File 'lib/docdata/response.rb', line 152

def pid
  if report && Response.payment_node(report) && Response.payment_node(report)[:id]
    Response.payment_node(report)[:id]
  else
    nil
  end      
end

#set_attributesObject

Set the attributes based on the API response



77
78
79
80
81
82
# File 'lib/docdata/response.rb', line 77

def set_attributes
  self.paid     = is_paid?
  self.amount   = amount_to_set if amount_to_set
  self.status   = capture_status if capture_status
  self.currency = currency_to_set
end

#status_xmlNokogiri::XML::Document

Note:

This is a fix for Nokogiri's trouble finding xpath elements after 'xlmns' attribute in a node.

Returns object, containing only the status section.

Returns:

  • (Nokogiri::XML::Document)

    object, containing only the status section



254
255
256
# File 'lib/docdata/response.rb', line 254

def status_xml
  @status_xml ||= Nokogiri.XML(doc.xpath("//S:Body").first.children.first.children.first.to_xml)
end