transact_pro 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 645ba37a51c3535eeab929d2f895de23781a90fd
4
+ data.tar.gz: 538bfa9d7043a9c363621cc09e1d0bf229783411
5
+ SHA512:
6
+ metadata.gz: 942111d185f8a9788f57f5e046561cc09e60930a77d7befd9c71eaa93877632428562197184dd3d5e5817c5ed198727047254a70d3ac2d1e11a465b6e6e2de4d
7
+ data.tar.gz: b73c4b1102249947015b3f5f10a86a31bc159a49bd1b67f5740997944809913bb3cfb13c2a8013c78712d5c45f0508acf690a24b9041915887f8ed0ed225d567
@@ -0,0 +1,27 @@
1
+ version: 2
2
+ jobs:
3
+ build:
4
+ working_directory: ~/transact_pro
5
+ docker:
6
+ #- image: circleci/ruby:2.1.10
7
+ - image: circleci/ruby@sha256:e49f95920f6294593e99cd6401556a36a8b47703b5bdac0b094b66ae1cdd6569
8
+ timezone: "Europe/Riga"
9
+ environment:
10
+ USER_IP: "78.23.51.103"
11
+
12
+ steps:
13
+ - checkout
14
+
15
+ - run: gem install bundler -v 1.16.0 --no-doc
16
+
17
+ - restore_cache:
18
+ key: transact_pro-v1-{{ checksum "Gemfile.lock" }}
19
+
20
+ - run: bundle install --path vendor/bundle
21
+
22
+ - save_cache:
23
+ key: transact_pro-v1-{{ checksum "Gemfile.lock" }}
24
+ paths:
25
+ - vendor/bundle
26
+
27
+ - run: bundle exec rspec
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at augusts.bautra@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in transact_pro.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,89 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ transact_pro (0.9.0)
5
+ rest-client (~> 2.0.2)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ addressable (2.5.2)
11
+ public_suffix (>= 2.0.2, < 4.0)
12
+ coderay (1.1.2)
13
+ coveralls (0.7.1)
14
+ multi_json (~> 1.3)
15
+ rest-client
16
+ simplecov (>= 0.7)
17
+ term-ansicolor
18
+ thor
19
+ crack (0.4.3)
20
+ safe_yaml (~> 1.0.0)
21
+ diff-lcs (1.3)
22
+ docile (1.1.5)
23
+ domain_name (0.5.20170404)
24
+ unf (>= 0.0.5, < 1.0.0)
25
+ hashdiff (0.3.7)
26
+ http-cookie (1.0.3)
27
+ domain_name (~> 0.5)
28
+ json (2.1.0)
29
+ method_source (0.9.0)
30
+ mime-types (3.1)
31
+ mime-types-data (~> 3.2015)
32
+ mime-types-data (3.2016.0521)
33
+ multi_json (1.12.2)
34
+ netrc (0.11.0)
35
+ pry (0.11.3)
36
+ coderay (~> 1.1.0)
37
+ method_source (~> 0.9.0)
38
+ public_suffix (2.0.5)
39
+ rake (10.5.0)
40
+ rest-client (2.0.2)
41
+ http-cookie (>= 1.0.2, < 2.0)
42
+ mime-types (>= 1.16, < 4.0)
43
+ netrc (~> 0.8)
44
+ rspec (3.7.0)
45
+ rspec-core (~> 3.7.0)
46
+ rspec-expectations (~> 3.7.0)
47
+ rspec-mocks (~> 3.7.0)
48
+ rspec-core (3.7.1)
49
+ rspec-support (~> 3.7.0)
50
+ rspec-expectations (3.7.0)
51
+ diff-lcs (>= 1.2.0, < 2.0)
52
+ rspec-support (~> 3.7.0)
53
+ rspec-mocks (3.7.0)
54
+ diff-lcs (>= 1.2.0, < 2.0)
55
+ rspec-support (~> 3.7.0)
56
+ rspec-support (3.7.0)
57
+ safe_yaml (1.0.4)
58
+ simplecov (0.15.1)
59
+ docile (~> 1.1.0)
60
+ json (>= 1.8, < 3)
61
+ simplecov-html (~> 0.10.0)
62
+ simplecov-html (0.10.2)
63
+ term-ansicolor (1.6.0)
64
+ tins (~> 1.0)
65
+ thor (0.20.0)
66
+ tins (1.16.3)
67
+ unf (0.1.4)
68
+ unf_ext
69
+ unf_ext (0.0.7.4)
70
+ webmock (3.2.1)
71
+ addressable (>= 2.3.6)
72
+ crack (>= 0.3.2)
73
+ hashdiff
74
+
75
+ PLATFORMS
76
+ ruby
77
+
78
+ DEPENDENCIES
79
+ bundler (~> 1.16)
80
+ coveralls (~> 0.7.1)
81
+ pry (~> 0.11.3)
82
+ rake (~> 10.0)
83
+ rspec (~> 3.7)
84
+ simplecov (~> 0.15.1)
85
+ transact_pro!
86
+ webmock
87
+
88
+ BUNDLED WITH
89
+ 1.16.1
data/LICENSE.txt ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-clause "New" or "Revised" License
2
+
3
+ Copyright (c) 2017 Creative.gs . All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without modification,
6
+ are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice,
9
+ this list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation and/or
13
+ other materials provided with the distribution.
14
+
15
+ 3. Neither the name of Creative.gs, TransactPro, 1stpayments.new nor the names of its contributors
16
+ may be used to endorse or promote products derived from this software without
17
+ specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY Creative.gs AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,145 @@
1
+ [![Version](https://badge.fury.io/rb/transact_pro.svg)](https://badge.fury.io/rb/transact_pro)
2
+ [![Build](https://circleci.com/gh/CreativeGS/transact_pro/tree/master.svg?style=shield)](https://circleci.com/gh/CreativeGS/transact_pro/tree/master)
3
+ [![Coverage](https://coveralls.io/repos/github/CreativeGS/transact_pro/badge.svg?branch=master)](https://coveralls.io/github/CreativeGS/transact_pro?branch=master)
4
+
5
+ # TransactPro
6
+ Lightweight Ruby wrapper for communicating with TransactPro 1stpayments.net card payment API.
7
+
8
+ ### What can this gem do?
9
+ Currently core functionality is supported - single and recurring SMS payments with card details entered gateway-side (zero hassle with [PCI compliance](https://www.pcisecuritystandards.org)), and payment outcome check request.
10
+ As of v1.0.0 (2018-01-04) the full functionality status list is:
11
+
12
+ | Functionality | method name | Page in doc | Support in gem | response data |
13
+ |---|---|---|---|---|
14
+ | SMS transaction init, card details entered merchant-side | *init | 12 | ✗ | - |
15
+ | SMS transaction init, card details entered gateway-side | *init | 21 | ✓ | `tid` & `redirect link` |
16
+ | SMS transaction init with card data save flag, card details entered gateway-side | *init_recurring_registration | 42 | ✓ | - |
17
+ | DMS init, card details entered merchant-side | make_hold | 37 | ✗ | - |
18
+ | DMS init, card details entered gateway-side | init_dms | 37 | ✗ | - |
19
+ | DMS execute | charge_hold | 37 | ✗ | - |
20
+ | Save card details for subsequent recurring payments, details entered gateway-side | init_store_card_sms | 45 | ✗ | - |
21
+ | Recurrent SMS, init a recurring payment | init_recurrent | 46 | ✓ | `tid` |
22
+ | Recurrent SMS, execute a recurring payment | charge_recurrent | 48 | ✓ | Status:Success... |
23
+ | Credit transaction init | init_credit | 17 | ✗ | - |
24
+ | Credit transaction execute | do_credit | 17 | ✗ | - |
25
+ | P2P transaction init | init_p2p | 18 | ✗ | - |
26
+ | P2P transaction execute | do_p2p | 18 | ✗ | - |
27
+ | MOTO transaction init | **moto_init | 48 | ✗ | - |
28
+ | MOTO payment execute | **moto_charge | 48 | ✗ | - |
29
+ | Payment cancellation | cancel_request | 23 | ✗ | - |
30
+ | DMS cancellation | cancel_dms | 38 | ✗ | - |
31
+ | Payment execution (charge) | charge | 24 | ✗ | - |
32
+ | Payment status request | status_request | 31 | ✓ | Status:Success... |
33
+ | Payment refund | ***refund | 34 | ✗ | "Refund Success" |
34
+ | Card verification | verify_card | 39 | ✗ | - |
35
+ | Terminal Limits | get_terminal_limits | 41 | ✗ | - |
36
+ | Reconciled Transactions | rt_api | 43 | ✗ | - |
37
+
38
+ *init request is the same for both card data entry strategies, since the receiving Merchant __Account__ determines what sort of response to give.
39
+ **moto methods are recurring payments performed on card data saved in a special manner. They use `init` and `charge` endpoints with tweaked parameters.
40
+ ***refunding can be done via the panel in merchantarea.
41
+
42
+ ## Installation
43
+ Bundle or manually install the latest version of the gem:
44
+
45
+ ```ruby
46
+ gem 'transact_pro'
47
+ ```
48
+
49
+ ## Usage
50
+ The gem implements `gateway`, `request` and `response` objects that handle communication with the remote API for you.
51
+ All communication is done synchroniously and without failsafes, so if something goes wrong during the remote request (HTTP timeout etc.), you get the raw error and get to handle it.
52
+
53
+ Please note that in this gem all configuration option hash keys are constant-case symbols like `:GUID` whereas all parameter keys for requests to the API are snake-case symbols like `:merchant_transaction_id`.
54
+
55
+ ### 1. `TransactPro::Gateway`
56
+
57
+ ![TransactPro account structure](assets/account_structure.png)
58
+
59
+ The gateway object encapsulates a _Merchant_ with GUID and a password, and at least one _Account_ with a routing string.
60
+
61
+ To this end, initialize gateway instances like so:
62
+
63
+ ```rb
64
+ options = {
65
+ TEST: false, # defaults to false, pass `true` if you want the gem to make requests to the sandbox endpoints
66
+ API_URI: "https://something.new" # gem has the endpoint uri in defaults, you may only need this if the domains used suddeny change
67
+ GUID: "CAZY-7319-WI00-0C40", # mandatory
68
+ PASSWORD: "g44B/pAENO2E", # mandatory
69
+ ACCOUNT_3D: "CS01", # default routing string of Account to be used for 3D transactions
70
+ ACCOUNT_NON3D: "CS02", # default routing string of Account to be used for non-3D transactions
71
+ ACCOUNT_RECURRING: "CS03", # default routing string of Account to be used for recurring payment execution
72
+ custom_return_url: "https://www.example.com/pay/transactpro/response?merchant_transaction_id=ZZZZZZZ" # can be overridden in transaction init request
73
+ custom_callback_url: "https://www.example.com/pay/transactpro/response?merchant_transaction_id=ZZZZZZZ" # can be overridden in transaction init request
74
+ }
75
+
76
+ gateway = TransactPro::Gateway.new(options)
77
+ ```
78
+
79
+ ### 2. `TransactPro::Request`
80
+
81
+ Use the `Gateway` instance's `#request` method to perform requests.
82
+
83
+ ```rb
84
+ options = {
85
+ method: :status_request, # mandatory, exclusively symbol objects for value
86
+ request_type: 'transaction_status',
87
+ init_transaction_id: "abc123",
88
+ # Note that passing :guid and :pwd is possible and `#call` will always override any defaults with the latest passed values, but generally you should rely on these values being set correctly from GUID and PASSWORD in gateway configuration.
89
+ guid: "..."
90
+ pwd: "..."
91
+ # Note that :rs is optional and will be inferred from gateway defaults, preferring 3D accounts to NON3D, where applicable.
92
+ rs: "..."
93
+ }
94
+
95
+ request_instance = gateway.request(options)
96
+ request_instance.call #=> response
97
+
98
+ # TransactPro::Request instances also have #to_s method to inspect what parameters are used in the request.
99
+ ```
100
+
101
+ ### 3. `TransactPro::Response`
102
+ `Response` objects are thin wrappers around the response bodies received from communicating with the TransactPro API.
103
+ Use `#to_s` on them to get the raw body and do any handling yourslef.
104
+ The gem provides a couple methods for ease of use:
105
+
106
+ ```rb
107
+ response = request_instance.call
108
+
109
+ response.redirect_link #=> "https://..." link to redirect users to for checkout, nil if not applicable
110
+
111
+ response.status #=> "OK" if all went well, "FAIL" if a payment status response and it did not go through, "ERROR" if API said request was bad
112
+
113
+ response.tid #=> the 40-symbol long hexdigit transaction ID, nil if not applicable
114
+
115
+ response.to_s #=> raw body
116
+
117
+ response.to_h #=> splits the response on "~" and then on first ":" to make key-value pairs, string keys!
118
+ ```
119
+
120
+ ## Contributing
121
+ Bug reports and pull requests are welcome on GitHub at https://github.com/CreativeGS/transact_pro. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
122
+
123
+ The project uses TDD approach to software development, follow these steps to set up:
124
+ 1. fork and clone the repo on github
125
+ 2. Install appropriate Ruby and Bundler
126
+ 3. `bundle`
127
+ 4. See if all specs are green with `rspec`
128
+ 5. (optional) Run specs with `USE_LIVE_SANDBOX=true rspec` to disable mocking of remote requests and make live requests to sandbox instead.
129
+ 5. TDD new features
130
+ 6. Make a Pull Request in github
131
+
132
+ ## Releasing a new version
133
+
134
+ ```
135
+ gem push # to set credentials
136
+ rake release
137
+ ```
138
+
139
+ ## License
140
+
141
+ The gem is available as open source under the terms of the [BSD-3-Clause License](https://opensource.org/licenses/BSD-3-Clause).
142
+
143
+ ## Code of Conduct
144
+
145
+ Everyone interacting in the TransactPro project’s codebases and issue trackers is expected to follow the [code of conduct](https://github.com/CreativeGS/transact_pro/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
Binary file
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "transact_pro"
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(__FILE__)
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,26 @@
1
+ require "digest"
2
+ require "rest-client"
3
+
4
+ require "transact_pro/request_specs"
5
+ require "transact_pro/gateway"
6
+ require "transact_pro/request"
7
+ require "transact_pro/response"
8
+ require "transact_pro/version"
9
+
10
+ module TransactPro
11
+ extend self
12
+
13
+ DEFAULTS = {
14
+ TEST: false,
15
+ PRODUCTION_ENV: {
16
+ API_URI: "https://www2.1stpayments.net/gwprocessor2.php"
17
+ },
18
+ TEST_ENV: {
19
+ API_URI: "https://gw2sandbox.tpro.lv:8443/gw2test/gwprocessor2.php"
20
+ }
21
+ }.freeze
22
+
23
+ def root
24
+ @@root ||= Pathname.new(Gem::Specification.find_by_name("transact_pro").gem_dir)
25
+ end
26
+ end
@@ -0,0 +1,34 @@
1
+ class TransactPro::Gateway
2
+ attr_reader :options
3
+
4
+ def initialize(options)
5
+ test = TransactPro::DEFAULTS[:TEST] || !!options[:TEST]
6
+
7
+ env_key = (test ? :TEST_ENV : :PRODUCTION_ENV)
8
+
9
+ @options = {
10
+ TEST: test,
11
+ API_URI: TransactPro::DEFAULTS[env_key][:API_URI],
12
+ pwd: Digest::SHA1.hexdigest(options[:PASSWORD].to_s),
13
+ guid: options[:GUID].to_s
14
+ }
15
+
16
+ @options.merge!(options)
17
+
18
+ unless @options[:GUID].to_s[%r'\A(?:\w){4}-(?:\w){4}-(?:\w){4}-(?:\w){4}\z']
19
+ raise ArgumentError.new("'#{@options[:GUID]}' is not a valid GUID for a gateway")
20
+ end
21
+
22
+ unless @options[:PASSWORD].to_s.size > 0
23
+ raise ArgumentError.new("'#{@options[:PASSWORD]}' is not a valid PASSWORD for a gateway")
24
+ end
25
+
26
+ if @options[:ACCOUNT_3D].to_s.size < 1 && @options[:ACCOUNT_NON3D].to_s.size < 1
27
+ raise ArgumentError.new("As a minimum specify a ACCOUNT_3D or a ACCOUNT_NON3D for a gateway")
28
+ end
29
+ end
30
+
31
+ def request(request_options)
32
+ TransactPro::Request.new(options.merge(request_options))
33
+ end
34
+ end
@@ -0,0 +1,97 @@
1
+ class TransactPro::Request
2
+ class ValidationError < RuntimeError
3
+ end
4
+
5
+ SUPPORTED_METHODS = %i|
6
+ init init_recurring_registration init_recurrent charge_recurrent
7
+ status_request
8
+ |.freeze
9
+
10
+ RECURRING_METHODS = %i|init_recurrent charge_recurrent|.freeze
11
+
12
+ attr_reader :options, :method
13
+
14
+ # Do not use this default initializer!
15
+ # Instead, initialize a Gateway and call #request method on that.
16
+ def initialize(options)
17
+ @options = options
18
+ @method = @options[:method]
19
+
20
+ unless SUPPORTED_METHODS.include?(@method)
21
+ raise ArgumentError.new(
22
+ "'#{@method}' is not a supported API request method"
23
+ )
24
+ end
25
+ end
26
+
27
+ def call
28
+ @defaults ||= TransactPro::RequestSpecs.const_get(
29
+ "#{method.to_s.upcase}_DEFAULTS"
30
+ )
31
+
32
+ @request_options ||= @defaults.merge(options)
33
+ @request_options[:rs] = routing_string
34
+
35
+ @spec ||= TransactPro::RequestSpecs.const_get(
36
+ "#{method.to_s.upcase}_SPEC"
37
+ )
38
+
39
+ @postable_params = {}
40
+ @spec.each do |k, spec|
41
+ do_validation =
42
+ if spec[:mandatory]
43
+ # mandatory key, always validate
44
+ @postable_params[k] = @request_options[k]
45
+ true
46
+ else
47
+ # non-mandatory key, include and validate only if it is present
48
+ if @request_options[k].to_s.size > 0
49
+ @postable_params[k] = @request_options[k]
50
+ true
51
+ else
52
+ false
53
+ end
54
+ end
55
+
56
+ validate(k, @postable_params[k], spec[:format]) if do_validation
57
+ end
58
+
59
+ @url = "#{@request_options[:API_URI]}?a=#{sendable_method}"
60
+
61
+ @raw_response = RestClient.post(@url, @postable_params)
62
+ @response = TransactPro::Response.new(@raw_response.to_s)
63
+ end
64
+
65
+ private
66
+ def validate(key, string, regex)
67
+ unless string[regex]
68
+ raise TransactPro::Request::ValidationError.new(
69
+ ":#{key} with value '#{string}' is invalid for request, "\
70
+ "expected a match for regex #{regex.inspect}"
71
+ )
72
+ end
73
+ end
74
+
75
+ def routing_string
76
+ @routing_string =
77
+ if options[:rs].to_s.size > 0
78
+ options[:rs]
79
+ elsif recurring_method?
80
+ options[:ACCOUNT_RECURRING]
81
+ else
82
+ # a regular user-facing method, preferring 3D account
83
+ options[:ACCOUNT_3D].to_s.size > 0 ?
84
+ options[:ACCOUNT_3D] :
85
+ options[:ACCOUNT_NON3D]
86
+ end
87
+ end
88
+
89
+ def recurring_method?
90
+ RECURRING_METHODS.include?(method)
91
+ end
92
+
93
+ def sendable_method
94
+ method == :init_recurring_registration ? :init : method
95
+ end
96
+
97
+ end
@@ -0,0 +1,169 @@
1
+ module TransactPro
2
+ module RequestSpecs
3
+ # Contants ending with _SPEC here describe the request body fields
4
+ # (whether the field is mandatory and supposed format)
5
+
6
+ # set of allowed characters:
7
+ # a: alphabetic characters are the upper case letters A through Z; the lower case letters a through z, and the blank (space) character.
8
+ # h: hexadecimal number.
9
+ # n: numeric characters are the numbers zero (0) through nine (9).
10
+ # s: special printable characters are any printable characters that are neither alphabetic nor numeric,
11
+ # have an ASCII hexadecimal value greater than 20, or an EBCDIC hexadecimal value greater than 40.
12
+ # Occurrences of values ASCII 00 – 1F and EBCDIC 00 – 3F are not valid. Not all special characters are
13
+ # usually enabled. See fields’ description for details."
14
+ # u: Unicode alphabetic characters.
15
+
16
+ GUID_REGEX = %r'\A[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}\z'
17
+ PASSWORD_DIGEST_REGEX = %r'\A.{40}\z'
18
+ ROUTING_REGEX = %r'\A[[:alnum:]]{1,12}\z' # an(1..12)
19
+ MERCHANT_TRANSACTION_ID = %r'\A.{5,50}\z' # ans(5..50)
20
+ TID_REGEX = %r'\A[0-9a-f]+\z'i # h(40)
21
+ USER_IP = %r'\A
22
+ (
23
+ ([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.
24
+ ){3}
25
+ ([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])
26
+ \z'x # ns(7..15)
27
+ DESCRIPTION = %r'\A.{5,255}\z' # uns(5..255)
28
+ AMOUNT = %r'\A[1-9]\d{2,}\z' # n
29
+ CURRENCY = %r'\A[[:upper:]]{3}\z' # a(3)
30
+ NAME_ON_CARD = %r'\A.{2,100}\z' # ans(2..100)
31
+ STREET = %r'\A.{2,50}\z' # ans(2..50)
32
+ ZIP = %r'\A.{2,15}\z' # ans(2..15)
33
+ CITY = %r'\A.{2,25}\z' # ans(2..25)
34
+ COUNTRY = %r'\A[[:alpha:]]{2}\z' # a(2)
35
+ STATE = %r'\A.{2,20}\z' # ans(2..20)
36
+ EMAIL = %r'\A.{1,100}\z' # ans(1..100)
37
+ PHONE = %r'\A[0-9\-_]{5,25}\z' # ns(5..25)
38
+ CARD_BIN = %r'\A\d{6}\z' # n(6)
39
+ BIN_NAME = %r'\A.{3,50}\z' # uns(3..50)
40
+ BIN_PHONE = %r'\A[0-9\-_]{3,25}\z' # ns(3..25)
41
+ MERCHANT_SITE_URL = %r'\A.{1,255}\z' # ans(1..255)
42
+ MERCHANT_REFERRING_NAME = %r'\A.{1,21}\z' # ans(1..21)
43
+ F_EXTENDED = %r'\A\d+\z' # n
44
+
45
+ # 10. Table
46
+ # Field Format Description
47
+ # guid ans(19) Your merchant GUID.
48
+ # pwd h(40) SHA1 hash of your processing password.
49
+ # rs an(1..12) Your routing string.
50
+ # merchant_transaction_id ans(5..50) Your transaction ID, must be unique for every transaction you submit to
51
+ # the gateway. The transaction ID must be from 5 to 50 characters.
52
+ # user_ip ns(7..15) Cardholder's IP, as string (AA.BB.CC.DD).
53
+ # description uns(5..255) Order items description, from 5 to 255 characters (Example: SDHC
54
+ # Memory card x 2, AAA battery pack x 1).
55
+ # amount n Transaction amount, in MINOR units (i.e. 2150 for $21.50 transaction).
56
+ # Notice: check JPY exception notice below!
57
+ # currency a(3) Transaction currency, ISO 4217 3-character code, USD, EUR, CHF etc.
58
+ # name_on_card ans(2..100) Cardholder name, as printed on a card (pass client name if card data
59
+ # collected at gateway side)
60
+ # street ans(2..50) Cardholder address – street. (min 2 symbols)
61
+ # zip ans(2..15) Cardholder address – ZIP. (min 2 symbols)
62
+ # city as(2..25) Cardholder address – City. (min 2 symbols)
63
+ # country a(2) Cardholder address – country, 2-letter ISO 3166-1-Alpha 2 code.
64
+ # state ans(2..20) Cardholder address – state (send NA if you don't have state information).
65
+ # email ans(1..100) Cardholder address – email
66
+ # phone ns(5..25) Cardholder phone number (min. 5 symbols).
67
+ # card_bin n(6) Cardholder card BIN (first 6 characters of CC number). - not required if
68
+ # card data collected at gateway side.
69
+ # bin_name uns(3..50) Cardholder bank name (non-mandatory).
70
+ # bin_phone ns(3..25) Cardholder bank phone given on a back side of used card
71
+ # (non-mandatory).
72
+ # merchant_site_url ans(1..255) Purchase site URL.
73
+ # merchant_referring_name ans(1..21) Must not be send by default. See chapter 3.5 for description if you need
74
+ # to use it.
75
+ INIT_SPEC = {
76
+ guid: {mandatory: true, format: GUID_REGEX},
77
+ pwd: {mandatory: true, format: PASSWORD_DIGEST_REGEX},
78
+ rs: {mandatory: true, format: ROUTING_REGEX},
79
+ merchant_transaction_id: {mandatory: true, format: MERCHANT_TRANSACTION_ID},
80
+ user_ip: {mandatory: true, format: USER_IP},
81
+ description: {mandatory: true, format: DESCRIPTION},
82
+ amount: {mandatory: true, format: AMOUNT},
83
+ currency: {mandatory: true, format: CURRENCY},
84
+ name_on_card: {mandatory: true, format: NAME_ON_CARD},
85
+ street: {mandatory: true, format: STREET},
86
+ zip: {mandatory: true, format: ZIP},
87
+ city: {mandatory: true, format: CITY},
88
+ country: {mandatory: true, format: COUNTRY},
89
+ state: {mandatory: true, format: STATE},
90
+ email: {mandatory: true, format: EMAIL},
91
+ phone: {mandatory: true, format: PHONE},
92
+ card_bin: {mandatory: false, format: CARD_BIN},
93
+ bin_name: {mandatory: false, format: BIN_NAME},
94
+ bin_phone: {mandatory: false, format: BIN_PHONE},
95
+ merchant_site_url: {mandatory: true, format: MERCHANT_SITE_URL},
96
+ merchant_referring_name: {mandatory: false, format: MERCHANT_REFERRING_NAME}
97
+ }.freeze
98
+
99
+ INIT_DEFAULTS = {
100
+ name_on_card: "John Doe",
101
+ street: "NA", zip: "NA", city: "NA", country: "NA", state: "NA",
102
+ email: "john_doe@example.com", phone: "00371000000"
103
+ }.freeze
104
+
105
+ INIT_RECURRING_REGISTRATION_SPEC = INIT_SPEC.
106
+ dup.merge(save_card: {mandatory: true, format: %r'\d+'}).freeze
107
+ INIT_RECURRING_REGISTRATION_DEFAULTS = INIT_DEFAULTS.
108
+ dup.merge(save_card: "1").freeze
109
+
110
+ # 32. Table
111
+ # Field Format Description
112
+ # guid ans(19) Your merchant GUID
113
+ # pwd h(40) SHA1 hash of your processing password
114
+ # rs an(1..12) Routing string
115
+ # original_init_id h(40) init_transaction_id of your original transaction
116
+ # merchant_transaction_id ans(5..50) Your transaction ID
117
+ # amount n Transaction amount, in MINOR units (i.e. 2150 for $21.50 transaction)
118
+ # description uns(5..255) Order items description
119
+ INIT_RECURRENT_SPEC = {
120
+ guid: {mandatory: true, format: GUID_REGEX},
121
+ pwd: {mandatory: true, format: PASSWORD_DIGEST_REGEX},
122
+ rs: {mandatory: true, format: ROUTING_REGEX},
123
+ original_init_id: {mandatory: true, format: TID_REGEX},
124
+ merchant_transaction_id: {mandatory: true, format: MERCHANT_TRANSACTION_ID},
125
+ amount: {mandatory: true, format: AMOUNT},
126
+ description: {mandatory: true, format: DESCRIPTION},
127
+ }.freeze
128
+
129
+ INIT_RECURRENT_DEFAULTS = {
130
+ # none
131
+ }.freeze
132
+
133
+ # 34. Table
134
+ # Field Format Description
135
+ # init_transaction_id h(40) init_transaction_id received for this recurrent transaction
136
+ # f_extended n Return extended charge details (optional)
137
+ CHARGE_RECURRENT_SPEC = {
138
+ guid: {mandatory: true, format: GUID_REGEX},
139
+ pwd: {mandatory: true, format: PASSWORD_DIGEST_REGEX},
140
+ init_transaction_id: {mandatory: true, format: TID_REGEX},
141
+ f_extended: {mandatory: false, format: F_EXTENDED},
142
+ }.freeze
143
+
144
+ CHARGE_RECURRENT_DEFAULTS = {
145
+ f_extended: "100" # determines the verbosity of responses
146
+ }.freeze
147
+
148
+ # 19. Table
149
+ # Field Format Value
150
+ # request_type as 'transaction_status'
151
+ # init_transaction_id h(40) Gateway Transaction ID
152
+ # f_extended n Return extended charge details, see section 2.4 of this manual for more details
153
+ # (optional)
154
+ # guid ans(19) Your GUID
155
+ # pwd h(40) SHA1 hash of your processing password
156
+ STATUS_REQUEST_SPEC = {
157
+ guid: {mandatory: true, format: GUID_REGEX},
158
+ pwd: {mandatory: true, format: PASSWORD_DIGEST_REGEX},
159
+ request_type: {mandatory: true, format: 'transaction_status'},
160
+ init_transaction_id: {mandatory: true, format: TID_REGEX},
161
+ f_extended: {mandatory: false, format: F_EXTENDED}
162
+ }.freeze
163
+
164
+ STATUS_REQUEST_DEFAULTS = {
165
+ request_type: 'transaction_status',
166
+ f_extended: "100", # determines the verbosity of responses
167
+ }.freeze
168
+ end
169
+ end
@@ -0,0 +1,57 @@
1
+ class TransactPro::Response
2
+ attr_reader :body
3
+
4
+ def initialize(body)
5
+ @body = body
6
+ end
7
+
8
+ def to_s
9
+ body
10
+ end
11
+
12
+ def to_h
13
+ @to_h ||= body.split("~").inject({}) do |mem, portion|
14
+ match = portion.match(%r'\A([^\:]+?)\:(.*)')
15
+ mem[match[1]] = match[2]
16
+ mem
17
+ end
18
+ end
19
+
20
+ def redirect_link
21
+ link_portion = body.split("~").detect do |portion|
22
+ portion[%r'\ARedirectOnsite:']
23
+ end
24
+
25
+ link_portion.nil? ?
26
+ nil :
27
+ link_portion.match(%r'\ARedirectOnsite:(https?://.*?tid=[[:alnum:]]+)'i)[1]
28
+ end
29
+
30
+ def status
31
+ status_portion = body.split("~").detect do |portion|
32
+ portion[%r'\A(OK)|(Status)\:']
33
+ end
34
+
35
+ if status_portion.nil?
36
+ "ERROR"
37
+ elsif status_portion[%r'\AOK']
38
+ "OK"
39
+ elsif status_portion[%r'\AStatus']
40
+ status = status_portion.match(%r'\AStatus:(.*)')[1]
41
+ status == "Success" ? "OK" : "FAIL"
42
+ else
43
+ "ERROR"
44
+ end
45
+ end
46
+
47
+ def tid
48
+ tid_portion = body.split("~").detect do |portion|
49
+ portion[%r'\AOK\:']
50
+ end
51
+
52
+ tid_portion.nil? ?
53
+ nil :
54
+ tid_portion.match(%r'\A(.*?)\:(.*)')[2]
55
+ end
56
+
57
+ end
@@ -0,0 +1,3 @@
1
+ module TransactPro
2
+ VERSION = "0.9.0"
3
+ end
@@ -0,0 +1,35 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "transact_pro/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "transact_pro"
8
+ spec.required_ruby_version = '>= 2'
9
+ spec.date = "2018-01-04"
10
+ spec.version = TransactPro::VERSION
11
+ spec.authors = ["Epigene"]
12
+ spec.email = ["cto@creative.gs", "augusts.bautra@gmail.com"]
13
+
14
+ spec.summary = "Ruby wrapper for communicating with TransactPro 1stpayments.net card payment API."
15
+ spec.homepage = "https://github.com/CreativeGS/transact_pro"
16
+ spec.license = "BSD-3-Clause"
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+ spec.bindir = "exe"
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_dependency "rest-client", "~> 2.0.2"
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.16"
28
+ spec.add_development_dependency "rake", "~> 10.0"
29
+ spec.add_development_dependency "rspec", "~> 3.7"
30
+ spec.add_development_dependency "webmock"#, "~> 3.7"
31
+ spec.add_development_dependency "pry", "~> 0.11.3"
32
+ spec.add_development_dependency "simplecov", "~> 0.15.1"
33
+ spec.add_development_dependency "coveralls", "~> 0.7.1"
34
+
35
+ end
metadata ADDED
@@ -0,0 +1,177 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: transact_pro
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - Epigene
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-01-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.16'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.16'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '10.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: '3.7'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '3.7'
69
+ - !ruby/object:Gem::Dependency
70
+ name: webmock
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: 0.11.3
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: 0.11.3
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: 0.15.1
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: 0.15.1
111
+ - !ruby/object:Gem::Dependency
112
+ name: coveralls
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: 0.7.1
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ version: 0.7.1
125
+ description:
126
+ email:
127
+ - cto@creative.gs
128
+ - augusts.bautra@gmail.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - .circleci/config.yml
134
+ - .gitignore
135
+ - .rspec
136
+ - CODE_OF_CONDUCT.md
137
+ - Gemfile
138
+ - Gemfile.lock
139
+ - LICENSE.txt
140
+ - README.md
141
+ - Rakefile
142
+ - assets/account_structure.png
143
+ - bin/console
144
+ - bin/setup
145
+ - lib/transact_pro.rb
146
+ - lib/transact_pro/gateway.rb
147
+ - lib/transact_pro/request.rb
148
+ - lib/transact_pro/request_specs.rb
149
+ - lib/transact_pro/response.rb
150
+ - lib/transact_pro/version.rb
151
+ - transact_pro.gemspec
152
+ homepage: https://github.com/CreativeGS/transact_pro
153
+ licenses:
154
+ - BSD-3-Clause
155
+ metadata: {}
156
+ post_install_message:
157
+ rdoc_options: []
158
+ require_paths:
159
+ - lib
160
+ required_ruby_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - '>='
163
+ - !ruby/object:Gem::Version
164
+ version: '2'
165
+ required_rubygems_version: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - '>='
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ requirements: []
171
+ rubyforge_project:
172
+ rubygems_version: 2.4.8
173
+ signing_key:
174
+ specification_version: 4
175
+ summary: Ruby wrapper for communicating with TransactPro 1stpayments.net card payment
176
+ API.
177
+ test_files: []