wirecard-elastic 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 621ede31a948a8e6d6c43f685b56f424de798b0e
4
- data.tar.gz: 71df9395ebfe66fc299d6cf4da4b1c50725c6d51
3
+ metadata.gz: 93c593aa04466a5217eddd272bdc0c62d959a0b0
4
+ data.tar.gz: f9d366855944b6d2b53d3c0ac782a349af9d1a2b
5
5
  SHA512:
6
- metadata.gz: 5063638dfa1c6940e398dbcb56875d0a02d763a8b6e9bdcb08bbb8528f5cf3864a110b82d20599ae3f803dd85c119bb4f76aaa9df6364be7a33d8b744f611bcc
7
- data.tar.gz: 3aa54477d500ab914f95c17d13a98b8b3bfc56737c895903a1c5a556bd4735486970c3c4e454a56eef82f4a5af1c9f568e17433bd189292d7ecc45687dc7e810
6
+ metadata.gz: 8631c8453ac3a939c988c6217bd1e08f2dead70882fdb7b4370f43098442488040269c5cc2e27c80964fa433b69af14844ba8f57fb380ccd2fcf9d8a12351cd5
7
+ data.tar.gz: 9ef1c8ac9c74c4503173a7c46cc12d95a45796ab1fa0353936cbd6077b23d3a4fc02d33bd1d6ab9ff84b24f68f455e985e915bceaf66bd1afa7ca87261c7f0db
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "wirecard/elastic"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,42 @@
1
+ require "wirecard/elastic/version"
2
+ require "wirecard/elastic/error"
3
+ require "wirecard/elastic/configuration"
4
+ require "wirecard/elastic/base"
5
+ require "wirecard/elastic/transaction"
6
+ require "wirecard/elastic/refund"
7
+ require "wirecard/elastic/utils/request"
8
+ require "wirecard/elastic/utils/response_format"
9
+ require "wirecard/elastic/utils/xml_builder"
10
+
11
+ module Wirecard
12
+ module Elastic
13
+
14
+ class << self
15
+
16
+ def transaction(merchant_id, transaction_id, payment_method)
17
+ Transaction.new(merchant_id, transaction_id, payment_method)
18
+ end
19
+
20
+ def refund(merchant_id, parent_transaction_id, payment_method)
21
+ Refund.new(merchant_id, parent_transaction_id, payment_method)
22
+ end
23
+
24
+ def configuration
25
+ @configuration ||= Configuration.new
26
+ if block_given?
27
+ yield @configuration
28
+ else
29
+ @configuration
30
+ end
31
+ end
32
+
33
+ def reset
34
+ @configuration = Configuration.new
35
+ end
36
+
37
+ alias :config :configuration
38
+
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,7 @@
1
+ module Wirecard
2
+ module Elastic
3
+ class Base
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ module Wirecard
2
+ module Elastic
3
+ class Configuration
4
+
5
+ attr_accessor :creditcard
6
+ attr_accessor :upop
7
+
8
+ def initialize
9
+ @upop = {}
10
+ @creditcard = {}
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module Wirecard
2
+ module Elastic
3
+ class Error < StandardError
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,81 @@
1
+ # refund a customer via the API
2
+ # this will make a double API call
3
+ # to first recover the original payment transaction
4
+ module Wirecard
5
+ module Elastic
6
+ class Refund < Base
7
+
8
+ REQUEST_IP_ADDRESS = "127.0.0.1".freeze
9
+ REFUND_MAP = {:purchase => :'refund-purchase', :debit => :'refund-debit'}.freeze
10
+
11
+ attr_reader :merchant_id, :parent_transaction_id, :request_id, :payment_method
12
+
13
+ def initialize(merchant_id, parent_transaction_id, payment_method)
14
+ @merchant_id = merchant_id
15
+ @parent_transaction_id = parent_transaction_id
16
+ @request_id = SecureRandom.uuid
17
+ @payment_method = payment_method
18
+ end
19
+
20
+ # process the query response
21
+ # return the response format
22
+ def response
23
+ @response ||= begin
24
+ response = Wirecard::Elastic::Utils::Request.new(query, payment_method, :post, body).response
25
+ if response.nil?
26
+ raise Wirecard::Elastic::Error, "The refund was not processed"
27
+ else
28
+ Utils::ResponseFormat.new(self, response)
29
+ end
30
+ end
31
+ end
32
+
33
+ # query URI to the API
34
+ def query
35
+ if parent_transaction.response.transaction_type == :purchase
36
+ @query ||= "payments"
37
+ elsif parent_transaction.response.transaction_type == :debit
38
+ @query ||= "paymentmethods"
39
+ end
40
+ end
41
+
42
+ # XML body we will send to the elastic API
43
+ def body
44
+ @body ||= Elastic::Utils::XmlBuilder.new(:refund, body_params).to_xml
45
+ end
46
+
47
+ private
48
+
49
+ # params we will use to fill the XML format request
50
+ def body_params
51
+ {
52
+ :merchant_account_id => merchant_id,
53
+ :request_id => request_id,
54
+ :parent_transaction_id => parent_transaction_id,
55
+ :ip_address => REQUEST_IP_ADDRESS
56
+ }.merge(remote_params)
57
+ end
58
+
59
+ # get some body params from the remote elastic API itslef rather than our database (safer)
60
+ def remote_params
61
+ {
62
+ :currency => parent_transaction.response.requested_amount_currency,
63
+ :amount => parent_transaction.response.requested_amount,
64
+ # potential bug because it's a symbol ?
65
+ :payment_method => parent_transaction.response.payment_method,
66
+ :transaction_type => refund_transaction_type
67
+ }
68
+ end
69
+
70
+ def refund_transaction_type
71
+ REFUND_MAP[parent_transaction.response.transaction_type]
72
+ end
73
+
74
+ # original transaction of the refund, requested remotely to elastic API
75
+ def parent_transaction
76
+ @parent_transaction ||= Wirecard::Elastic::Transaction.new(merchant_id, parent_transaction_id, payment_method)
77
+ end
78
+
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,13 @@
1
+ <payment xmlns="http://www.elastic-payments.com/schema/payment">
2
+ <merchant-account-id>{{MERCHANT_ACCOUNT_ID}}</merchant-account-id>
3
+ <request-id>{{REQUEST_ID}}</request-id>
4
+ <transaction-type>{{TRANSACTION_TYPE}}</transaction-type>
5
+ <parent-transaction-id>{{PARENT_TRANSACTION_ID}}</parent-transaction-id>
6
+
7
+ <requested-amount currency="{{CURRENCY}}">{{AMOUNT}}</requested-amount>
8
+ <payment-methods>
9
+ <payment-method name="{{PAYMENT_METHOD}}"/>
10
+ </payment-methods>
11
+
12
+ <ip-address>{{IP_ADDRESS}}</ip-address>
13
+ </payment>
@@ -0,0 +1,53 @@
1
+ # recover a transaction details from the Wirecard API
2
+ module Wirecard
3
+ module Elastic
4
+ class Transaction < Base
5
+
6
+ VALID_STATUS_LIST = [:success, :failed].freeze
7
+
8
+ attr_reader :merchant_id, :transaction_id, :payment_method
9
+
10
+ def initialize(merchant_id, transaction_id, payment_method)
11
+ @merchant_id = merchant_id
12
+ @transaction_id = transaction_id
13
+ @payment_method = payment_method
14
+ end
15
+
16
+ def response
17
+ @response ||= begin
18
+ response = Wirecard::Elastic::Utils::Request.new(query, payment_method).response
19
+ if response.nil?
20
+ raise Wirecard::Elastic::Error, "The transaction was not found"
21
+ else
22
+ Utils::ResponseFormat.new(self, response)
23
+ end
24
+ end
25
+ end
26
+
27
+ # query URI to the API
28
+ def query
29
+ @query ||= "merchants/#{merchant_id}/payments/#{transaction_id}"
30
+ end
31
+
32
+ # check the response consistency and raise possible issues
33
+ # if the response got errors, otherwise it continues to process
34
+ # by returning the object itself
35
+ def raise_response_issues
36
+ raise Wirecard::Elastic::Error, "The status of the transaction is not correct (#{response.request_status})" unless valid_status?
37
+ raise Wirecard::Elastic::Error, "The transaction could not be verified. API access refused." if negative_response?
38
+ self
39
+ end
40
+
41
+ private
42
+
43
+ def valid_status?
44
+ VALID_STATUS_LIST.include? response.transaction_state
45
+ end
46
+
47
+ def negative_response?
48
+ response.transaction_state == :failed && response.request_status == :error
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,102 @@
1
+ require 'net/http'
2
+
3
+ # send the request to Wirecard API via authentication
4
+ # get the response from it
5
+ module Wirecard
6
+ module Elastic
7
+ module Utils
8
+ class Request
9
+
10
+ CONTENT_TYPE = 'text/xml'.freeze
11
+
12
+ attr_reader :engine_url, :username, :password, :method, :body, :query, :payment_method
13
+
14
+ # uri_query gets the URI of request to the API
15
+ # method specify if it has to be a :get or :post
16
+ # body understood by the API is basically XML
17
+ def initialize(uri_query, payment_method, method=:get, body='')
18
+ @payment_method = payment_method
19
+ @method = method
20
+ @body = body
21
+ setup_access!
22
+ @query = "#{engine_url}#{uri_query}.json"
23
+ end
24
+
25
+ # get the http raw response to the API
26
+ # it's supposed to be a string, check out #response to get the hashed version
27
+ def raw_response
28
+ @raw_response ||= Net::HTTP.start(request_uri.host, request_uri.port,
29
+ :use_ssl => https_request?,
30
+ :verify_mode => OpenSSL::SSL::VERIFY_NONE) { |connection| dispatch!(connection) }
31
+ end
32
+
33
+ # check the body of the response and return it or `nil`
34
+ # NOTE : sometimes the API answers with bullshit like a HTML 404 ERROR
35
+ # so we have to check if the body is valid beforehand
36
+ def response
37
+ @response ||= JSON.parse(raw_response.body).deep_symbolize_keys if valid_body?
38
+ end
39
+
40
+ private
41
+
42
+ def valid_body?
43
+ raw_response.body && valid_json?(raw_response.body)
44
+ end
45
+
46
+ def valid_json?(json)
47
+ JSON.parse(json)
48
+ true
49
+ rescue JSON::ParserError
50
+ false
51
+ end
52
+
53
+ # connect and authenticate the client to the API server
54
+ def dispatch!(connection)
55
+ request.basic_auth username, password # authentification here
56
+ request.body = body # body (XML for instance)
57
+ request.content_type = CONTENT_TYPE # XML
58
+ connection.request request # give a response
59
+ end
60
+
61
+ # prepare the request and manage the differents methods used
62
+ def request
63
+ @request ||= begin
64
+ if method == :get
65
+ Net::HTTP::Get.new(request_uri.request_uri)
66
+ elsif method == :post
67
+ Net::HTTP::Post.new(request_uri.request_uri)
68
+ else
69
+ raise Wirecard::Elastic::Error, "Request method not recognized"
70
+ end
71
+ end
72
+ end
73
+
74
+ def request_uri
75
+ @request_uri ||= URI(query)
76
+ end
77
+
78
+ def https_request?
79
+ request_uri.scheme == 'https'
80
+ end
81
+
82
+ private
83
+
84
+ def setup_access!
85
+ @engine_url = access[:engine_url]
86
+ @username = access[:username]
87
+ @password = access[:password]
88
+ end
89
+
90
+ def access
91
+ config = Wirecard::Elastic.configuration.instance_variable_get("@#{payment_method}")
92
+ if config.nil?
93
+ raise Wirecard::Elastic::Error, "Can't recover #{payment_method} details. Please check your configuration."
94
+ else
95
+ config
96
+ end
97
+ end
98
+
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,91 @@
1
+ require 'rexml/text'
2
+
3
+ # format the response and handle / convert the result hash
4
+ # it's used throughout the whole ElasticApi library when a `response`
5
+ # has to be returned
6
+ module Wirecard
7
+ module Elastic
8
+ module Utils
9
+ class ResponseFormat
10
+
11
+ # will force symbol conversion for those specific methods calls
12
+ # *method.status will return a symbol
13
+ # *method.anything will return the raw value
14
+ # NOTE : `transaction_type` isn't here because we don't want to turn `refund-purchase` into `refund_purchase`
15
+ # we use UNDERSCORE_MAP for that
16
+ SYMBOLS_MAP = [:request_status, :transaction_type, :transaction_state, :payment_method]
17
+ UNDERSCORE_MAP = [:request_status, :transaction_state, :payment_method]
18
+
19
+ attr_reader :origin, :raw
20
+
21
+ # .to_call will convert the `method_name` into
22
+ # the raw method matching to it and sybmolize
23
+ class << self
24
+ def to_call(method_name)
25
+ "raw_#{method_name}".to_sym
26
+ end
27
+ end
28
+
29
+ def initialize(origin, raw)
30
+ @origin = origin
31
+ @raw = raw
32
+ end
33
+
34
+ # we are calling the different raw_* methods
35
+ # if someone tries to access an unknown method
36
+ # it can also convert some strings responses
37
+ # into symbols on the way
38
+ # TODO : could be refactored (chaining if are bad.)
39
+ def method_missing(method_symbol, *arguments, &block)
40
+ to_call = ResponseFormat.to_call(method_symbol)
41
+ if self.respond_to?(to_call)
42
+ response = self.send(to_call)
43
+ if SYMBOLS_MAP.include?(method_symbol)
44
+ if UNDERSCORE_MAP.include?(method_symbol)
45
+ symbolize_data(underscore_data(response))
46
+ else
47
+ symbolize_data(response)
48
+ end
49
+ else
50
+ response
51
+ end
52
+ end
53
+ end
54
+
55
+ def raw_request_id; cycle(:"request-id"); end
56
+ def raw_request_status; cycle(:statuses, :status, 0, :severity); end
57
+ def raw_requested_amount; cycle(:"requested-amount", :value); end
58
+ # raw_currency original
59
+ def raw_requested_amount_currency; cycle(:"requested-amount", :currency); end
60
+ def raw_transaction_id; cycle(:"transaction-id"); end
61
+ def raw_transaction_type; cycle(:"transaction-type"); end
62
+ # raw_status originaly (TO TEST A LOT BEFORE TO REMOVE THIS COMMENT)
63
+ def raw_transaction_state; cycle(:"transaction-state"); end
64
+ def raw_payment_method; cycle(:"payment-methods", :"payment-method", 0, :name); end
65
+
66
+ private
67
+
68
+ # cool method to try to go through a hash, could be WAY improved
69
+ # but who got time for that ?
70
+ def cycle(*elements)
71
+ position = raw[:payment] || raw[:payment]&.[](:"merchant-account-id")
72
+ elements.each do |element|
73
+ position = position&.[](element)
74
+ return position if position.nil?
75
+ end
76
+ position
77
+ end
78
+
79
+ # convert the data to a symbol
80
+ def symbolize_data(data)
81
+ data.to_s.to_sym
82
+ end
83
+
84
+ def underscore_data(data)
85
+ data.to_s.gsub("-", "_")
86
+ end
87
+
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,47 @@
1
+ require 'rexml/text'
2
+
3
+ # build a XML from a template and some variables
4
+ # output a string
5
+ module Wirecard
6
+ module Elastic
7
+ module Utils
8
+ class XmlBuilder
9
+
10
+ TEMPLATE_FORMAT = "UTF-8".freeze
11
+ TEMPLATE_PATH = "../../templates/".freeze
12
+
13
+ attr_reader :template_name, :request
14
+
15
+ # template_name is contained in /templates/
16
+ # the request matches the variables to convert (in hash) e.g. :refund
17
+ def initialize(template_name, request)
18
+ @template_name = template_name
19
+ @request = request
20
+ end
21
+
22
+ # actually convert the file into a full XML with processed variables
23
+ def to_xml
24
+ xml_template = File.open(template_path, "r:#{TEMPLATE_FORMAT}", &:read)
25
+ xml_template.gsub(/{{\w+}}/, request_params)
26
+ end
27
+
28
+ private
29
+
30
+ def request_params
31
+ request.each_with_object({}) do |(k,v), h|
32
+ h["{{#{k.upcase}}}"] = REXML::Text.new(v.to_s)
33
+ end
34
+ end
35
+
36
+ def template_path
37
+ File.expand_path "#{TEMPLATE_PATH}#{template_file}", __FILE__
38
+ end
39
+
40
+ def template_file
41
+ "#{template_name}.xml"
42
+ end
43
+
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,5 @@
1
+ module Wirecard
2
+ module Elastic
3
+ VERSION = "0.1.1"
4
+ end
5
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'wirecard/elastic/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "wirecard-elastic"
8
+ spec.version = Wirecard::Elastic::VERSION
9
+ spec.authors = ["Loschcode"]
10
+ spec.email = ["laurent.schaffner.code@gmail.com"]
11
+
12
+ spec.summary = "Wirecard support for Elastic Api"
13
+ spec.description = "Wirecard support for Elastic Api"
14
+ spec.homepage = "https://github.com/Loschcode/wirecard-elastic"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.12"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "pry-rails"
24
+ spec.add_development_dependency "rspec"
25
+
26
+ spec.add_dependency "activesupport"
27
+
28
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wirecard-elastic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Loschcode
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-10-25 00:00:00.000000000 Z
11
+ date: 2016-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,48 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry-rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
41
83
  description: Wirecard support for Elastic Api
42
84
  email:
43
85
  - laurent.schaffner.code@gmail.com
@@ -45,8 +87,26 @@ executables: []
45
87
  extensions: []
46
88
  extra_rdoc_files: []
47
89
  files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - Gemfile
48
93
  - README.md
49
- homepage: https://github.com/Loschcode/wirecard-elastic-api
94
+ - Rakefile
95
+ - bin/console
96
+ - bin/setup
97
+ - lib/wirecard/elastic.rb
98
+ - lib/wirecard/elastic/base.rb
99
+ - lib/wirecard/elastic/configuration.rb
100
+ - lib/wirecard/elastic/error.rb
101
+ - lib/wirecard/elastic/refund.rb
102
+ - lib/wirecard/elastic/templates/refund.xml
103
+ - lib/wirecard/elastic/transaction.rb
104
+ - lib/wirecard/elastic/utils/request.rb
105
+ - lib/wirecard/elastic/utils/response_format.rb
106
+ - lib/wirecard/elastic/utils/xml_builder.rb
107
+ - lib/wirecard/elastic/version.rb
108
+ - wirecard-elastic.gemspec
109
+ homepage: https://github.com/Loschcode/wirecard-elastic
50
110
  licenses: []
51
111
  metadata: {}
52
112
  post_install_message: